From 8584e8909ff2eed746a6c5f4077688e1c4070c70 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Fri, 18 Jul 2025 15:41:06 -0400 Subject: [PATCH 001/199] Update mfc python and cmake to support OpenMP --- CMakeLists.txt | 40 ++++++++++++++++++++++++++++------------ toolchain/mfc/args.py | 9 +++++++-- toolchain/mfc/build.py | 6 +++++- toolchain/mfc/state.py | 26 ++++++++++++++++++++++---- 4 files changed, 62 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8269c1cb48..4c7a35187f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ project(MFC LANGUAGES C CXX Fortran) option(MFC_MPI "Build with MPI" ON) option(MFC_OpenACC "Build with OpenACC" OFF) +option(MFC_OpenMP "Build with OpenMP" OFF) option(MFC_GCov "Build with GCov" OFF) option(MFC_Unified "Build with unified CPU & GPU memory (GH-200 only)" OFF) option(MFC_PRE_PROCESS "Build pre_process" OFF) @@ -393,7 +394,7 @@ HANDLE_SOURCES(syscheck OFF) # being used. function(MFC_SETUP_TARGET) - cmake_parse_arguments(ARGS "OpenACC;MPI;SILO;HDF5;FFTW" "TARGET" "SOURCES" ${ARGN}) + cmake_parse_arguments(ARGS "OpenACC;MPI;SILO;HDF5;FFTW;OpenMP" "TARGET" "SOURCES" ${ARGN}) add_executable(${ARGS_TARGET} ${ARGS_SOURCES}) set(IPO_TARGETS ${ARGS_TARGET}) @@ -447,7 +448,7 @@ function(MFC_SETUP_TARGET) endif() if (ARGS_FFTW) - if (MFC_OpenACC AND ARGS_OpenACC) + if ((MFC_OpenACC AND ARGS_OpenACC) OR (MFC_OpenMP AND ARGS_OpenMP)) if (CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC" OR CMAKE_Fortran_COMPILER_ID STREQUAL "PGI") find_package(CUDAToolkit REQUIRED) target_link_libraries(${a_target} PRIVATE CUDA::cudart CUDA::cufft) @@ -461,16 +462,31 @@ function(MFC_SETUP_TARGET) endif() endif() - if (MFC_OpenACC AND ARGS_OpenACC) - find_package(OpenACC) + if ((MFC_OpenACC AND ARGS_OpenACC) OR (MFC_OpenMP AND ARGS_OpenMP)) + if ((MFC_OpenACC AND ARGS_OpenACC)) + find_package(OpenACC) - # This should be equivalent to if (NOT OpenACC_FC_FOUND) - if (NOT TARGET OpenACC::OpenACC_Fortran) - message(FATAL_ERROR "OpenACC + Fortran is unsupported.") - endif() + # This should be equivalent to if (NOT OpenACC_FC_FOUND) + if (NOT TARGET OpenACC::OpenACC_Fortran) + message(FATAL_ERROR "OpenACC + Fortran is unsupported.") + endif() - target_link_libraries(${a_target} PRIVATE OpenACC::OpenACC_Fortran) - target_compile_definitions(${a_target} PRIVATE MFC_OpenACC) + target_link_libraries(${a_target} PRIVATE OpenACC::OpenACC_Fortran) + target_compile_definitions(${a_target} PRIVATE MFC_OpenACC MFC_GPU) + elseif((MFC_OpenMP AND ARGS_OpenMP)) + find_package(OpenMP) + + # This should be equivalent to if (NOT OpenACC_FC_FOUND) + if (NOT TARGET OpenMP::OpenMP_Fortran) + message(FATAL_ERROR "OpenMP + Fortran is unsupported.") + endif() + + target_link_libraries(${a_target} PRIVATE OpenMP::OpenMP_Fortran) + target_compile_definitions(${a_target} PRIVATE MFC_OpenMP MFC_GPU) + if(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC" OR CMAKE_Fortran_COMPILER_ID STREQUAL "PGI") + target_compile_options(${a_target} PRIVATE "-mp=gpu") + endif() + endif() if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") # FIXME: This should work with other cards than gfx90a ones. @@ -535,7 +551,7 @@ endif() if (MFC_SIMULATION) MFC_SETUP_TARGET(TARGET simulation SOURCES "${simulation_SRCs}" - MPI OpenACC FFTW) + MPI FFTW OpenACC OpenMP) endif() if (MFC_POST_PROCESS) @@ -550,7 +566,7 @@ endif() if (MFC_SYSCHECK) MFC_SETUP_TARGET(TARGET syscheck SOURCES "${syscheck_SRCs}" - MPI OpenACC) + MPI OpenACC OpenMP) endif() if (MFC_DOCUMENTATION) diff --git a/toolchain/mfc/args.py b/toolchain/mfc/args.py index d3de6769c3..b73bf93763 100644 --- a/toolchain/mfc/args.py +++ b/toolchain/mfc/args.py @@ -4,9 +4,10 @@ from .build import TARGETS, DEFAULT_TARGETS from .common import MFCException, format_list_to_string from .test.cases import list_cases +from .state import gpuConfigOptions, MFCConfig # pylint: disable=too-many-locals, too-many-branches, too-many-statements -def parse(config): +def parse(config: MFCConfig): parser = argparse.ArgumentParser( prog="./mfc.sh", description="""\ @@ -46,7 +47,7 @@ def parse(config): compare.add_argument("-rel", "--reltol", metavar="RELTOL", type=float, default=1e-12, help="Relative tolerance.") compare.add_argument("-abs", "--abstol", metavar="ABSTOL", type=float, default=1e-12, help="Absolute tolerance.") - def add_common_arguments(p, mask = None): + def add_common_arguments(p: argparse.ArgumentParser, mask = None): if mask is None: mask = "" @@ -57,6 +58,10 @@ def add_common_arguments(p, mask = None): if "m" not in mask: for f in dataclasses.fields(config): + if f.name == 'gpu': + p.add_argument(f"--{f.name}", action="store", nargs='?', default=gpuConfigOptions.ACC.value, choices=[e.value for e in gpuConfigOptions]) + p.add_argument(f"--no-{f.name}", action="store_const", const = gpuConfigOptions.NONE.value, dest=f.name, help=f"Turn the {f.name} option OFF.") + continue p.add_argument( f"--{f.name}", action="store_true", help=f"Turn the {f.name} option ON.") p.add_argument(f"--no-{f.name}", action="store_false", dest=f.name, help=f"Turn the {f.name} option OFF.") diff --git a/toolchain/mfc/build.py b/toolchain/mfc/build.py index 2de738986d..422f400154 100644 --- a/toolchain/mfc/build.py +++ b/toolchain/mfc/build.py @@ -6,6 +6,7 @@ format_list_to_string from .state import ARG, CFG from .run import input +from .state import gpuConfigOptions @dataclasses.dataclass class MFCTarget: @@ -141,7 +142,10 @@ def configure(self, case: Case): if not self.isDependency: flags.append(f"-DMFC_MPI={ 'ON' if ARG('mpi') else 'OFF'}") - flags.append(f"-DMFC_OpenACC={'ON' if ARG('gpu') else 'OFF'}") + # flags.append(f"-DMFC_OpenACC={'ON' if ARG('acc') else 'OFF'}") + # flags.append(f"-DMFC_OpenMP={'ON' if ARG('mp') else 'OFF'}") + flags.append(f"-DMFC_OpenACC={'ON' if (ARG('gpu') == gpuConfigOptions.ACC.value) else 'OFF'}") + flags.append(f"-DMFC_OpenMP={'ON' if (ARG('gpu') == gpuConfigOptions.MP.value) else 'OFF'}") flags.append(f"-DMFC_GCov={ 'ON' if ARG('gcov') else 'OFF'}") flags.append(f"-DMFC_Unified={'ON' if ARG('unified') else 'OFF'}") diff --git a/toolchain/mfc/state.py b/toolchain/mfc/state.py index fa7d438e77..383a458ec9 100644 --- a/toolchain/mfc/state.py +++ b/toolchain/mfc/state.py @@ -1,10 +1,18 @@ import typing, dataclasses +from enum import Enum, unique +@unique +class gpuConfigOptions(Enum): + NONE = 'no' + ACC = 'acc' + MP = 'mp' @dataclasses.dataclass class MFCConfig: mpi: bool = True - gpu: bool = False + gpu: str = gpuConfigOptions.NONE.value + # mp: bool = False + # acc: bool = False debug: bool = False gcov: bool = False unified: bool = False @@ -21,7 +29,7 @@ def from_dict(d: dict): return r - def items(self) -> typing.List[typing.Tuple[str, bool]]: + def items(self) -> typing.Iterable[typing.Tuple[str, typing.Any]]: return dataclasses.asdict(self).items() def make_options(self) -> typing.List[str]: @@ -44,8 +52,18 @@ def __eq__(self, other) -> bool: def __str__(self) -> str: """ Returns a string like "mpi=No & gpu=No & debug=No & gcov=No & unified=No" """ - - return ' & '.join([ f"{k}={'Yes' if v else 'No'}" for k, v in self.items() ]) + strings = [] + for k,v in self.items(): + if isinstance(v, bool): + strings.append(f"{k}={'Yes' if v else 'No'}") + elif isinstance(v, str): + strings.append(f"{k}={v.capitalize()}") + elif isinstance(v, int): + strings.append(f"{k}={v}") + else: + strings.append(f"{k}={v.__str__()}") + + return ' & '.join(strings) gCFG: MFCConfig = MFCConfig() From 7521731f889e7acd8ca4819986cbc88ac3bf14a3 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Fri, 18 Jul 2025 18:26:21 -0400 Subject: [PATCH 002/199] Fixed issue with not compiling on CPU builds --- toolchain/mfc/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/mfc/build.py b/toolchain/mfc/build.py index 422f400154..a5ce9d70db 100644 --- a/toolchain/mfc/build.py +++ b/toolchain/mfc/build.py @@ -18,7 +18,7 @@ class Dependencies: def compute(self) -> typing.Set: r = self.all[:] - r += self.gpu[:] if ARG("gpu") else self.cpu[:] + r += self.gpu[:] if (ARG("gpu") != gpuConfigOptions.NONE.value) else self.cpu[:] return r From 90c67381972c855265ab9a284ca1900df3e998cb Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Fri, 18 Jul 2025 18:50:10 -0400 Subject: [PATCH 003/199] Temporary commit --- src/common/include/parallel_macros.fpp | 64 +++++++++++++++++++++++++- src/common/m_nvtx.f90 | 6 +-- src/simulation/m_fftw.fpp | 19 ++++---- src/simulation/m_start_up.fpp | 22 ++++++--- toolchain/cmake/configuration.cmake.in | 1 + 5 files changed, 92 insertions(+), 20 deletions(-) diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index 8d0a5a673b..bb1bc7caf1 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -367,14 +367,64 @@ $:end_acc_directive #:enddef +#:def GEN_MP_PARENTHESES_CLAUSE(clause_name, clause_modifier, clause_str) + #:set clause_regex = re.compile(',(?![^(]*\\))') + #:assert isinstance(clause_name, str) + #:if clause_str is not None + #:set count = 0 + #:assert isinstance(clause_str, str) + #:assert clause_str[0] == '[' and clause_str[-1] == ']' + #:for c in clause_str + #:if c == '(' + #:set count = count + 1 + #:elif c == ')' + #:set count = count - 1 + #:endif + #:if c == ',' and count > 1 + #:stop 'Nested parentheses with comma inside is not supported. Incorrect clause: {}'.format(clause_str) + #:elif count < 0 + #:stop 'Missing parentheses. Incorrect clause: {}'.format(clause_str) + #:endif + #:endfor + #:set clause_str = re.sub(clause_regex, ';', clause_str) + #:set clause_list = [x.strip() for x in clause_str.strip('[]').split(';')] + $:ASSERT_LIST(clause_list, str) + #:set clause_str = clause_name + '(' + clause_modifier + ':' + ', '.join(clause_list) + ') ' + #:else + #:set clause_str = '' + #:endif + $:clause_str +#:enddef + +#:def GEN_TO_STR(to) + #:set to_str = GEN_MP_PARENTHESES_CLAUSE('map', 'to', to) + $:to_str +#:enddef + + +#:def GEN_ALLOC_STR(alloc) + #:set alloc_str = GEN_MP_PARENTHESES_CLAUSE('map', 'alloc', alloc) + $:alloc_str +#:enddef + #:def GPU_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraAccArgs=None) #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') #:set create_val = GEN_CREATE_STR(create) #:set attach_val = GEN_ATTACH_STR(attach) + #:set to_val = GEN_TO_STR(copyin) + #:set alloc_val = GEN_ALLOC_STR(create) + #:set alloc_val2 = GEN_ALLOC_STR(attach) #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = copyin_val.strip('\n') + create_val.strip('\n') + attach_val.strip('\n') - #:set acc_directive = '!$acc enter data ' + clause_val + extraAccArgs_val.strip('\n') + #:set extraMpArgs_val = '' + #:set acc_clause_val = copyin_val.strip('\n') + create_val.strip('\n') + attach_val.strip('\n') + #:set mp_clause_val = to_val.strip('\n') + alloc_val.strip('\n') + alloc_val2.strip('\n') + #:set acc_directive = '!$acc enter data ' + acc_clause_val + extraAccArgs_val.strip('\n') + #:set mp_directive = '!$omp target enter data ' + mp_clause_val + extraMpArgs_val.strip('\n') +#if MFC_OpenACC $:acc_directive +#elif MFC_OpenMP + $:mp_directive +#endif #:enddef #:def GPU_EXIT_DATA(copyout=None, delete=None, detach=None, extraAccArgs=None) @@ -421,5 +471,15 @@ $:acc_directive #:enddef +#:def USE_GPU_MODULE() + +#if defined(MFC_OpenACC) + use openacc +#elif defined(MFC_OpenMP) + use omp_lib +#endif + +#:enddef + #:endmute ! New line at end of file is required for FYPP diff --git a/src/common/m_nvtx.f90 b/src/common/m_nvtx.f90 index ce3273751a..524bf77781 100644 --- a/src/common/m_nvtx.f90 +++ b/src/common/m_nvtx.f90 @@ -25,7 +25,7 @@ module m_nvtx type(c_ptr) :: message ! ascii char end type nvtxEventAttributes -#if defined(MFC_OpenACC) && defined(__PGI) +#if defined(MFC_GPU) && defined(__PGI) interface nvtxRangePush ! push range with custom label and standard color @@ -58,7 +58,7 @@ subroutine nvtxStartRange(name, id) integer, intent(IN), optional :: id type(nvtxEventAttributes) :: event -#if defined(MFC_OpenACC) && defined(__PGI) +#if defined(MFC_GPU) && defined(__PGI) tempName = trim(name)//c_null_char @@ -74,7 +74,7 @@ subroutine nvtxStartRange(name, id) end subroutine nvtxStartRange subroutine nvtxEndRange -#if defined(MFC_OpenACC) && defined(__PGI) +#if defined(MFC_GPU) && defined(__PGI) call nvtxRangePop #endif end subroutine nvtxEndRange diff --git a/src/simulation/m_fftw.fpp b/src/simulation/m_fftw.fpp index 852fb90290..9563b99a6d 100644 --- a/src/simulation/m_fftw.fpp +++ b/src/simulation/m_fftw.fpp @@ -15,9 +15,9 @@ module m_fftw use m_mpi_proxy !< Message passing interface (MPI) module proxy -#if defined(MFC_OpenACC) && defined(__PGI) +#if defined(MFC_GPU) && defined(__PGI) use cufft -#elif defined(MFC_OpenACC) +#elif defined(MFC_GPU) use hipfort use hipfort_check use hipfort_hipfft @@ -29,7 +29,7 @@ module m_fftw s_apply_fourier_filter, & s_finalize_fftw_module -#if !defined(MFC_OpenACC) +#if !defined(MFC_GPU) include 'fftw3.f03' #endif @@ -45,13 +45,14 @@ module m_fftw complex(c_double_complex), pointer :: data_fltr_cmplx(:) !< !! Filtered complex data in Fourier space -#if defined(MFC_OpenACC) +#if defined(MFC_GPU) $:GPU_DECLARE(create='[real_size,cmplx_size,x_size,batch_size,Nfq]') real(dp), allocatable, target :: data_real_gpu(:) complex(dp), allocatable, target :: data_cmplx_gpu(:) complex(dp), allocatable, target :: data_fltr_cmplx_gpu(:) $:GPU_DECLARE(create='[data_real_gpu,data_cmplx_gpu,data_fltr_cmplx_gpu]') + !$omp declare target (data_real_gpu,data_cmplx_gpu,data_fltr_cmplx_gpu) #if defined(__PGI) integer :: fwd_plan_gpu, bwd_plan_gpu @@ -81,8 +82,7 @@ contains x_size = m + 1 batch_size = x_size*sys_size -#if defined(MFC_OpenACC) - +#if defined(MFC_GPU) rank = 1; istride = 1; ostride = 1 allocate (gpu_fft_size(1:rank), iembed(1:rank), oembed(1:rank)) @@ -107,7 +107,7 @@ contains bwd_plan = fftw_plan_dft_c2r_1d(real_size, data_fltr_cmplx, data_real, FFTW_ESTIMATE) #endif -#if defined(MFC_OpenACC) +#if defined(MFC_GPU) @:ALLOCATE(data_real_gpu(1:real_size*x_size*sys_size)) @:ALLOCATE(data_cmplx_gpu(1:cmplx_size*x_size*sys_size)) @:ALLOCATE(data_fltr_cmplx_gpu(1:cmplx_size*x_size*sys_size)) @@ -139,7 +139,8 @@ contains ! Restrict filter to processors that have cells adjacent to axis if (bc_y%beg >= 0) return -#if defined(MFC_OpenACC) +#if defined(MFC_GPU) + $:GPU_PARALLEL_LOOP(collapse=3) do k = 1, sys_size do j = 0, m @@ -302,7 +303,7 @@ contains !! applying the Fourier filter in the azimuthal direction. impure subroutine s_finalize_fftw_module -#if defined(MFC_OpenACC) +#if defined(MFC_GPU) integer :: ierr !< Generic flag used to identify and report GPU errors @:DEALLOCATE(data_real_gpu, data_fltr_cmplx_gpu, data_cmplx_gpu) #if defined(__PGI) diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index 782418b416..4d83080b19 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -68,9 +68,12 @@ module m_start_up use m_helper_basic !< Functions to compare floating point numbers -#ifdef MFC_OpenACC - use openacc -#endif + $:USE_GPU_MODULE() +! #if defined(MFC_OpenACC) +! use openacc +! #elif defined(MFC_OpenMP) +! use omp_lib +! #endif use m_nvtx @@ -1329,14 +1332,16 @@ contains impure subroutine s_initialize_mpi_domain integer :: ierr -#ifdef MFC_OpenACC +#ifdef MFC_GPU real(wp) :: starttime, endtime integer :: num_devices, local_size, num_nodes, ppn, my_device_num integer :: dev, devNum, local_rank #ifdef MFC_MPI integer :: local_comm #endif +#if defined(MFC_OpenACC) integer(acc_device_kind) :: devtype +#endif #endif ! Initializing MPI execution environment @@ -1344,7 +1349,7 @@ contains call s_mpi_initialize() ! Bind GPUs if OpenACC is enabled -#ifdef MFC_OpenACC +#ifdef MFC_GPU #ifndef MFC_MPI local_size = 1 local_rank = 0 @@ -1354,12 +1359,17 @@ contains call MPI_Comm_size(local_comm, local_size, ierr) call MPI_Comm_rank(local_comm, local_rank, ierr) #endif - +#if defined(MFC_OpenACC) devtype = acc_get_device_type() devNum = acc_get_num_devices(devtype) dev = mod(local_rank, devNum) call acc_set_device_num(dev, devtype) +#elif defined(MFC_OpenMP) + devNum = omp_get_num_devices() + dev = mod(local_rank, devNum) + call omp_set_default_device(dev) +#endif #endif ! The rank 0 processor assigns default values to the user inputs prior to diff --git a/toolchain/cmake/configuration.cmake.in b/toolchain/cmake/configuration.cmake.in index a9b9b5399c..4cdd90fcaa 100644 --- a/toolchain/cmake/configuration.cmake.in +++ b/toolchain/cmake/configuration.cmake.in @@ -14,6 +14,7 @@ CMake Configuration: MPI : ${MFC_MPI} OpenACC : ${MFC_OpenACC} + OpenMP : ${MFC_OpenMP} Fypp : ${FYPP_EXE} Doxygen : ${DOXYGEN_EXECUTABLE} From 06a783e22562184f2a28f17434544b121f633a7d Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Sun, 20 Jul 2025 16:21:21 -0400 Subject: [PATCH 004/199] OMP parallel and parallel loop --- src/common/include/acc_macros.fpp | 59 +++++++ src/common/include/omp_macros.fpp | 157 ++++++++++++++++++ src/common/include/parallel_macros.fpp | 113 +++---------- src/common/include/shared_parallel_macros.fpp | 91 ++++++++++ 4 files changed, 333 insertions(+), 87 deletions(-) create mode 100644 src/common/include/acc_macros.fpp create mode 100644 src/common/include/omp_macros.fpp create mode 100644 src/common/include/shared_parallel_macros.fpp diff --git a/src/common/include/acc_macros.fpp b/src/common/include/acc_macros.fpp new file mode 100644 index 0000000000..9375799bde --- /dev/null +++ b/src/common/include/acc_macros.fpp @@ -0,0 +1,59 @@ +#:include 'shared_parallel_macros.fpp' + +#:def ACC_PARALLEL(code, private=None, default='present', firstprivate=None, reduction=None, reductionOp=None, & + & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & + & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None) + #:set default_val = GEN_DEFAULT_STR(default) + #:set private_val = GEN_PRIVATE_STR(private, False).strip('\n') + GEN_PRIVATE_STR(firstprivate, True).strip('\n') + #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) + #:set copy_val = GEN_COPY_STR(copy) + #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') + #:set copyout_val = GEN_COPYOUT_STR(copyout) + #:set create_val = GEN_CREATE_STR(create) + #:set no_create_val = GEN_NOCREATE_STR(no_create) + #:set present_val = GEN_PRESENT_STR(present) + #:set deviceptr_val = GEN_DEVICEPTR_STR(deviceptr) + #:set attach_val = GEN_ATTACH_STR(attach) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set acc_clause_val = default_val.strip('\n') + private_val.strip('\n') + reduction_val.strip('\n') + & + & copy_val.strip('\n') + copyin_val.strip('\n') + & + & copyout_val.strip('\n') + create_val.strip('\n') + & + & no_create_val.strip('\n') + present_val.strip('\n') + & + & deviceptr_val.strip('\n') + attach_val.strip('\n') + #:set acc_directive = '!$acc parallel ' + & + & acc_clause_val + extraAccArgs_val.strip('\n') + #:set end_acc_directive = '!$acc end parallel' + $:acc_directive + $:code + $:end_acc_directive +#:enddef + +#:def ACC_PARALLEL_LOOP(collapse=None, private=None, parallelism='[gang, vector]', & + & default='present', firstprivate=None, reduction=None, reductionOp=None, & + & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & + & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None) + #:set collapse_val = GEN_COLLAPSE_STR(collapse) + #:set parallelism_val = GEN_PARALLELISM_STR(parallelism) + #:set default_val = GEN_DEFAULT_STR(default) + #:set private_val = GEN_PRIVATE_STR(private, False).strip('\n') + GEN_PRIVATE_STR(firstprivate, True).strip('\n') + #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) + #:set copy_val = GEN_COPY_STR(copy) + #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') + #:set copyout_val = GEN_COPYOUT_STR(copyout) + #:set create_val = GEN_CREATE_STR(create) + #:set no_create_val = GEN_NOCREATE_STR(no_create) + #:set present_val = GEN_PRESENT_STR(present) + #:set deviceptr_val = GEN_DEVICEPTR_STR(deviceptr) + #:set attach_val = GEN_ATTACH_STR(attach) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = collapse_val.strip('\n') + parallelism_val.strip('\n') + & + & default_val.strip('\n') + private_val.strip('\n') + reduction_val.strip('\n') + & + & copy_val.strip('\n') + copyin_val.strip('\n') + & + & copyout_val.strip('\n') + create_val.strip('\n') + & + & no_create_val.strip('\n') + present_val.strip('\n') + & + & deviceptr_val.strip('\n') + attach_val.strip('\n') + #:set acc_directive = '!$acc parallel loop ' + & + & clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef +! New line at end of file is required for FYPP \ No newline at end of file diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp new file mode 100644 index 0000000000..4a27e8f093 --- /dev/null +++ b/src/common/include/omp_macros.fpp @@ -0,0 +1,157 @@ +#:include 'shared_parallel_macros.fpp' + +#:def OMP_MAP_STR(map_type, var_list) + #:assert map_type is not None + #:assert isinstance(map_type, str) + #:if var_list is not None + #:set map_clause = 'map(' + map_type + ':' + #:set map_val = GEN_CLAUSE(map_clause, var_list) + #:else + #:set map_val = '' + #:endif + $:map_val +#:enddef + +#:def OMP_DEFAULT_STR(default) + #:if default is not None + #:assert isinstance(default, str) + #:assert (default == 'present' or default == 'none') + #:if default == 'present' + #:set default_val = 'defaultmap(present:all) ' + #:elif default == 'none' + #:stop 'Not Supported Yet' + #:endif + #:else + #:set default_val = '' + #:endif + $:default_val +#:enddef + +#:def OMP_DEFAULT_STR(default) + #:if default is not None + #:assert isinstance(default, str) + #:assert (default == 'present' or default == 'none') + #:if default == 'present' + #:set default_val = 'defaultmap(present:aggregate) defaultmap(present:allocatable) ' + #:elif default == 'none' + #:stop 'Not Supported Yet' + #:endif + #:else + #:set default_val = '' + #:endif + $:default_val +#:enddef + +#:def OMP_COPY_STR(copy) + #:set copy_val = OMP_MAP_STR('tofrom', copy) + $:copy_val +#:enddef + +#:def OMP_COPYIN_STR(copyin) + #:set copyin_val = OMP_MAP_STR('to', copyin) + $:copyin_val +#:enddef + +#:def OMP_COPYOUT_STR(copyout) + #:set copyout_val = OMP_MAP_STR('from', copyout) + $:copyout_val +#:enddef + +#:def OMP_CREATE_STR(create) + #:set create_val = OMP_MAP_STR('alloc', create) + $:create_val +#:enddef + +#:def OMP_NOCREATE_STR(no_create) + #:if no_create is not None + #:stop 'no_create is not supported yet' + #:endif + #:set no_create_val = '' + $:no_create_val +#:enddef + +#:def OMP_PRESENT_STR(present) + #:set present_val = OMP_MAP_STR('present,alloc', present) + $:present_val +#:enddef + +#:def OMP_DEVICEPTR_STR(deviceptr) + #:set deviceptr_val = GEN_PARENTHESES_CLAUSE('use_device_ptr', deviceptr) + $:deviceptr_val +#:enddef + +#:def OMP_ATTACH_STR(attach) + #:if attach is not None + #:stop 'attach is not supported yet' + #:endif + #:set attach_val = '' + $:attach_val +#:enddef + +#:def OMP_PARALLELISM_STR(parallelism) + #:set temp = '' + $:temp +#:enddef + +#:def OMP_PARALLEL(code, private=None, default='present', firstprivate=None, reduction=None, reductionOp=None, & + & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & + & no_create=None, present=None, deviceptr=None, attach=None, extraOmpArgs=None) + #:set default_val = OMP_DEFAULT_STR(default) + #:set private_val = GEN_PRIVATE_STR(private, False).strip('\n') + GEN_PRIVATE_STR(firstprivate, True).strip('\n') + #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) + #:set copy_val = OMP_COPY_STR(copy) + #:set copyin_val = OMP_COPYIN_STR(copyin).strip('\n') + OMP_COPYIN_STR(copyinReadOnly).strip('\n') + #:set copyout_val = OMP_COPYOUT_STR(copyout) + #:set create_val = OMP_CREATE_STR(create) + #:set no_create_val = OMP_NOCREATE_STR(no_create) + #:set present_val = OMP_PRESENT_STR(present) + #:set deviceptr_val = OMP_DEVICEPTR_STR(deviceptr) + #:set attach_val = OMP_ATTACH_STR(attach) + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) + #:set omp_clause_val = default_val.strip('\n') + private_val.strip('\n') + reduction_val.strip('\n') + & + & copy_val.strip('\n') + copyin_val.strip('\n') + & + & copyout_val.strip('\n') + create_val.strip('\n') + & + & no_create_val.strip('\n') + present_val.strip('\n') + & + & deviceptr_val.strip('\n') + attach_val.strip('\n')) + + #:set omp_clause_val = 'defaultmap(firstprivate:scalar) ' + omp_clause_val.strip('\n') + #:set omp_directive = '!$omp target teams ' + omp_clause_val + extraOmpArgs_val.strip('\n') + + #:set end_omp_directive = '!$omp end target teams' + $:omp_directive + $:code + $:omp_end_directive +#:enddef + +#:def OMP_PARALLEL_LOOP(collapse=None, private=None, parallelism='[gang, vector]', & + & default='present', firstprivate=None, reduction=None, reductionOp=None, & + & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & + & no_create=None, present=None, deviceptr=None, attach=None, extraOmpArgs=None) + + #:set collapse_val = GEN_COLLAPSE_STR(collapse) + #:set parallelism_val = OMP_PARALLELISM_STR(parallelism) + #! #:set default_val = OMP_DEFAULT_STR(default) + #:set default_val = '' + #:set private_val = GEN_PRIVATE_STR(private, False).strip('\n') + GEN_PRIVATE_STR(firstprivate, True).strip('\n') + #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) + #:set copy_val = OMP_COPY_STR(copy) + #:set copyin_val = OMP_COPYIN_STR(copyin).strip('\n') + OMP_COPYIN_STR(copyinReadOnly).strip('\n') + #:set copyout_val = OMP_COPYOUT_STR(copyout) + #:set create_val = OMP_CREATE_STR(create) + #:set no_create_val = OMP_NOCREATE_STR(no_create) + #:set present_val = OMP_PRESENT_STR(present) + #:set deviceptr_val = OMP_DEVICEPTR_STR(deviceptr) + #:set attach_val = OMP_ATTACH_STR(attach) + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) + #:set clause_val = collapse_val.strip('\n') + parallelism_val.strip('\n') + & + & default_val.strip('\n') + private_val.strip('\n') + reduction_val.strip('\n') + & + & copy_val.strip('\n') + copyin_val.strip('\n') + & + & copyout_val.strip('\n') + create_val.strip('\n') + & + & no_create_val.strip('\n') + present_val.strip('\n') + & + & deviceptr_val.strip('\n') + attach_val.strip('\n') + #! Hardcoding the parallelism for now + #:set omp_directive = '!$omp target teams distribute parallel do simd ' + & + & clause_val + extraOmpArgs_val.strip('\n') + $:omp_directive +#:enddef +! New line at end of file is required for FYPP \ No newline at end of file diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index bb1bc7caf1..00dc95493e 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -1,4 +1,7 @@ #:mute +#:include 'shared_parallel_macros.fpp' +#:include 'omp_macros.fpp' +#:include 'acc_macros.fpp' #:def ASSERT_LIST(data, datatype) #:assert data is not None @@ -106,15 +109,7 @@ $:link_val #:enddef -#:def GEN_EXTRA_ARGS_STR(extraArgs) - #:if extraArgs is not None - #:assert isinstance(extraArgs, str) - #:set extraArgs_val = extraArgs - #:else - #:set extraArgs_val = '' - #:endif - $:extraArgs_val -#:enddef + #:def GEN_PARALLELISM_STR(parallelism) #:if parallelism is not None @@ -154,36 +149,6 @@ $:default_val #:enddef -#:def GEN_REDUCTION_STR(reduction, reductionOp) - #:if reduction is not None and reductionOp is not None - #:assert isinstance(reduction, str) - #:assert isinstance(reductionOp, str) - #:assert reduction[0] == '[' and reduction[-1] == ']' - #:assert reductionOp[0] == '[' and reductionOp[-1] == ']' - #:set reduction = reduction.replace(' ', '') - #:set reduction = reduction[1:-1] - #:set reduction_list = reduction.split('],') - #:set reduction_list = [str + ']' for str in reduction_list] - #:assert all(str[0] == '[' and str[-1] == ']' for str in reduction_list) - - #:set reductionOp_list = [x.strip() for x in reductionOp.strip('[]').split(',')] - $:ASSERT_LIST(reduction_list, str) - $:ASSERT_LIST(reductionOp_list, str) - #:assert len(reduction_list) == len(reductionOp_list) - #:set reduction_val = '' - #:for i in range(len(reduction_list)) - #:set temp_clause = GEN_PARENTHESES_CLAUSE('reduction', reduction_list[i]).strip('\n') - #:set ind = temp_clause.find('reduction(') + len('reduction(') - #:set reduction_val = reduction_val.strip('\n') + temp_clause[:ind] + reductionOp_list[i] + ':' + temp_clause[ind:] - #:endfor - #:elif reduction is not None or reductionOp is not None - #:stop 'Cannot set the reduction list or reduction operation without setting the other' - #:else - #:set reduction_val = '' - #:endif - $:reduction_val -#:enddef - #:def GEN_HOST_STR(host) #:set host_val = GEN_PARENTHESES_CLAUSE('host', host) $:host_val @@ -201,60 +166,34 @@ #:def GPU_PARALLEL(code, private=None, default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & - & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None) - #:set default_val = GEN_DEFAULT_STR(default) - #:set private_val = GEN_PRIVATE_STR(private, False).strip('\n') + GEN_PRIVATE_STR(firstprivate, True).strip('\n') - #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) - #:set copy_val = GEN_COPY_STR(copy) - #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') - #:set copyout_val = GEN_COPYOUT_STR(copyout) - #:set create_val = GEN_CREATE_STR(create) - #:set no_create_val = GEN_NOCREATE_STR(no_create) - #:set present_val = GEN_PRESENT_STR(present) - #:set deviceptr_val = GEN_DEVICEPTR_STR(deviceptr) - #:set attach_val = GEN_ATTACH_STR(attach) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = default_val.strip('\n') + private_val.strip('\n') + reduction_val.strip('\n') + & - & copy_val.strip('\n') + copyin_val.strip('\n') + & - & copyout_val.strip('\n') + create_val.strip('\n') + & - & no_create_val.strip('\n') + present_val.strip('\n') + & - & deviceptr_val.strip('\n') + attach_val.strip('\n') - #:set acc_directive = '!$acc parallel ' + & - & clause_val + extraAccArgs_val.strip('\n') - #:set end_acc_directive = '!$acc end parallel' - $:acc_directive + & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None, extraOmpArgs=None) + + #:set acc_code = ACC_PARALLEL(code, private, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraAccArgs) + #:set omp_code = OMP_PARALLEL(code, private, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraOmpArgs) + +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#else $:code - $:end_acc_directive -#:enddef +#endif +#:enddef #:def GPU_PARALLEL_LOOP(collapse=None, private=None, parallelism='[gang, vector]', & & default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & - & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None) - #:set collapse_val = GEN_COLLAPSE_STR(collapse) - #:set parallelism_val = GEN_PARALLELISM_STR(parallelism) - #:set default_val = GEN_DEFAULT_STR(default) - #:set private_val = GEN_PRIVATE_STR(private, False).strip('\n') + GEN_PRIVATE_STR(firstprivate, True).strip('\n') - #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) - #:set copy_val = GEN_COPY_STR(copy) - #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') - #:set copyout_val = GEN_COPYOUT_STR(copyout) - #:set create_val = GEN_CREATE_STR(create) - #:set no_create_val = GEN_NOCREATE_STR(no_create) - #:set present_val = GEN_PRESENT_STR(present) - #:set deviceptr_val = GEN_DEVICEPTR_STR(deviceptr) - #:set attach_val = GEN_ATTACH_STR(attach) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = collapse_val.strip('\n') + parallelism_val.strip('\n') + & - & default_val.strip('\n') + private_val.strip('\n') + reduction_val.strip('\n') + & - & copy_val.strip('\n') + copyin_val.strip('\n') + & - & copyout_val.strip('\n') + create_val.strip('\n') + & - & no_create_val.strip('\n') + present_val.strip('\n') + & - & deviceptr_val.strip('\n') + attach_val.strip('\n') - #:set acc_directive = '!$acc parallel loop ' + & - & clause_val + extraAccArgs_val.strip('\n') - $:acc_directive + & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None, extraOmpArgs=None) + + #:set acc_code = ACC_PARALLEL_LOOP(collapse, private, parallelism, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraAccArgs) + #:set omp_code = OMP_PARALLEL_LOOP(collapse, private, parallelism, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraOmpArgs) + +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#endif #:enddef #:def GPU_ROUTINE(function_name=None, parallelism=None, nohost=False, cray_inline=False, extraAccArgs=None) diff --git a/src/common/include/shared_parallel_macros.fpp b/src/common/include/shared_parallel_macros.fpp new file mode 100644 index 0000000000..eadb2211f4 --- /dev/null +++ b/src/common/include/shared_parallel_macros.fpp @@ -0,0 +1,91 @@ +#:def GEN_CLAUSE(clause_name, clause_str) + #:set clause_regex = re.compile(',(?![^(]*\\))') + #:assert isinstance(clause_name, str) + #:if clause_str is not None + #:set count = 0 + #:assert isinstance(clause_str, str) + #:assert clause_str[0] == '[' and clause_str[-1] == ']' + #:for c in clause_str + #:if c == '(' + #:set count = count + 1 + #:elif c == ')' + #:set count = count - 1 + #:endif + #:if c == ',' and count > 1 + #:stop 'Nested parentheses with comma inside is not supported. Incorrect clause: {}'.format(clause_str) + #:elif count < 0 + #:stop 'Missing parentheses. Incorrect clause: {}'.format(clause_str) + #:endif + #:endfor + #:set clause_str = re.sub(clause_regex, ';', clause_str) + #:set clause_list = [x.strip() for x in clause_str.strip('[]').split(';')] + $:ASSERT_LIST(clause_list, str) + #:set clause_str = clause_name + ', '.join(clause_list) + ') ' + #:else + #:set clause_str = '' + #:endif + $:clause_str +#:enddef + +#:def GEN_PARENTHESES_CLAUSE(clause_name, clause_str) + #:assert isinstance(clause_name, str) + #:if clause_str is not None + #:assert isinstance(clause_str, str) + #:set clause = clause_name + '(' + #:set clause_str = GEN_CLAUSE(clause, clause_str) + #:else + #:set clause_str = '' + #:endif + $:clause_str +#:enddef + +#:def GEN_PRIVATE_STR(private, initialized_values) + #:assert isinstance(initialized_values, bool) + #:if initialized_values == True + #:set private_val = GEN_PARENTHESES_CLAUSE('firstprivate', private) + #:else + #:set private_val = GEN_PARENTHESES_CLAUSE('private', private) + #:endif + $:private_val +#:enddef + +#:def GEN_REDUCTION_STR(reduction, reductionOp) + #:if reduction is not None and reductionOp is not None + #:assert isinstance(reduction, str) + #:assert isinstance(reductionOp, str) + #:assert reduction[0] == '[' and reduction[-1] == ']' + #:assert reductionOp[0] == '[' and reductionOp[-1] == ']' + #:set reduction = reduction.replace(' ', '') + #:set reduction = reduction[1:-1] + #:set reduction_list = reduction.split('],') + #:set reduction_list = [str + ']' for str in reduction_list] + #:assert all(str[0] == '[' and str[-1] == ']' for str in reduction_list) + + #:set reductionOp_list = [x.strip() for x in reductionOp.strip('[]').split(',')] + $:ASSERT_LIST(reduction_list, str) + $:ASSERT_LIST(reductionOp_list, str) + #:assert len(reduction_list) == len(reductionOp_list) + #:set reduction_val = '' + #:for i in range(len(reduction_list)) + #:set temp_clause = GEN_PARENTHESES_CLAUSE('reduction', reduction_list[i]).strip('\n') + #:set ind = temp_clause.find('reduction(') + len('reduction(') + #:set reduction_val = reduction_val.strip('\n') + temp_clause[:ind] + reductionOp_list[i] + ':' + temp_clause[ind:] + #:endfor + #:elif reduction is not None or reductionOp is not None + #:stop 'Cannot set the reduction list or reduction operation without setting the other' + #:else + #:set reduction_val = '' + #:endif + $:reduction_val +#:enddef + +#:def GEN_EXTRA_ARGS_STR(extraArgs) + #:if extraArgs is not None + #:assert isinstance(extraArgs, str) + #:set extraArgs_val = extraArgs + #:else + #:set extraArgs_val = '' + #:endif + $:extraArgs_val +#:enddef +! New line at end of file is required for FYPP \ No newline at end of file From 2abfad5f5fd5a3bb5135602e57ac8750c6f823f7 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Sun, 20 Jul 2025 16:25:07 -0400 Subject: [PATCH 005/199] Removed pure markings --- src/common/m_boundary_common.fpp | 22 +++++++-------- src/common/m_eigen_solver.f90 | 16 +++++------ src/common/m_finite_differences.fpp | 4 +-- src/common/m_helper.fpp | 36 ++++++++++++------------ src/common/m_helper_basic.fpp | 12 ++++---- src/common/m_phase_change.fpp | 16 +++++------ src/common/m_variables_conversion.fpp | 12 ++++---- src/simulation/m_acoustic_src.fpp | 14 ++++----- src/simulation/m_bubbles.fpp | 34 +++++++++++----------- src/simulation/m_bubbles_EE.fpp | 4 +-- src/simulation/m_bubbles_EL.fpp | 12 ++++---- src/simulation/m_bubbles_EL_kernels.fpp | 18 ++++++------ src/simulation/m_cbc.fpp | 2 +- src/simulation/m_compute_cbc.fpp | 26 ++++++++--------- src/simulation/m_derived_variables.fpp | 2 +- src/simulation/m_hyperelastic.fpp | 4 +-- src/simulation/m_hypoelastic.fpp | 2 +- src/simulation/m_ibm.fpp | 10 +++---- src/simulation/m_mhd.fpp | 2 +- src/simulation/m_pressure_relaxation.fpp | 12 ++++---- src/simulation/m_qbmm.fpp | 14 ++++----- src/simulation/m_riemann_solvers.fpp | 12 ++++---- src/simulation/m_sim_helpers.fpp | 10 +++---- src/simulation/m_surface_tension.fpp | 2 +- src/simulation/m_weno.fpp | 2 +- 25 files changed, 150 insertions(+), 150 deletions(-) diff --git a/src/common/m_boundary_common.fpp b/src/common/m_boundary_common.fpp index 3dc4da2c2e..3335a79b53 100644 --- a/src/common/m_boundary_common.fpp +++ b/src/common/m_boundary_common.fpp @@ -276,7 +276,7 @@ contains end subroutine s_populate_variables_buffers - pure subroutine s_ghost_cell_extrapolation(q_prim_vf, bc_dir, bc_loc, k, l) + subroutine s_ghost_cell_extrapolation(q_prim_vf, bc_dir, bc_loc, k, l) $:GPU_ROUTINE(function_name='s_ghost_cell_extrapolation', & & parallelism='[seq]', cray_inline=True) type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf @@ -337,7 +337,7 @@ contains end subroutine s_ghost_cell_extrapolation - pure subroutine s_symmetry(q_prim_vf, bc_dir, bc_loc, k, l, pb_in, mv_in) + subroutine s_symmetry(q_prim_vf, bc_dir, bc_loc, k, l, pb_in, mv_in) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf real(wp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in @@ -597,7 +597,7 @@ contains end subroutine s_symmetry - pure subroutine s_periodic(q_prim_vf, bc_dir, bc_loc, k, l, pb_in, mv_in) + subroutine s_periodic(q_prim_vf, bc_dir, bc_loc, k, l, pb_in, mv_in) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf real(wp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in @@ -736,7 +736,7 @@ contains end subroutine s_periodic - pure subroutine s_axis(q_prim_vf, pb_in, mv_in, k, l) + subroutine s_axis(q_prim_vf, pb_in, mv_in, k, l) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in @@ -795,7 +795,7 @@ contains end subroutine s_axis - pure subroutine s_slip_wall(q_prim_vf, bc_dir, bc_loc, k, l) + subroutine s_slip_wall(q_prim_vf, bc_dir, bc_loc, k, l) $:GPU_ROUTINE(function_name='s_slip_wall',parallelism='[seq]', & & cray_inline=True) type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf @@ -886,7 +886,7 @@ contains end subroutine s_slip_wall - pure subroutine s_no_slip_wall(q_prim_vf, bc_dir, bc_loc, k, l) + subroutine s_no_slip_wall(q_prim_vf, bc_dir, bc_loc, k, l) $:GPU_ROUTINE(function_name='s_no_slip_wall',parallelism='[seq]', & & cray_inline=True) @@ -1014,7 +1014,7 @@ contains end subroutine s_no_slip_wall - pure subroutine s_dirichlet(q_prim_vf, bc_dir, bc_loc, k, l) + subroutine s_dirichlet(q_prim_vf, bc_dir, bc_loc, k, l) $:GPU_ROUTINE(function_name='s_dirichlet',parallelism='[seq]', & & cray_inline=True) type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf @@ -1079,7 +1079,7 @@ contains end subroutine s_dirichlet - pure subroutine s_qbmm_extrapolation(bc_dir, bc_loc, k, l, pb_in, mv_in) + subroutine s_qbmm_extrapolation(bc_dir, bc_loc, k, l, pb_in, mv_in) $:GPU_ROUTINE(parallelism='[seq]') real(wp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in integer, intent(in) :: bc_dir, bc_loc @@ -1274,7 +1274,7 @@ contains end if end subroutine s_populate_capillary_buffers - pure subroutine s_color_function_periodic(c_divs, bc_dir, bc_loc, k, l) + subroutine s_color_function_periodic(c_divs, bc_dir, bc_loc, k, l) $:GPU_ROUTINE(function_name='s_color_function_periodic', & & parallelism='[seq]', cray_inline=True) type(scalar_field), dimension(num_dims + 1), intent(inout) :: c_divs @@ -1329,7 +1329,7 @@ contains end subroutine s_color_function_periodic - pure subroutine s_color_function_reflective(c_divs, bc_dir, bc_loc, k, l) + subroutine s_color_function_reflective(c_divs, bc_dir, bc_loc, k, l) $:GPU_ROUTINE(function_name='s_color_function_reflective', & & parallelism='[seq]', cray_inline=True) type(scalar_field), dimension(num_dims + 1), intent(inout) :: c_divs @@ -1408,7 +1408,7 @@ contains end subroutine s_color_function_reflective - pure subroutine s_color_function_ghost_cell_extrapolation(c_divs, bc_dir, bc_loc, k, l) + subroutine s_color_function_ghost_cell_extrapolation(c_divs, bc_dir, bc_loc, k, l) $:GPU_ROUTINE(function_name='s_color_function_ghost_cell_extrapolation', & & parallelism='[seq]', cray_inline=True) type(scalar_field), dimension(num_dims + 1), intent(inout) :: c_divs diff --git a/src/common/m_eigen_solver.f90 b/src/common/m_eigen_solver.f90 index 2bf38d04bd..5003075c88 100644 --- a/src/common/m_eigen_solver.f90 +++ b/src/common/m_eigen_solver.f90 @@ -35,7 +35,7 @@ module m_eigen_solver !! @param fv2 temporary storage array !! @param fv3 temporary storage array !! @param ierr an error completion code - pure subroutine cg(nm, nl, ar, ai, wr, wi, zr, zi, fv1, fv2, fv3, ierr) + subroutine cg(nm, nl, ar, ai, wr, wi, zr, zi, fv1, fv2, fv3, ierr) integer, intent(in) :: nm, nl real(wp), dimension(nm, nl), intent(inout) :: ar, ai real(wp), dimension(nl), intent(out) :: wr, wi @@ -78,7 +78,7 @@ end subroutine cg !! (2) j=1, ,low-1 or i=igh+1, ,nl. !! @param scale the information determining the permutations and scaling !! factors used. - pure subroutine cbal(nm, nl, ar, ai, low, igh, scale) + subroutine cbal(nm, nl, ar, ai, low, igh, scale) integer, intent(in) :: nm, nl real(wp), dimension(nm, nl), intent(inout) :: ar, ai integer, intent(out) :: low, igh @@ -221,7 +221,7 @@ end subroutine cbal !! if cbal has not been used, set igh=nl. !! @param ortr further information about the transformations !! @param orti further information about the transformations - pure subroutine corth(nm, nl, low, igh, ar, ai, ortr, orti) + subroutine corth(nm, nl, low, igh, ar, ai, ortr, orti) integer, intent(in) :: nm, nl, low, igh real(wp), dimension(nm, nl), intent(inout) :: ar, ai real(wp), dimension(igh), intent(out) :: ortr, orti @@ -345,7 +345,7 @@ end subroutine corth !! @param zr the real part of the eigenvectors !! @param zi the imaginary part of the eigenvectors !! @param ierr an error completion code - pure subroutine comqr2(nm, nl, low, igh, ortr, orti, hr, hi, wr, wi, zr, zi, ierr) + subroutine comqr2(nm, nl, low, igh, ortr, orti, hr, hi, wr, wi, zr, zi, ierr) integer, intent(in) :: nm, nl, low, igh real(wp), dimension(nm, nl), intent(inout) :: hr, hi real(wp), dimension(nl), intent(out) :: wr, wi @@ -708,7 +708,7 @@ end subroutine comqr2 !! their first ml columns !! @param zi the imaginary part of the eigenvectors to be back !! transformed in their first ml columns - pure subroutine cbabk2(nm, nl, low, igh, scale, ml, zr, zi) + subroutine cbabk2(nm, nl, low, igh, scale, ml, zr, zi) integer, intent(in) :: nm, nl, low, igh real(wp), intent(in) :: scale(nl) integer, intent(in) :: ml @@ -754,7 +754,7 @@ pure subroutine cbabk2(nm, nl, low, igh, scale, ml, zr, zi) 200 return end subroutine cbabk2 - pure elemental subroutine csroot(xr, xi, yr, yi) + elemental subroutine csroot(xr, xi, yr, yi) real(wp), intent(in) :: xr, xi real(wp), intent(out) :: yr, yi @@ -774,7 +774,7 @@ pure elemental subroutine csroot(xr, xi, yr, yi) return end subroutine csroot - pure elemental subroutine cdiv(ar, ai, br, bi, cr, ci) + elemental subroutine cdiv(ar, ai, br, bi, cr, ci) real(wp), intent(in) :: ar, ai, br, bi real(wp), intent(out) :: cr, ci real(wp) :: s, ars, ais, brs, bis @@ -790,7 +790,7 @@ pure elemental subroutine cdiv(ar, ai, br, bi, cr, ci) return end subroutine cdiv - pure elemental subroutine pythag(a, b, c) + elemental subroutine pythag(a, b, c) real(wp), intent(in) :: a, b real(wp), intent(out) :: c diff --git a/src/common/m_finite_differences.fpp b/src/common/m_finite_differences.fpp index 2430374f4f..4b7e399ad5 100644 --- a/src/common/m_finite_differences.fpp +++ b/src/common/m_finite_differences.fpp @@ -8,7 +8,7 @@ module m_finite_differences contains - pure subroutine s_compute_fd_divergence(div, fields, ix_s, iy_s, iz_s) + subroutine s_compute_fd_divergence(div, fields, ix_s, iy_s, iz_s) type(scalar_field), intent(INOUT) :: div type(scalar_field), intent(IN) :: fields(1:3) @@ -69,7 +69,7 @@ contains !! @param q Number of cells in the s-coordinate direction !! @param s_cc Locations of the cell-centers in the s-coordinate direction !! @param fd_coeff_s Finite-diff. coefficients in the s-coordinate direction - pure subroutine s_compute_finite_difference_coefficients(q, s_cc, fd_coeff_s, local_buff_size, & + subroutine s_compute_finite_difference_coefficients(q, s_cc, fd_coeff_s, local_buff_size, & fd_number_in, fd_order_in, offset_s) integer :: lB, lE !< loop bounds diff --git a/src/common/m_helper.fpp b/src/common/m_helper.fpp index f432ca12fa..c8a17a1875 100644 --- a/src/common/m_helper.fpp +++ b/src/common/m_helper.fpp @@ -45,7 +45,7 @@ contains !! @param vftmp is the void fraction !! @param Rtmp is the bubble radii !! @param ntmp is the output number bubble density - pure subroutine s_comp_n_from_prim(vftmp, Rtmp, ntmp, weights) + subroutine s_comp_n_from_prim(vftmp, Rtmp, ntmp, weights) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: vftmp real(wp), dimension(nb), intent(in) :: Rtmp @@ -59,7 +59,7 @@ contains end subroutine s_comp_n_from_prim - pure subroutine s_comp_n_from_cons(vftmp, nRtmp, ntmp, weights) + subroutine s_comp_n_from_cons(vftmp, nRtmp, ntmp, weights) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: vftmp real(wp), dimension(nb), intent(in) :: nRtmp @@ -222,7 +222,7 @@ contains !! @param peclet Peclet number !! @param Re_trans Real part of the transport coefficients !! @param Im_trans Imaginary part of the transport coefficients - pure elemental subroutine s_transcoeff(omega, peclet, Re_trans, Im_trans) + elemental subroutine s_transcoeff(omega, peclet, Re_trans, Im_trans) real(wp), intent(in) :: omega, peclet real(wp), intent(out) :: Re_trans, Im_trans @@ -241,7 +241,7 @@ contains end subroutine s_transcoeff - pure elemental subroutine s_int_to_str(i, res) + elemental subroutine s_int_to_str(i, res) integer, intent(in) :: i character(len=*), intent(inout) :: res @@ -292,7 +292,7 @@ contains !! @param a First vector. !! @param b Second vector. !! @return The cross product of the two vectors. - pure function f_cross(a, b) result(c) + function f_cross(a, b) result(c) real(wp), dimension(3), intent(in) :: a, b real(wp), dimension(3) :: c @@ -305,7 +305,7 @@ contains !> This procedure swaps two real numbers. !! @param lhs Left-hand side. !! @param rhs Right-hand side. - pure elemental subroutine s_swap(lhs, rhs) + elemental subroutine s_swap(lhs, rhs) real(wp), intent(inout) :: lhs, rhs real(wp) :: ltemp @@ -318,7 +318,7 @@ contains !> This procedure creates a transformation matrix. !! @param p Parameters for the transformation. !! @return Transformation matrix. - pure function f_create_transform_matrix(param, center) result(out_matrix) + function f_create_transform_matrix(param, center) result(out_matrix) type(ic_model_parameters), intent(in) :: param real(wp), dimension(1:3), optional, intent(in) :: center @@ -379,7 +379,7 @@ contains !> This procedure transforms a vector by a matrix. !! @param vec Vector to transform. !! @param matrix Transformation matrix. - pure subroutine s_transform_vec(vec, matrix) + subroutine s_transform_vec(vec, matrix) real(wp), dimension(1:3), intent(inout) :: vec real(wp), dimension(1:4, 1:4), intent(in) :: matrix @@ -394,7 +394,7 @@ contains !> This procedure transforms a triangle by a matrix, one vertex at a time. !! @param triangle Triangle to transform. !! @param matrix Transformation matrix. - pure subroutine s_transform_triangle(triangle, matrix, matrix_n) + subroutine s_transform_triangle(triangle, matrix, matrix_n) type(t_triangle), intent(inout) :: triangle real(wp), dimension(1:4, 1:4), intent(in) :: matrix, matrix_n @@ -412,7 +412,7 @@ contains !> This procedure transforms a model by a matrix, one triangle at a time. !! @param model Model to transform. !! @param matrix Transformation matrix. - pure subroutine s_transform_model(model, matrix, matrix_n) + subroutine s_transform_model(model, matrix, matrix_n) type(t_model), intent(inout) :: model real(wp), dimension(1:4, 1:4), intent(in) :: matrix, matrix_n @@ -428,7 +428,7 @@ contains !> This procedure creates a bounding box for a model. !! @param model Model to create bounding box for. !! @return Bounding box. - pure function f_create_bbox(model) result(bbox) + function f_create_bbox(model) result(bbox) type(t_model), intent(in) :: model type(t_bbox) :: bbox @@ -457,7 +457,7 @@ contains !! @param lhs logical input. !! @param rhs other logical input. !! @return xored result. - pure elemental function f_xor(lhs, rhs) result(res) + elemental function f_xor(lhs, rhs) result(res) logical, intent(in) :: lhs, rhs logical :: res @@ -468,7 +468,7 @@ contains !> This procedure converts logical to 1 or 0. !! @param perdicate A Logical argument. !! @return 1 if .true., 0 if .false.. - pure elemental function f_logical_to_int(predicate) result(int) + elemental function f_logical_to_int(predicate) result(int) logical, intent(in) :: predicate integer :: int @@ -484,7 +484,7 @@ contains !! @param x is the input value !! @param l is the degree !! @return P is the unassociated legendre polynomial evaluated at x - pure recursive function unassociated_legendre(x, l) result(result_P) + recursive function unassociated_legendre(x, l) result(result_P) integer, intent(in) :: l real(wp), intent(in) :: x @@ -506,7 +506,7 @@ contains !! @param l is the degree !! @param m_order is the order !! @return Y is the spherical harmonic function evaluated at x and phi - pure recursive function spherical_harmonic_func(x, phi, l, m_order) result(Y) + recursive function spherical_harmonic_func(x, phi, l, m_order) result(Y) integer, intent(in) :: l, m_order real(wp), intent(in) :: x, phi @@ -528,7 +528,7 @@ contains !! @param l is the degree !! @param m_order is the order !! @return P is the associated legendre polynomial evaluated at x - pure recursive function associated_legendre(x, l, m_order) result(result_P) + recursive function associated_legendre(x, l, m_order) result(result_P) integer, intent(in) :: l, m_order real(wp), intent(in) :: x @@ -553,7 +553,7 @@ contains !> This function calculates the double factorial value of an integer !! @param n_in is the input integer !! @return R is the double factorial value of n - pure elemental function double_factorial(n_in) result(R_result) + elemental function double_factorial(n_in) result(R_result) integer, intent(in) :: n_in integer, parameter :: int64_kind = selected_int_kind(18) ! 18 bytes for 64-bit integer @@ -567,7 +567,7 @@ contains !> The following function calculates the factorial value of an integer !! @param n_in is the input integer !! @return R is the factorial value of n - pure elemental function factorial(n_in) result(R_result) + elemental function factorial(n_in) result(R_result) integer, intent(in) :: n_in integer, parameter :: int64_kind = selected_int_kind(18) ! 18 bytes for 64-bit integer diff --git a/src/common/m_helper_basic.fpp b/src/common/m_helper_basic.fpp index 359055a44d..0ee3102938 100644 --- a/src/common/m_helper_basic.fpp +++ b/src/common/m_helper_basic.fpp @@ -26,7 +26,7 @@ contains !! @param b Second number. !! @param tol_input Relative error (default = 1.e-10_wp). !! @return Result of the comparison. - logical pure elemental function f_approx_equal(a, b, tol_input) result(res) + logical elemental function f_approx_equal(a, b, tol_input) result(res) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: a, b real(wp), optional, intent(in) :: tol_input @@ -52,7 +52,7 @@ contains !! @param b Array that contains several point numbers. !! @param tol_input Relative error (default = 1e-10_wp). !! @return Result of the comparison. - logical pure function f_approx_in_array(a, b, tol_input) result(res) + logical function f_approx_in_array(a, b, tol_input) result(res) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: a real(wp), intent(in) :: b(:) @@ -78,7 +78,7 @@ contains !> Checks if a real(wp) variable is of default value. !! @param var Variable to check. - logical pure elemental function f_is_default(var) result(res) + logical elemental function f_is_default(var) result(res) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: var @@ -87,7 +87,7 @@ contains !> Checks if ALL elements of a real(wp) array are of default value. !! @param var_array Array to check. - logical pure function f_all_default(var_array) result(res) + logical function f_all_default(var_array) result(res) real(wp), intent(in) :: var_array(:) ! logical :: res_array(size(var_array)) ! integer :: i @@ -103,14 +103,14 @@ contains !> Checks if a real(wp) variable is an integer. !! @param var Variable to check. - logical pure elemental function f_is_integer(var) result(res) + logical elemental function f_is_integer(var) result(res) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: var res = f_approx_equal(var, real(nint(var), wp)) end function f_is_integer - pure subroutine s_configure_coordinate_bounds(weno_polyn, buff_size, idwint, idwbuff, & + subroutine s_configure_coordinate_bounds(weno_polyn, buff_size, idwint, idwbuff, & viscous, bubbles_lagrange, m, n, p, num_dims, igr) integer, intent(in) :: weno_polyn, m, n, p, num_dims diff --git a/src/common/m_phase_change.fpp b/src/common/m_phase_change.fpp index e04242a787..8f4cdf51c5 100644 --- a/src/common/m_phase_change.fpp +++ b/src/common/m_phase_change.fpp @@ -80,7 +80,7 @@ contains !! model, also considering mass depletion, depending on the incoming !! state conditions. !! @param q_cons_vf Cell-average conservative variables - pure subroutine s_infinite_relaxation_k(q_cons_vf) + subroutine s_infinite_relaxation_k(q_cons_vf) type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf real(wp) :: pS, pSOV, pSSL !< equilibrium pressure for mixture, overheated vapor, and subcooled liquid @@ -279,14 +279,14 @@ contains !! @param j generic loop iterator for x direction !! @param k generic loop iterator for y direction !! @param l generic loop iterator for z direction - !! @param MFL flag that tells whether the fluid is pure gas (0), pure liquid (1), or a mixture (2) + !! @param MFL flag that tells whether the fluid is gas (0), liquid (1), or a mixture (2) !! @param pS equilibrium pressure at the interface !! @param p_infpT stiffness for the participating fluids under pT-equilibrium !! @param rM sum of the reacting masses !! @param q_cons_vf Cell-average conservative variables !! @param rhoe mixture energy !! @param TS equilibrium temperature at the interface - pure subroutine s_infinite_pt_relaxation_k(j, k, l, MFL, pS, p_infpT, q_cons_vf, rhoe, TS) + subroutine s_infinite_pt_relaxation_k(j, k, l, MFL, pS, p_infpT, q_cons_vf, rhoe, TS) $:GPU_ROUTINE(function_name='s_infinite_pt_relaxation_k', & & parallelism='[seq]', cray_inline=True) @@ -386,7 +386,7 @@ contains !! @param rhoe mixture energy !! @param q_cons_vf Cell-average conservative variables !! @param TS equilibrium temperature at the interface - pure subroutine s_infinite_ptg_relaxation_k(j, k, l, pS, p_infpT, rhoe, q_cons_vf, TS) + subroutine s_infinite_ptg_relaxation_k(j, k, l, pS, p_infpT, rhoe, q_cons_vf, TS) $:GPU_ROUTINE(function_name='s_infinite_ptg_relaxation_k', & & parallelism='[seq]', cray_inline=True) @@ -507,7 +507,7 @@ contains !! @param j generic loop iterator for x direction !! @param k generic loop iterator for y direction !! @param l generic loop iterator for z direction - pure subroutine s_correct_partial_densities(MCT, q_cons_vf, rM, j, k, l) + subroutine s_correct_partial_densities(MCT, q_cons_vf, rM, j, k, l) $:GPU_ROUTINE(function_name='s_correct_partial_densities', & & parallelism='[seq]', cray_inline=True) @@ -566,7 +566,7 @@ contains !! @param pS equilibrium pressure at the interface !! @param q_cons_vf Cell-average conservative variables !! @param TJac Transpose of the Jacobian Matrix - pure subroutine s_compute_jacobian_matrix(InvJac, j, Jac, k, l, mCPD, mCVGP, mCVGP2, pS, q_cons_vf, TJac) + subroutine s_compute_jacobian_matrix(InvJac, j, Jac, k, l, mCPD, mCVGP, mCVGP2, pS, q_cons_vf, TJac) $:GPU_ROUTINE(function_name='s_compute_jacobian_matrix', & & parallelism='[seq]', cray_inline=True) @@ -669,7 +669,7 @@ contains !! @param pS equilibrium pressure at the interface !! @param rhoe mixture energy !! @param R2D (2D) residue array - pure subroutine s_compute_pTg_residue(j, k, l, mCPD, mCVGP, mQD, q_cons_vf, pS, rhoe, R2D) + subroutine s_compute_pTg_residue(j, k, l, mCPD, mCVGP, mQD, q_cons_vf, pS, rhoe, R2D) $:GPU_ROUTINE(function_name='s_compute_pTg_residue', & & parallelism='[seq]', cray_inline=True) @@ -716,7 +716,7 @@ contains !! @param pSat Saturation Pressure !! @param TSat Saturation Temperature !! @param TSIn equilibrium Temperature - pure elemental subroutine s_TSat(pSat, TSat, TSIn) + elemental subroutine s_TSat(pSat, TSat, TSIn) $:GPU_ROUTINE(function_name='s_TSat',parallelism='[seq]', & & cray_inline=True) diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index b9ef279f9e..32821fb679 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -464,7 +464,7 @@ contains end subroutine s_convert_species_to_mixture_variables - pure subroutine s_convert_species_to_mixture_variables_acc(rho_K, & + subroutine s_convert_species_to_mixture_variables_acc(rho_K, & gamma_K, pi_inf_K, qv_K, & alpha_K, alpha_rho_K, Re_K, & G_K, G) @@ -543,7 +543,7 @@ contains end subroutine s_convert_species_to_mixture_variables_acc - pure subroutine s_convert_species_to_mixture_variables_bubbles_acc(rho_K, & + subroutine s_convert_species_to_mixture_variables_bubbles_acc(rho_K, & gamma_K, pi_inf_K, qv_K, & alpha_K, alpha_rho_K, Re_K) $:GPU_ROUTINE(function_name='s_convert_species_to_mixture_variables_bubbles_acc', & @@ -737,7 +737,7 @@ contains end subroutine s_initialize_variables_conversion_module !Initialize mv at the quadrature nodes based on the initialized moments and sigma - pure subroutine s_initialize_mv(qK_cons_vf, mv) + subroutine s_initialize_mv(qK_cons_vf, mv) type(scalar_field), dimension(sys_size), intent(in) :: qK_cons_vf @@ -770,7 +770,7 @@ contains end subroutine s_initialize_mv !Initialize pb at the quadrature nodes using isothermal relations (Preston model) - pure subroutine s_initialize_pb(qK_cons_vf, mv, pb) + subroutine s_initialize_pb(qK_cons_vf, mv, pb) type(scalar_field), dimension(sys_size), intent(in) :: qK_cons_vf real(wp), dimension(idwint(1)%beg:, idwint(2)%beg:, idwint(3)%beg:, 1:, 1:), intent(in) :: mv @@ -1622,7 +1622,7 @@ contains end subroutine s_finalize_variables_conversion_module #ifndef MFC_PRE_PROCESS - pure subroutine s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, adv, vel_sum, c_c, c) + subroutine s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, adv, vel_sum, c_c, c) $:GPU_ROUTINE(function_name='s_compute_speed_of_sound', & & parallelism='[seq]', cray_inline=True) @@ -1689,7 +1689,7 @@ contains #endif #ifndef MFC_PRE_PROCESS - pure subroutine s_compute_fast_magnetosonic_speed(rho, c, B, norm, c_fast, h) + subroutine s_compute_fast_magnetosonic_speed(rho, c, B, norm, c_fast, h) $:GPU_ROUTINE(function_name='s_compute_fast_magnetosonic_speed', & & parallelism='[seq]', cray_inline=True) diff --git a/src/simulation/m_acoustic_src.fpp b/src/simulation/m_acoustic_src.fpp index b14528b9d5..28009427bb 100644 --- a/src/simulation/m_acoustic_src.fpp +++ b/src/simulation/m_acoustic_src.fpp @@ -345,7 +345,7 @@ contains !! @param frequency_local Frequency at the spatial location for sine and square waves !! @param gauss_sigma_time_local sigma in time for Gaussian pulse !! @param source Source term amplitude - pure elemental subroutine s_source_temporal(sim_time, c, ai, term_index, frequency_local, gauss_sigma_time_local, source, sum_BB) + elemental subroutine s_source_temporal(sim_time, c, ai, term_index, frequency_local, gauss_sigma_time_local, source, sum_BB) $:GPU_ROUTINE(parallelism='[seq]') integer, intent(in) :: ai, term_index real(wp), intent(in) :: sim_time, c, sum_BB @@ -504,7 +504,7 @@ contains !! @param source Source term amplitude !! @param angle Angle of the source term with respect to the x-axis (for 2D or 2D axisymmetric) !! @param xyz_to_r_ratios Ratios of the [xyz]-component of the source term to the magnitude (for 3D) - pure subroutine s_source_spatial(j, k, l, loc, ai, source, angle, xyz_to_r_ratios) + subroutine s_source_spatial(j, k, l, loc, ai, source, angle, xyz_to_r_ratios) integer, intent(in) :: j, k, l, ai real(wp), dimension(3), intent(in) :: loc real(wp), intent(out) :: source, angle, xyz_to_r_ratios(3) @@ -540,7 +540,7 @@ contains !! @param sig Sigma value for the Gaussian distribution !! @param r Displacement from source to current point !! @param source Source term amplitude - pure subroutine s_source_spatial_planar(ai, sig, r, source) + subroutine s_source_spatial_planar(ai, sig, r, source) integer, intent(in) :: ai real(wp), intent(in) :: sig, r(3) real(wp), intent(out) :: source @@ -570,7 +570,7 @@ contains !! @param source Source term amplitude !! @param angle Angle of the source term with respect to the x-axis (for 2D or 2D axisymmetric) !! @param xyz_to_r_ratios Ratios of the [xyz]-component of the source term to the magnitude (for 3D) - pure subroutine s_source_spatial_transducer(ai, sig, r, source, angle, xyz_to_r_ratios) + subroutine s_source_spatial_transducer(ai, sig, r, source, angle, xyz_to_r_ratios) integer, intent(in) :: ai real(wp), intent(in) :: sig, r(3) real(wp), intent(out) :: source, angle, xyz_to_r_ratios(3) @@ -615,7 +615,7 @@ contains !! @param source Source term amplitude !! @param angle Angle of the source term with respect to the x-axis (for 2D or 2D axisymmetric) !! @param xyz_to_r_ratios Ratios of the [xyz]-component of the source term to the magnitude (for 3D) - pure subroutine s_source_spatial_transducer_array(ai, sig, r, source, angle, xyz_to_r_ratios) + subroutine s_source_spatial_transducer_array(ai, sig, r, source, angle, xyz_to_r_ratios) integer, intent(in) :: ai real(wp), intent(in) :: sig, r(3) real(wp), intent(out) :: source, angle, xyz_to_r_ratios(3) @@ -697,7 +697,7 @@ contains !! @param ai Acoustic source index !! @param c Speed of sound !! @return frequency_local Converted frequency - pure elemental function f_frequency_local(freq_conv_flag, ai, c) + elemental function f_frequency_local(freq_conv_flag, ai, c) $:GPU_ROUTINE(parallelism='[seq]') logical, intent(in) :: freq_conv_flag integer, intent(in) :: ai @@ -716,7 +716,7 @@ contains !! @param c Speed of sound !! @param ai Acoustic source index !! @return gauss_sigma_time_local Converted Gaussian sigma time - pure elemental function f_gauss_sigma_time_local(gauss_conv_flag, ai, c) + elemental function f_gauss_sigma_time_local(gauss_conv_flag, ai, c) $:GPU_ROUTINE(parallelism='[seq]') logical, intent(in) :: gauss_conv_flag integer, intent(in) :: ai diff --git a/src/simulation/m_bubbles.fpp b/src/simulation/m_bubbles.fpp index 0ec758dc22..549c38873c 100644 --- a/src/simulation/m_bubbles.fpp +++ b/src/simulation/m_bubbles.fpp @@ -40,7 +40,7 @@ contains !! @param f_bub_adv_src Source for bubble volume fraction !! @param f_divu Divergence of velocity !! @param fCson Speed of sound from fP (EL) - pure elemental function f_rddot(fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, fntait, fBtait, f_bub_adv_src, f_divu, fCson) + elemental function f_rddot(fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, fntait, fBtait, f_bub_adv_src, f_divu, fCson) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fRho, fP, fR, fV, fR0, fpb, fpbdot, alf real(wp), intent(in) :: fntait, fBtait, f_bub_adv_src, f_divu @@ -81,7 +81,7 @@ contains !! @param fR Current bubble radius !! @param fV Current bubble velocity !! @param fpb Internal bubble pressure - pure elemental function f_cpbw(fR0, fR, fV, fpb) + elemental function f_cpbw(fR0, fR, fV, fpb) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fR0, fR, fV, fpb @@ -100,7 +100,7 @@ contains !! @param fCpinf Driving bubble pressure !! @param fntait Tait EOS parameter !! @param fBtait Tait EOS parameter - pure elemental function f_H(fCpbw, fCpinf, fntait, fBtait) + elemental function f_H(fCpbw, fCpinf, fntait, fBtait) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fCpbw, fCpinf, fntait, fBtait @@ -120,7 +120,7 @@ contains !! @param fntait Tait EOS parameter !! @param fBtait Tait EOS parameter !! @param fH Bubble enthalpy - pure elemental function f_cgas(fCpinf, fntait, fBtait, fH) + elemental function f_cgas(fCpinf, fntait, fBtait, fH) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fCpinf, fntait, fBtait, fH @@ -143,7 +143,7 @@ contains !! @param fBtait Tait EOS parameter !! @param advsrc Advection equation source term !! @param divu Divergence of velocity - pure elemental function f_cpinfdot(fRho, fP, falf, fntait, fBtait, advsrc, divu) + elemental function f_cpinfdot(fRho, fP, falf, fntait, fBtait, advsrc, divu) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fRho, fP, falf, fntait, fBtait, advsrc, divu @@ -173,7 +173,7 @@ contains !! @param fV Current bubble velocity !! @param fR0 Equilibrium bubble radius !! @param fpbdot Time derivative of the internal bubble pressure - pure elemental function f_Hdot(fCpbw, fCpinf, fCpinf_dot, fntait, fBtait, fR, fV, fR0, fpbdot) + elemental function f_Hdot(fCpbw, fCpinf, fCpinf_dot, fntait, fBtait, fR, fV, fR0, fpbdot) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fCpbw, fCpinf, fCpinf_dot, fntait, fBtait real(wp), intent(in) :: fR, fV, fR0, fpbdot @@ -209,7 +209,7 @@ contains !! @param fV Current bubble velocity !! @param fR0 Equilibrium bubble radius !! @param fCpbw Boundary wall pressure - pure elemental function f_rddot_RP(fCp, fRho, fR, fV, fCpbw) + elemental function f_rddot_RP(fCp, fRho, fR, fV, fCpbw) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fCp, fRho, fR, fV, fCpbw @@ -232,7 +232,7 @@ contains !! @param fcgas Current gas sound speed !! @param fntait Tait EOS parameter !! @param fBtait Tait EOS parameter - pure elemental function f_rddot_G(fCpbw, fR, fV, fH, fHdot, fcgas, fntait, fBtait) + elemental function f_rddot_G(fCpbw, fR, fV, fH, fHdot, fcgas, fntait, fBtait) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fCpbw, fR, fV, fH, fHdot real(wp), intent(in) :: fcgas, fntait, fBtait @@ -255,7 +255,7 @@ contains !! @param fR Current bubble radius !! @param fV Current bubble velocity !! @param fpb Internal bubble pressure - pure elemental function f_cpbw_KM(fR0, fR, fV, fpb) + elemental function f_cpbw_KM(fR0, fR, fV, fpb) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fR0, fR, fV, fpb real(wp) :: f_cpbw_KM @@ -282,7 +282,7 @@ contains !! @param fV Current bubble velocity !! @param fR0 Equilibrium bubble radius !! @param fC Current sound speed - pure elemental function f_rddot_KM(fpbdot, fCp, fCpbw, fRho, fR, fV, fR0, fC) + elemental function f_rddot_KM(fpbdot, fCp, fCpbw, fRho, fR, fV, fR0, fC) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fpbdot, fCp, fCpbw real(wp), intent(in) :: fRho, fR, fV, fR0, fC @@ -316,7 +316,7 @@ contains !> Subroutine that computes bubble wall properties for vapor bubbles !! @param pb Internal bubble pressure !! @param iR0 Current bubble size index - pure elemental subroutine s_bwproperty(pb_in, iR0, chi_vw_out, k_mw_out, rho_mw_out) + elemental subroutine s_bwproperty(pb_in, iR0, chi_vw_out, k_mw_out, rho_mw_out) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: pb_in integer, intent(in) :: iR0 @@ -346,7 +346,7 @@ contains !! @param fbeta_c Mass transfer coefficient (EL) !! @param fR_m Mixture gas constant (EL) !! @param fgamma_m Mixture gamma (EL) - pure elemental subroutine s_vflux(fR, fV, fpb, fmass_v, iR0, vflux, fmass_n, fbeta_c, fR_m, fgamma_m) + elemental subroutine s_vflux(fR, fV, fpb, fmass_v, iR0, vflux, fmass_n, fbeta_c, fR_m, fgamma_m) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fR real(wp), intent(in) :: fV @@ -404,7 +404,7 @@ contains !! @param fbeta_t Mass transfer coefficient (EL) !! @param fR_m Mixture gas constant (EL) !! @param fgamma_m Mixture gamma (EL) - pure elemental function f_bpres_dot(fvflux, fR, fV, fpb, fmass_v, iR0, fbeta_t, fR_m, fgamma_m) + elemental function f_bpres_dot(fvflux, fR, fV, fpb, fmass_v, iR0, fbeta_t, fR_m, fgamma_m) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: fvflux real(wp), intent(in) :: fR @@ -461,7 +461,7 @@ contains !! @param fbeta_t Heat transfer coefficient (EL) !! @param fCson Speed of sound (EL) !! @param adap_dt_stop Fail-safe exit if max iteration count reached - pure subroutine s_advance_step(fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, & + subroutine s_advance_step(fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, & fntait, fBtait, f_bub_adv_src, f_divu, & bub_id, fmass_v, fmass_n, fbeta_c, & fbeta_t, fCson, adap_dt_stop) @@ -594,7 +594,7 @@ contains !! @param f_divu Divergence of velocity !! @param fCson Speed of sound (EL) !! @param h Time step size - pure subroutine s_initial_substep_h(fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, & + subroutine s_initial_substep_h(fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, & fntait, fBtait, f_bub_adv_src, f_divu, & fCson, h) $:GPU_ROUTINE(function_name='s_initial_substep_h',parallelism='[seq]', & @@ -676,7 +676,7 @@ contains !! @param myV_tmp Bubble radial velocity at each stage !! @param myPb_tmp Internal bubble pressure at each stage (EL) !! @param myMv_tmp Mass of vapor in the bubble at each stage (EL) - pure subroutine s_advance_substep(err, fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, & + subroutine s_advance_substep(err, fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, & fntait, fBtait, f_bub_adv_src, f_divu, & bub_id, fmass_v, fmass_n, fbeta_c, & fbeta_t, fCson, h, & @@ -778,7 +778,7 @@ contains !! @param fMv_tmp Mass of vapor in the bubble !! @param fdPbdt_tmp Rate of change of the internal bubble pressure !! @param fdMvdt_tmp Rate of change of the mass of vapor in the bubble - pure elemental subroutine s_advance_EL(fR_tmp, fV_tmp, fPb_tmp, fMv_tmp, bub_id, & + elemental subroutine s_advance_EL(fR_tmp, fV_tmp, fPb_tmp, fMv_tmp, bub_id, & fmass_n, fbeta_c, fbeta_t, fdPbdt_tmp, advance_EL) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(IN) :: fR_tmp, fV_tmp, fPb_tmp, fMv_tmp diff --git a/src/simulation/m_bubbles_EE.fpp b/src/simulation/m_bubbles_EE.fpp index b43a89e2e5..d2aa192750 100644 --- a/src/simulation/m_bubbles_EE.fpp +++ b/src/simulation/m_bubbles_EE.fpp @@ -71,7 +71,7 @@ contains ! Compute the bubble volume fraction alpha from the bubble number density n !! @param q_cons_vf is the conservative variable - pure subroutine s_comp_alpha_from_n(q_cons_vf) + subroutine s_comp_alpha_from_n(q_cons_vf) type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf real(wp) :: nR3bar integer(wp) :: i, j, k, l @@ -92,7 +92,7 @@ contains end subroutine s_comp_alpha_from_n - pure subroutine s_compute_bubbles_EE_rhs(idir, q_prim_vf, divu_in) + subroutine s_compute_bubbles_EE_rhs(idir, q_prim_vf, divu_in) integer, intent(in) :: idir type(scalar_field), dimension(sys_size), intent(in) :: q_prim_vf diff --git a/src/simulation/m_bubbles_EL.fpp b/src/simulation/m_bubbles_EL.fpp index bacd19497d..b1e06f2f85 100644 --- a/src/simulation/m_bubbles_EL.fpp +++ b/src/simulation/m_bubbles_EL.fpp @@ -739,7 +739,7 @@ contains !! @param gamma Liquid specific heat ratio !! @param pi_inf Liquid stiffness !! @param cson Calculated speed of sound - pure subroutine s_compute_cson_from_pinf(q_prim_vf, pinf, cell, rhol, gamma, pi_inf, cson) + subroutine s_compute_cson_from_pinf(q_prim_vf, pinf, cell, rhol, gamma, pi_inf, cson) $:GPU_ROUTINE(function_name='s_compute_cson_from_pinf', & & parallelism='[seq]', cray_inline=True) @@ -807,7 +807,7 @@ contains !! @param f_pinfl Driving pressure !! @param cell Bubble cell !! @param Romega Control volume radius - pure subroutine s_get_pinf(bub_id, q_prim_vf, ptype, f_pinfl, cell, preterm1, term2, Romega) + subroutine s_get_pinf(bub_id, q_prim_vf, ptype, f_pinfl, cell, preterm1, term2, Romega) $:GPU_ROUTINE(function_name='s_get_pinf',parallelism='[seq]', & & cray_inline=True) @@ -1136,7 +1136,7 @@ contains !! @param pos Input coordinates !! @param cell Computational coordinate of the cell !! @param scoord Calculated particle coordinates - pure subroutine s_locate_cell(pos, cell, scoord) + subroutine s_locate_cell(pos, cell, scoord) real(wp), dimension(3), intent(in) :: pos real(wp), dimension(3), intent(out) :: scoord @@ -1209,7 +1209,7 @@ contains !> The purpose of this procedure is to determine if the global coordinates of the bubbles !! are present in the current MPI processor (including ghost cells). !! @param pos_part Spatial coordinates of the bubble - pure function particle_in_domain(pos_part) + function particle_in_domain(pos_part) logical :: particle_in_domain real(wp), dimension(3), intent(in) :: pos_part @@ -1262,7 +1262,7 @@ contains !> The purpose of this procedure is to determine if the lagrangian bubble is located in the !! physical domain. The ghost cells are not part of the physical domain. !! @param pos_part Spatial coordinates of the bubble - pure function particle_in_domain_physical(pos_part) + function particle_in_domain_physical(pos_part) logical :: particle_in_domain_physical real(wp), dimension(3), intent(in) :: pos_part @@ -1281,7 +1281,7 @@ contains !! @param q Input scalar field !! @param dq Output gradient of q !! @param dir Gradient spatial direction - pure subroutine s_gradient_dir(q, dq, dir) + subroutine s_gradient_dir(q, dq, dir) type(scalar_field), intent(inout) :: q type(scalar_field), intent(inout) :: dq diff --git a/src/simulation/m_bubbles_EL_kernels.fpp b/src/simulation/m_bubbles_EL_kernels.fpp index 48ea3bad9a..6f9c71a4c0 100644 --- a/src/simulation/m_bubbles_EL_kernels.fpp +++ b/src/simulation/m_bubbles_EL_kernels.fpp @@ -22,7 +22,7 @@ contains !! @param lbk_s Computational coordinates of the bubbles !! @param lbk_pos Spatial coordinates of the bubbles !! @param updatedvar Eulerian variable to be updated - pure subroutine s_smoothfunction(nBubs, lbk_rad, lbk_vel, lbk_s, lbk_pos, updatedvar) + subroutine s_smoothfunction(nBubs, lbk_rad, lbk_vel, lbk_s, lbk_pos, updatedvar) integer, intent(in) :: nBubs real(wp), dimension(1:lag_params%nBubs_glb, 1:3, 1:2), intent(in) :: lbk_s, lbk_pos @@ -40,7 +40,7 @@ contains !> The purpose of this procedure contains the algorithm to use the delta kernel function to map the effect of the bubbles. !! The effect of the bubbles only affects the cell where the bubble is located. - pure subroutine s_deltafunc(nBubs, lbk_rad, lbk_vel, lbk_s, updatedvar) + subroutine s_deltafunc(nBubs, lbk_rad, lbk_vel, lbk_s, updatedvar) integer, intent(in) :: nBubs real(wp), dimension(1:lag_params%nBubs_glb, 1:3, 1:2), intent(in) :: lbk_s @@ -95,7 +95,7 @@ contains !> The purpose of this procedure contains the algorithm to use the gaussian kernel function to map the effect of the bubbles. !! The effect of the bubbles affects the 3X3x3 cells that surround the bubble. - pure subroutine s_gaussian(nBubs, lbk_rad, lbk_vel, lbk_s, lbk_pos, updatedvar) + subroutine s_gaussian(nBubs, lbk_rad, lbk_vel, lbk_s, lbk_pos, updatedvar) integer, intent(in) :: nBubs real(wp), dimension(1:lag_params%nBubs_glb, 1:3, 1:2), intent(in) :: lbk_s, lbk_pos @@ -199,7 +199,7 @@ contains end subroutine s_gaussian !> The purpose of this subroutine is to apply the gaussian kernel function for each bubble (Maeda and Colonius, 2018)). - pure subroutine s_applygaussian(center, cellaux, nodecoord, stddsv, strength_idx, func) + subroutine s_applygaussian(center, cellaux, nodecoord, stddsv, strength_idx, func) $:GPU_ROUTINE(function_name='s_applygaussian',parallelism='[seq]', & & cray_inline=True) @@ -267,7 +267,7 @@ contains !> The purpose of this subroutine is to check if the current cell is outside the computational domain or not (including ghost cells). !! @param cellaux Tested cell to smear the bubble effect in. !! @param celloutside If true, then cellaux is outside the computational domain. - pure subroutine s_check_celloutside(cellaux, celloutside) + subroutine s_check_celloutside(cellaux, celloutside) $:GPU_ROUTINE(function_name='s_check_celloutside',parallelism='[seq]', & & cray_inline=True) @@ -301,7 +301,7 @@ contains !> This subroutine relocates the current cell, if it intersects a symmetric boundary. !! @param cell Cell of the current bubble !! @param cellaux Cell to map the bubble effect in. - pure subroutine s_shift_cell_symmetric_bc(cellaux, cell) + subroutine s_shift_cell_symmetric_bc(cellaux, cell) $:GPU_ROUTINE(function_name='s_shift_cell_symmetric_bc', & & parallelism='[seq]', cray_inline=True) @@ -340,7 +340,7 @@ contains !! @param cell Cell where the bubble is located !! @param volpart Volume of the bubble !! @param stddsv Standard deviaton - pure subroutine s_compute_stddsv(cell, volpart, stddsv) + subroutine s_compute_stddsv(cell, volpart, stddsv) $:GPU_ROUTINE(function_name='s_compute_stddsv',parallelism='[seq]', & & cray_inline=True) @@ -379,7 +379,7 @@ contains !> The purpose of this procedure is to calculate the characteristic cell volume !! @param cell Computational coordinates (x, y, z) !! @param Charvol Characteristic volume - pure elemental subroutine s_get_char_vol(cellx, celly, cellz, Charvol) + elemental subroutine s_get_char_vol(cellx, celly, cellz, Charvol) $:GPU_ROUTINE(function_name='s_get_char_vol',parallelism='[seq]', & & cray_inline=True) @@ -402,7 +402,7 @@ contains !! real type into integer. !! @param s Computational coordinates of the bubble, real type !! @param get_cell Computational coordinates of the bubble, integer type - pure subroutine s_get_cell(s_cell, get_cell) + subroutine s_get_cell(s_cell, get_cell) $:GPU_ROUTINE(function_name='s_get_cell',parallelism='[seq]', & & cray_inline=True) diff --git a/src/simulation/m_cbc.fpp b/src/simulation/m_cbc.fpp index da6cba12ac..1cb84e55c7 100644 --- a/src/simulation/m_cbc.fpp +++ b/src/simulation/m_cbc.fpp @@ -1571,7 +1571,7 @@ contains end subroutine s_finalize_cbc ! Detext if the problem has any characteristic boundary conditions - pure elemental subroutine s_any_cbc_boundaries(toggle) + elemental subroutine s_any_cbc_boundaries(toggle) logical, intent(inout) :: toggle diff --git a/src/simulation/m_compute_cbc.fpp b/src/simulation/m_compute_cbc.fpp index 694f6735b2..a6e19c0ed4 100644 --- a/src/simulation/m_compute_cbc.fpp +++ b/src/simulation/m_compute_cbc.fpp @@ -19,7 +19,7 @@ module m_compute_cbc contains !> Base L1 calculation - pure function f_base_L1(lambda, rho, c, dpres_ds, dvel_ds) result(L1) + function f_base_L1(lambda, rho, c, dpres_ds, dvel_ds) result(L1) $:GPU_ROUTINE(parallelism='[seq]') real(wp), dimension(3), intent(in) :: lambda real(wp), intent(in) :: rho, c, dpres_ds @@ -29,7 +29,7 @@ contains end function f_base_L1 !> Fill density L variables - pure subroutine s_fill_density_L(L, lambda_factor, lambda2, c, mf, dalpha_rho_ds, dpres_ds) + subroutine s_fill_density_L(L, lambda_factor, lambda2, c, mf, dalpha_rho_ds, dpres_ds) $:GPU_ROUTINE(parallelism='[seq]') real(wp), dimension(sys_size), intent(inout) :: L real(wp), intent(in) :: lambda_factor, lambda2, c @@ -43,7 +43,7 @@ contains end subroutine s_fill_density_L !> Fill velocity L variables - pure subroutine s_fill_velocity_L(L, lambda_factor, lambda2, dvel_ds) + subroutine s_fill_velocity_L(L, lambda_factor, lambda2, dvel_ds) $:GPU_ROUTINE(parallelism='[seq]') real(wp), dimension(sys_size), intent(inout) :: L real(wp), intent(in) :: lambda_factor, lambda2 @@ -56,7 +56,7 @@ contains end subroutine s_fill_velocity_L !> Fill advection L variables - pure subroutine s_fill_advection_L(L, lambda_factor, lambda2, dadv_ds) + subroutine s_fill_advection_L(L, lambda_factor, lambda2, dadv_ds) $:GPU_ROUTINE(parallelism='[seq]') real(wp), dimension(sys_size), intent(inout) :: L real(wp), intent(in) :: lambda_factor, lambda2 @@ -69,7 +69,7 @@ contains end subroutine s_fill_advection_L !> Fill chemistry L variables - pure subroutine s_fill_chemistry_L(L, lambda_factor, lambda2, dYs_ds) + subroutine s_fill_chemistry_L(L, lambda_factor, lambda2, dYs_ds) $:GPU_ROUTINE(parallelism='[seq]') real(wp), dimension(sys_size), intent(inout) :: L real(wp), intent(in) :: lambda_factor, lambda2 @@ -84,7 +84,7 @@ contains end subroutine s_fill_chemistry_L !> Slip wall CBC (Thompson 1990, pg. 451) - pure subroutine s_compute_slip_wall_L(lambda, L, rho, c, dpres_ds, dvel_ds) + subroutine s_compute_slip_wall_L(lambda, L, rho, c, dpres_ds, dvel_ds) $:GPU_ROUTINE(function_name='s_compute_slip_wall_L',parallelism='[seq]', & & cray_inline=True) @@ -100,7 +100,7 @@ contains end subroutine s_compute_slip_wall_L !> Nonreflecting subsonic buffer CBC (Thompson 1987, pg. 13) - pure subroutine s_compute_nonreflecting_subsonic_buffer_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) + subroutine s_compute_nonreflecting_subsonic_buffer_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) $:GPU_ROUTINE(function_name='s_compute_nonreflecting_subsonic_buffer_L', & & parallelism='[seq]', cray_inline=True) @@ -128,7 +128,7 @@ contains end subroutine s_compute_nonreflecting_subsonic_buffer_L !> Nonreflecting subsonic inflow CBC (Thompson 1990, pg. 455) - pure subroutine s_compute_nonreflecting_subsonic_inflow_L(lambda, L, rho, c, dpres_ds, dvel_ds) + subroutine s_compute_nonreflecting_subsonic_inflow_L(lambda, L, rho, c, dpres_ds, dvel_ds) $:GPU_ROUTINE(function_name='s_compute_nonreflecting_subsonic_inflow_L', & & parallelism='[seq]', cray_inline=True) @@ -143,7 +143,7 @@ contains end subroutine s_compute_nonreflecting_subsonic_inflow_L !> Nonreflecting subsonic outflow CBC (Thompson 1990, pg. 454) - pure subroutine s_compute_nonreflecting_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) + subroutine s_compute_nonreflecting_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) $:GPU_ROUTINE(function_name='s_compute_nonreflecting_subsonic_outflow_L', & & parallelism='[seq]', cray_inline=True) @@ -165,7 +165,7 @@ contains end subroutine s_compute_nonreflecting_subsonic_outflow_L !> Force-free subsonic outflow CBC (Thompson 1990, pg. 454) - pure subroutine s_compute_force_free_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds) + subroutine s_compute_force_free_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds) $:GPU_ROUTINE(function_name='s_compute_force_free_subsonic_outflow_L', & & parallelism='[seq]', cray_inline=True) @@ -185,7 +185,7 @@ contains end subroutine s_compute_force_free_subsonic_outflow_L !> Constant pressure subsonic outflow CBC (Thompson 1990, pg. 455) - pure subroutine s_compute_constant_pressure_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds) + subroutine s_compute_constant_pressure_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds) $:GPU_ROUTINE(function_name='s_compute_constant_pressure_subsonic_outflow_L', & & parallelism='[seq]', cray_inline=True) @@ -205,7 +205,7 @@ contains end subroutine s_compute_constant_pressure_subsonic_outflow_L !> Supersonic inflow CBC (Thompson 1990, pg. 453) - pure subroutine s_compute_supersonic_inflow_L(L) + subroutine s_compute_supersonic_inflow_L(L) $:GPU_ROUTINE(function_name='s_compute_supersonic_inflow_L', & & parallelism='[seq]', cray_inline=True) @@ -215,7 +215,7 @@ contains end subroutine s_compute_supersonic_inflow_L !> Supersonic outflow CBC (Thompson 1990, pg. 453) - pure subroutine s_compute_supersonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) + subroutine s_compute_supersonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) $:GPU_ROUTINE(function_name='s_compute_supersonic_outflow_L', & & parallelism='[seq]', cray_inline=True) diff --git a/src/simulation/m_derived_variables.fpp b/src/simulation/m_derived_variables.fpp index 8da88a3a91..467737937e 100644 --- a/src/simulation/m_derived_variables.fpp +++ b/src/simulation/m_derived_variables.fpp @@ -187,7 +187,7 @@ contains !! @param q_prim_vf2 Primitive variables !! @param q_prim_vf3 Primitive variables !! @param q_sf Acceleration component - pure subroutine s_derive_acceleration_component(i, q_prim_vf0, q_prim_vf1, & + subroutine s_derive_acceleration_component(i, q_prim_vf0, q_prim_vf1, & q_prim_vf2, q_prim_vf3, q_sf) integer, intent(in) :: i diff --git a/src/simulation/m_hyperelastic.fpp b/src/simulation/m_hyperelastic.fpp index f4a24fba7a..ba9cc97850 100644 --- a/src/simulation/m_hyperelastic.fpp +++ b/src/simulation/m_hyperelastic.fpp @@ -218,7 +218,7 @@ contains !! calculate the inverse of grad_xi to obtain F, F is a nxn tensor !! calculate the FFtranspose to obtain the btensor, btensor is nxn tensor !! btensor is symmetric, save the data space - pure subroutine s_neoHookean_cauchy_solver(btensor_in, q_prim_vf, G_param, j, k, l) + subroutine s_neoHookean_cauchy_solver(btensor_in, q_prim_vf, G_param, j, k, l) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf type(scalar_field), dimension(b_size), intent(inout) :: btensor_in @@ -257,7 +257,7 @@ contains !! calculate the inverse of grad_xi to obtain F, F is a nxn tensor !! calculate the FFtranspose to obtain the btensor, btensor is nxn tensor !! btensor is symmetric, save the data space - pure subroutine s_Mooney_Rivlin_cauchy_solver(btensor_in, q_prim_vf, G_param, j, k, l) + subroutine s_Mooney_Rivlin_cauchy_solver(btensor_in, q_prim_vf, G_param, j, k, l) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf type(scalar_field), dimension(b_size), intent(inout) :: btensor_in diff --git a/src/simulation/m_hypoelastic.fpp b/src/simulation/m_hypoelastic.fpp index 3f736b0b0b..f763928a64 100644 --- a/src/simulation/m_hypoelastic.fpp +++ b/src/simulation/m_hypoelastic.fpp @@ -381,7 +381,7 @@ contains end subroutine s_finalize_hypoelastic_module - pure subroutine s_compute_damage_state(q_cons_vf, rhs_vf) + subroutine s_compute_damage_state(q_cons_vf, rhs_vf) type(scalar_field), dimension(sys_size), intent(in) :: q_cons_vf type(scalar_field), dimension(sys_size), intent(inout) :: rhs_vf diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index 9b18f5b5fc..09263c1ab5 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -127,7 +127,7 @@ contains !! @param q_prim_vf Primitive variables !! @param pb Internal bubble pressure !! @param mv Mass of vapor in bubble - pure subroutine s_ibm_correct_state(q_cons_vf, q_prim_vf, pb_in, mv_in) + subroutine s_ibm_correct_state(q_cons_vf, q_prim_vf, pb_in, mv_in) type(scalar_field), & dimension(sys_size), & @@ -420,7 +420,7 @@ contains !> Function that finds the number of ghost points, used for allocating !! memory. - pure subroutine s_find_num_ghost_points(num_gps_out, num_inner_gps_out) + subroutine s_find_num_ghost_points(num_gps_out, num_inner_gps_out) integer, intent(out) :: num_gps_out integer, intent(out) :: num_inner_gps_out @@ -468,7 +468,7 @@ contains end subroutine s_find_num_ghost_points !> Function that finds the ghost points - pure subroutine s_find_ghost_points(ghost_points_in, inner_points_in) + subroutine s_find_ghost_points(ghost_points_in, inner_points_in) type(ghost_point), dimension(num_gps), intent(INOUT) :: ghost_points_in type(ghost_point), dimension(num_inner_gps), intent(INOUT) :: inner_points_in @@ -583,7 +583,7 @@ contains end subroutine s_find_ghost_points !> Function that computes the interpolation coefficients of image points - pure subroutine s_compute_interpolation_coeffs(ghost_points_in) + subroutine s_compute_interpolation_coeffs(ghost_points_in) type(ghost_point), dimension(num_gps), intent(INOUT) :: ghost_points_in @@ -737,7 +737,7 @@ contains !> Function that uses the interpolation coefficients and the current state !! at the cell centers in order to estimate the state at the image point - pure subroutine s_interpolate_image_point(q_prim_vf, gp, alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP, r_IP, v_IP, pb_IP, mv_IP, nmom_IP, pb_in, mv_in, presb_IP, massv_IP) + subroutine s_interpolate_image_point(q_prim_vf, gp, alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP, r_IP, v_IP, pb_IP, mv_IP, nmom_IP, pb_in, mv_in, presb_IP, massv_IP) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), & dimension(sys_size), & diff --git a/src/simulation/m_mhd.fpp b/src/simulation/m_mhd.fpp index 8112b3af7e..9306dcb760 100644 --- a/src/simulation/m_mhd.fpp +++ b/src/simulation/m_mhd.fpp @@ -67,7 +67,7 @@ contains !! S = - (divB) [ 0, Bx, By, Bz, vdotB, vx, vy, vz ]^T !! @param q_prim_vf Primitive variables !! @param rhs_vf rhs variables - pure subroutine s_compute_mhd_powell_rhs(q_prim_vf, rhs_vf) + subroutine s_compute_mhd_powell_rhs(q_prim_vf, rhs_vf) type(scalar_field), dimension(sys_size), intent(in) :: q_prim_vf type(scalar_field), dimension(sys_size), intent(inout) :: rhs_vf diff --git a/src/simulation/m_pressure_relaxation.fpp b/src/simulation/m_pressure_relaxation.fpp index 5affd3342f..63fc17b328 100644 --- a/src/simulation/m_pressure_relaxation.fpp +++ b/src/simulation/m_pressure_relaxation.fpp @@ -65,7 +65,7 @@ contains !> The main pressure relaxation procedure !! @param q_cons_vf Cell-average conservative variables - pure subroutine s_pressure_relaxation_procedure(q_cons_vf) + subroutine s_pressure_relaxation_procedure(q_cons_vf) type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf integer :: j, k, l @@ -82,7 +82,7 @@ contains end subroutine s_pressure_relaxation_procedure !> Process pressure relaxation for a single cell - pure subroutine s_relax_cell_pressure(q_cons_vf, j, k, l) + subroutine s_relax_cell_pressure(q_cons_vf, j, k, l) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf @@ -102,7 +102,7 @@ contains end subroutine s_relax_cell_pressure !> Check if pressure relaxation is needed for this cell - pure logical function s_needs_pressure_relaxation(q_cons_vf, j, k, l) + logical function s_needs_pressure_relaxation(q_cons_vf, j, k, l) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(in) :: q_cons_vf @@ -120,7 +120,7 @@ contains end function s_needs_pressure_relaxation !> Correct volume fractions to physical bounds - pure subroutine s_correct_volume_fractions(q_cons_vf, j, k, l) + subroutine s_correct_volume_fractions(q_cons_vf, j, k, l) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf @@ -150,7 +150,7 @@ contains end subroutine s_correct_volume_fractions !> Main pressure equilibration using Newton-Raphson - pure subroutine s_equilibrate_pressure(q_cons_vf, j, k, l) + subroutine s_equilibrate_pressure(q_cons_vf, j, k, l) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf @@ -219,7 +219,7 @@ contains end subroutine s_equilibrate_pressure !> Correct internal energies using equilibrated pressure - pure subroutine s_correct_internal_energies(q_cons_vf, j, k, l) + subroutine s_correct_internal_energies(q_cons_vf, j, k, l) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf diff --git a/src/simulation/m_qbmm.fpp b/src/simulation/m_qbmm.fpp index 027c47a567..c7a75f2c96 100644 --- a/src/simulation/m_qbmm.fpp +++ b/src/simulation/m_qbmm.fpp @@ -411,7 +411,7 @@ contains end subroutine s_initialize_qbmm_module - pure subroutine s_compute_qbmm_rhs(idir, q_cons_vf, q_prim_vf, rhs_vf, flux_n_vf, pb, rhs_pb) + subroutine s_compute_qbmm_rhs(idir, q_cons_vf, q_prim_vf, rhs_vf, flux_n_vf, pb, rhs_pb) integer, intent(in) :: idir type(scalar_field), dimension(sys_size), intent(in) :: q_cons_vf, q_prim_vf @@ -562,7 +562,7 @@ contains end subroutine s_compute_qbmm_rhs !Coefficient array for non-polytropic model (pb and mv values are accounted in wght_pb and wght_mv) - pure subroutine s_coeff_nonpoly(pres, rho, c, coeffs) + subroutine s_coeff_nonpoly(pres, rho, c, coeffs) $:GPU_ROUTINE(function_name='s_coeff_nonpoly',parallelism='[seq]', & & cray_inline=True) @@ -633,7 +633,7 @@ contains end subroutine s_coeff_nonpoly !Coefficient array for polytropic model (pb for each R0 bin accounted for in wght_pb) - pure subroutine s_coeff(pres, rho, c, coeffs) + subroutine s_coeff(pres, rho, c, coeffs) $:GPU_ROUTINE(function_name='s_coeff',parallelism='[seq]', & & cray_inline=True) @@ -868,7 +868,7 @@ contains end if end subroutine s_coeff_selector - pure subroutine s_chyqmom(momin, wght, abscX, abscY) + subroutine s_chyqmom(momin, wght, abscX, abscY) $:GPU_ROUTINE(function_name='s_chyqmom',parallelism='[seq]', & & cray_inline=True) @@ -926,7 +926,7 @@ contains end subroutine s_chyqmom - pure subroutine s_hyqmom(frho, fup, fmom) + subroutine s_hyqmom(frho, fup, fmom) $:GPU_ROUTINE(function_name='s_hyqmom',parallelism='[seq]', & & cray_inline=True) @@ -946,7 +946,7 @@ contains end subroutine s_hyqmom - pure function f_quad(abscX, abscY, wght_in, q, r, s) + function f_quad(abscX, abscY, wght_in, q, r, s) $:GPU_ROUTINE(parallelism='[seq]') real(wp), dimension(nnode, nb), intent(in) :: abscX, abscY, wght_in real(wp), intent(in) :: q, r, s @@ -962,7 +962,7 @@ contains end function f_quad - pure function f_quad2D(abscX, abscY, wght_in, pow) + function f_quad2D(abscX, abscY, wght_in, pow) $:GPU_ROUTINE(parallelism='[seq]') real(wp), dimension(nnode), intent(in) :: abscX, abscY, wght_in real(wp), dimension(3), intent(in) :: pow diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index 8196403564..bae30f3fd6 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -203,7 +203,7 @@ contains !! For more information please refer to: !! 1) s_compute_cartesian_viscous_source_flux !! 2) s_compute_cylindrical_viscous_source_flux - pure subroutine s_compute_viscous_source_flux(velL_vf, & + subroutine s_compute_viscous_source_flux(velL_vf, & dvelL_dx_vf, & dvelL_dy_vf, & dvelL_dz_vf, & @@ -3795,7 +3795,7 @@ contains !! @param[in] ix Global X-direction loop bounds (int_bounds_info). !! @param[in] iy Global Y-direction loop bounds (int_bounds_info). !! @param[in] iz Global Z-direction loop bounds (int_bounds_info). - pure subroutine s_compute_cylindrical_viscous_source_flux(velL_vf, & + subroutine s_compute_cylindrical_viscous_source_flux(velL_vf, & dvelL_dx_vf, dvelL_dy_vf, dvelL_dz_vf, & velR_vf, & dvelR_dx_vf, dvelR_dy_vf, dvelR_dz_vf, & @@ -3956,7 +3956,7 @@ contains !! @param[in] ix X-direction loop bounds (int_bounds_info). !! @param[in] iy Y-direction loop bounds (int_bounds_info). !! @param[in] iz Z-direction loop bounds (int_bounds_info). - pure subroutine s_compute_cartesian_viscous_source_flux(dvelL_dx_vf, & + subroutine s_compute_cartesian_viscous_source_flux(dvelL_dx_vf, & dvelL_dy_vf, & dvelL_dz_vf, & dvelR_dx_vf, & @@ -4082,7 +4082,7 @@ contains !! @param[in] Re_shear Shear Reynolds number. !! @param[in] divergence_v Velocity divergence (du/dx + dv/dy + dw/dz). !! @param[out] tau_shear_out Calculated shear stress tensor (stress on i-face, j-direction). - pure subroutine s_calculate_shear_stress_tensor(vel_grad_avg, Re_shear, divergence_v, tau_shear_out) + subroutine s_calculate_shear_stress_tensor(vel_grad_avg, Re_shear, divergence_v, tau_shear_out) $:GPU_ROUTINE(parallelism='[seq]') implicit none @@ -4116,7 +4116,7 @@ contains !! @param[in] Re_bulk Bulk Reynolds number. !! @param[in] divergence_v Velocity divergence (du/dx + dv/dy + dw/dz). !! @param[out] tau_bulk_out Calculated bulk stress tensor (stress on i-face, i-direction). - pure subroutine s_calculate_bulk_stress_tensor(Re_bulk, divergence_v, tau_bulk_out) + subroutine s_calculate_bulk_stress_tensor(Re_bulk, divergence_v, tau_bulk_out) $:GPU_ROUTINE(parallelism='[seq]') implicit none @@ -4143,7 +4143,7 @@ contains !! @param flux_src_vf Intercell source fluxes !! @param flux_gsrc_vf Intercell geometric source fluxes !! @param norm_dir Dimensional splitting coordinate direction - pure subroutine s_finalize_riemann_solver(flux_vf, flux_src_vf, & + subroutine s_finalize_riemann_solver(flux_vf, flux_src_vf, & flux_gsrc_vf, & norm_dir) diff --git a/src/simulation/m_sim_helpers.fpp b/src/simulation/m_sim_helpers.fpp index 565524e80b..2ff6d889dd 100644 --- a/src/simulation/m_sim_helpers.fpp +++ b/src/simulation/m_sim_helpers.fpp @@ -20,7 +20,7 @@ contains !! @param k y coordinate index !! @param l z coordinate index !! @return fltr_dtheta Modified dtheta value for cylindrical coordinates - pure function f_compute_filtered_dtheta(k, l) result(fltr_dtheta) + function f_compute_filtered_dtheta(k, l) result(fltr_dtheta) $:GPU_ROUTINE(parallelism='[seq]') integer, intent(in) :: k, l real(wp) :: fltr_dtheta @@ -47,7 +47,7 @@ contains !! @param k y coordinate index !! @param l z coordinate index !! @return cfl_terms computed CFL terms for 2D/3D cases - pure function f_compute_multidim_cfl_terms(vel, c, j, k, l) result(cfl_terms) + function f_compute_multidim_cfl_terms(vel, c, j, k, l) result(cfl_terms) $:GPU_ROUTINE(parallelism='[seq]') real(wp), dimension(num_vels), intent(in) :: vel real(wp), intent(in) :: c @@ -89,7 +89,7 @@ contains !! @param j x index !! @param k y index !! @param l z index - pure subroutine s_compute_enthalpy(q_prim_vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) + subroutine s_compute_enthalpy(q_prim_vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) $:GPU_ROUTINE(function_name='s_compute_enthalpy',parallelism='[seq]', & & cray_inline=True) @@ -181,7 +181,7 @@ contains !! @param icfl_sf cell-centered inviscid cfl number !! @param vcfl_sf (optional) cell-centered viscous CFL number !! @param Rc_sf (optional) cell centered Rc - pure subroutine s_compute_stability_from_dt(vel, c, rho, Re_l, j, k, l, icfl_sf, vcfl_sf, Rc_sf) + subroutine s_compute_stability_from_dt(vel, c, rho, Re_l, j, k, l, icfl_sf, vcfl_sf, Rc_sf) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in), dimension(num_vels) :: vel real(wp), intent(in) :: c, rho @@ -244,7 +244,7 @@ contains !! @param j x coordinate !! @param k y coordinate !! @param l z coordinate - pure subroutine s_compute_dt_from_cfl(vel, c, max_dt, rho, Re_l, j, k, l) + subroutine s_compute_dt_from_cfl(vel, c, max_dt, rho, Re_l, j, k, l) $:GPU_ROUTINE(parallelism='[seq]') real(wp), dimension(num_vels), intent(in) :: vel real(wp), intent(in) :: c, rho diff --git a/src/simulation/m_surface_tension.fpp b/src/simulation/m_surface_tension.fpp index 5d23d8e4c3..8c61a422fb 100644 --- a/src/simulation/m_surface_tension.fpp +++ b/src/simulation/m_surface_tension.fpp @@ -65,7 +65,7 @@ contains end if end subroutine s_initialize_surface_tension_module - pure subroutine s_compute_capillary_source_flux( & + subroutine s_compute_capillary_source_flux( & vSrc_rsx_vf, vSrc_rsy_vf, vSrc_rsz_vf, & flux_src_vf, & id, isx, isy, isz) diff --git a/src/simulation/m_weno.fpp b/src/simulation/m_weno.fpp index 6bc9d004d9..5c525c4664 100644 --- a/src/simulation/m_weno.fpp +++ b/src/simulation/m_weno.fpp @@ -1183,7 +1183,7 @@ contains !! @param j First-coordinate cell index !! @param k Secone-coordinate cell index !! @param l Thire-coordinate cell index - pure subroutine s_preserve_monotonicity(v_rs_ws, vL_rs_vf, vR_rs_vf) + subroutine s_preserve_monotonicity(v_rs_ws, vL_rs_vf, vR_rs_vf) real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(IN) :: v_rs_ws real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(INOUT) :: vL_rs_vf, vR_rs_vf From db1b8c518d0c3b0e44f45c72c20e8820058b8911 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Sun, 20 Jul 2025 23:06:07 -0400 Subject: [PATCH 006/199] Added routine and declare and partial data, non compiling --- src/common/include/acc_macros.fpp | 81 ++++++++++++++ src/common/include/omp_macros.fpp | 112 +++++++++++++++---- src/common/include/parallel_macros.fpp | 143 +++++++------------------ src/common/m_phase_change.fpp | 6 +- src/simulation/m_global_parameters.fpp | 5 +- src/simulation/m_ibm.fpp | 5 +- 6 files changed, 224 insertions(+), 128 deletions(-) diff --git a/src/common/include/acc_macros.fpp b/src/common/include/acc_macros.fpp index 9375799bde..a2dc19b525 100644 --- a/src/common/include/acc_macros.fpp +++ b/src/common/include/acc_macros.fpp @@ -56,4 +56,85 @@ & clause_val + extraAccArgs_val.strip('\n') $:acc_directive #:enddef + +#:def ACC_ROUTINE(function_name=None, parallelism=None, nohost=False, extraAccArgs=None) + #:set parallelism_val = GEN_PARALLELISM_STR(parallelism) + #:assert isinstance(nohost, bool) + #:if nohost == True + #:set nohost_val = 'nohost' + #:else + #:set nohost_val = '' + #:endif + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = parallelism_val.strip('\n') + nohost_val.strip('\n') + #:set acc_directive = '!$acc routine ' + & + & clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef + +#:def ACC_DECLARE(copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, present=None, deviceptr=None, link=None, extraAccArgs=None) + #:set copy_val = GEN_COPY_STR(copy) + #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') + #:set copyout_val = GEN_COPYOUT_STR(copyout) + #:set create_val = GEN_CREATE_STR(create) + #:set present_val = GEN_PRESENT_STR(present) + #:set deviceptr_val = GEN_DEVICEPTR_STR(deviceptr) + #:set link_val = GEN_LINK_STR(link) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = copy_val.strip('\n') + copyin_val.strip('\n') + & + & copyout_val.strip('\n') + create_val.strip('\n') + & + & present_val.strip('\n') + deviceptr_val.strip('\n') + & + & link_val.strip('\n') + #:set acc_directive = '!$acc declare ' + clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef + +#:def ACC_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraAccArgs=None) + #:set collapse_val = GEN_COLLAPSE_STR(collapse) + #:set parallelism_val = GEN_PARALLELISM_STR(parallelism) + #:if data_dependency is not None + #:assert isinstance(data_dependency, str) + #:assert (data_dependency == 'auto' or data_dependency == 'independent') + #:set data_dependency_val = data_dependency + #:else + #:set data_dependency_val = '' + #:endif + #:set private_val = GEN_PRIVATE_STR(private, False) + #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = collapse_val.strip('\n') + parallelism_val.strip('\n') + & + & data_dependency_val.strip('\n') + private_val.strip('\n') + & + & reduction_val.strip('\n') + #:set acc_directive = '!$acc loop ' + & + & clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef + +#:def ACC_DATA(code, copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, no_create=None, present=None, deviceptr=None, attach=None, default=None, extraAccArgs=None) + #:assert code is not None + #:assert isinstance(code, str) + #:if code == '' or code.isspace() + #:stop 'GPU_DATA macro has no effect on the code as it is not surrounding any code' + #:endif + #:set copy_val = GEN_COPY_STR(copy) + #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') + #:set copyout_val = GEN_COPYOUT_STR(copyout) + #:set create_val = GEN_CREATE_STR(create) + #:set no_create_val = GEN_NOCREATE_STR(no_create) + #:set present_val = GEN_PRESENT_STR(present) + #:set deviceptr_val = GEN_DEVICEPTR_STR(deviceptr) + #:set attach_val = GEN_ATTACH_STR(attach) + #:set default_val = GEN_DEFAULT_STR(default) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = copy_val.strip('\n') + copyin_val.strip('\n') + & + & copyout_val.strip('\n') + create_val.strip('\n') + & + & no_create_val.strip('\n') + present_val.strip('\n') + & + & deviceptr_val.strip('\n') + attach_val.strip('\n') + & + & default_val.strip('\n') + #:set acc_directive = '!$acc data ' + clause_val + extraAccArgs_val.strip('\n') + #:set end_acc_directive = '!$acc end data' + $:acc_directive + $:code + $:end_acc_directive +#:enddef ! New line at end of file is required for FYPP \ No newline at end of file diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 4a27e8f093..23e17fbb21 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -17,22 +17,8 @@ #:assert isinstance(default, str) #:assert (default == 'present' or default == 'none') #:if default == 'present' - #:set default_val = 'defaultmap(present:all) ' - #:elif default == 'none' - #:stop 'Not Supported Yet' - #:endif - #:else - #:set default_val = '' - #:endif - $:default_val -#:enddef - -#:def OMP_DEFAULT_STR(default) - #:if default is not None - #:assert isinstance(default, str) - #:assert (default == 'present' or default == 'none') - #:if default == 'present' - #:set default_val = 'defaultmap(present:aggregate) defaultmap(present:allocatable) ' + #! #:set default_val = 'defaultmap(present:aggregate) defaultmap(present:allocatable) ' + #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer)' #:elif default == 'none' #:stop 'Not Supported Yet' #:endif @@ -81,13 +67,19 @@ #:enddef #:def OMP_ATTACH_STR(attach) - #:if attach is not None - #:stop 'attach is not supported yet' - #:endif + #! #:if attach is not None + #! #:stop 'attach is not supported yet' + #! #:endif #:set attach_val = '' $:attach_val #:enddef +#:def OMP_TO_STR(to) + #! Not yet implemented + #:set to_val = '' + $:to_val +#:enddef + #:def OMP_PARALLELISM_STR(parallelism) #:set temp = '' $:temp @@ -130,7 +122,7 @@ #:set collapse_val = GEN_COLLAPSE_STR(collapse) #:set parallelism_val = OMP_PARALLELISM_STR(parallelism) - #! #:set default_val = OMP_DEFAULT_STR(default) + #:set default_val = OMP_DEFAULT_STR(default) #:set default_val = '' #:set private_val = GEN_PRIVATE_STR(private, False).strip('\n') + GEN_PRIVATE_STR(firstprivate, True).strip('\n') #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) @@ -154,4 +146,84 @@ & clause_val + extraOmpArgs_val.strip('\n') $:omp_directive #:enddef + +#:def OMP_ROUTINE(function_name, nohost, extraOmpArgs) + #:assert isinstance(nohost, bool) + #:if nohost == True + #:set nohost_val = 'device_type(nohost) ' + #:else + #:set nohost_val = 'device_type(any) ' + #:endif + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) + #:if function_name is not None + #:set function_name_val = '(' + function_name + ') ' + #:else + #:set function_name_val = '' + #:endif + #:set clause_val = nohost_val.strip('\n') + #:set omp_directive = '!$omp declare target ' + & + & clause_val + extraOmpArgs_val.strip('\n') + $:omp_directive +#:enddef + +#:def OMP_DECLARE(copyin=None, copyinReadOnly=None, create=None, link=None, extraOmpArgs=None) + #:set copyin_val = OMP_TO_STR(copyin).strip('\n') + OMP_TO_STR(copyinReadOnly).strip('\n') + #:set create_val = GEN_CLAUSE('(', create) + #:set link_val = GEN_LINK_STR(link) + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) + #:set clause_val = copyin_val.strip('\n') + & + & create_val.strip('\n') + link_val.strip('\n') + #:set omp_directive = '!$omp declare target ' + clause_val + extraOmpArgs_val.strip('\n') + $:omp_directive +#:enddef + +#! Not implemented yet +#:def OMP_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraAccArgs=None) + #:set collapse_val = GEN_COLLAPSE_STR(collapse) + #:set parallelism_val = GEN_PARALLELISM_STR(parallelism) + #:if data_dependency is not None + #:assert isinstance(data_dependency, str) + #:assert (data_dependency == 'auto' or data_dependency == 'independent') + #:set data_dependency_val = data_dependency + #:else + #:set data_dependency_val = '' + #:endif + #:set private_val = GEN_PRIVATE_STR(private, False) + #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = collapse_val.strip('\n') + parallelism_val.strip('\n') + & + & data_dependency_val.strip('\n') + private_val.strip('\n') + & + & reduction_val.strip('\n') + #:set acc_directive = '!$acc loop ' + & + & clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef + +#:def OMP_DATA(code, copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, no_create=None, present=None, deviceptr=None, attach=None, default=None, extraOmpArgs=None) + #:assert code is not None + #:assert isinstance(code, str) + #:if code == '' or code.isspace() + #:stop 'GPU_DATA macro has no effect on the code as it is not surrounding any code' + #:endif + #:set copy_val = OMP_COPY_STR(copy) + #:set copyin_val = OMP_COPYIN_STR(copyin).strip('\n') + OMP_COPYIN_STR(copyinReadOnly).strip('\n') + #:set copyout_val = OMP_COPYOUT_STR(copyout) + #:set create_val = OMP_CREATE_STR(create) + #:set no_create_val = OMP_NOCREATE_STR(no_create) + #:set present_val = OMP_PRESENT_STR(present) + #:set deviceptr_val = OMP_DEVICEPTR_STR(deviceptr) + #:set attach_val = OMP_ATTACH_STR(attach) + #:set default_val = OMP_DEFAULT_STR(default) + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) + #:set clause_val = copy_val.strip('\n') + copyin_val.strip('\n') + & + & copyout_val.strip('\n') + create_val.strip('\n') + & + & no_create_val.strip('\n') + present_val.strip('\n') + & + & deviceptr_val.strip('\n') + attach_val.strip('\n') + & + & default_val.strip('\n') + #:set omp_directive = '!$omp target data ' + clause_val + extraOmpArgs_val.strip('\n') + #:set end_omp_directive = '!$omp end target data' + $:omp_directive + $:code + $:end_omp_directive +#:enddef ! New line at end of file is required for FYPP \ No newline at end of file diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index 00dc95493e..6594de7098 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -196,19 +196,11 @@ #endif #:enddef -#:def GPU_ROUTINE(function_name=None, parallelism=None, nohost=False, cray_inline=False, extraAccArgs=None) +#:def GPU_ROUTINE(function_name=None, parallelism=None, nohost=False, cray_inline=False, extraAccArgs=None, extraOmpArgs=None) #:assert isinstance(cray_inline, bool) - #:set parallelism_val = GEN_PARALLELISM_STR(parallelism) - #:assert isinstance(nohost, bool) - #:if nohost == True - #:set nohost_val = 'nohost' - #:else - #:set nohost_val = '' - #:endif - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = parallelism_val.strip('\n') + nohost_val.strip('\n') - #:set acc_directive = '!$acc routine ' + & - & clause_val + extraAccArgs_val.strip('\n') + #:set acc_directive = ACC_ROUTINE(function_name=function_name, parallelism=parallelism, nohost=nohost, extraAccArgs=extraAccArgs) + #:set omp_directive = OMP_ROUTINE(function_name=function_name, nohost=nohost, extraOmpArgs=extraOmpArgs) + #:if cray_inline == True #:if not isinstance(function_name, str) #:stop "When inlining for Cray Compiler, function name must be given and given as a string" @@ -216,29 +208,33 @@ #:set cray_directive = ('!DIR$ INLINEALWAYS ' + function_name).strip('\n') #ifdef _CRAYFTN $:cray_directive -#else +#elif MFC_OpenACC $:acc_directive +#elif MFC_OpenMP + $:omp_directive #endif #:else +#if MFC_OpenACC $:acc_directive +#elif MFC_OpenMP + $:omp_directive +#endif #:endif #:enddef -#:def GPU_DECLARE(copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, present=None, deviceptr=None, link=None, extraAccArgs=None) - #:set copy_val = GEN_COPY_STR(copy) - #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') - #:set copyout_val = GEN_COPYOUT_STR(copyout) - #:set create_val = GEN_CREATE_STR(create) - #:set present_val = GEN_PRESENT_STR(present) - #:set deviceptr_val = GEN_DEVICEPTR_STR(deviceptr) - #:set link_val = GEN_LINK_STR(link) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = copy_val.strip('\n') + copyin_val.strip('\n') + & - & copyout_val.strip('\n') + create_val.strip('\n') + & - & present_val.strip('\n') + deviceptr_val.strip('\n') + & - & link_val.strip('\n') - #:set acc_directive = '!$acc declare ' + clause_val + extraAccArgs_val.strip('\n') - $:acc_directive +#:def GPU_DECLARE(copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, present=None, deviceptr=None, link=None, extraAccArgs=None, extraOmpArgs=None) + #:set acc_code = ACC_DECLARE(copy=copy, copyin=copyin, copyinReadOnly=copyinReadOnly, copyout=copyout, create=create, present=present, deviceptr=deviceptr, link=link, extraAccArgs=None) + #:assert copyout is None + #:assert present is None + #:assert deviceptr is None + #:assert copy is None + #:set omp_code = OMP_DECLARE(copyin=copyin, copyinReadOnly=copyinReadOnly, create=create, link=link, extraOmpArgs=extraOmpArgs) + +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#endif #:enddef #:def GPU_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraAccArgs=None) @@ -262,32 +258,17 @@ $:acc_directive #:enddef -#:def GPU_DATA(code, copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, no_create=None, present=None, deviceptr=None, attach=None, default=None, extraAccArgs=None) - #:assert code is not None - #:assert isinstance(code, str) - #:if code == '' or code.isspace() - #:stop 'GPU_DATA macro has no effect on the code as it is not surrounding any code' - #:endif - #:set copy_val = GEN_COPY_STR(copy) - #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') - #:set copyout_val = GEN_COPYOUT_STR(copyout) - #:set create_val = GEN_CREATE_STR(create) - #:set no_create_val = GEN_NOCREATE_STR(no_create) - #:set present_val = GEN_PRESENT_STR(present) - #:set deviceptr_val = GEN_DEVICEPTR_STR(deviceptr) - #:set attach_val = GEN_ATTACH_STR(attach) - #:set default_val = GEN_DEFAULT_STR(default) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = copy_val.strip('\n') + copyin_val.strip('\n') + & - & copyout_val.strip('\n') + create_val.strip('\n') + & - & no_create_val.strip('\n') + present_val.strip('\n') + & - & deviceptr_val.strip('\n') + attach_val.strip('\n') + & - & default_val.strip('\n') - #:set acc_directive = '!$acc data ' + clause_val + extraAccArgs_val.strip('\n') - #:set end_acc_directive = '!$acc end data' - $:acc_directive +#:def GPU_DATA(code, copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, no_create=None, present=None, deviceptr=None, attach=None, default=None, extraAccArgs=None, extraOmpArgs=None) + #:set acc_code = ACC_DATA(code=code, copy=copy, copyin=copyin, copyinReadOnly=copyinReadOnly, copyout=copyout, create=create, no_create=no_create, present=present, deviceptr=deviceptr, attach=attach, default=default, extraAccArgs=extraAccArgs) + #:set omp_code = OMP_DATA(code=code, copy=copy, copyin=copyin, copyinReadOnly=copyinReadOnly, copyout=copyout, create=create, no_create=no_create, present=present, deviceptr=deviceptr, attach=attach, default=default, extraOmpArgs=extraOmpArgs) + +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#else $:code - $:end_acc_directive +#endif #:enddef #:def GPU_HOST_DATA(code, use_device=None, extraAccArgs=None) @@ -306,64 +287,20 @@ $:end_acc_directive #:enddef -#:def GEN_MP_PARENTHESES_CLAUSE(clause_name, clause_modifier, clause_str) - #:set clause_regex = re.compile(',(?![^(]*\\))') - #:assert isinstance(clause_name, str) - #:if clause_str is not None - #:set count = 0 - #:assert isinstance(clause_str, str) - #:assert clause_str[0] == '[' and clause_str[-1] == ']' - #:for c in clause_str - #:if c == '(' - #:set count = count + 1 - #:elif c == ')' - #:set count = count - 1 - #:endif - #:if c == ',' and count > 1 - #:stop 'Nested parentheses with comma inside is not supported. Incorrect clause: {}'.format(clause_str) - #:elif count < 0 - #:stop 'Missing parentheses. Incorrect clause: {}'.format(clause_str) - #:endif - #:endfor - #:set clause_str = re.sub(clause_regex, ';', clause_str) - #:set clause_list = [x.strip() for x in clause_str.strip('[]').split(';')] - $:ASSERT_LIST(clause_list, str) - #:set clause_str = clause_name + '(' + clause_modifier + ':' + ', '.join(clause_list) + ') ' - #:else - #:set clause_str = '' - #:endif - $:clause_str -#:enddef - -#:def GEN_TO_STR(to) - #:set to_str = GEN_MP_PARENTHESES_CLAUSE('map', 'to', to) - $:to_str -#:enddef - - -#:def GEN_ALLOC_STR(alloc) - #:set alloc_str = GEN_MP_PARENTHESES_CLAUSE('map', 'alloc', alloc) - $:alloc_str -#:enddef - #:def GPU_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraAccArgs=None) #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') #:set create_val = GEN_CREATE_STR(create) #:set attach_val = GEN_ATTACH_STR(attach) - #:set to_val = GEN_TO_STR(copyin) - #:set alloc_val = GEN_ALLOC_STR(create) - #:set alloc_val2 = GEN_ALLOC_STR(attach) + #! #:set to_val = GEN_TO_STR(copyin) + #! #:set alloc_val = GEN_ALLOC_STR(create) + #! #:set alloc_val2 = GEN_ALLOC_STR(attach) #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set extraMpArgs_val = '' + #! #:set extraMpArgs_val = '' #:set acc_clause_val = copyin_val.strip('\n') + create_val.strip('\n') + attach_val.strip('\n') - #:set mp_clause_val = to_val.strip('\n') + alloc_val.strip('\n') + alloc_val2.strip('\n') + #! #:set mp_clause_val = to_val.strip('\n') + alloc_val.strip('\n') + alloc_val2.strip('\n') #:set acc_directive = '!$acc enter data ' + acc_clause_val + extraAccArgs_val.strip('\n') - #:set mp_directive = '!$omp target enter data ' + mp_clause_val + extraMpArgs_val.strip('\n') -#if MFC_OpenACC + #! #:set mp_directive = '!$omp target enter data ' + mp_clause_val + extraMpArgs_val.strip('\n') $:acc_directive -#elif MFC_OpenMP - $:mp_directive -#endif #:enddef #:def GPU_EXIT_DATA(copyout=None, delete=None, detach=None, extraAccArgs=None) diff --git a/src/common/m_phase_change.fpp b/src/common/m_phase_change.fpp index 8f4cdf51c5..5a64cb6d29 100644 --- a/src/common/m_phase_change.fpp +++ b/src/common/m_phase_change.fpp @@ -89,11 +89,11 @@ contains real(wp) :: rho, rM, m1, m2, MCT !< total density, total reacting mass, individual reacting masses real(wp) :: TvF !< total volume fraction - $:GPU_DECLARE(create='[pS,pSOV,pSSL,TS,TSOV,TSSL,TSatOV,TSatSL]') - $:GPU_DECLARE(create='[rhoe,dynE,rhos,rho,rM,m1,m2,MCT,TvF]') + ! $:GPU_DECLARE(create='[pS,pSOV,pSSL,TS,TSOV,TSSL,TSatOV,TSatSL]') + ! $:GPU_DECLARE(create='[rhoe,dynE,rhos,rho,rM,m1,m2,MCT,TvF]') real(wp), dimension(num_fluids) :: p_infOV, p_infpT, p_infSL, sk, hk, gk, ek, rhok - $:GPU_DECLARE(create='[p_infOV,p_infpT,p_infSL,sk,hk,gk,ek,rhok]') + ! $:GPU_DECLARE(create='[p_infOV,p_infpT,p_infSL,sk,hk,gk,ek,rhok]') !< Generic loop iterators integer :: i, j, k, l diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp index fa6185c207..a9271506e1 100644 --- a/src/simulation/m_global_parameters.fpp +++ b/src/simulation/m_global_parameters.fpp @@ -212,10 +212,13 @@ module m_global_parameters !> @{ type(int_bounds_info) :: bc_x, bc_y, bc_z !> @} +#if defined(MFC_OpenACC) $:GPU_DECLARE(create='[bc_x%vb1, bc_x%vb2, bc_x%vb3, bc_x%ve1, bc_x%ve2, bc_x%ve3]') $:GPU_DECLARE(create='[bc_y%vb1, bc_y%vb2, bc_y%vb3, bc_y%ve1, bc_y%ve2, bc_y%ve3]') $:GPU_DECLARE(create='[bc_z%vb1, bc_z%vb2, bc_z%vb3, bc_z%ve1, bc_z%ve2, bc_z%ve3]') - +#elif defined(MFC_OpenMP) + $:GPU_DECLARE(create='[bc_x, bc_y, bc_z]') +#endif type(bounds_info) :: x_domain, y_domain, z_domain real(wp) :: x_a, y_a, z_a real(wp) :: x_b, y_b, z_b diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index 09263c1ab5..df6ea1145b 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -45,8 +45,11 @@ module m_ibm integer :: num_gps !< Number of ghost points integer :: num_inner_gps !< Number of ghost points +#if defined(MFC_OpenACC) $:GPU_DECLARE(create='[gp_layers,num_gps,num_inner_gps]') - +#elif defined(MFC_OpenMP) + $:GPU_DECLARE(create='[num_gps,num_inner_gps]') +#endif contains !> Allocates memory for the variables in the IBM module From ed29d13bb1977df5a31d63d32eadf355e8636372 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Mon, 21 Jul 2025 14:00:21 -0400 Subject: [PATCH 007/199] Some manual changes to codebase, and implemented attach --- src/common/include/omp_macros.fpp | 12 ++++++------ src/simulation/m_acoustic_src.fpp | 4 +++- src/simulation/m_fftw.fpp | 2 +- src/simulation/m_global_parameters.fpp | 1 + 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 23e17fbb21..2a3ff7dfac 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -17,8 +17,8 @@ #:assert isinstance(default, str) #:assert (default == 'present' or default == 'none') #:if default == 'present' - #! #:set default_val = 'defaultmap(present:aggregate) defaultmap(present:allocatable) ' - #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer)' + #! #:set default_val = 'defaultmap(present:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer)' + #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(tofrom:allocatable) defaultmap(tofrom:pointer)' #:elif default == 'none' #:stop 'Not Supported Yet' #:endif @@ -98,7 +98,7 @@ #:set no_create_val = OMP_NOCREATE_STR(no_create) #:set present_val = OMP_PRESENT_STR(present) #:set deviceptr_val = OMP_DEVICEPTR_STR(deviceptr) - #:set attach_val = OMP_ATTACH_STR(attach) + #:set attach_val = OMP_MAP_STR('tofrom', attach) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set omp_clause_val = default_val.strip('\n') + private_val.strip('\n') + reduction_val.strip('\n') + & & copy_val.strip('\n') + copyin_val.strip('\n') + & @@ -106,7 +106,7 @@ & no_create_val.strip('\n') + present_val.strip('\n') + & & deviceptr_val.strip('\n') + attach_val.strip('\n')) - #:set omp_clause_val = 'defaultmap(firstprivate:scalar) ' + omp_clause_val.strip('\n') + #:set omp_clause_val = omp_clause_val.strip('\n') #:set omp_directive = '!$omp target teams ' + omp_clause_val + extraOmpArgs_val.strip('\n') #:set end_omp_directive = '!$omp end target teams' @@ -133,7 +133,7 @@ #:set no_create_val = OMP_NOCREATE_STR(no_create) #:set present_val = OMP_PRESENT_STR(present) #:set deviceptr_val = OMP_DEVICEPTR_STR(deviceptr) - #:set attach_val = OMP_ATTACH_STR(attach) + #:set attach_val = OMP_MAP_STR('tofrom', attach) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set clause_val = collapse_val.strip('\n') + parallelism_val.strip('\n') + & & default_val.strip('\n') + private_val.strip('\n') + reduction_val.strip('\n') + & @@ -212,7 +212,7 @@ #:set no_create_val = OMP_NOCREATE_STR(no_create) #:set present_val = OMP_PRESENT_STR(present) #:set deviceptr_val = OMP_DEVICEPTR_STR(deviceptr) - #:set attach_val = OMP_ATTACH_STR(attach) + #:set attach_val = OMP_MAP_STR('tofrom', attach) #:set default_val = OMP_DEFAULT_STR(default) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set clause_val = copy_val.strip('\n') + copyin_val.strip('\n') + & diff --git a/src/simulation/m_acoustic_src.fpp b/src/simulation/m_acoustic_src.fpp index 28009427bb..1b328e3d1f 100644 --- a/src/simulation/m_acoustic_src.fpp +++ b/src/simulation/m_acoustic_src.fpp @@ -178,6 +178,7 @@ contains end do end do end do + ! !$omp end target teams distribute parallel do simd ! Keep outer loop sequel because different sources can have very different number of points do ai = 1, num_source @@ -200,7 +201,8 @@ contains allocate (phi_rn(1:bb_num_freq(ai))) if (pulse(ai) == 4) then - call random_number(phi_rn(1:bb_num_freq(ai))) + ! call random_number(phi_rn(1:bb_num_freq(ai))) + phi_rn(1:bb_num_freq(ai)) = 1 ! Ensure all the ranks have the same random phase shift call s_mpi_send_random_number(phi_rn, bb_num_freq(ai)) end if diff --git a/src/simulation/m_fftw.fpp b/src/simulation/m_fftw.fpp index 9563b99a6d..fabd15255e 100644 --- a/src/simulation/m_fftw.fpp +++ b/src/simulation/m_fftw.fpp @@ -264,6 +264,7 @@ contains end do end do + #:endcall GPU_DATA #else Nfq = 3 @@ -295,7 +296,6 @@ contains end do end do #endif - #:endcall GPU_DATA end subroutine s_apply_fourier_filter !> The purpose of this subroutine is to destroy the fftw plan diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp index a9271506e1..9ae61c5112 100644 --- a/src/simulation/m_global_parameters.fpp +++ b/src/simulation/m_global_parameters.fpp @@ -184,6 +184,7 @@ module m_global_parameters #:endfor real(wp), dimension(3) :: accel_bf $:GPU_DECLARE(create='[accel_bf]') + $:GPU_DECLARE(create='[k_x,w_x,p_x,g_x,k_y,w_y,p_y,g_y,k_z,w_z,p_z,g_z]') integer :: cpu_start, cpu_end, cpu_rate From c1b41a68f32afe7cdab9a292d844d0b535b32c84 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Mon, 21 Jul 2025 17:08:30 -0400 Subject: [PATCH 008/199] Changed parallel loop to also include the end parallel --- src/common/include/acc_macros.fpp | 5 +- src/common/include/omp_macros.fpp | 28 +--- src/common/include/parallel_macros.fpp | 34 ++--- src/common/m_boundary_common.fpp | 36 +++-- src/common/m_chemistry.fpp | 3 +- src/common/m_finite_differences.fpp | 3 +- src/common/m_helper_basic.fpp | 2 +- src/common/m_mpi_common.fpp | 54 ++++--- src/common/m_phase_change.fpp | 3 +- src/common/m_variables_conversion.fpp | 9 +- src/simulation/m_acoustic_src.fpp | 12 +- src/simulation/m_body_forces.fpp | 15 +- src/simulation/m_bubbles_EE.fpp | 21 ++- src/simulation/m_bubbles_EL.fpp | 68 ++++++--- src/simulation/m_bubbles_EL_kernels.fpp | 6 +- src/simulation/m_cbc.fpp | 108 ++++++++----- src/simulation/m_data_output.fpp | 3 +- src/simulation/m_fftw.fpp | 24 ++- src/simulation/m_hyperelastic.fpp | 4 +- src/simulation/m_hypoelastic.fpp | 42 +++-- src/simulation/m_ibm.fpp | 12 +- src/simulation/m_mhd.fpp | 3 +- src/simulation/m_mpi_proxy.fpp | 18 ++- src/simulation/m_pressure_relaxation.fpp | 3 +- src/simulation/m_qbmm.fpp | 12 +- src/simulation/m_rhs.fpp | 151 +++++++++--------- src/simulation/m_riemann_solvers.fpp | 187 ++++++++++++----------- src/simulation/m_surface_tension.fpp | 36 +++-- src/simulation/m_time_steppers.fpp | 61 +++++--- src/simulation/m_viscous.fpp | 137 +++++++++++------ src/simulation/m_weno.fpp | 30 ++-- 31 files changed, 668 insertions(+), 462 deletions(-) diff --git a/src/common/include/acc_macros.fpp b/src/common/include/acc_macros.fpp index a2dc19b525..4da5ab0231 100644 --- a/src/common/include/acc_macros.fpp +++ b/src/common/include/acc_macros.fpp @@ -28,7 +28,7 @@ $:end_acc_directive #:enddef -#:def ACC_PARALLEL_LOOP(collapse=None, private=None, parallelism='[gang, vector]', & +#:def ACC_PARALLEL_LOOP(code, collapse=None, private=None, parallelism='[gang, vector]', & & default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None) @@ -54,7 +54,10 @@ & deviceptr_val.strip('\n') + attach_val.strip('\n') #:set acc_directive = '!$acc parallel loop ' + & & clause_val + extraAccArgs_val.strip('\n') + #:set acc_end_directive = '!$acc end parallel loop' $:acc_directive + $:code + $:acc_end_directive #:enddef #:def ACC_ROUTINE(function_name=None, parallelism=None, nohost=False, extraAccArgs=None) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 2a3ff7dfac..04b1c25465 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -115,7 +115,7 @@ $:omp_end_directive #:enddef -#:def OMP_PARALLEL_LOOP(collapse=None, private=None, parallelism='[gang, vector]', & +#:def OMP_PARALLEL_LOOP(code, collapse=None, private=None, parallelism='[gang, vector]', & & default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & & no_create=None, present=None, deviceptr=None, attach=None, extraOmpArgs=None) @@ -144,7 +144,10 @@ #! Hardcoding the parallelism for now #:set omp_directive = '!$omp target teams distribute parallel do simd ' + & & clause_val + extraOmpArgs_val.strip('\n') + #:set omp_end_directive = '!$omp end target teams distribute parallel do simd' $:omp_directive + $:code + $:omp_end_directive #:enddef #:def OMP_ROUTINE(function_name, nohost, extraOmpArgs) @@ -178,25 +181,10 @@ #:enddef #! Not implemented yet -#:def OMP_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraAccArgs=None) - #:set collapse_val = GEN_COLLAPSE_STR(collapse) - #:set parallelism_val = GEN_PARALLELISM_STR(parallelism) - #:if data_dependency is not None - #:assert isinstance(data_dependency, str) - #:assert (data_dependency == 'auto' or data_dependency == 'independent') - #:set data_dependency_val = data_dependency - #:else - #:set data_dependency_val = '' - #:endif - #:set private_val = GEN_PRIVATE_STR(private, False) - #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = collapse_val.strip('\n') + parallelism_val.strip('\n') + & - & data_dependency_val.strip('\n') + private_val.strip('\n') + & - & reduction_val.strip('\n') - #:set acc_directive = '!$acc loop ' + & - & clause_val + extraAccArgs_val.strip('\n') - $:acc_directive +#:def OMP_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraOmpArgs=None) + #! loop is going to be ignored since all loops right now are seq + #:set temp = '' + $:temp #:enddef #:def OMP_DATA(code, copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, no_create=None, present=None, deviceptr=None, attach=None, default=None, extraOmpArgs=None) diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index 6594de7098..ee0577613a 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -181,13 +181,13 @@ #:enddef -#:def GPU_PARALLEL_LOOP(collapse=None, private=None, parallelism='[gang, vector]', & +#:def GPU_PARALLEL_LOOP(code, collapse=None, private=None, parallelism='[gang, vector]', & & default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None, extraOmpArgs=None) - #:set acc_code = ACC_PARALLEL_LOOP(collapse, private, parallelism, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraAccArgs) - #:set omp_code = OMP_PARALLEL_LOOP(collapse, private, parallelism, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraOmpArgs) + #:set acc_code = ACC_PARALLEL_LOOP(code, collapse, private, parallelism, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraAccArgs) + #:set omp_code = OMP_PARALLEL_LOOP(code, collapse, private, parallelism, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraOmpArgs) #if defined(MFC_OpenACC) $:acc_code @@ -237,25 +237,15 @@ #endif #:enddef -#:def GPU_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraAccArgs=None) - #:set collapse_val = GEN_COLLAPSE_STR(collapse) - #:set parallelism_val = GEN_PARALLELISM_STR(parallelism) - #:if data_dependency is not None - #:assert isinstance(data_dependency, str) - #:assert (data_dependency == 'auto' or data_dependency == 'independent') - #:set data_dependency_val = data_dependency - #:else - #:set data_dependency_val = '' - #:endif - #:set private_val = GEN_PRIVATE_STR(private, False) - #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = collapse_val.strip('\n') + parallelism_val.strip('\n') + & - & data_dependency_val.strip('\n') + private_val.strip('\n') + & - & reduction_val.strip('\n') - #:set acc_directive = '!$acc loop ' + & - & clause_val + extraAccArgs_val.strip('\n') - $:acc_directive +#:def GPU_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraAccArgs=None, extraOmpArgs=None) + #:set acc_code = ACC_LOOP(collapse=collapse, parallelism=parallelism, data_dependency=data_dependency, reduction=reduction, reductionOp=reductionOp, private=private, extraAccArgs=extraAccArgs) + #:set omp_code = OMP_LOOP(collapse=collapse, parallelism=parallelism, data_dependency=data_dependency, reduction=reduction, reductionOp=reductionOp, private=private, extraOmpArgs=extraOmpArgs) + +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#endif #:enddef #:def GPU_DATA(code, copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, no_create=None, present=None, deviceptr=None, attach=None, default=None, extraAccArgs=None, extraOmpArgs=None) diff --git a/src/common/m_boundary_common.fpp b/src/common/m_boundary_common.fpp index 3335a79b53..fb61b78d96 100644 --- a/src/common/m_boundary_common.fpp +++ b/src/common/m_boundary_common.fpp @@ -91,7 +91,7 @@ contains if (bc_x%beg >= 0) then call s_mpi_sendrecv_variables_buffers(q_prim_vf, 1, -1, sys_size, pb_in, mv_in) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, p do k = 0, n select case (int(bc_type(1, -1)%sf(0, k, l))) @@ -115,12 +115,13 @@ contains end if end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bc_x%end >= 0) then call s_mpi_sendrecv_variables_buffers(q_prim_vf, 1, 1, sys_size, pb_in, mv_in) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, p do k = 0, n select case (int(bc_type(1, 1)%sf(0, k, l))) @@ -144,6 +145,7 @@ contains end if end do end do + #:endcall GPU_PARALLEL_LOOP end if ! Population of Buffers in y-direction @@ -153,7 +155,7 @@ contains if (bc_y%beg >= 0) then call s_mpi_sendrecv_variables_buffers(q_prim_vf, 2, -1, sys_size, pb_in, mv_in) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, p do k = -buff_size, m + buff_size select case (int(bc_type(2, -1)%sf(k, 0, l))) @@ -180,12 +182,13 @@ contains end if end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bc_y%end >= 0) then call s_mpi_sendrecv_variables_buffers(q_prim_vf, 2, 1, sys_size, pb_in, mv_in) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, p do k = -buff_size, m + buff_size select case (int(bc_type(2, 1)%sf(k, 0, l))) @@ -209,6 +212,7 @@ contains end if end do end do + #:endcall GPU_PARALLEL_LOOP end if ! Population of Buffers in z-direction @@ -218,7 +222,7 @@ contains if (bc_z%beg >= 0) then call s_mpi_sendrecv_variables_buffers(q_prim_vf, 3, -1, sys_size, pb_in, mv_in) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = -buff_size, n + buff_size do k = -buff_size, m + buff_size select case (int(bc_type(3, -1)%sf(k, l, 0))) @@ -242,12 +246,13 @@ contains end if end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bc_z%end >= 0) then call s_mpi_sendrecv_variables_buffers(q_prim_vf, 3, 1, sys_size, pb_in, mv_in) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = -buff_size, n + buff_size do k = -buff_size, m + buff_size select case (int(bc_type(3, 1)%sf(k, l, 0))) @@ -271,6 +276,7 @@ contains end if end do end do + #:endcall GPU_PARALLEL_LOOP end if ! END: Population of Buffers in z-direction @@ -1162,7 +1168,7 @@ contains if (bc_x%beg >= 0) then call s_mpi_sendrecv_variables_buffers(c_divs, 1, -1, num_dims + 1) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, p do k = 0, n select case (bc_type(1, -1)%sf(0, k, l)) @@ -1175,12 +1181,13 @@ contains end select end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bc_x%end >= 0) then call s_mpi_sendrecv_variables_buffers(c_divs, 1, 1, num_dims + 1) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, p do k = 0, n select case (bc_type(1, 1)%sf(0, k, l)) @@ -1193,6 +1200,7 @@ contains end select end do end do + #:endcall GPU_PARALLEL_LOOP end if if (n == 0) return @@ -1201,7 +1209,7 @@ contains if (bc_y%beg >= 0) then call s_mpi_sendrecv_variables_buffers(c_divs, 2, -1, num_dims + 1) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, p do k = -buff_size, m + buff_size select case (bc_type(2, -1)%sf(k, 0, l)) @@ -1214,12 +1222,13 @@ contains end select end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bc_y%end >= 0) then call s_mpi_sendrecv_variables_buffers(c_divs, 2, 1, num_dims + 1) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, p do k = -buff_size, m + buff_size select case (bc_type(2, 1)%sf(k, 0, l)) @@ -1232,6 +1241,7 @@ contains end select end do end do + #:endcall GPU_PARALLEL_LOOP end if if (p == 0) return @@ -1240,7 +1250,7 @@ contains if (bc_z%beg >= 0) then call s_mpi_sendrecv_variables_buffers(c_divs, 3, -1, num_dims + 1) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = -buff_size, n + buff_size do k = -buff_size, m + buff_size select case (bc_type(3, -1)%sf(k, l, 0)) @@ -1253,12 +1263,13 @@ contains end select end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bc_z%end >= 0) then call s_mpi_sendrecv_variables_buffers(c_divs, 3, 1, num_dims + 1) else - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = -buff_size, n + buff_size do k = -buff_size, m + buff_size select case (bc_type(3, 1)%sf(k, l, 0)) @@ -1271,6 +1282,7 @@ contains end select end do end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_populate_capillary_buffers diff --git a/src/common/m_chemistry.fpp b/src/common/m_chemistry.fpp index 71aa890e87..a2ed576ff9 100644 --- a/src/common/m_chemistry.fpp +++ b/src/common/m_chemistry.fpp @@ -99,7 +99,7 @@ contains real(wp), dimension(num_species) :: Ys real(wp), dimension(num_species) :: omega - $:GPU_PARALLEL_LOOP(collapse=3, private='[Ys, omega]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[Ys, omega]') do z = bounds(3)%beg, bounds(3)%end do y = bounds(2)%beg, bounds(2)%end do x = bounds(1)%beg, bounds(1)%end @@ -126,6 +126,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_chemistry_reaction_flux diff --git a/src/common/m_finite_differences.fpp b/src/common/m_finite_differences.fpp index 4b7e399ad5..07dee3c024 100644 --- a/src/common/m_finite_differences.fpp +++ b/src/common/m_finite_differences.fpp @@ -18,7 +18,7 @@ contains real(wp) :: divergence - $:GPU_PARALLEL_LOOP(collapse=3, private='[divergence]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[divergence]') do x = ix_s%beg, ix_s%end do y = iy_s%beg, iy_s%end do z = iz_s%beg, iz_s%end @@ -56,6 +56,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_fd_divergence diff --git a/src/common/m_helper_basic.fpp b/src/common/m_helper_basic.fpp index 0ee3102938..91eebe1992 100644 --- a/src/common/m_helper_basic.fpp +++ b/src/common/m_helper_basic.fpp @@ -111,7 +111,7 @@ contains end function f_is_integer subroutine s_configure_coordinate_bounds(weno_polyn, buff_size, idwint, idwbuff, & - viscous, bubbles_lagrange, m, n, p, num_dims, igr) + viscous, bubbles_lagrange, m, n, p, num_dims, igr) integer, intent(in) :: weno_polyn, m, n, p, num_dims integer, intent(inout) :: buff_size diff --git a/src/common/m_mpi_common.fpp b/src/common/m_mpi_common.fpp index da485fa3ac..2deb0c36ef 100644 --- a/src/common/m_mpi_common.fpp +++ b/src/common/m_mpi_common.fpp @@ -687,7 +687,7 @@ contains #:for mpi_dir in [1, 2, 3] if (mpi_dir == ${mpi_dir}$) then #:if mpi_dir == 1 - $:GPU_PARALLEL_LOOP(collapse=4,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') do l = 0, p do k = 0, n do j = 0, buff_size - 1 @@ -698,9 +698,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then - $:GPU_PARALLEL_LOOP(collapse=4,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') do l = 0, p do k = 0, n do j = 0, buff_size - 1 @@ -714,8 +715,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do l = 0, p do k = 0, n do j = 0, buff_size - 1 @@ -729,9 +731,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if #:elif mpi_dir == 2 - $:GPU_PARALLEL_LOOP(collapse=4,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') do i = 1, nVar do l = 0, p do k = 0, buff_size - 1 @@ -744,9 +747,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do i = nVar + 1, nVar + 4 do l = 0, p do k = 0, buff_size - 1 @@ -761,8 +765,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do i = nVar + 1, nVar + 4 do l = 0, p do k = 0, buff_size - 1 @@ -777,9 +782,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if #:else - $:GPU_PARALLEL_LOOP(collapse=4,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') do i = 1, nVar do l = 0, buff_size - 1 do k = -buff_size, n + buff_size @@ -792,9 +798,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do i = nVar + 1, nVar + 4 do l = 0, buff_size - 1 do k = -buff_size, n + buff_size @@ -809,8 +816,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do i = nVar + 1, nVar + 4 do l = 0, buff_size - 1 do k = -buff_size, n + buff_size @@ -825,6 +833,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if #:endif end if @@ -879,7 +888,7 @@ contains #:for mpi_dir in [1, 2, 3] if (mpi_dir == ${mpi_dir}$) then #:if mpi_dir == 1 - $:GPU_PARALLEL_LOOP(collapse=4,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') do l = 0, p do k = 0, n do j = -buff_size, -1 @@ -897,9 +906,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do l = 0, p do k = 0, n do j = -buff_size, -1 @@ -913,8 +923,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do l = 0, p do k = 0, n do j = -buff_size, -1 @@ -928,9 +939,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if #:elif mpi_dir == 2 - $:GPU_PARALLEL_LOOP(collapse=4,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') do i = 1, nVar do l = 0, p do k = -buff_size, -1 @@ -949,9 +961,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do i = nVar + 1, nVar + 4 do l = 0, p do k = -buff_size, -1 @@ -966,8 +979,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do i = nVar + 1, nVar + 4 do l = 0, p do k = -buff_size, -1 @@ -982,10 +996,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if #:else ! Unpacking buffer from bc_z%beg - $:GPU_PARALLEL_LOOP(collapse=4,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') do i = 1, nVar do l = -buff_size, -1 do k = -buff_size, n + buff_size @@ -1005,9 +1020,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do i = nVar + 1, nVar + 4 do l = -buff_size, -1 do k = -buff_size, n + buff_size @@ -1023,8 +1039,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=5,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') do i = nVar + 1, nVar + 4 do l = -buff_size, -1 do k = -buff_size, n + buff_size @@ -1040,6 +1057,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if #:endif end if diff --git a/src/common/m_phase_change.fpp b/src/common/m_phase_change.fpp index 5a64cb6d29..76e76e9d64 100644 --- a/src/common/m_phase_change.fpp +++ b/src/common/m_phase_change.fpp @@ -99,7 +99,7 @@ contains integer :: i, j, k, l ! starting equilibrium solver - $:GPU_PARALLEL_LOOP(collapse=3, private='[p_infOV, p_infpT, p_infSL, & + #:call GPU_PARALLEL_LOOP(collapse=3, private='[p_infOV, p_infpT, p_infSL, & & sk, hk, gk, ek, rhok,pS, pSOV, pSSL, & & TS, TSOV, TSatOV, TSatSL, TSSL, rhoe, & & dynE, rhos, rho, rM, m1, m2, MCT, TvF]') @@ -272,6 +272,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_infinite_relaxation_k diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index 32821fb679..33094bfb4f 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -873,9 +873,7 @@ contains end if #:endif - $:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_K, alpha_rho_K, Re_K, & - & nRtmp, rho_K, gamma_K, pi_inf_K,qv_K, & - & dyn_pres_K, rhoYks, B]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_K, alpha_rho_K, Re_K, nRtmp, rho_K, gamma_K, pi_inf_K,qv_K, dyn_pres_K, rhoYks, B]') do l = ibounds(3)%beg, ibounds(3)%end do k = ibounds(2)%beg, ibounds(2)%end do j = ibounds(1)%beg, ibounds(1)%end @@ -1165,6 +1163,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_convert_conservative_to_primitive_variables @@ -1489,8 +1488,7 @@ contains ! Computing the flux variables from the primitive variables, without ! accounting for the contribution of either viscosity or capillarity #ifdef MFC_SIMULATION - $:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_K, vel_K, & - & alpha_K, Re_K, Y_K]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_K, vel_K, alpha_K, Re_K, Y_K]') do l = is3b, is3e do k = is2b, is2e do j = is1b, is1e @@ -1596,6 +1594,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #endif end subroutine s_convert_primitive_to_flux_variables diff --git a/src/simulation/m_acoustic_src.fpp b/src/simulation/m_acoustic_src.fpp index 1b328e3d1f..fe03b073d7 100644 --- a/src/simulation/m_acoustic_src.fpp +++ b/src/simulation/m_acoustic_src.fpp @@ -166,7 +166,7 @@ contains sim_time = t_step*dt - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -178,7 +178,7 @@ contains end do end do end do - ! !$omp end target teams distribute parallel do simd + #:endcall GPU_PARALLEL_LOOP ! Keep outer loop sequel because different sources can have very different number of points do ai = 1, num_source @@ -221,7 +221,7 @@ contains deallocate (phi_rn) - $:GPU_PARALLEL_LOOP(private='[myalpha,myalpha_rho]') + #:call GPU_PARALLEL_LOOP(private='[myalpha,myalpha_rho]') do i = 1, num_points j = source_spatials(ai)%coord(1, i) k = source_spatials(ai)%coord(2, i) @@ -318,10 +318,11 @@ contains end if end do + #:endcall GPU_PARALLEL_LOOP end do ! Update the rhs variables - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -337,6 +338,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_acoustic_src_calculations !> This subroutine gives the temporally varying amplitude of the pulse @@ -718,7 +720,7 @@ contains !! @param c Speed of sound !! @param ai Acoustic source index !! @return gauss_sigma_time_local Converted Gaussian sigma time - elemental function f_gauss_sigma_time_local(gauss_conv_flag, ai, c) + function f_gauss_sigma_time_local(gauss_conv_flag, ai, c) $:GPU_ROUTINE(parallelism='[seq]') logical, intent(in) :: gauss_conv_flag integer, intent(in) :: ai diff --git a/src/simulation/m_body_forces.fpp b/src/simulation/m_body_forces.fpp index 1ea2c3be3b..9bf2f5a022 100644 --- a/src/simulation/m_body_forces.fpp +++ b/src/simulation/m_body_forces.fpp @@ -79,7 +79,7 @@ contains type(scalar_field), dimension(sys_size), intent(in) :: q_cons_vf integer :: i, j, k, l !< standard iterators - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -91,6 +91,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_mixture_density @@ -109,7 +110,7 @@ contains call s_compute_acceleration(mytime) call s_compute_mixture_density(q_cons_vf) - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = momxb, E_idx do l = 0, p do k = 0, n @@ -119,10 +120,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (bf_x) then ! x-direction body forces - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -133,11 +135,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bf_y) then ! y-direction body forces - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -148,11 +151,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bf_z) then ! z-direction body forces - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -163,6 +167,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if diff --git a/src/simulation/m_bubbles_EE.fpp b/src/simulation/m_bubbles_EE.fpp index d2aa192750..3e180d9585 100644 --- a/src/simulation/m_bubbles_EE.fpp +++ b/src/simulation/m_bubbles_EE.fpp @@ -76,7 +76,7 @@ contains real(wp) :: nR3bar integer(wp) :: i, j, k, l - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -89,6 +89,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_comp_alpha_from_n @@ -103,7 +104,7 @@ contains if (idir == 1) then if (.not. qbmm) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -115,11 +116,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if elseif (idir == 2) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -130,10 +132,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (idir == 3) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -144,6 +147,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if @@ -173,7 +177,7 @@ contains integer :: dmBub_id !< Dummy variables for unified subgrid bubble subroutines real(wp) :: dmMass_v, dmMass_n, dmBeta_c, dmBeta_t, dmCson - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -189,9 +193,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP adap_dt_stop_max = 0 - $:GPU_PARALLEL_LOOP(collapse=3, private='[Rtmp, Vtmp, myalpha_rho, myalpha]', & + #:call GPU_PARALLEL_LOOP(collapse=3, private='[Rtmp, Vtmp, myalpha_rho, myalpha]', & & reduction='[[adap_dt_stop_max]]', reductionOp='[MAX]', & & copy='[adap_dt_stop_max]') do l = 0, p @@ -321,11 +326,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (adap_dt .and. adap_dt_stop_max > 0) call s_mpi_abort("Adaptive time stepping failed to converge.") if (.not. adap_dt) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do q = 0, n do i = 0, m @@ -344,6 +350,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_compute_bubble_EE_source diff --git a/src/simulation/m_bubbles_EL.fpp b/src/simulation/m_bubbles_EL.fpp index b1e06f2f85..3f4135dec3 100644 --- a/src/simulation/m_bubbles_EL.fpp +++ b/src/simulation/m_bubbles_EL.fpp @@ -529,7 +529,7 @@ contains ! Subgrid p_inf model based on Maeda and Colonius (2018). if (lag_params%pressure_corrector) then ! Calculate velocity potentials (valid for one bubble per cell) - $:GPU_PARALLEL_LOOP(private='[k,cell]') + #:call GPU_PARALLEL_LOOP(private='[k,cell]') do k = 1, nBubs call s_get_pinf(k, q_prim_vf, 2, paux, cell, preterm1, term2, Romega) myR0 = bub_R0(k) @@ -546,11 +546,12 @@ contains bub_dphidt(k) = bub_dphidt(k)/(1._wp - term1_fac) end if end do + #:endcall GPU_PARALLEL_LOOP end if ! Radial motion model adap_dt_stop_max = 0 - $:GPU_PARALLEL_LOOP(private='[k,myalpha_rho,myalpha,Re,cell]', & + #:call GPU_PARALLEL_LOOP(private='[k,myalpha_rho,myalpha,Re,cell]', & & reduction='[[adap_dt_stop_max]]',reductionOp='[MAX]', & & copy='[adap_dt_stop_max]',copyin='[stage]') do k = 1, nBubs @@ -616,17 +617,19 @@ contains adap_dt_stop_max = max(adap_dt_stop_max, adap_dt_stop) end do + #:endcall GPU_PARALLEL_LOOP if (adap_dt .and. adap_dt_stop_max > 0) call s_mpi_abort("Adaptive time stepping failed to converge.") ! Bubbles remain in a fixed position - $:GPU_PARALLEL_LOOP(collapse=2, private='[k]', copyin='[stage]') + #:call GPU_PARALLEL_LOOP(collapse=2, private='[k]', copyin='[stage]') do k = 1, nBubs do l = 1, 3 mtn_dposdt(k, l, stage) = 0._wp mtn_dveldt(k, l, stage) = 0._wp end do end do + #:endcall GPU_PARALLEL_LOOP call nvtxEndRange @@ -650,7 +653,7 @@ contains if (lag_params%solver_approach == 2) then if (p == 0) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do k = 0, p do j = 0, n do i = 0, m @@ -665,8 +668,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do k = 0, p do j = 0, n do i = 0, m @@ -680,13 +684,14 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if do l = 1, num_dims call s_gradient_dir(q_prim_vf(E_idx), q_beta%vf(3), l) - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 0, p do j = 0, n do i = 0, m @@ -699,9 +704,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP !source in energy - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = idwbuff(3)%beg, idwbuff(3)%end do j = idwbuff(2)%beg, idwbuff(2)%end do i = idwbuff(1)%beg, idwbuff(1)%end @@ -709,10 +715,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP call s_gradient_dir(q_beta%vf(3), q_beta%vf(4), l) - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 0, p do j = 0, n do i = 0, m @@ -724,6 +731,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end do end if @@ -769,7 +777,7 @@ contains call nvtxStartRange("BUBBLES-LAGRANGE-KERNELS") - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, q_beta_idx do l = idwbuff(3)%beg, idwbuff(3)%end do k = idwbuff(2)%beg, idwbuff(2)%end @@ -779,12 +787,13 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP call s_smoothfunction(nBubs, intfc_rad, intfc_vel, & mtn_s, mtn_pos, q_beta) !Store 1-beta - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = idwbuff(3)%beg, idwbuff(3)%end do k = idwbuff(2)%beg, idwbuff(2)%end do j = idwbuff(1)%beg, idwbuff(1)%end @@ -795,6 +804,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP call nvtxEndRange @@ -1025,7 +1035,7 @@ contains integer :: k if (time_stepper == 1) then ! 1st order TVD RK - $:GPU_PARALLEL_LOOP(private='[k]') + #:call GPU_PARALLEL_LOOP(private='[k]') do k = 1, nBubs !u{1} = u{n} + dt * RHS{n} intfc_rad(k, 1) = intfc_rad(k, 1) + dt*intfc_draddt(k, 1) @@ -1035,6 +1045,7 @@ contains gas_p(k, 1) = gas_p(k, 1) + dt*gas_dpdt(k, 1) gas_mv(k, 1) = gas_mv(k, 1) + dt*gas_dmvdt(k, 1) end do + #:endcall GPU_PARALLEL_LOOP call s_transfer_data_to_tmp() call s_write_void_evol(mytime) @@ -1047,7 +1058,7 @@ contains elseif (time_stepper == 2) then ! 2nd order TVD RK if (stage == 1) then - $:GPU_PARALLEL_LOOP(private='[k]') + #:call GPU_PARALLEL_LOOP(private='[k]') do k = 1, nBubs !u{1} = u{n} + dt * RHS{n} intfc_rad(k, 2) = intfc_rad(k, 1) + dt*intfc_draddt(k, 1) @@ -1057,9 +1068,10 @@ contains gas_p(k, 2) = gas_p(k, 1) + dt*gas_dpdt(k, 1) gas_mv(k, 2) = gas_mv(k, 1) + dt*gas_dmvdt(k, 1) end do + #:endcall GPU_PARALLEL_LOOP elseif (stage == 2) then - $:GPU_PARALLEL_LOOP(private='[k]') + #:call GPU_PARALLEL_LOOP(private='[k]') do k = 1, nBubs !u{1} = u{n} + (1/2) * dt * (RHS{n} + RHS{1}) intfc_rad(k, 1) = intfc_rad(k, 1) + dt*(intfc_draddt(k, 1) + intfc_draddt(k, 2))/2._wp @@ -1069,6 +1081,7 @@ contains gas_p(k, 1) = gas_p(k, 1) + dt*(gas_dpdt(k, 1) + gas_dpdt(k, 2))/2._wp gas_mv(k, 1) = gas_mv(k, 1) + dt*(gas_dmvdt(k, 1) + gas_dmvdt(k, 2))/2._wp end do + #:endcall GPU_PARALLEL_LOOP call s_transfer_data_to_tmp() call s_write_void_evol(mytime) @@ -1083,7 +1096,7 @@ contains elseif (time_stepper == 3) then ! 3rd order TVD RK if (stage == 1) then - $:GPU_PARALLEL_LOOP(private='[k]') + #:call GPU_PARALLEL_LOOP(private='[k]') do k = 1, nBubs !u{1} = u{n} + dt * RHS{n} intfc_rad(k, 2) = intfc_rad(k, 1) + dt*intfc_draddt(k, 1) @@ -1093,9 +1106,10 @@ contains gas_p(k, 2) = gas_p(k, 1) + dt*gas_dpdt(k, 1) gas_mv(k, 2) = gas_mv(k, 1) + dt*gas_dmvdt(k, 1) end do + #:endcall GPU_PARALLEL_LOOP elseif (stage == 2) then - $:GPU_PARALLEL_LOOP(private='[k]') + #:call GPU_PARALLEL_LOOP(private='[k]') do k = 1, nBubs !u{2} = u{n} + (1/4) * dt * [RHS{n} + RHS{1}] intfc_rad(k, 2) = intfc_rad(k, 1) + dt*(intfc_draddt(k, 1) + intfc_draddt(k, 2))/4._wp @@ -1105,8 +1119,9 @@ contains gas_p(k, 2) = gas_p(k, 1) + dt*(gas_dpdt(k, 1) + gas_dpdt(k, 2))/4._wp gas_mv(k, 2) = gas_mv(k, 1) + dt*(gas_dmvdt(k, 1) + gas_dmvdt(k, 2))/4._wp end do + #:endcall GPU_PARALLEL_LOOP elseif (stage == 3) then - $:GPU_PARALLEL_LOOP(private='[k]') + #:call GPU_PARALLEL_LOOP(private='[k]') do k = 1, nBubs !u{n+1} = u{n} + (2/3) * dt * [(1/4)* RHS{n} + (1/4)* RHS{1} + RHS{2}] intfc_rad(k, 1) = intfc_rad(k, 1) + (2._wp/3._wp)*dt*(intfc_draddt(k, 1)/4._wp + intfc_draddt(k, 2)/4._wp + intfc_draddt(k, 3)) @@ -1116,6 +1131,7 @@ contains gas_p(k, 1) = gas_p(k, 1) + (2._wp/3._wp)*dt*(gas_dpdt(k, 1)/4._wp + gas_dpdt(k, 2)/4._wp + gas_dpdt(k, 3)) gas_mv(k, 1) = gas_mv(k, 1) + (2._wp/3._wp)*dt*(gas_dmvdt(k, 1)/4._wp + gas_dmvdt(k, 2)/4._wp + gas_dmvdt(k, 3)) end do + #:endcall GPU_PARALLEL_LOOP call s_transfer_data_to_tmp() call s_write_void_evol(mytime) @@ -1192,7 +1208,7 @@ contains integer :: k - $:GPU_PARALLEL_LOOP(private='[k]') + #:call GPU_PARALLEL_LOOP(private='[k]') do k = 1, nBubs gas_p(k, 2) = gas_p(k, 1) gas_mv(k, 2) = gas_mv(k, 1) @@ -1203,6 +1219,7 @@ contains mtn_vel(k, 1:3, 2) = mtn_vel(k, 1:3, 1) mtn_s(k, 1:3, 2) = mtn_s(k, 1:3, 1) end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_transfer_data_to_tmp @@ -1291,7 +1308,7 @@ contains if (dir == 1) then ! Gradient in x dir. - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 0, p do j = 0, n do i = 0, m @@ -1303,10 +1320,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else if (dir == 2) then ! Gradient in y dir. - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 0, p do j = 0, n do i = 0, m @@ -1318,9 +1336,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else ! Gradient in z dir. - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 0, p do j = 0, n do i = 0, m @@ -1332,6 +1351,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -1414,9 +1434,7 @@ contains lag_void_max = 0._wp lag_void_avg = 0._wp lag_vol = 0._wp - $:GPU_PARALLEL_LOOP(collapse=3, reduction='[[lag_vol, lag_void_avg], & - & [lag_void_max]]', reductionOp='[+, MAX]', & - & copy='[lag_vol, lag_void_avg, lag_void_max]') + #:call GPU_PARALLEL_LOOP(collapse=3, reduction='[[lag_vol, lag_void_avg], [lag_void_max]]', reductionOp='[+, MAX]', copy='[lag_vol, lag_void_avg, lag_void_max]') do k = 0, p do j = 0, n do i = 0, m @@ -1429,6 +1447,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #ifdef MFC_MPI if (num_procs > 1) then @@ -1600,7 +1619,7 @@ contains integer :: k - $:GPU_PARALLEL_LOOP(reduction='[[Rmax_glb], [Rmin_glb]]', & + #:call GPU_PARALLEL_LOOP(reduction='[[Rmax_glb], [Rmin_glb]]', & & reductionOp='[MAX, MIN]', copy='[Rmax_glb,Rmin_glb]') do k = 1, nBubs Rmax_glb = max(Rmax_glb, intfc_rad(k, 1)/bub_R0(k)) @@ -1608,6 +1627,7 @@ contains Rmax_stats(k) = max(Rmax_stats(k), intfc_rad(k, 1)/bub_R0(k)) Rmin_stats(k) = min(Rmin_stats(k), intfc_rad(k, 1)/bub_R0(k)) end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_calculate_lag_bubble_stats diff --git a/src/simulation/m_bubbles_EL_kernels.fpp b/src/simulation/m_bubbles_EL_kernels.fpp index 6f9c71a4c0..529b08bfd9 100644 --- a/src/simulation/m_bubbles_EL_kernels.fpp +++ b/src/simulation/m_bubbles_EL_kernels.fpp @@ -55,7 +55,7 @@ contains real(wp), dimension(3) :: s_coord integer :: l - $:GPU_PARALLEL_LOOP(private='[l,s_coord,cell]') + #:call GPU_PARALLEL_LOOP(private='[l,s_coord,cell]') do l = 1, nBubs volpart = 4._wp/3._wp*pi*lbk_rad(l, 2)**3._wp @@ -90,6 +90,7 @@ contains updatedvar%vf(5)%sf(cell(1), cell(2), cell(3)) = updatedvar%vf(5)%sf(cell(1), cell(2), cell(3)) + addFun3 end if end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_deltafunc @@ -120,7 +121,7 @@ contains smearGridz = smearGrid if (p == 0) smearGridz = 1 - $:GPU_PARALLEL_LOOP(private='[nodecoord,l,s_coord,cell,center]', copyin='[smearGrid,smearGridz]') + #:call GPU_PARALLEL_LOOP(private='[nodecoord,l,s_coord,cell,center]', copyin='[smearGrid,smearGridz]') do l = 1, nBubs nodecoord(1:3) = 0 center(1:3) = 0._wp @@ -195,6 +196,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_gaussian diff --git a/src/simulation/m_cbc.fpp b/src/simulation/m_cbc.fpp index 1cb84e55c7..e4682c575d 100644 --- a/src/simulation/m_cbc.fpp +++ b/src/simulation/m_cbc.fpp @@ -695,7 +695,7 @@ contains F_src_rs${XYZ}$_vf, & is1, is2, is3, idwbuff(2)%beg, idwbuff(3)%beg) - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = 1, flux_cbc_index do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -706,8 +706,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = advxb, advxe do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -718,6 +719,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP ! PI4 of flux_rs_vf and flux_src_rs_vf at j = 1/2, 3/2 else @@ -726,7 +728,7 @@ contains F_src_rs${XYZ}$_vf, & is1, is2, is3, idwbuff(2)%beg, idwbuff(3)%beg) - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, flux_cbc_index do j = 0, 1 do r = is3%beg, is3%end @@ -745,8 +747,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = advxb, advxe do j = 0, 1 do r = is3%beg, is3%end @@ -765,14 +768,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! FD2 or FD4 of RHS at j = 0 - $:GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, & - & mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, & - & dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, & - & dYs_ds, h_k, Cp_i, Gamma_i, Xs]') + #:call GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, dYs_ds, h_k, Cp_i, Gamma_i, Xs]') do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1103,6 +1104,7 @@ contains end do end do + #:endcall GPU_PARALLEL_LOOP end if #:endfor @@ -1163,7 +1165,7 @@ contains ! Reshaping Inputted Data in x-direction if (cbc_dir == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1174,8 +1176,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = 0, buff_size @@ -1185,8 +1188,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, flux_cbc_index do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1198,8 +1202,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1208,9 +1213,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = advxb, advxe do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1221,8 +1227,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1232,6 +1239,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! END: Reshaping Inputted Data in x-direction @@ -1239,7 +1247,7 @@ contains ! Reshaping Inputted Data in y-direction elseif (cbc_dir == 2) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1250,8 +1258,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = 0, buff_size @@ -1261,8 +1270,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, flux_cbc_index do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1274,8 +1284,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1284,9 +1295,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = advxb, advxe do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1297,8 +1309,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1308,6 +1321,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! END: Reshaping Inputted Data in y-direction @@ -1315,7 +1329,7 @@ contains ! Reshaping Inputted Data in z-direction else - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1326,8 +1340,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = 0, buff_size @@ -1337,8 +1352,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, flux_cbc_index do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1350,8 +1366,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1360,9 +1377,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = advxb, advxe do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1373,8 +1391,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1384,6 +1403,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -1413,7 +1433,7 @@ contains ! Reshaping Outputted Data in x-direction if (cbc_dir == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, flux_cbc_index do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1425,7 +1445,8 @@ contains end do end do end do - $:GPU_PARALLEL_LOOP(collapse=3) + #:endcall GPU_PARALLEL_LOOP + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1434,9 +1455,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = advxb, advxe do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1447,8 +1469,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1458,13 +1481,14 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! END: Reshaping Outputted Data in x-direction ! Reshaping Outputted Data in y-direction elseif (cbc_dir == 2) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, flux_cbc_index do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1476,8 +1500,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1486,9 +1511,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = advxb, advxe do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1499,8 +1525,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1510,6 +1537,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! END: Reshaping Outputted Data in y-direction @@ -1517,7 +1545,7 @@ contains ! Reshaping Outputted Data in z-direction else - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, flux_cbc_index do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1529,8 +1557,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1539,9 +1568,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = advxb, advxe do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1552,8 +1582,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do r = is3%beg, is3%end do k = is2%beg, is2%end do j = -1, buff_size @@ -1563,6 +1594,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if diff --git a/src/simulation/m_data_output.fpp b/src/simulation/m_data_output.fpp index 117429487b..9f80df014e 100644 --- a/src/simulation/m_data_output.fpp +++ b/src/simulation/m_data_output.fpp @@ -279,7 +279,7 @@ contains integer :: j, k, l ! Computing Stability Criteria at Current Time-step - $:GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') do l = 0, p do k = 0, n do j = 0, m @@ -296,6 +296,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP ! end: Computing Stability Criteria at Current Time-step diff --git a/src/simulation/m_fftw.fpp b/src/simulation/m_fftw.fpp index fabd15255e..d6eb430dcc 100644 --- a/src/simulation/m_fftw.fpp +++ b/src/simulation/m_fftw.fpp @@ -141,7 +141,7 @@ contains if (bc_y%beg >= 0) return #if defined(MFC_GPU) - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 1, sys_size do j = 0, m do l = 1, cmplx_size @@ -149,8 +149,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 1, sys_size do j = 0, m do l = 0, p @@ -158,6 +159,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP p_real => data_real_gpu p_cmplx => data_cmplx_gpu @@ -175,7 +177,7 @@ contains Nfq = 3 $:GPU_UPDATE(device='[Nfq]') - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 1, sys_size do j = 0, m do l = 1, Nfq @@ -183,6 +185,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #:call GPU_HOST_DATA(use_device='[p_real, p_fltr_cmplx]') #if defined(__PGI) @@ -193,7 +196,7 @@ contains #endif #:endcall GPU_HOST_DATA - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 1, sys_size do j = 0, m do l = 0, p @@ -202,10 +205,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP do i = 1, fourier_rings - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 1, sys_size do j = 0, m do l = 1, cmplx_size @@ -213,8 +217,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3, firstprivate='[i]') + #:call GPU_PARALLEL_LOOP(collapse=3, firstprivate='[i]') do k = 1, sys_size do j = 0, m do l = 0, p @@ -222,6 +227,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #:call GPU_HOST_DATA(use_device='[p_real, p_cmplx]') #if defined(__PGI) @@ -235,7 +241,7 @@ contains Nfq = min(floor(2_dp*real(i, dp)*pi), cmplx_size) $:GPU_UPDATE(device='[Nfq]') - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do k = 1, sys_size do j = 0, m do l = 1, Nfq @@ -243,6 +249,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #:call GPU_HOST_DATA(use_device='[p_real, p_fltr_cmplx]') #if defined(__PGI) @@ -253,7 +260,7 @@ contains #endif #:endcall GPU_HOST_DATA - $:GPU_PARALLEL_LOOP(collapse=3, firstprivate='[i]') + #:call GPU_PARALLEL_LOOP(collapse=3, firstprivate='[i]') do k = 1, sys_size do j = 0, m do l = 0, p @@ -262,6 +269,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end do #:endcall GPU_DATA diff --git a/src/simulation/m_hyperelastic.fpp b/src/simulation/m_hyperelastic.fpp index ba9cc97850..9cb7bd4c43 100644 --- a/src/simulation/m_hyperelastic.fpp +++ b/src/simulation/m_hyperelastic.fpp @@ -106,8 +106,7 @@ contains real(wp) :: G_local integer :: j, k, l, i, r - $:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_K, alpha_rho_K, rho, & - & gamma, pi_inf, qv, G_local, Re, tensora, tensorb]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_K, alpha_rho_K, rho, gamma, pi_inf, qv, G_local, Re, tensora, tensorb]') do l = 0, p do k = 0, n do j = 0, m @@ -208,6 +207,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_hyperelastic_rmt_stress_update !> The following subroutine handles the calculation of the btensor. diff --git a/src/simulation/m_hypoelastic.fpp b/src/simulation/m_hypoelastic.fpp index f763928a64..84be088fae 100644 --- a/src/simulation/m_hypoelastic.fpp +++ b/src/simulation/m_hypoelastic.fpp @@ -104,7 +104,7 @@ contains ! calculate velocity gradients + rho_K and G_K ! TODO: re-organize these loops one by one for GPU efficiency if possible? - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -112,8 +112,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -126,9 +127,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (ndirs > 1) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -136,8 +138,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -153,11 +156,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP ! 3D if (ndirs == 3) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -166,8 +170,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -187,10 +192,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -212,9 +218,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP ! apply rhs source term to elastic stress equation - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -226,9 +233,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (idir == 2) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -261,9 +269,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (idir == 3) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -327,11 +336,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (cyl_coord .and. idir == 2) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -359,6 +369,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if @@ -393,13 +404,14 @@ contains if (n == 0) then l = 0; q = 0 - $:GPU_PARALLEL_LOOP() + #:call GPU_PARALLEL_LOOP() do k = 0, m rhs_vf(damage_idx)%sf(k, l, q) = (alpha_bar*max(abs(q_cons_vf(stress_idx%beg)%sf(k, l, q)) - tau_star, 0._wp))**cont_damage_s end do + #:endcall GPU_PARALLEL_LOOP elseif (p == 0) then q = 0 - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, n do k = 0, m ! Maximum principal stress @@ -412,8 +424,9 @@ contains rhs_vf(damage_idx)%sf(k, l, q) = (alpha_bar*max(tau_p - tau_star, 0._wp))**cont_damage_s end do end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q = 0, p do l = 0, n do k = 0, m @@ -450,6 +463,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_compute_damage_state diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index df6ea1145b..97d31f9bc8 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -169,11 +169,7 @@ contains type(ghost_point) :: gp type(ghost_point) :: innerp - $:GPU_PARALLEL_LOOP(private='[physical_loc,dyn_pres,alpha_rho_IP, & - & alpha_IP,pres_IP,vel_IP,vel_g,vel_norm_IP,r_IP, & - & v_IP,pb_IP,mv_IP,nmom_IP,presb_IP,massv_IP,rho, & - & gamma,pi_inf,Re_K,G_K,Gs,gp,innerp,norm,buf, & - & j,k,l,q]') + #:call GPU_PARALLEL_LOOP(private='[physical_loc,dyn_pres,alpha_rho_IP, alpha_IP,pres_IP,vel_IP,vel_g,vel_norm_IP,r_IP, v_IP,pb_IP,mv_IP,nmom_IP,presb_IP,massv_IP,rho, gamma,pi_inf,Re_K,G_K,Gs,gp,innerp,norm,buf, j,k,l,q]') do i = 1, num_gps gp = ghost_points(i) @@ -315,11 +311,10 @@ contains end do end if end do + #:endcall GPU_PARALLEL_LOOP !Correct the state of the inner points in IBs - $:GPU_PARALLEL_LOOP(private='[physical_loc,dyn_pres,alpha_rho_IP, & - & alpha_IP,vel_g,rho,gamma,pi_inf,Re_K,innerp, & - & j,k,l,q]') + #:call GPU_PARALLEL_LOOP(private='[physical_loc,dyn_pres,alpha_rho_IP, alpha_IP,vel_g,rho,gamma,pi_inf,Re_K,innerp,j,k,l,q]') do i = 1, num_inner_gps innerp = inner_points(i) @@ -332,6 +327,7 @@ contains q_cons_vf(q)%sf(j, k, l) = 0._wp end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_ibm_correct_state diff --git a/src/simulation/m_mhd.fpp b/src/simulation/m_mhd.fpp index 9306dcb760..43d8aeef18 100644 --- a/src/simulation/m_mhd.fpp +++ b/src/simulation/m_mhd.fpp @@ -76,7 +76,7 @@ contains real(wp), dimension(3) :: v, B real(wp) :: divB, vdotB - $:GPU_PARALLEL_LOOP(collapse=3, private='[v, B]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[v, B]') do q = 0, p do l = 0, n do k = 0, m @@ -129,6 +129,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_mhd_powell_rhs diff --git a/src/simulation/m_mpi_proxy.fpp b/src/simulation/m_mpi_proxy.fpp index fc08409e36..915146fdfe 100644 --- a/src/simulation/m_mpi_proxy.fpp +++ b/src/simulation/m_mpi_proxy.fpp @@ -299,7 +299,7 @@ contains #:for mpi_dir in [1, 2, 3] if (mpi_dir == ${mpi_dir}$) then #:if mpi_dir == 1 - $:GPU_PARALLEL_LOOP(collapse=3,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') do l = 0, p do k = 0, n do j = 0, gp_layers - 1 @@ -308,8 +308,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #:elif mpi_dir == 2 - $:GPU_PARALLEL_LOOP(collapse=3,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') do l = 0, p do k = 0, gp_layers - 1 do j = -gp_layers, m + gp_layers @@ -319,8 +320,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #:else - $:GPU_PARALLEL_LOOP(collapse=3,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') do l = 0, gp_layers - 1 do k = -gp_layers, n + gp_layers do j = -gp_layers, m + gp_layers @@ -330,6 +332,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #:endif end if #:endfor @@ -347,7 +350,7 @@ contains #:for mpi_dir in [1, 2, 3] if (mpi_dir == ${mpi_dir}$) then #:if mpi_dir == 1 - $:GPU_PARALLEL_LOOP(collapse=3,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') do l = 0, p do k = 0, n do j = -gp_layers, -1 @@ -356,8 +359,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #:elif mpi_dir == 2 - $:GPU_PARALLEL_LOOP(collapse=3,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') do l = 0, p do k = -gp_layers, -1 do j = -gp_layers, m + gp_layers @@ -367,9 +371,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #:else ! Unpacking buffer from bc_z%beg - $:GPU_PARALLEL_LOOP(collapse=3,private='[r]') + #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') do l = -gp_layers, -1 do k = -gp_layers, n + gp_layers do j = -gp_layers, m + gp_layers @@ -380,6 +385,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #:endif end if #:endfor diff --git a/src/simulation/m_pressure_relaxation.fpp b/src/simulation/m_pressure_relaxation.fpp index 63fc17b328..5449e84058 100644 --- a/src/simulation/m_pressure_relaxation.fpp +++ b/src/simulation/m_pressure_relaxation.fpp @@ -70,7 +70,7 @@ contains type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf integer :: j, k, l - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -78,6 +78,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_pressure_relaxation_procedure diff --git a/src/simulation/m_qbmm.fpp b/src/simulation/m_qbmm.fpp index c7a75f2c96..c5fbd486b4 100644 --- a/src/simulation/m_qbmm.fpp +++ b/src/simulation/m_qbmm.fpp @@ -433,7 +433,7 @@ contains end select if (.not. polytropic) then - $:GPU_PARALLEL_LOOP(collapse=5,private='[nb_q,nR,nR2,R,R2,nb_dot,nR_dot,nR2_dot,var,AX]') + #:call GPU_PARALLEL_LOOP(collapse=5,private='[nb_q,nR,nR2,R,R2,nb_dot,nR_dot,nR2_dot,var,AX]') do i = 1, nb do q = 1, nnode do l = 0, p @@ -534,11 +534,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! The following block is not repeated and is left as is if (idir == 1) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do q = 0, n do i = 0, m @@ -557,6 +558,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_compute_qbmm_rhs @@ -712,10 +714,7 @@ contains is1_qbmm = ix; is2_qbmm = iy; is3_qbmm = iz $:GPU_UPDATE(device='[is1_qbmm,is2_qbmm,is3_qbmm]') - $:GPU_PARALLEL_LOOP(collapse=3, private='[moms, msum, wght, abscX, & - & abscY, wght_pb, wght_mv, wght_ht, coeff, ht, r, q, & - & n_tait, B_tait, pres, rho, nbub, c, alf, momsum, & - & drdt, drdt2, chi_vw, x_vw, rho_mw, k_mw, T_bar, grad_T]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[moms, msum, wght, abscX, abscY, wght_pb, wght_mv, wght_ht, coeff, ht, r, q, n_tait, B_tait, pres, rho, nbub, c, alf, momsum, drdt, drdt2, chi_vw, x_vw, rho_mw, k_mw, T_bar, grad_T]') do id3 = is3_qbmm%beg, is3_qbmm%end do id2 = is2_qbmm%beg, is2_qbmm%end do id1 = is1_qbmm%beg, is1_qbmm%end @@ -852,6 +851,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP contains ! Helper to select the correct coefficient routine diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index ae66f00011..526751323f 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -636,7 +636,7 @@ contains if (.not. igr) then ! Association/Population of Working Variables - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = idwbuff(3)%beg, idwbuff(3)%end do k = idwbuff(2)%beg, idwbuff(2)%end @@ -646,11 +646,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP ! Converting Conservative to Primitive Variables if (mpp_lim .and. bubbles_euler) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = idwbuff(3)%beg, idwbuff(3)%end do k = idwbuff(2)%beg, idwbuff(2)%end do j = idwbuff(1)%beg, idwbuff(1)%end @@ -667,6 +668,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -908,7 +910,7 @@ contains ! END: Dimensional Splitting Loop if (ib) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -920,6 +922,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! Additional Physics and Source Temrs @@ -974,7 +977,7 @@ contains if (run_time_info .or. probe_wrt .or. ib .or. bubbles_lagrange) then if (.not. igr) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = idwbuff(3)%beg, idwbuff(3)%end do k = idwbuff(2)%beg, idwbuff(2)%end @@ -984,6 +987,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -1015,7 +1019,7 @@ contains real(wp) :: advected_qty_val, pressure_val, velocity_val if (alt_soundspeed) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do q_loop = 0, p do l_loop = 0, n do k_loop = 0, m @@ -1038,6 +1042,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if select case (idir) @@ -1049,7 +1054,7 @@ contains call s_cbc(q_prim_vf%vf, flux_n(idir)%vf, flux_src_n_vf%vf, idir, 1, irx, iry, irz) end if - $:GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,flux_face1,flux_face2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,flux_face1,flux_face2]') do j = 1, sys_size do q_loop = 0, p do l_loop = 0, n @@ -1062,10 +1067,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (model_eqns == 3) then - $:GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, & - & pressure_val,flux_face1,flux_face2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, pressure_val,flux_face1,flux_face2]') do q_loop = 0, p do l_loop = 0, n do k_loop = 0, m @@ -1082,6 +1087,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if call s_add_directional_advection_source_terms(idir, rhs_vf, q_cons_vf, q_prim_vf, flux_src_n_vf, Kterm) @@ -1094,7 +1100,7 @@ contains call s_cbc(q_prim_vf%vf, flux_n(idir)%vf, flux_src_n_vf%vf, idir, 1, irx, iry, irz) end if - $:GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,flux_face1,flux_face2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,flux_face1,flux_face2]') do j = 1, sys_size do l = 0, p do k = 0, n @@ -1107,10 +1113,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (model_eqns == 3) then - $:GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, & - & pressure_val,flux_face1,flux_face2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, pressure_val,flux_face1,flux_face2]') do l = 0, p do k = 0, n do q = 0, m @@ -1132,10 +1138,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (cyl_coord) then - $:GPU_PARALLEL_LOOP(collapse=4,private='[flux_face1,flux_face2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[flux_face1,flux_face2]') do j = 1, sys_size do l = 0, p do k = 0, n @@ -1148,6 +1155,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if call s_add_directional_advection_source_terms(idir, rhs_vf, q_cons_vf, q_prim_vf, flux_src_n_vf, Kterm) @@ -1161,8 +1169,7 @@ contains end if if (grid_geometry == 3) then ! Cylindrical Coordinates - $:GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,velocity_val, & - & flux_face1,flux_face2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,velocity_val,flux_face1,flux_face2]') do j = 1, sys_size do k = 0, p do q = 0, n @@ -1177,7 +1184,8 @@ contains end do end do end do - $:GPU_PARALLEL_LOOP(collapse=4,private='[flux_face1,flux_face2]') + #:endcall GPU_PARALLEL_LOOP + #:call GPU_PARALLEL_LOOP(collapse=4,private='[flux_face1,flux_face2]') do j = 1, sys_size do k = 0, p do q = 0, n @@ -1190,8 +1198,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else ! Cartesian Coordinates - $:GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,flux_face1,flux_face2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,flux_face1,flux_face2]') do j = 1, sys_size do k = 0, p do q = 0, n @@ -1204,11 +1213,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (model_eqns == 3) then - $:GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, & - & pressure_val,flux_face1,flux_face2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, pressure_val,flux_face1,flux_face2]') do k = 0, p do q = 0, n do l = 0, m @@ -1225,6 +1234,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if call s_add_directional_advection_source_terms(idir, rhs_vf, q_cons_vf, q_prim_vf, flux_src_n_vf, Kterm) @@ -1252,8 +1262,7 @@ contains case (1) ! x-direction use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) if (use_standard_riemann) then - $:GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, & - & local_term_coeff,local_flux1,local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') do j_adv = advxb, advxe do q_idx = 0, p ! z_extent do l_idx = 0, n ! y_extent @@ -1268,12 +1277,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else ! Other Riemann solvers if (alt_soundspeed) then if (bubbles_euler .neqv. .true.) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, & - & local_q_cons_val, local_k_term_val, & - & local_term_coeff, local_flux1, local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') do q_idx = 0, p; do l_idx = 0, n; do k_idx = 0, m local_inv_ds = 1._wp/dx(k_idx) local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(k_idx, l_idx, q_idx) @@ -1284,11 +1292,9 @@ contains rhs_vf_arg(advxe)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(advxe)%sf(k_idx, l_idx, q_idx) + & local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) end do; end do; end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds,& - & local_q_cons_val, local_k_term_val, & - & local_term_coeff, local_flux1, & - & local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds,local_q_cons_val, local_k_term_val,local_term_coeff, local_flux1, local_flux2]') do q_idx = 0, p; do l_idx = 0, n; do k_idx = 0, m local_inv_ds = 1._wp/dx(k_idx) local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(k_idx, l_idx, q_idx) @@ -1299,10 +1305,10 @@ contains rhs_vf_arg(advxb)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(advxb)%sf(k_idx, l_idx, q_idx) + & local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) end do; end do; end do + #:endcall GPU_PARALLEL_LOOP end if else ! NOT alt_soundspeed - $:GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, & - & local_term_coeff,local_flux1,local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') do j_adv = advxb, advxe do q_idx = 0, p; do l_idx = 0, n; do k_idx = 0, m local_inv_ds = 1._wp/dx(k_idx) @@ -1312,6 +1318,7 @@ contains rhs_vf_arg(j_adv)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(j_adv)%sf(k_idx, l_idx, q_idx) + & local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) end do; end do; end do + #:endcall GPU_PARALLEL_LOOP end do end if end if @@ -1319,8 +1326,7 @@ contains case (2) ! y-direction: loops q_idx (x), k_idx (y), l_idx (z); sf(q_idx, k_idx, l_idx); dy(k_idx); Kterm(q_idx,k_idx,l_idx) use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) if (use_standard_riemann) then - $:GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, & - & local_term_coeff,local_flux1,local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') do j_adv = advxb, advxe do l_idx = 0, p ! z_extent do k_idx = 0, n ! y_extent @@ -1335,13 +1341,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else ! Other Riemann solvers if (alt_soundspeed) then if (bubbles_euler .neqv. .true.) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, & - & local_q_cons_val, local_k_term_val, & - & local_term_coeff, local_flux1, & - & local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m local_inv_ds = 1._wp/dy(k_idx) local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(q_idx, k_idx, l_idx) @@ -1356,11 +1360,9 @@ contains (local_k_term_val/(2._wp*y_cc(k_idx)))*(local_flux1 + local_flux2) end if end do; end do; end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, & - & local_q_cons_val, local_k_term_val, & - & local_term_coeff, local_flux1, & - & local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val,local_term_coeff, local_flux1, local_flux2]') do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m local_inv_ds = 1._wp/dy(k_idx) local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(q_idx, k_idx, l_idx) @@ -1375,10 +1377,10 @@ contains (local_k_term_val/(2._wp*y_cc(k_idx)))*(local_flux1 + local_flux2) end if end do; end do; end do + #:endcall GPU_PARALLEL_LOOP end if else ! NOT alt_soundspeed - $:GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, & - & local_term_coeff,local_flux1,local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') do j_adv = advxb, advxe do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m local_inv_ds = 1._wp/dy(k_idx) @@ -1388,6 +1390,7 @@ contains rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) + & local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) end do; end do; end do + #:endcall GPU_PARALLEL_LOOP end do end if end if @@ -1400,8 +1403,7 @@ contains end if if (use_standard_riemann) then - $:GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, & - & local_term_coeff,local_flux1,local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') do j_adv = advxb, advxe do k_idx = 0, p ! z_extent do q_idx = 0, n ! y_extent @@ -1416,13 +1418,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else ! Other Riemann solvers if (alt_soundspeed) then if (bubbles_euler .neqv. .true.) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, & - & local_q_cons_val, local_k_term_val, & - & local_term_coeff, local_flux1, & - & local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds,local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m local_inv_ds = 1._wp/dz(k_idx) local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx) @@ -1433,11 +1433,9 @@ contains rhs_vf_arg(advxe)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(advxe)%sf(l_idx, q_idx, k_idx) + & local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) end do; end do; end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, & - & local_q_cons_val, local_k_term_val, & - & local_term_coeff, local_flux1, & - & local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m local_inv_ds = 1._wp/dz(k_idx) local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx) @@ -1448,10 +1446,10 @@ contains rhs_vf_arg(advxb)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(advxb)%sf(l_idx, q_idx, k_idx) + & local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) end do; end do; end do + #:endcall GPU_PARALLEL_LOOP end if else ! NOT alt_soundspeed - $:GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, & - & local_term_coeff,local_flux1,local_flux2]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') do j_adv = advxb, advxe do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m local_inv_ds = 1._wp/dz(k_idx) @@ -1461,6 +1459,7 @@ contains rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) + & local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) end do; end do; end do + #:endcall GPU_PARALLEL_LOOP end do end if end if @@ -1483,7 +1482,7 @@ contains if (idir == 1) then ! x-direction if (surface_tension) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -1495,9 +1494,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -1511,11 +1511,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (idir == 2) then ! y-direction if (surface_tension) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -1527,6 +1528,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (cyl_coord .and. ((bc_y%beg == -2) .or. (bc_y%beg == -14))) then @@ -1547,7 +1549,7 @@ contains idwbuff(1), idwbuff(2), idwbuff(3)) end if - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, p do j = 0, m $:GPU_LOOP(parallelism='[seq]') @@ -1559,10 +1561,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 1, n do j = 0, m @@ -1576,9 +1579,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -1592,6 +1596,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! Applying the geometrical viscous Riemann source fluxes calculated as average @@ -1599,7 +1604,7 @@ contains if (cyl_coord) then if ((bc_y%beg == -2) .or. (bc_y%beg == -14)) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 1, n do j = 0, m @@ -1613,9 +1618,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (viscous) then - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = 0, p do j = 0, m $:GPU_LOOP(parallelism='[seq]') @@ -1626,10 +1632,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if else - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -1643,14 +1650,14 @@ contains end do end do end do - + #:endcall GPU_PARALLEL_LOOP end if end if elseif (idir == 3) then ! z-direction if (surface_tension) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -1662,9 +1669,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -1678,9 +1686,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (grid_geometry == 3) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -1696,6 +1705,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -1801,7 +1811,7 @@ contains $:GPU_UPDATE(device='[is1,is2,is3,iv]') if (recon_dir == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -1812,8 +1822,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else if (recon_dir == 2) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -1824,8 +1835,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else if (recon_dir == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -1836,6 +1848,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_reconstruct_cell_boundary_values_first_order diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index bae30f3fd6..9214cc4893 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -357,14 +357,7 @@ contains #:for NORM_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (norm_dir == ${NORM_DIR}$) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, & - & vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R, & - & G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, & - & s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, & - & Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, & - & Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, & - & pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, & - & zcoef, vel_L_tmp, vel_R_tmp]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -1002,6 +995,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if #:endfor @@ -1188,14 +1182,7 @@ contains ! 6-EQUATION MODEL WITH HLLC if (model_eqns == 3) then !ME3 - $:GPU_PARALLEL_LOOP(collapse=3, private='[vel_L, vel_R, & - & vel_K_Star, Re_L, Re_R, rho_avg, h_avg, & - & gamma_avg, s_L, s_R, s_S, vel_avg_rms, & - & alpha_L, alpha_R, Ys_L, Ys_R, Xs_L, Xs_R, & - & Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, Yi_avg, & - & Phi_avg, h_iL, h_iR, h_avg_2, tau_e_L, & - & tau_e_R, G_L, G_R, flux_ene_e, xi_field_L, & - & xi_field_R, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel_L, vel_R, vel_K_Star, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, vel_avg_rms, alpha_L, alpha_R, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, tau_e_L, tau_e_R, G_L, G_R, flux_ene_e, xi_field_L, xi_field_R, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -1618,13 +1605,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (model_eqns == 4) then !ME4 - $:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, & - & alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, & - & rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, & - & vel_avg_rms, nbub_L, nbub_R, ptilde_L, ptilde_R]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, vel_avg_rms, nbub_L, nbub_R, ptilde_L, ptilde_R]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -1871,14 +1856,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (model_eqns == 2 .and. bubbles_euler) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[R0_L, R0_R, V0_L, & - & V0_R, P0_L, P0_R, pbw_L, pbw_R, vel_L, & - & vel_R, rho_avg, alpha_L, alpha_R, h_avg, & - & gamma_avg, s_L, s_R, s_S, nbub_L, nbub_R, & - & ptilde_L, ptilde_R, vel_avg_rms, Re_L, Re_R, & - & pcorr, zcoef, vel_L_tmp, vel_R_tmp]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[R0_L, R0_R, V0_L, V0_R, P0_L, P0_R, pbw_L, pbw_R, vel_L, vel_R, rho_avg, alpha_L, alpha_R, h_avg, gamma_avg, s_L, s_R, s_S, nbub_L, nbub_R, ptilde_L, ptilde_R, vel_avg_rms, Re_L, Re_R, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -2341,17 +2322,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else ! 5-EQUATION MODEL WITH HLLC - $:GPU_PARALLEL_LOOP(collapse=3, private='[vel_L, vel_R, & - & Re_L, Re_R, rho_avg, h_avg, gamma_avg, & - & alpha_L, alpha_R, s_L, s_R, s_S, & - & vel_avg_rms, pcorr, zcoef, vel_L_tmp, & - & vel_R_tmp, Ys_L, Ys_R, Xs_L, Xs_R, & - & Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, tau_e_L, & - & tau_e_R, xi_field_L, xi_field_R, Yi_avg, & - & Phi_avg, h_iL, h_iR, h_avg_2]', & - & copyin='[is1, is2, is3]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel_L, vel_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, alpha_L, alpha_R, s_L, s_R, s_S, vel_avg_rms, pcorr, zcoef, vel_L_tmp, vel_R_tmp, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, tau_e_L, tau_e_R, xi_field_L, xi_field_R, Yi_avg,Phi_avg, h_iL, h_iR, h_avg_2]', copyin='[is1, is2, is3]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -2855,6 +2829,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if #:endfor @@ -2967,12 +2942,7 @@ contains #:for NORM_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (norm_dir == ${NORM_DIR}$) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, & - & alpha_rho_R, vel, alpha_L, alpha_R, rho, pres, & - & E, H_no_mag, gamma, pi_inf, qv, vel_rms, B, & - & c, c_fast, pres_mag, U_L, U_R, U_starL, & - & U_starR, U_doubleL, U_doubleR, F_L, F_R, & - & F_starL, F_starR, F_hlld]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel, alpha_L, alpha_R, rho, pres,E, H_no_mag, gamma, pi_inf, qv, vel_rms, B, c, c_fast, pres_mag, U_L, U_R, U_starL, U_starR, U_doubleL, U_doubleR, F_L, F_R, F_starL, F_starR, F_hlld]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -3144,6 +3114,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if #:endfor @@ -3346,7 +3317,7 @@ contains if (norm_dir == 1) then if (bc_x%beg == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at beginning - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = 1, sys_size do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3355,9 +3326,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (viscous) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do k = isy%beg, isy%end @@ -3367,9 +3339,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (n > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do k = isy%beg, isy%end @@ -3379,9 +3352,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (p > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do k = isy%beg, isy%end @@ -3391,6 +3365,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -3401,7 +3376,7 @@ contains if (bc_x%end == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at end - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = 1, sys_size do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3410,10 +3385,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (viscous) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do k = isy%beg, isy%end @@ -3423,9 +3399,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (n > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do k = isy%beg, isy%end @@ -3435,9 +3412,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (p > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do k = isy%beg, isy%end @@ -3447,6 +3425,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -3460,7 +3439,7 @@ contains elseif (norm_dir == 2) then if (bc_y%beg == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at beginning - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = 1, sys_size do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3469,10 +3448,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (viscous) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do j = isx%beg, isx%end @@ -3481,8 +3461,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do j = isx%beg, isx%end @@ -3491,9 +3472,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (p > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do j = isx%beg, isx%end @@ -3502,6 +3484,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -3510,7 +3493,7 @@ contains if (bc_y%end == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at end - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = 1, sys_size do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3519,10 +3502,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (viscous) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do j = isx%beg, isx%end @@ -3531,8 +3515,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do j = isx%beg, isx%end @@ -3541,9 +3526,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (p > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do l = isz%beg, isz%end do j = isx%beg, isx%end @@ -3552,6 +3538,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -3563,7 +3550,7 @@ contains else if (bc_z%beg == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at beginning - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = 1, sys_size do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3572,9 +3559,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (viscous) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do k = isy%beg, isy%end do j = isx%beg, isx%end @@ -3583,7 +3571,8 @@ contains end do end do end do - $:GPU_PARALLEL_LOOP(collapse=3) + #:endcall GPU_PARALLEL_LOOP + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do k = isy%beg, isy%end do j = isx%beg, isx%end @@ -3592,7 +3581,8 @@ contains end do end do end do - $:GPU_PARALLEL_LOOP(collapse=3) + #:endcall GPU_PARALLEL_LOOP + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do k = isy%beg, isy%end do j = isx%beg, isx%end @@ -3601,13 +3591,14 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if if (bc_z%end == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at end - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = 1, sys_size do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3616,9 +3607,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (viscous) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do k = isy%beg, isy%end do j = isx%beg, isx%end @@ -3627,8 +3619,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do k = isy%beg, isy%end do j = isx%beg, isx%end @@ -3637,8 +3630,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do i = momxb, momxe do k = isy%beg, isy%end do j = isx%beg, isx%end @@ -3647,6 +3641,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -3690,7 +3685,7 @@ contains if (viscous .or. (surface_tension)) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = momxb, E_idx do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3700,11 +3695,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (qbmm) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, 4 do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3714,13 +3710,14 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! Reshaping Inputted Data in y-direction elseif (norm_dir == 2) then if (viscous .or. (surface_tension)) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = momxb, E_idx do l = is3%beg, is3%end do j = is1%beg, is1%end @@ -3730,10 +3727,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (qbmm) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, 4 do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3743,13 +3741,14 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! Reshaping Inputted Data in z-direction else if (viscous .or. (surface_tension)) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = momxb, E_idx do j = is1%beg, is1%end do k = is2%beg, is2%end @@ -3759,10 +3758,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (qbmm) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, 4 do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3772,6 +3772,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -3828,10 +3829,7 @@ contains integer :: i_vel !!< Loop iterator for velocity components. integer :: idx_rp(3) !!< Indices $(j,k,l)$ of 'right' point for averaging. - $:GPU_PARALLEL_LOOP(collapse=3, private='[idx_rp, avg_v_int, & - & avg_dvdx_int, avg_dvdy_int, avg_dvdz_int, Re_s, Re_b, & - & vel_src_int, r_eff, divergence_cyl, stress_vector_shear, & - & stress_normal_bulk, div_v_term_const]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[idx_rp, avg_v_int, avg_dvdx_int, avg_dvdy_int, avg_dvdz_int, Re_s, Re_b, vel_src_int, r_eff, divergence_cyl, stress_vector_shear, stress_normal_bulk, div_v_term_const]') do l = iz%beg, iz%end do k = iy%beg, iy%end do j = ix%beg, ix%end @@ -3937,6 +3935,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_cylindrical_viscous_source_flux @@ -3990,9 +3989,7 @@ contains real(wp) :: divergence_v !< Velocity divergence at interface. - $:GPU_PARALLEL_LOOP(collapse=3, private='[idx_right_phys, vel_grad_avg, & - & current_tau_shear, current_tau_bulk, vel_src_at_interface, & - & Re_shear, Re_bulk, divergence_v, i_dim, vel_comp_idx]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[idx_right_phys, vel_grad_avg, current_tau_shear, current_tau_bulk, vel_src_at_interface, Re_shear, Re_bulk, divergence_v, i_dim, vel_comp_idx]') do l_loop = isz%beg, isz%end do k_loop = isy%beg, isy%end do j_loop = isx%beg, isx%end @@ -4073,6 +4070,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_cartesian_viscous_source_flux @@ -4157,7 +4155,7 @@ contains ! Reshaping Outputted Data in y-direction if (norm_dir == 2) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = is3%beg, is3%end do j = is1%beg, is1%end @@ -4168,9 +4166,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (cyl_coord) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = is3%beg, is3%end do j = is1%beg, is1%end @@ -4181,9 +4180,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3%beg, is3%end do j = is1%beg, is1%end do k = is2%beg, is2%end @@ -4192,9 +4192,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1 .or. riemann_solver == 4) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = advxb + 1, advxe do l = is3%beg, is3%end do j = is1%beg, is1%end @@ -4205,11 +4206,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! Reshaping Outputted Data in z-direction elseif (norm_dir == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do j = is1%beg, is1%end do k = is2%beg, is2%end @@ -4221,8 +4223,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (grid_geometry == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do j = is1%beg, is1%end do k = is2%beg, is2%end @@ -4234,9 +4237,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do j = is1%beg, is1%end do k = is2%beg, is2%end do l = is3%beg, is3%end @@ -4245,9 +4249,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1 .or. riemann_solver == 4) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = advxb + 1, advxe do j = is1%beg, is1%end do k = is2%beg, is2%end @@ -4258,10 +4263,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if elseif (norm_dir == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -4272,8 +4278,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -4282,9 +4289,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1 .or. riemann_solver == 4) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = advxb + 1, advxe do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -4295,6 +4303,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if diff --git a/src/simulation/m_surface_tension.fpp b/src/simulation/m_surface_tension.fpp index 8c61a422fb..c817f7cce5 100644 --- a/src/simulation/m_surface_tension.fpp +++ b/src/simulation/m_surface_tension.fpp @@ -85,9 +85,7 @@ contains integer :: j, k, l, i if (id == 1) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[Omega, w1L, w2L, w3L, & - & w1R, w2R, w3R, w1, w2, w3, normWL, & - & normWR, normW]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[Omega, w1L, w2L, w3L, w1R, w2R, w3R, w1, w2, w3, normWL, normWR, normW]') do l = isz%beg, isz%end do k = isy%beg, isy%end do j = isx%beg, isx%end @@ -129,12 +127,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (id == 2) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[Omega, w1L, w2L, w3L, & - & w1R, w2R, w3R, w1, w2, w3, normWL, normWR, & - & normW]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[Omega, w1L, w2L, w3L, w1R, w2R, w3R, w1, w2, w3, normWL, normWR, normW]') do l = isz%beg, isz%end do k = isy%beg, isy%end do j = isx%beg, isx%end @@ -176,12 +173,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (id == 3) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[Omega, w1L, w2L, w3L, & - & w1R, w2R, w3R, w1, w2, w3, normWL, normWR, & - & normW]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[Omega, w1L, w2L, w3L, w1R, w2R, w3R, w1, w2, w3, normWL, normWR, normW]') do l = isz%beg, isz%end do k = isy%beg, isy%end do j = isx%beg, isx%end @@ -223,6 +219,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if @@ -243,7 +240,7 @@ contains isx%end = m; isy%end = n; isz%end = p ! compute gradient components - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -252,8 +249,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -262,9 +260,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (p > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -273,9 +272,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m @@ -291,6 +291,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP call s_populate_capillary_buffers(c_divs, bc_type) @@ -338,7 +339,7 @@ contains $:GPU_UPDATE(device='[is1,is2,is3,iv]') if (recon_dir == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -349,8 +350,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else if (recon_dir == 2) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -361,8 +363,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else if (recon_dir == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -373,6 +376,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_reconstruct_cell_boundary_values_capillary diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index d040650bfa..84aa0b4107 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -390,7 +390,7 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -402,10 +402,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP + !Evolve pb and mv for non-polytropic qbmm if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -419,10 +421,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -436,6 +439,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, dt) @@ -496,7 +500,7 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -508,10 +512,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP !Evolve pb and mv for non-polytropic qbmm if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -526,9 +531,10 @@ contains end do end do end if + #:endcall GPU_PARALLEL_LOOP if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -542,6 +548,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) @@ -568,7 +575,7 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -581,9 +588,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -598,10 +606,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -616,6 +625,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) @@ -682,7 +692,7 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -694,10 +704,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP !Evolve pb and mv for non-polytropic qbmm if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -711,10 +722,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -728,6 +740,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) @@ -754,7 +767,7 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -767,9 +780,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -784,10 +798,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -802,6 +817,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt/4._wp) @@ -827,7 +843,7 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=3) - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -840,9 +856,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -857,10 +874,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (qbmm .and. (.not. polytropic)) then - $:GPU_PARALLEL_LOOP(collapse=5) + #:call GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb do l = 0, p do k = 0, n @@ -875,6 +893,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) @@ -1002,7 +1021,7 @@ contains idwint) end if - $:GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') do l = 0, p do k = 0, n do j = 0, m @@ -1019,6 +1038,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL(copyout='[dt_local]', copyin='[max_dt]') dt_local = minval(max_dt) @@ -1049,7 +1069,7 @@ contains call nvtxStartRange("RHS-BODYFORCES") call s_compute_body_forces_rhs(q_prim_vf_in, q_cons_vf, rhs_vf_in) - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = momxb, E_idx do l = 0, p do k = 0, n @@ -1060,6 +1080,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP call nvtxEndRange diff --git a/src/simulation/m_viscous.fpp b/src/simulation/m_viscous.fpp index 2aeec0a532..d22fa9c5dd 100644 --- a/src/simulation/m_viscous.fpp +++ b/src/simulation/m_viscous.fpp @@ -77,7 +77,7 @@ contains $:GPU_UPDATE(device='[is1_viscous,is2_viscous,is3_viscous]') - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg, is2_viscous%end do j = is1_viscous%beg, is1_viscous%end @@ -88,9 +88,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP + if (shear_stress) then ! Shear stresses - $:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, & - & alpha_rho_visc, Re_visc, tau_Re]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, alpha_rho_visc, Re_visc, tau_Re]') do l = is3_viscous%beg, is3_viscous%end do k = -1, 1 do j = is1_viscous%beg, is1_viscous%end @@ -194,11 +195,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bulk_stress) then ! Bulk stresses - $:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, & - & alpha_rho_visc, Re_visc, tau_Re]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, alpha_rho_visc, Re_visc, tau_Re]') do l = is3_viscous%beg, is3_viscous%end do k = -1, 1 do j = is1_viscous%beg, is1_viscous%end @@ -297,13 +298,13 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (p == 0) return if (shear_stress) then ! Shear stresses - $:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, & - & alpha_rho_visc, Re_visc, tau_Re]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, alpha_rho_visc, Re_visc, tau_Re]') do l = is3_viscous%beg, is3_viscous%end do k = -1, 1 do j = is1_viscous%beg, is1_viscous%end @@ -408,11 +409,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bulk_stress) then ! Bulk stresses - $:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, & - & alpha_rho_visc, Re_visc, tau_Re]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, alpha_rho_visc, Re_visc, tau_Re]') do l = is3_viscous%beg, is3_viscous%end do k = -1, 1 do j = is1_viscous%beg, is1_viscous%end @@ -509,6 +510,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_compute_viscous_stress_tensor @@ -593,7 +595,7 @@ contains $:GPU_UPDATE(device='[is1_viscous,is2_viscous,is3_viscous]') - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do k = iy%beg, iy%end do j = is1_viscous%beg + 1, is1_viscous%end @@ -607,8 +609,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg, is2_viscous%end do j = is1_viscous%beg, is1_viscous%end - 1 @@ -622,10 +625,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (n > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do j = is2_viscous%beg + 1, is2_viscous%end do k = is1_viscous%beg, is1_viscous%end @@ -639,8 +643,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do j = is2_viscous%beg, is2_viscous%end - 1 do k = is1_viscous%beg, is1_viscous%end @@ -654,8 +659,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do j = is2_viscous%beg + 1, is2_viscous%end do k = is1_viscous%beg + 1, is1_viscous%end - 1 @@ -673,8 +679,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do j = is2_viscous%beg, is2_viscous%end - 1 do k = is1_viscous%beg + 1, is1_viscous%end - 1 @@ -693,8 +700,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg + 1, is2_viscous%end - 1 do j = is1_viscous%beg + 1, is1_viscous%end @@ -713,8 +721,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg + 1, is2_viscous%end - 1 do j = is1_viscous%beg, is1_viscous%end - 1 @@ -733,10 +742,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (p > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do j = is3_viscous%beg + 1, is3_viscous%end do l = is2_viscous%beg, is2_viscous%end do k = is1_viscous%beg, is1_viscous%end @@ -751,8 +761,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do j = is3_viscous%beg, is3_viscous%end - 1 do l = is2_viscous%beg, is2_viscous%end do k = is1_viscous%beg, is1_viscous%end @@ -767,8 +778,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg + 1, is3_viscous%end - 1 do k = is2_viscous%beg, is2_viscous%end do j = is1_viscous%beg + 1, is1_viscous%end @@ -788,8 +800,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg + 1, is3_viscous%end - 1 do k = is2_viscous%beg, is2_viscous%end do j = is1_viscous%beg, is1_viscous%end - 1 @@ -809,8 +822,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg + 1, is3_viscous%end - 1 do j = is2_viscous%beg + 1, is2_viscous%end do k = is1_viscous%beg, is1_viscous%end @@ -830,8 +844,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg + 1, is3_viscous%end - 1 do j = is2_viscous%beg, is2_viscous%end - 1 do k = is1_viscous%beg, is1_viscous%end @@ -851,8 +866,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do j = is3_viscous%beg + 1, is3_viscous%end do l = is2_viscous%beg + 1, is2_viscous%end - 1 do k = is1_viscous%beg, is1_viscous%end @@ -872,8 +888,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do j = is3_viscous%beg, is3_viscous%end - 1 do l = is2_viscous%beg + 1, is2_viscous%end - 1 do k = is1_viscous%beg, is1_viscous%end @@ -893,7 +910,8 @@ contains end do end do end do - $:GPU_PARALLEL_LOOP(collapse=3) + #:endcall GPU_PARALLEL_LOOP + #:call GPU_PARALLEL_LOOP(collapse=3) do j = is3_viscous%beg + 1, is3_viscous%end do l = is2_viscous%beg, is2_viscous%end do k = is1_viscous%beg + 1, is1_viscous%end - 1 @@ -913,7 +931,8 @@ contains end do end do end do - $:GPU_PARALLEL_LOOP(collapse=3) + #:endcall GPU_PARALLEL_LOOP + #:call GPU_PARALLEL_LOOP(collapse=3) do j = is3_viscous%beg, is3_viscous%end - 1 do l = is2_viscous%beg, is2_viscous%end do k = is1_viscous%beg + 1, is1_viscous%end - 1 @@ -932,6 +951,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP do i = iv%beg, iv%end call s_compute_fd_gradient(q_prim_qp%vf(i), & @@ -1023,7 +1043,7 @@ contains if (viscous) then if (weno_Re_flux) then if (norm_dir == 2) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do l = is3_viscous%beg, is3_viscous%end do j = is1_viscous%beg, is1_viscous%end @@ -1034,8 +1054,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (norm_dir == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do j = is1_viscous%beg, is1_viscous%end do k = is2_viscous%beg, is2_viscous%end @@ -1046,8 +1067,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (norm_dir == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg, is2_viscous%end @@ -1058,6 +1080,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if end if @@ -1122,7 +1145,7 @@ contains if (viscous) then if (weno_Re_flux) then if (norm_dir == 2) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do l = is3_viscous%beg, is3_viscous%end do j = is1_viscous%beg, is1_viscous%end @@ -1133,8 +1156,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (norm_dir == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do j = is1_viscous%beg, is1_viscous%end do k = is2_viscous%beg, is2_viscous%end @@ -1145,8 +1169,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (norm_dir == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = iv%beg, iv%end do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg, is2_viscous%end @@ -1157,6 +1182,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end if end if @@ -1210,7 +1236,7 @@ contains ! cell-boundaries, to calculate the cell-averaged first-order ! spatial derivatives inside the cell. - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg, is2_viscous%end do j = is1_viscous%beg + 1, is1_viscous%end - 1 @@ -1226,6 +1252,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP ! END: First-Order Spatial Derivatives in x-direction @@ -1238,7 +1265,7 @@ contains ! cell-boundaries, to calculate the cell-averaged first-order ! spatial derivatives inside the cell. - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg + 1, is2_viscous%end - 1 do j = is1_viscous%beg, is1_viscous%end @@ -1254,6 +1281,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP ! END: First-Order Spatial Derivatives in y-direction @@ -1266,7 +1294,7 @@ contains ! cell-boundaries, to calculate the cell-averaged first-order ! spatial derivatives inside the cell. - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg + 1, is3_viscous%end - 1 do k = is2_viscous%beg, is2_viscous%end do j = is1_viscous%beg, is1_viscous%end @@ -1282,6 +1310,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! END: First-Order Spatial Derivatives in z-direction @@ -1321,7 +1350,7 @@ contains $:GPU_UPDATE(device='[is1_viscous,is2_viscous,is3_viscous]') - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg, is2_viscous%end do j = is1_viscous%beg, is1_viscous%end @@ -1331,9 +1360,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (n > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg, is2_viscous%end do j = is1_viscous%beg, is1_viscous%end @@ -1343,10 +1373,11 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if if (p > 0) then - $:GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = is3_viscous%beg, is3_viscous%end do k = is2_viscous%beg, is2_viscous%end do j = is1_viscous%beg, is1_viscous%end @@ -1356,9 +1387,10 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = idwbuff(3)%beg, idwbuff(3)%end do k = idwbuff(2)%beg, idwbuff(2)%end grad_x%sf(idwbuff(1)%beg, k, l) = & @@ -1369,8 +1401,9 @@ contains (x_cc(idwbuff(1)%end) - x_cc(idwbuff(1)%end - 2)) end do end do + #:endcall GPU_PARALLEL_LOOP if (n > 0) then - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = idwbuff(3)%beg, idwbuff(3)%end do j = idwbuff(1)%beg, idwbuff(1)%end grad_y%sf(j, idwbuff(2)%beg, l) = & @@ -1381,8 +1414,9 @@ contains (y_cc(idwbuff(2)%end) - y_cc(idwbuff(2)%end - 2)) end do end do + #:endcall GPU_PARALLEL_LOOP if (p > 0) then - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do k = idwbuff(2)%beg, idwbuff(2)%end do j = idwbuff(1)%beg, idwbuff(1)%end grad_z%sf(j, k, idwbuff(3)%beg) = & @@ -1393,49 +1427,54 @@ contains (z_cc(idwbuff(3)%end) - z_cc(idwbuff(3)%end - 2)) end do end do + #:endcall GPU_PARALLEL_LOOP end if end if if (bc_x%beg <= BC_GHOST_EXTRAP) then - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = idwbuff(3)%beg, idwbuff(3)%end do k = idwbuff(2)%beg, idwbuff(2)%end grad_x%sf(0, k, l) = (-3._wp*var%sf(0, k, l) + 4._wp*var%sf(1, k, l) - var%sf(2, k, l))/ & (x_cc(2) - x_cc(0)) end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bc_x%end <= BC_GHOST_EXTRAP) then - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = idwbuff(3)%beg, idwbuff(3)%end do k = idwbuff(2)%beg, idwbuff(2)%end grad_x%sf(m, k, l) = (3._wp*var%sf(m, k, l) - 4._wp*var%sf(m - 1, k, l) + var%sf(m - 2, k, l))/ & (x_cc(m) - x_cc(m - 2)) end do end do + #:endcall GPU_PARALLEL_LOOP end if if (n > 0) then if (bc_y%beg <= BC_GHOST_EXTRAP .and. bc_y%beg /= BC_NULL) then - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = idwbuff(3)%beg, idwbuff(3)%end do j = idwbuff(1)%beg, idwbuff(1)%end grad_y%sf(j, 0, l) = (-3._wp*var%sf(j, 0, l) + 4._wp*var%sf(j, 1, l) - var%sf(j, 2, l))/ & (y_cc(2) - y_cc(0)) end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bc_y%end <= BC_GHOST_EXTRAP) then - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do l = idwbuff(3)%beg, idwbuff(3)%end do j = idwbuff(1)%beg, idwbuff(1)%end grad_y%sf(j, n, l) = (3._wp*var%sf(j, n, l) - 4._wp*var%sf(j, n - 1, l) + var%sf(j, n - 2, l))/ & (y_cc(n) - y_cc(n - 2)) end do end do + #:endcall GPU_PARALLEL_LOOP end if if (p > 0) then if (bc_z%beg <= BC_GHOST_EXTRAP) then - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do k = idwbuff(2)%beg, idwbuff(2)%end do j = idwbuff(1)%beg, idwbuff(1)%end grad_z%sf(j, k, 0) = & @@ -1443,9 +1482,10 @@ contains (z_cc(2) - z_cc(0)) end do end do + #:endcall GPU_PARALLEL_LOOP end if if (bc_z%end <= BC_GHOST_EXTRAP) then - $:GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2) do k = idwbuff(2)%beg, idwbuff(2)%end do j = idwbuff(1)%beg, idwbuff(1)%end grad_z%sf(j, k, p) = & @@ -1453,6 +1493,7 @@ contains (z_cc(p) - z_cc(p - 2)) end do end do + #:endcall GPU_PARALLEL_LOOP end if end if end if diff --git a/src/simulation/m_weno.fpp b/src/simulation/m_weno.fpp index 5c525c4664..9dd9dcfbf7 100644 --- a/src/simulation/m_weno.fpp +++ b/src/simulation/m_weno.fpp @@ -668,7 +668,7 @@ contains if (weno_order == 1) then if (weno_dir == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, ubound(v_vf, 1) do l = is3_weno%beg, is3_weno%end do k = is2_weno%beg, is2_weno%end @@ -679,8 +679,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else if (weno_dir == 2) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, ubound(v_vf, 1) do l = is3_weno%beg, is3_weno%end do k = is2_weno%beg, is2_weno%end @@ -691,8 +692,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else if (weno_dir == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, ubound(v_vf, 1) do l = is3_weno%beg, is3_weno%end do k = is2_weno%beg, is2_weno%end @@ -703,11 +705,12 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if elseif (weno_order == 3) then #:for WENO_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (weno_dir == ${WENO_DIR}$) then - $:GPU_PARALLEL_LOOP(collapse=4,private='[beta,dvd,poly,omega,alpha,tau]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[beta,dvd,poly,omega,alpha,tau]') do l = is3_weno%beg, is3_weno%end do k = is2_weno%beg, is2_weno%end do j = is1_weno%beg, is1_weno%end @@ -780,12 +783,13 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if #:endfor elseif (weno_order == 5) then #:for WENO_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (weno_dir == ${WENO_DIR}$) then - $:GPU_PARALLEL_LOOP(collapse=3,private='[dvd,poly,beta,alpha,omega,tau,delta]') + #:call GPU_PARALLEL_LOOP(collapse=3,private='[dvd,poly,beta,alpha,omega,tau,delta]') do l = is3_weno%beg, is3_weno%end do k = is2_weno%beg, is2_weno%end do j = is1_weno%beg, is1_weno%end @@ -894,6 +898,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP if (mp_weno) then call s_preserve_monotonicity(v_rs_ws_${XYZ}$, vL_rs_vf_${XYZ}$, & @@ -904,7 +909,7 @@ contains elseif (weno_order == 7) then #:for WENO_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (weno_dir == ${WENO_DIR}$) then - $:GPU_PARALLEL_LOOP(collapse=3,private='[poly,beta,alpha,omega,tau,delta,dvd,v]') + #:call GPU_PARALLEL_LOOP(collapse=3,private='[poly,beta,alpha,omega,tau,delta,dvd,v]') do l = is3_weno%beg, is3_weno%end do k = is2_weno%beg, is2_weno%end do j = is1_weno%beg, is1_weno%end @@ -1089,6 +1094,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if #:endfor @@ -1126,7 +1132,7 @@ contains $:GPU_UPDATE(device='[v_size]') if (weno_dir == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do j = 1, v_size do q = is3_weno%beg, is3_weno%end do l = is2_weno%beg, is2_weno%end @@ -1136,13 +1142,14 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! Reshaping/Projecting onto Characteristic Fields in y-direction if (n == 0) return if (weno_dir == 2) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do j = 1, v_size do q = is3_weno%beg, is3_weno%end do l = is2_weno%beg, is2_weno%end @@ -1152,13 +1159,14 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if ! Reshaping/Projecting onto Characteristic Fields in z-direction if (p == 0) return if (weno_dir == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do j = 1, v_size do q = is3_weno%beg, is3_weno%end do l = is2_weno%beg, is2_weno%end @@ -1168,6 +1176,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_initialize_weno @@ -1217,7 +1226,7 @@ contains real(wp), parameter :: alpha_mp = 2._wp real(wp), parameter :: beta_mp = 4._wp/3._wp - $:GPU_PARALLEL_LOOP(collapse=4,private='[d]') + #:call GPU_PARALLEL_LOOP(collapse=4,private='[d]') do l = is3_weno%beg, is3_weno%end do k = is2_weno%beg, is2_weno%end do j = is1_weno%beg, is1_weno%end @@ -1342,6 +1351,7 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_preserve_monotonicity From 29e9404cae87bfcab60445df9dc6a28832f502d0 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Mon, 21 Jul 2025 17:16:46 -0400 Subject: [PATCH 009/199] Ran formatter --- src/common/include/parallel_macros.fpp | 9 +- src/common/m_boundary_common.fpp | 402 +- src/common/m_chemistry.fpp | 32 +- src/common/m_finite_differences.fpp | 60 +- src/common/m_mpi_common.fpp | 364 +- src/common/m_phase_change.fpp | 237 +- src/common/m_variables_conversion.fpp | 640 +-- src/simulation/m_acoustic_src.fpp | 194 +- src/simulation/m_body_forces.fpp | 76 +- src/simulation/m_bubbles.fpp | 20 +- src/simulation/m_bubbles_EE.fpp | 314 +- src/simulation/m_bubbles_EL.fpp | 482 +- src/simulation/m_bubbles_EL_kernels.fpp | 194 +- src/simulation/m_cbc.fpp | 1044 ++--- src/simulation/m_data_output.fpp | 22 +- src/simulation/m_derived_variables.fpp | 2 +- src/simulation/m_fftw.fpp | 122 +- src/simulation/m_hyperelastic.fpp | 182 +- src/simulation/m_hypoelastic.fpp | 476 +- src/simulation/m_ibm.fpp | 260 +- src/simulation/m_mhd.fpp | 92 +- src/simulation/m_mpi_proxy.fpp | 82 +- src/simulation/m_pressure_relaxation.fpp | 10 +- src/simulation/m_qbmm.fpp | 428 +- src/simulation/m_rhs.fpp | 880 ++-- src/simulation/m_riemann_solvers.fpp | 5134 +++++++++++----------- src/simulation/m_surface_tension.fpp | 240 +- src/simulation/m_time_steppers.fpp | 932 ++-- src/simulation/m_viscous.fpp | 1390 +++--- src/simulation/m_weno.fpp | 924 ++-- 30 files changed, 7620 insertions(+), 7624 deletions(-) diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index ee0577613a..a2199f9cfd 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -1,4 +1,3 @@ -#:mute #:include 'shared_parallel_macros.fpp' #:include 'omp_macros.fpp' #:include 'acc_macros.fpp' @@ -109,8 +108,6 @@ $:link_val #:enddef - - #:def GEN_PARALLELISM_STR(parallelism) #:if parallelism is not None #:assert isinstance(parallelism, str) @@ -167,7 +164,7 @@ #:def GPU_PARALLEL(code, private=None, default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None, extraOmpArgs=None) - + #:set acc_code = ACC_PARALLEL(code, private, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraAccArgs) #:set omp_code = OMP_PARALLEL(code, private, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraOmpArgs) @@ -185,7 +182,7 @@ & default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None, extraOmpArgs=None) - + #:set acc_code = ACC_PARALLEL_LOOP(code, collapse, private, parallelism, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraAccArgs) #:set omp_code = OMP_PARALLEL_LOOP(code, collapse, private, parallelism, default, firstprivate, reduction, reductionOp, copy, copyin, copyinReadOnly, copyout, create, no_create, present, deviceptr, attach, extraOmpArgs) @@ -346,6 +343,4 @@ #endif #:enddef - -#:endmute ! New line at end of file is required for FYPP diff --git a/src/common/m_boundary_common.fpp b/src/common/m_boundary_common.fpp index fb61b78d96..bb92ec70c1 100644 --- a/src/common/m_boundary_common.fpp +++ b/src/common/m_boundary_common.fpp @@ -92,29 +92,29 @@ contains call s_mpi_sendrecv_variables_buffers(q_prim_vf, 1, -1, sys_size, pb_in, mv_in) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = 0, n - select case (int(bc_type(1, -1)%sf(0, k, l))) - case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) - call s_ghost_cell_extrapolation(q_prim_vf, 1, -1, k, l) - case (BC_REFLECTIVE) - call s_symmetry(q_prim_vf, 1, -1, k, l, pb_in, mv_in) - case (BC_PERIODIC) - call s_periodic(q_prim_vf, 1, -1, k, l, pb_in, mv_in) - case (BC_SLIP_WALL) - call s_slip_wall(q_prim_vf, 1, -1, k, l) - case (BC_NO_SLIP_WALL) - call s_no_slip_wall(q_prim_vf, 1, -1, k, l) - case (BC_DIRICHLET) - call s_dirichlet(q_prim_vf, 1, -1, k, l) - end select - - if (qbmm .and. (.not. polytropic) .and. & - (bc_type(1, -1)%sf(0, k, l) <= BC_GHOST_EXTRAP)) then - call s_qbmm_extrapolation(1, -1, k, l, pb_in, mv_in) - end if + do l = 0, p + do k = 0, n + select case (int(bc_type(1, -1)%sf(0, k, l))) + case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) + call s_ghost_cell_extrapolation(q_prim_vf, 1, -1, k, l) + case (BC_REFLECTIVE) + call s_symmetry(q_prim_vf, 1, -1, k, l, pb_in, mv_in) + case (BC_PERIODIC) + call s_periodic(q_prim_vf, 1, -1, k, l, pb_in, mv_in) + case (BC_SLIP_WALL) + call s_slip_wall(q_prim_vf, 1, -1, k, l) + case (BC_NO_SLIP_WALL) + call s_no_slip_wall(q_prim_vf, 1, -1, k, l) + case (BC_DIRICHLET) + call s_dirichlet(q_prim_vf, 1, -1, k, l) + end select + + if (qbmm .and. (.not. polytropic) .and. & + (bc_type(1, -1)%sf(0, k, l) <= BC_GHOST_EXTRAP)) then + call s_qbmm_extrapolation(1, -1, k, l, pb_in, mv_in) + end if + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -122,29 +122,29 @@ contains call s_mpi_sendrecv_variables_buffers(q_prim_vf, 1, 1, sys_size, pb_in, mv_in) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = 0, n - select case (int(bc_type(1, 1)%sf(0, k, l))) - case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) ! Ghost-cell extrap. BC at end - call s_ghost_cell_extrapolation(q_prim_vf, 1, 1, k, l) - case (BC_REFLECTIVE) - call s_symmetry(q_prim_vf, 1, 1, k, l, pb_in, mv_in) - case (BC_PERIODIC) - call s_periodic(q_prim_vf, 1, 1, k, l, pb_in, mv_in) - case (BC_SLIP_WALL) - call s_slip_wall(q_prim_vf, 1, 1, k, l) - case (BC_NO_SLIP_WALL) - call s_no_slip_wall(q_prim_vf, 1, 1, k, l) - case (BC_DIRICHLET) - call s_dirichlet(q_prim_vf, 1, 1, k, l) - end select - - if (qbmm .and. (.not. polytropic) .and. & - (bc_type(1, 1)%sf(0, k, l) <= BC_GHOST_EXTRAP)) then - call s_qbmm_extrapolation(1, 1, k, l, pb_in, mv_in) - end if + do l = 0, p + do k = 0, n + select case (int(bc_type(1, 1)%sf(0, k, l))) + case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) ! Ghost-cell extrap. BC at end + call s_ghost_cell_extrapolation(q_prim_vf, 1, 1, k, l) + case (BC_REFLECTIVE) + call s_symmetry(q_prim_vf, 1, 1, k, l, pb_in, mv_in) + case (BC_PERIODIC) + call s_periodic(q_prim_vf, 1, 1, k, l, pb_in, mv_in) + case (BC_SLIP_WALL) + call s_slip_wall(q_prim_vf, 1, 1, k, l) + case (BC_NO_SLIP_WALL) + call s_no_slip_wall(q_prim_vf, 1, 1, k, l) + case (BC_DIRICHLET) + call s_dirichlet(q_prim_vf, 1, 1, k, l) + end select + + if (qbmm .and. (.not. polytropic) .and. & + (bc_type(1, 1)%sf(0, k, l) <= BC_GHOST_EXTRAP)) then + call s_qbmm_extrapolation(1, 1, k, l, pb_in, mv_in) + end if + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -156,32 +156,32 @@ contains call s_mpi_sendrecv_variables_buffers(q_prim_vf, 2, -1, sys_size, pb_in, mv_in) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = -buff_size, m + buff_size - select case (int(bc_type(2, -1)%sf(k, 0, l))) - case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) - call s_ghost_cell_extrapolation(q_prim_vf, 2, -1, k, l) - case (BC_AXIS) - call s_axis(q_prim_vf, pb_in, mv_in, k, l) - case (BC_REFLECTIVE) - call s_symmetry(q_prim_vf, 2, -1, k, l, pb_in, mv_in) - case (BC_PERIODIC) - call s_periodic(q_prim_vf, 2, -1, k, l, pb_in, mv_in) - case (BC_SLIP_WALL) - call s_slip_wall(q_prim_vf, 2, -1, k, l) - case (BC_NO_SLIP_WALL) - call s_no_slip_wall(q_prim_vf, 2, -1, k, l) - case (BC_DIRICHLET) - call s_dirichlet(q_prim_vf, 2, -1, k, l) - end select - - if (qbmm .and. (.not. polytropic) .and. & - (bc_type(2, -1)%sf(k, 0, l) <= BC_GHOST_EXTRAP) .and. & - (bc_type(2, -1)%sf(k, 0, l) /= BC_AXIS)) then - call s_qbmm_extrapolation(2, -1, k, l, pb_in, mv_in) - end if + do l = 0, p + do k = -buff_size, m + buff_size + select case (int(bc_type(2, -1)%sf(k, 0, l))) + case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) + call s_ghost_cell_extrapolation(q_prim_vf, 2, -1, k, l) + case (BC_AXIS) + call s_axis(q_prim_vf, pb_in, mv_in, k, l) + case (BC_REFLECTIVE) + call s_symmetry(q_prim_vf, 2, -1, k, l, pb_in, mv_in) + case (BC_PERIODIC) + call s_periodic(q_prim_vf, 2, -1, k, l, pb_in, mv_in) + case (BC_SLIP_WALL) + call s_slip_wall(q_prim_vf, 2, -1, k, l) + case (BC_NO_SLIP_WALL) + call s_no_slip_wall(q_prim_vf, 2, -1, k, l) + case (BC_DIRICHLET) + call s_dirichlet(q_prim_vf, 2, -1, k, l) + end select + + if (qbmm .and. (.not. polytropic) .and. & + (bc_type(2, -1)%sf(k, 0, l) <= BC_GHOST_EXTRAP) .and. & + (bc_type(2, -1)%sf(k, 0, l) /= BC_AXIS)) then + call s_qbmm_extrapolation(2, -1, k, l, pb_in, mv_in) + end if + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -189,29 +189,29 @@ contains call s_mpi_sendrecv_variables_buffers(q_prim_vf, 2, 1, sys_size, pb_in, mv_in) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = -buff_size, m + buff_size - select case (int(bc_type(2, 1)%sf(k, 0, l))) - case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) - call s_ghost_cell_extrapolation(q_prim_vf, 2, 1, k, l) - case (BC_REFLECTIVE) - call s_symmetry(q_prim_vf, 2, 1, k, l, pb_in, mv_in) - case (BC_PERIODIC) - call s_periodic(q_prim_vf, 2, 1, k, l, pb_in, mv_in) - case (BC_SLIP_WALL) - call s_slip_wall(q_prim_vf, 2, 1, k, l) - case (BC_NO_SLIP_WALL) - call s_no_slip_wall(q_prim_vf, 2, 1, k, l) - case (BC_DIRICHLET) - call s_dirichlet(q_prim_vf, 2, 1, k, l) - end select - - if (qbmm .and. (.not. polytropic) .and. & - (bc_type(2, 1)%sf(k, 0, l) <= BC_GHOST_EXTRAP)) then - call s_qbmm_extrapolation(2, 1, k, l, pb_in, mv_in) - end if + do l = 0, p + do k = -buff_size, m + buff_size + select case (int(bc_type(2, 1)%sf(k, 0, l))) + case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) + call s_ghost_cell_extrapolation(q_prim_vf, 2, 1, k, l) + case (BC_REFLECTIVE) + call s_symmetry(q_prim_vf, 2, 1, k, l, pb_in, mv_in) + case (BC_PERIODIC) + call s_periodic(q_prim_vf, 2, 1, k, l, pb_in, mv_in) + case (BC_SLIP_WALL) + call s_slip_wall(q_prim_vf, 2, 1, k, l) + case (BC_NO_SLIP_WALL) + call s_no_slip_wall(q_prim_vf, 2, 1, k, l) + case (BC_DIRICHLET) + call s_dirichlet(q_prim_vf, 2, 1, k, l) + end select + + if (qbmm .and. (.not. polytropic) .and. & + (bc_type(2, 1)%sf(k, 0, l) <= BC_GHOST_EXTRAP)) then + call s_qbmm_extrapolation(2, 1, k, l, pb_in, mv_in) + end if + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -223,29 +223,29 @@ contains call s_mpi_sendrecv_variables_buffers(q_prim_vf, 3, -1, sys_size, pb_in, mv_in) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = -buff_size, n + buff_size - do k = -buff_size, m + buff_size - select case (int(bc_type(3, -1)%sf(k, l, 0))) - case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) - call s_ghost_cell_extrapolation(q_prim_vf, 3, -1, k, l) - case (BC_REFLECTIVE) - call s_symmetry(q_prim_vf, 3, -1, k, l, pb_in, mv_in) - case (BC_PERIODIC) - call s_periodic(q_prim_vf, 3, -1, k, l, pb_in, mv_in) - case (BC_SLIP_WALL) - call s_slip_wall(q_prim_vf, 3, -1, k, l) - case (BC_NO_SLIP_WALL) - call s_no_slip_wall(q_prim_vf, 3, -1, k, l) - case (BC_DIRICHLET) - call s_dirichlet(q_prim_vf, 3, -1, k, l) - end select - - if (qbmm .and. (.not. polytropic) .and. & - (bc_type(3, -1)%sf(k, l, 0) <= BC_GHOST_EXTRAP)) then - call s_qbmm_extrapolation(3, -1, k, l, pb_in, mv_in) - end if + do l = -buff_size, n + buff_size + do k = -buff_size, m + buff_size + select case (int(bc_type(3, -1)%sf(k, l, 0))) + case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) + call s_ghost_cell_extrapolation(q_prim_vf, 3, -1, k, l) + case (BC_REFLECTIVE) + call s_symmetry(q_prim_vf, 3, -1, k, l, pb_in, mv_in) + case (BC_PERIODIC) + call s_periodic(q_prim_vf, 3, -1, k, l, pb_in, mv_in) + case (BC_SLIP_WALL) + call s_slip_wall(q_prim_vf, 3, -1, k, l) + case (BC_NO_SLIP_WALL) + call s_no_slip_wall(q_prim_vf, 3, -1, k, l) + case (BC_DIRICHLET) + call s_dirichlet(q_prim_vf, 3, -1, k, l) + end select + + if (qbmm .and. (.not. polytropic) .and. & + (bc_type(3, -1)%sf(k, l, 0) <= BC_GHOST_EXTRAP)) then + call s_qbmm_extrapolation(3, -1, k, l, pb_in, mv_in) + end if + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -253,29 +253,29 @@ contains call s_mpi_sendrecv_variables_buffers(q_prim_vf, 3, 1, sys_size, pb_in, mv_in) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = -buff_size, n + buff_size - do k = -buff_size, m + buff_size - select case (int(bc_type(3, 1)%sf(k, l, 0))) - case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) - call s_ghost_cell_extrapolation(q_prim_vf, 3, 1, k, l) - case (BC_REFLECTIVE) - call s_symmetry(q_prim_vf, 3, 1, k, l, pb_in, mv_in) - case (BC_PERIODIC) - call s_periodic(q_prim_vf, 3, 1, k, l, pb_in, mv_in) - case (BC_SlIP_WALL) - call s_slip_wall(q_prim_vf, 3, 1, k, l) - case (BC_NO_SLIP_WALL) - call s_no_slip_wall(q_prim_vf, 3, 1, k, l) - case (BC_DIRICHLET) - call s_dirichlet(q_prim_vf, 3, 1, k, l) - end select - - if (qbmm .and. (.not. polytropic) .and. & - (bc_type(3, 1)%sf(k, l, 0) <= BC_GHOST_EXTRAP)) then - call s_qbmm_extrapolation(3, 1, k, l, pb_in, mv_in) - end if + do l = -buff_size, n + buff_size + do k = -buff_size, m + buff_size + select case (int(bc_type(3, 1)%sf(k, l, 0))) + case (BC_CHAR_SUP_OUTFLOW:BC_GHOST_EXTRAP) + call s_ghost_cell_extrapolation(q_prim_vf, 3, 1, k, l) + case (BC_REFLECTIVE) + call s_symmetry(q_prim_vf, 3, 1, k, l, pb_in, mv_in) + case (BC_PERIODIC) + call s_periodic(q_prim_vf, 3, 1, k, l, pb_in, mv_in) + case (BC_SlIP_WALL) + call s_slip_wall(q_prim_vf, 3, 1, k, l) + case (BC_NO_SLIP_WALL) + call s_no_slip_wall(q_prim_vf, 3, 1, k, l) + case (BC_DIRICHLET) + call s_dirichlet(q_prim_vf, 3, 1, k, l) + end select + + if (qbmm .and. (.not. polytropic) .and. & + (bc_type(3, 1)%sf(k, l, 0) <= BC_GHOST_EXTRAP)) then + call s_qbmm_extrapolation(3, 1, k, l, pb_in, mv_in) + end if + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if ! END: Population of Buffers in z-direction @@ -1169,18 +1169,18 @@ contains call s_mpi_sendrecv_variables_buffers(c_divs, 1, -1, num_dims + 1) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = 0, n - select case (bc_type(1, -1)%sf(0, k, l)) - case (BC_PERIODIC) - call s_color_function_periodic(c_divs, 1, -1, k, l) - case (BC_REFLECTIVE) - call s_color_function_reflective(c_divs, 1, -1, k, l) - case default - call s_color_function_ghost_cell_extrapolation(c_divs, 1, -1, k, l) - end select + do l = 0, p + do k = 0, n + select case (bc_type(1, -1)%sf(0, k, l)) + case (BC_PERIODIC) + call s_color_function_periodic(c_divs, 1, -1, k, l) + case (BC_REFLECTIVE) + call s_color_function_reflective(c_divs, 1, -1, k, l) + case default + call s_color_function_ghost_cell_extrapolation(c_divs, 1, -1, k, l) + end select + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1188,18 +1188,18 @@ contains call s_mpi_sendrecv_variables_buffers(c_divs, 1, 1, num_dims + 1) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = 0, n - select case (bc_type(1, 1)%sf(0, k, l)) - case (BC_PERIODIC) - call s_color_function_periodic(c_divs, 1, 1, k, l) - case (BC_REFLECTIVE) - call s_color_function_reflective(c_divs, 1, 1, k, l) - case default - call s_color_function_ghost_cell_extrapolation(c_divs, 1, 1, k, l) - end select + do l = 0, p + do k = 0, n + select case (bc_type(1, 1)%sf(0, k, l)) + case (BC_PERIODIC) + call s_color_function_periodic(c_divs, 1, 1, k, l) + case (BC_REFLECTIVE) + call s_color_function_reflective(c_divs, 1, 1, k, l) + case default + call s_color_function_ghost_cell_extrapolation(c_divs, 1, 1, k, l) + end select + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1210,18 +1210,18 @@ contains call s_mpi_sendrecv_variables_buffers(c_divs, 2, -1, num_dims + 1) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = -buff_size, m + buff_size - select case (bc_type(2, -1)%sf(k, 0, l)) - case (BC_PERIODIC) - call s_color_function_periodic(c_divs, 2, -1, k, l) - case (BC_REFLECTIVE) - call s_color_function_reflective(c_divs, 2, -1, k, l) - case default - call s_color_function_ghost_cell_extrapolation(c_divs, 2, -1, k, l) - end select + do l = 0, p + do k = -buff_size, m + buff_size + select case (bc_type(2, -1)%sf(k, 0, l)) + case (BC_PERIODIC) + call s_color_function_periodic(c_divs, 2, -1, k, l) + case (BC_REFLECTIVE) + call s_color_function_reflective(c_divs, 2, -1, k, l) + case default + call s_color_function_ghost_cell_extrapolation(c_divs, 2, -1, k, l) + end select + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1229,18 +1229,18 @@ contains call s_mpi_sendrecv_variables_buffers(c_divs, 2, 1, num_dims + 1) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = -buff_size, m + buff_size - select case (bc_type(2, 1)%sf(k, 0, l)) - case (BC_PERIODIC) - call s_color_function_periodic(c_divs, 2, 1, k, l) - case (BC_REFLECTIVE) - call s_color_function_reflective(c_divs, 2, 1, k, l) - case default - call s_color_function_ghost_cell_extrapolation(c_divs, 2, 1, k, l) - end select + do l = 0, p + do k = -buff_size, m + buff_size + select case (bc_type(2, 1)%sf(k, 0, l)) + case (BC_PERIODIC) + call s_color_function_periodic(c_divs, 2, 1, k, l) + case (BC_REFLECTIVE) + call s_color_function_reflective(c_divs, 2, 1, k, l) + case default + call s_color_function_ghost_cell_extrapolation(c_divs, 2, 1, k, l) + end select + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1251,18 +1251,18 @@ contains call s_mpi_sendrecv_variables_buffers(c_divs, 3, -1, num_dims + 1) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = -buff_size, n + buff_size - do k = -buff_size, m + buff_size - select case (bc_type(3, -1)%sf(k, l, 0)) - case (BC_PERIODIC) - call s_color_function_periodic(c_divs, 3, -1, k, l) - case (BC_REFLECTIVE) - call s_color_function_reflective(c_divs, 3, -1, k, l) - case default - call s_color_function_ghost_cell_extrapolation(c_divs, 3, -1, k, l) - end select + do l = -buff_size, n + buff_size + do k = -buff_size, m + buff_size + select case (bc_type(3, -1)%sf(k, l, 0)) + case (BC_PERIODIC) + call s_color_function_periodic(c_divs, 3, -1, k, l) + case (BC_REFLECTIVE) + call s_color_function_reflective(c_divs, 3, -1, k, l) + case default + call s_color_function_ghost_cell_extrapolation(c_divs, 3, -1, k, l) + end select + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1270,18 +1270,18 @@ contains call s_mpi_sendrecv_variables_buffers(c_divs, 3, 1, num_dims + 1) else #:call GPU_PARALLEL_LOOP(collapse=2) - do l = -buff_size, n + buff_size - do k = -buff_size, m + buff_size - select case (bc_type(3, 1)%sf(k, l, 0)) - case (BC_PERIODIC) - call s_color_function_periodic(c_divs, 3, 1, k, l) - case (BC_REFLECTIVE) - call s_color_function_reflective(c_divs, 3, 1, k, l) - case default - call s_color_function_ghost_cell_extrapolation(c_divs, 3, 1, k, l) - end select + do l = -buff_size, n + buff_size + do k = -buff_size, m + buff_size + select case (bc_type(3, 1)%sf(k, l, 0)) + case (BC_PERIODIC) + call s_color_function_periodic(c_divs, 3, 1, k, l) + case (BC_REFLECTIVE) + call s_color_function_reflective(c_divs, 3, 1, k, l) + case default + call s_color_function_ghost_cell_extrapolation(c_divs, 3, 1, k, l) + end select + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end subroutine s_populate_capillary_buffers diff --git a/src/common/m_chemistry.fpp b/src/common/m_chemistry.fpp index a2ed576ff9..e9e5bc5ee8 100644 --- a/src/common/m_chemistry.fpp +++ b/src/common/m_chemistry.fpp @@ -100,32 +100,32 @@ contains real(wp), dimension(num_species) :: omega #:call GPU_PARALLEL_LOOP(collapse=3, private='[Ys, omega]') - do z = bounds(3)%beg, bounds(3)%end - do y = bounds(2)%beg, bounds(2)%end - do x = bounds(1)%beg, bounds(1)%end + do z = bounds(3)%beg, bounds(3)%end + do y = bounds(2)%beg, bounds(2)%end + do x = bounds(1)%beg, bounds(1)%end - $:GPU_LOOP(parallelism='[seq]') - do eqn = chemxb, chemxe - Ys(eqn - chemxb + 1) = q_prim_qp(eqn)%sf(x, y, z) - end do + $:GPU_LOOP(parallelism='[seq]') + do eqn = chemxb, chemxe + Ys(eqn - chemxb + 1) = q_prim_qp(eqn)%sf(x, y, z) + end do - rho = q_cons_qp(contxe)%sf(x, y, z) - T = q_T_sf%sf(x, y, z) + rho = q_cons_qp(contxe)%sf(x, y, z) + T = q_T_sf%sf(x, y, z) - call get_net_production_rates(rho, T, Ys, omega) + call get_net_production_rates(rho, T, Ys, omega) - $:GPU_LOOP(parallelism='[seq]') - do eqn = chemxb, chemxe + $:GPU_LOOP(parallelism='[seq]') + do eqn = chemxb, chemxe - omega_m = molecular_weights(eqn - chemxb + 1)*omega(eqn - chemxb + 1) + omega_m = molecular_weights(eqn - chemxb + 1)*omega(eqn - chemxb + 1) - rhs_vf(eqn)%sf(x, y, z) = rhs_vf(eqn)%sf(x, y, z) + omega_m + rhs_vf(eqn)%sf(x, y, z) = rhs_vf(eqn)%sf(x, y, z) + omega_m - end do + end do + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_chemistry_reaction_flux diff --git a/src/common/m_finite_differences.fpp b/src/common/m_finite_differences.fpp index 07dee3c024..c01953e216 100644 --- a/src/common/m_finite_differences.fpp +++ b/src/common/m_finite_differences.fpp @@ -19,43 +19,43 @@ contains real(wp) :: divergence #:call GPU_PARALLEL_LOOP(collapse=3, private='[divergence]') - do x = ix_s%beg, ix_s%end - do y = iy_s%beg, iy_s%end - do z = iz_s%beg, iz_s%end - - if (x == ix_s%beg) then - divergence = (-3._wp*fields(1)%sf(x, y, z) + 4._wp*fields(1)%sf(x + 1, y, z) - fields(1)%sf(x + 2, y, z))/(x_cc(x + 2) - x_cc(x)) - else if (x == ix_s%end) then - divergence = (+3._wp*fields(1)%sf(x, y, z) - 4._wp*fields(1)%sf(x - 1, y, z) + fields(1)%sf(x - 2, y, z))/(x_cc(x) - x_cc(x - 2)) - else - divergence = (fields(1)%sf(x + 1, y, z) - fields(1)%sf(x - 1, y, z))/(x_cc(x + 1) - x_cc(x - 1)) - end if - - if (n > 0) then - if (y == iy_s%beg) then - divergence = divergence + (-3._wp*fields(2)%sf(x, y, z) + 4._wp*fields(2)%sf(x, y + 1, z) - fields(2)%sf(x, y + 2, z))/(y_cc(y + 2) - y_cc(y)) - else if (y == iy_s%end) then - divergence = divergence + (+3._wp*fields(2)%sf(x, y, z) - 4._wp*fields(2)%sf(x, y - 1, z) + fields(2)%sf(x, y - 2, z))/(y_cc(y) - y_cc(y - 2)) + do x = ix_s%beg, ix_s%end + do y = iy_s%beg, iy_s%end + do z = iz_s%beg, iz_s%end + + if (x == ix_s%beg) then + divergence = (-3._wp*fields(1)%sf(x, y, z) + 4._wp*fields(1)%sf(x + 1, y, z) - fields(1)%sf(x + 2, y, z))/(x_cc(x + 2) - x_cc(x)) + else if (x == ix_s%end) then + divergence = (+3._wp*fields(1)%sf(x, y, z) - 4._wp*fields(1)%sf(x - 1, y, z) + fields(1)%sf(x - 2, y, z))/(x_cc(x) - x_cc(x - 2)) else - divergence = divergence + (fields(2)%sf(x, y + 1, z) - fields(2)%sf(x, y - 1, z))/(y_cc(y + 1) - y_cc(y - 1)) + divergence = (fields(1)%sf(x + 1, y, z) - fields(1)%sf(x - 1, y, z))/(x_cc(x + 1) - x_cc(x - 1)) end if - end if - if (p > 0) then - if (z == iz_s%beg) then - divergence = divergence + (-3._wp*fields(3)%sf(x, y, z) + 4._wp*fields(3)%sf(x, y, z + 1) - fields(3)%sf(x, y, z + 2))/(z_cc(z + 2) - z_cc(z)) - else if (z == iz_s%end) then - divergence = divergence + (+3._wp*fields(3)%sf(x, y, z) - 4._wp*fields(3)%sf(x, y, z - 1) + fields(2)%sf(x, y, z - 2))/(z_cc(z) - z_cc(z - 2)) - else - divergence = divergence + (fields(3)%sf(x, y, z + 1) - fields(3)%sf(x, y, z - 1))/(z_cc(z + 1) - z_cc(z - 1)) + if (n > 0) then + if (y == iy_s%beg) then + divergence = divergence + (-3._wp*fields(2)%sf(x, y, z) + 4._wp*fields(2)%sf(x, y + 1, z) - fields(2)%sf(x, y + 2, z))/(y_cc(y + 2) - y_cc(y)) + else if (y == iy_s%end) then + divergence = divergence + (+3._wp*fields(2)%sf(x, y, z) - 4._wp*fields(2)%sf(x, y - 1, z) + fields(2)%sf(x, y - 2, z))/(y_cc(y) - y_cc(y - 2)) + else + divergence = divergence + (fields(2)%sf(x, y + 1, z) - fields(2)%sf(x, y - 1, z))/(y_cc(y + 1) - y_cc(y - 1)) + end if + end if + + if (p > 0) then + if (z == iz_s%beg) then + divergence = divergence + (-3._wp*fields(3)%sf(x, y, z) + 4._wp*fields(3)%sf(x, y, z + 1) - fields(3)%sf(x, y, z + 2))/(z_cc(z + 2) - z_cc(z)) + else if (z == iz_s%end) then + divergence = divergence + (+3._wp*fields(3)%sf(x, y, z) - 4._wp*fields(3)%sf(x, y, z - 1) + fields(2)%sf(x, y, z - 2))/(z_cc(z) - z_cc(z - 2)) + else + divergence = divergence + (fields(3)%sf(x, y, z + 1) - fields(3)%sf(x, y, z - 1))/(z_cc(z + 1) - z_cc(z - 1)) + end if end if - end if - div%sf(x, y, z) = div%sf(x, y, z) + divergence + div%sf(x, y, z) = div%sf(x, y, z) + divergence + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_fd_divergence @@ -71,7 +71,7 @@ contains !! @param s_cc Locations of the cell-centers in the s-coordinate direction !! @param fd_coeff_s Finite-diff. coefficients in the s-coordinate direction subroutine s_compute_finite_difference_coefficients(q, s_cc, fd_coeff_s, local_buff_size, & - fd_number_in, fd_order_in, offset_s) + fd_number_in, fd_order_in, offset_s) integer :: lB, lE !< loop bounds integer, intent(IN) :: q diff --git a/src/common/m_mpi_common.fpp b/src/common/m_mpi_common.fpp index 2deb0c36ef..098dbe82d6 100644 --- a/src/common/m_mpi_common.fpp +++ b/src/common/m_mpi_common.fpp @@ -688,151 +688,151 @@ contains if (mpi_dir == ${mpi_dir}$) then #:if mpi_dir == 1 #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') - do l = 0, p - do k = 0, n - do j = 0, buff_size - 1 - do i = 1, nVar - r = (i - 1) + v_size*(j + buff_size*(k + (n + 1)*l)) - buff_send(r) = q_comm(i)%sf(j + pack_offset, k, l) + do l = 0, p + do k = 0, n + do j = 0, buff_size - 1 + do i = 1, nVar + r = (i - 1) + v_size*(j + buff_size*(k + (n + 1)*l)) + buff_send(r) = q_comm(i)%sf(j + pack_offset, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') - do l = 0, p - do k = 0, n - do j = 0, buff_size - 1 - do i = nVar + 1, nVar + 4 - do q = 1, nb - r = (i - 1) + (q - 1)*4 + v_size* & - (j + buff_size*(k + (n + 1)*l)) - buff_send(r) = pb_in(j + pack_offset, k, l, i - nVar, q) + do l = 0, p + do k = 0, n + do j = 0, buff_size - 1 + do i = nVar + 1, nVar + 4 + do q = 1, nb + r = (i - 1) + (q - 1)*4 + v_size* & + (j + buff_size*(k + (n + 1)*l)) + buff_send(r) = pb_in(j + pack_offset, k, l, i - nVar, q) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do l = 0, p - do k = 0, n - do j = 0, buff_size - 1 - do i = nVar + 1, nVar + 4 - do q = 1, nb - r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & - (j + buff_size*(k + (n + 1)*l)) - buff_send(r) = mv_in(j + pack_offset, k, l, i - nVar, q) + do l = 0, p + do k = 0, n + do j = 0, buff_size - 1 + do i = nVar + 1, nVar + 4 + do q = 1, nb + r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & + (j + buff_size*(k + (n + 1)*l)) + buff_send(r) = mv_in(j + pack_offset, k, l, i - nVar, q) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:elif mpi_dir == 2 #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') - do i = 1, nVar - do l = 0, p - do k = 0, buff_size - 1 - do j = -buff_size, m + buff_size - r = (i - 1) + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - (k + buff_size*l)) - buff_send(r) = q_comm(i)%sf(j, k + pack_offset, l) + do i = 1, nVar + do l = 0, p + do k = 0, buff_size - 1 + do j = -buff_size, m + buff_size + r = (i - 1) + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + (k + buff_size*l)) + buff_send(r) = q_comm(i)%sf(j, k + pack_offset, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do i = nVar + 1, nVar + 4 - do l = 0, p - do k = 0, buff_size - 1 - do j = -buff_size, m + buff_size - do q = 1, nb - r = (i - 1) + (q - 1)*4 + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - (k + buff_size*l)) - buff_send(r) = pb_in(j, k + pack_offset, l, i - nVar, q) + do i = nVar + 1, nVar + 4 + do l = 0, p + do k = 0, buff_size - 1 + do j = -buff_size, m + buff_size + do q = 1, nb + r = (i - 1) + (q - 1)*4 + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + (k + buff_size*l)) + buff_send(r) = pb_in(j, k + pack_offset, l, i - nVar, q) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do i = nVar + 1, nVar + 4 - do l = 0, p - do k = 0, buff_size - 1 - do j = -buff_size, m + buff_size - do q = 1, nb - r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - (k + buff_size*l)) - buff_send(r) = mv_in(j, k + pack_offset, l, i - nVar, q) + do i = nVar + 1, nVar + 4 + do l = 0, p + do k = 0, buff_size - 1 + do j = -buff_size, m + buff_size + do q = 1, nb + r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + (k + buff_size*l)) + buff_send(r) = mv_in(j, k + pack_offset, l, i - nVar, q) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:else #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') - do i = 1, nVar - do l = 0, buff_size - 1 - do k = -buff_size, n + buff_size - do j = -buff_size, m + buff_size - r = (i - 1) + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - ((k + buff_size) + (n + 2*buff_size + 1)*l)) - buff_send(r) = q_comm(i)%sf(j, k, l + pack_offset) + do i = 1, nVar + do l = 0, buff_size - 1 + do k = -buff_size, n + buff_size + do j = -buff_size, m + buff_size + r = (i - 1) + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + ((k + buff_size) + (n + 2*buff_size + 1)*l)) + buff_send(r) = q_comm(i)%sf(j, k, l + pack_offset) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do i = nVar + 1, nVar + 4 - do l = 0, buff_size - 1 - do k = -buff_size, n + buff_size - do j = -buff_size, m + buff_size - do q = 1, nb - r = (i - 1) + (q - 1)*4 + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - ((k + buff_size) + (n + 2*buff_size + 1)*l)) - buff_send(r) = pb_in(j, k, l + pack_offset, i - nVar, q) + do i = nVar + 1, nVar + 4 + do l = 0, buff_size - 1 + do k = -buff_size, n + buff_size + do j = -buff_size, m + buff_size + do q = 1, nb + r = (i - 1) + (q - 1)*4 + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + ((k + buff_size) + (n + 2*buff_size + 1)*l)) + buff_send(r) = pb_in(j, k, l + pack_offset, i - nVar, q) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do i = nVar + 1, nVar + 4 - do l = 0, buff_size - 1 - do k = -buff_size, n + buff_size - do j = -buff_size, m + buff_size - do q = 1, nb - r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - ((k + buff_size) + (n + 2*buff_size + 1)*l)) - buff_send(r) = mv_in(j, k, l + pack_offset, i - nVar, q) + do i = nVar + 1, nVar + 4 + do l = 0, buff_size - 1 + do k = -buff_size, n + buff_size + do j = -buff_size, m + buff_size + do q = 1, nb + r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + ((k + buff_size) + (n + 2*buff_size + 1)*l)) + buff_send(r) = mv_in(j, k, l + pack_offset, i - nVar, q) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:endif @@ -889,174 +889,174 @@ contains if (mpi_dir == ${mpi_dir}$) then #:if mpi_dir == 1 #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') - do l = 0, p - do k = 0, n - do j = -buff_size, -1 - do i = 1, nVar - r = (i - 1) + v_size* & - (j + buff_size*((k + 1) + (n + 1)*l)) - q_comm(i)%sf(j + unpack_offset, k, l) = buff_recv(r) + do l = 0, p + do k = 0, n + do j = -buff_size, -1 + do i = 1, nVar + r = (i - 1) + v_size* & + (j + buff_size*((k + 1) + (n + 1)*l)) + q_comm(i)%sf(j + unpack_offset, k, l) = buff_recv(r) #if defined(__INTEL_COMPILER) - if (ieee_is_nan(q_comm(i)%sf(j, k, l))) then - print *, "Error", j, k, l, i - error stop "NaN(s) in recv" - end if + if (ieee_is_nan(q_comm(i)%sf(j, k, l))) then + print *, "Error", j, k, l, i + error stop "NaN(s) in recv" + end if #endif + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do l = 0, p - do k = 0, n - do j = -buff_size, -1 - do i = nVar + 1, nVar + 4 - do q = 1, nb - r = (i - 1) + (q - 1)*4 + v_size* & - (j + buff_size*((k + 1) + (n + 1)*l)) - pb_in(j + unpack_offset, k, l, i - nVar, q) = buff_recv(r) + do l = 0, p + do k = 0, n + do j = -buff_size, -1 + do i = nVar + 1, nVar + 4 + do q = 1, nb + r = (i - 1) + (q - 1)*4 + v_size* & + (j + buff_size*((k + 1) + (n + 1)*l)) + pb_in(j + unpack_offset, k, l, i - nVar, q) = buff_recv(r) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do l = 0, p - do k = 0, n - do j = -buff_size, -1 - do i = nVar + 1, nVar + 4 - do q = 1, nb - r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & - (j + buff_size*((k + 1) + (n + 1)*l)) - mv_in(j + unpack_offset, k, l, i - nVar, q) = buff_recv(r) + do l = 0, p + do k = 0, n + do j = -buff_size, -1 + do i = nVar + 1, nVar + 4 + do q = 1, nb + r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & + (j + buff_size*((k + 1) + (n + 1)*l)) + mv_in(j + unpack_offset, k, l, i - nVar, q) = buff_recv(r) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:elif mpi_dir == 2 #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') - do i = 1, nVar - do l = 0, p - do k = -buff_size, -1 - do j = -buff_size, m + buff_size - r = (i - 1) + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - ((k + buff_size) + buff_size*l)) - q_comm(i)%sf(j, k + unpack_offset, l) = buff_recv(r) + do i = 1, nVar + do l = 0, p + do k = -buff_size, -1 + do j = -buff_size, m + buff_size + r = (i - 1) + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + ((k + buff_size) + buff_size*l)) + q_comm(i)%sf(j, k + unpack_offset, l) = buff_recv(r) #if defined(__INTEL_COMPILER) - if (ieee_is_nan(q_comm(i)%sf(j, k, l))) then - print *, "Error", j, k, l, i - error stop "NaN(s) in recv" - end if + if (ieee_is_nan(q_comm(i)%sf(j, k, l))) then + print *, "Error", j, k, l, i + error stop "NaN(s) in recv" + end if #endif + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do i = nVar + 1, nVar + 4 - do l = 0, p - do k = -buff_size, -1 - do j = -buff_size, m + buff_size - do q = 1, nb - r = (i - 1) + (q - 1)*4 + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - ((k + buff_size) + buff_size*l)) - pb_in(j, k + unpack_offset, l, i - nVar, q) = buff_recv(r) + do i = nVar + 1, nVar + 4 + do l = 0, p + do k = -buff_size, -1 + do j = -buff_size, m + buff_size + do q = 1, nb + r = (i - 1) + (q - 1)*4 + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + ((k + buff_size) + buff_size*l)) + pb_in(j, k + unpack_offset, l, i - nVar, q) = buff_recv(r) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do i = nVar + 1, nVar + 4 - do l = 0, p - do k = -buff_size, -1 - do j = -buff_size, m + buff_size - do q = 1, nb - r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - ((k + buff_size) + buff_size*l)) - mv_in(j, k + unpack_offset, l, i - nVar, q) = buff_recv(r) + do i = nVar + 1, nVar + 4 + do l = 0, p + do k = -buff_size, -1 + do j = -buff_size, m + buff_size + do q = 1, nb + r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + ((k + buff_size) + buff_size*l)) + mv_in(j, k + unpack_offset, l, i - nVar, q) = buff_recv(r) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:else ! Unpacking buffer from bc_z%beg #:call GPU_PARALLEL_LOOP(collapse=4,private='[r]') - do i = 1, nVar - do l = -buff_size, -1 - do k = -buff_size, n + buff_size - do j = -buff_size, m + buff_size - r = (i - 1) + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - ((k + buff_size) + (n + 2*buff_size + 1)* & - (l + buff_size))) - q_comm(i)%sf(j, k, l + unpack_offset) = buff_recv(r) + do i = 1, nVar + do l = -buff_size, -1 + do k = -buff_size, n + buff_size + do j = -buff_size, m + buff_size + r = (i - 1) + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + ((k + buff_size) + (n + 2*buff_size + 1)* & + (l + buff_size))) + q_comm(i)%sf(j, k, l + unpack_offset) = buff_recv(r) #if defined(__INTEL_COMPILER) - if (ieee_is_nan(q_comm(i)%sf(j, k, l))) then - print *, "Error", j, k, l, i - error stop "NaN(s) in recv" - end if + if (ieee_is_nan(q_comm(i)%sf(j, k, l))) then + print *, "Error", j, k, l, i + error stop "NaN(s) in recv" + end if #endif + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (qbmm_comm) then #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do i = nVar + 1, nVar + 4 - do l = -buff_size, -1 - do k = -buff_size, n + buff_size - do j = -buff_size, m + buff_size - do q = 1, nb - r = (i - 1) + (q - 1)*4 + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - ((k + buff_size) + (n + 2*buff_size + 1)* & - (l + buff_size))) - pb_in(j, k, l + unpack_offset, i - nVar, q) = buff_recv(r) + do i = nVar + 1, nVar + 4 + do l = -buff_size, -1 + do k = -buff_size, n + buff_size + do j = -buff_size, m + buff_size + do q = 1, nb + r = (i - 1) + (q - 1)*4 + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + ((k + buff_size) + (n + 2*buff_size + 1)* & + (l + buff_size))) + pb_in(j, k, l + unpack_offset, i - nVar, q) = buff_recv(r) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=5,private='[r]') - do i = nVar + 1, nVar + 4 - do l = -buff_size, -1 - do k = -buff_size, n + buff_size - do j = -buff_size, m + buff_size - do q = 1, nb - r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & - ((j + buff_size) + (m + 2*buff_size + 1)* & - ((k + buff_size) + (n + 2*buff_size + 1)* & - (l + buff_size))) - mv_in(j, k, l + unpack_offset, i - nVar, q) = buff_recv(r) + do i = nVar + 1, nVar + 4 + do l = -buff_size, -1 + do k = -buff_size, n + buff_size + do j = -buff_size, m + buff_size + do q = 1, nb + r = (i - 1) + (q - 1)*4 + nb*4 + v_size* & + ((j + buff_size) + (m + 2*buff_size + 1)* & + ((k + buff_size) + (n + 2*buff_size + 1)* & + (l + buff_size))) + mv_in(j, k, l + unpack_offset, i - nVar, q) = buff_recv(r) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:endif diff --git a/src/common/m_phase_change.fpp b/src/common/m_phase_change.fpp index 76e76e9d64..c36cff840d 100644 --- a/src/common/m_phase_change.fpp +++ b/src/common/m_phase_change.fpp @@ -99,179 +99,176 @@ contains integer :: i, j, k, l ! starting equilibrium solver - #:call GPU_PARALLEL_LOOP(collapse=3, private='[p_infOV, p_infpT, p_infSL, & - & sk, hk, gk, ek, rhok,pS, pSOV, pSSL, & - & TS, TSOV, TSatOV, TSatSL, TSSL, rhoe, & - & dynE, rhos, rho, rM, m1, m2, MCT, TvF]') - do j = 0, m - do k = 0, n - do l = 0, p + #:call GPU_PARALLEL_LOOP(collapse=3, private='[p_infOV, p_infpT, p_infSL, sk, hk, gk, ek, rhok,pS, pSOV, pSSL, TS, TSOV, TSatOV, TSatSL, TSSL, rhoe, dynE, rhos, rho, rM, m1, m2, MCT, TvF]') + do j = 0, m + do k = 0, n + do l = 0, p - rho = 0.0_wp; TvF = 0.0_wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids + rho = 0.0_wp; TvF = 0.0_wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - ! Mixture density - rho = rho + q_cons_vf(i + contxb - 1)%sf(j, k, l) + ! Mixture density + rho = rho + q_cons_vf(i + contxb - 1)%sf(j, k, l) - ! Total Volume Fraction - TvF = TvF + q_cons_vf(i + advxb - 1)%sf(j, k, l) + ! Total Volume Fraction + TvF = TvF + q_cons_vf(i + advxb - 1)%sf(j, k, l) - end do + end do - ! calculating the total reacting mass for the phase change process. By hypothesis, this should not change - ! throughout the phase-change process. - rM = q_cons_vf(lp + contxb - 1)%sf(j, k, l) + q_cons_vf(vp + contxb - 1)%sf(j, k, l) + ! calculating the total reacting mass for the phase change process. By hypothesis, this should not change + ! throughout the phase-change process. + rM = q_cons_vf(lp + contxb - 1)%sf(j, k, l) + q_cons_vf(vp + contxb - 1)%sf(j, k, l) - ! correcting negative (reacting) mass fraction values in case they happen - call s_correct_partial_densities(MCT, q_cons_vf, rM, j, k, l) + ! correcting negative (reacting) mass fraction values in case they happen + call s_correct_partial_densities(MCT, q_cons_vf, rM, j, k, l) - ! fixing m1 and m2 AFTER correcting the partial densities. Note that these values must be stored for the phase - ! change process that will happen a posteriori - m1 = q_cons_vf(lp + contxb - 1)%sf(j, k, l) + ! fixing m1 and m2 AFTER correcting the partial densities. Note that these values must be stored for the phase + ! change process that will happen a posteriori + m1 = q_cons_vf(lp + contxb - 1)%sf(j, k, l) - m2 = q_cons_vf(vp + contxb - 1)%sf(j, k, l) + m2 = q_cons_vf(vp + contxb - 1)%sf(j, k, l) - ! kinetic energy as an auxiliary variable to the calculation of the total internal energy - dynE = 0.0_wp - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, momxe + ! kinetic energy as an auxiliary variable to the calculation of the total internal energy + dynE = 0.0_wp + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, momxe - dynE = dynE + 5.0e-1_wp*q_cons_vf(i)%sf(j, k, l)**2/rho + dynE = dynE + 5.0e-1_wp*q_cons_vf(i)%sf(j, k, l)**2/rho - end do + end do - ! calculating the total energy that MUST be preserved throughout the pT- and pTg-relaxation procedures - ! at each of the cells. The internal energy is calculated as the total energy minus the kinetic - ! energy to preserved its value at sharp interfaces - rhoe = q_cons_vf(E_idx)%sf(j, k, l) - dynE + ! calculating the total energy that MUST be preserved throughout the pT- and pTg-relaxation procedures + ! at each of the cells. The internal energy is calculated as the total energy minus the kinetic + ! energy to preserved its value at sharp interfaces + rhoe = q_cons_vf(E_idx)%sf(j, k, l) - dynE - ! Calling pT-equilibrium for either finishing phase-change module, or as an IC for the pTg-equilibrium - ! for this case, MFL cannot be either 0 or 1, so I chose it to be 2 - call s_infinite_pt_relaxation_k(j, k, l, 2, pS, p_infpT, q_cons_vf, rhoe, TS) + ! Calling pT-equilibrium for either finishing phase-change module, or as an IC for the pTg-equilibrium + ! for this case, MFL cannot be either 0 or 1, so I chose it to be 2 + call s_infinite_pt_relaxation_k(j, k, l, 2, pS, p_infpT, q_cons_vf, rhoe, TS) - ! check if pTg-equilibrium is required - ! NOTE that NOTHING else needs to be updated OTHER than the individual partial densities - ! given the outputs from the pT- and pTg-equilibrium solvers are just p and one of the partial masses - ! (pTg- case) - if ((relax_model == 6) .and. ((q_cons_vf(lp + contxb - 1)%sf(j, k, l) > mixM*rM) & - .and. (q_cons_vf(vp + contxb - 1)%sf(j, k, l) > mixM*rM)) & - .and. (pS < pCr) .and. (TS < TCr)) then + ! check if pTg-equilibrium is required + ! NOTE that NOTHING else needs to be updated OTHER than the individual partial densities + ! given the outputs from the pT- and pTg-equilibrium solvers are just p and one of the partial masses + ! (pTg- case) + if ((relax_model == 6) .and. ((q_cons_vf(lp + contxb - 1)%sf(j, k, l) > mixM*rM) & + .and. (q_cons_vf(vp + contxb - 1)%sf(j, k, l) > mixM*rM)) & + .and. (pS < pCr) .and. (TS < TCr)) then - ! Checking if phase change is needed, by checking whether the final solution is either subcoooled - ! liquid or overheated vapor. + ! Checking if phase change is needed, by checking whether the final solution is either subcoooled + ! liquid or overheated vapor. - ! overheated vapor case - ! depleting the mass of liquid - q_cons_vf(lp + contxb - 1)%sf(j, k, l) = mixM*rM + ! overheated vapor case + ! depleting the mass of liquid + q_cons_vf(lp + contxb - 1)%sf(j, k, l) = mixM*rM - ! tranferring the total mass to vapor - q_cons_vf(vp + contxb - 1)%sf(j, k, l) = (1.0_wp - mixM)*rM + ! tranferring the total mass to vapor + q_cons_vf(vp + contxb - 1)%sf(j, k, l) = (1.0_wp - mixM)*rM - ! calling pT-equilibrium for overheated vapor, which is MFL = 0 - call s_infinite_pt_relaxation_k(j, k, l, 0, pSOV, p_infOV, q_cons_vf, rhoe, TSOV) + ! calling pT-equilibrium for overheated vapor, which is MFL = 0 + call s_infinite_pt_relaxation_k(j, k, l, 0, pSOV, p_infOV, q_cons_vf, rhoe, TSOV) - ! calculating Saturation temperature - call s_TSat(pSOV, TSatOV, TSOV) + ! calculating Saturation temperature + call s_TSat(pSOV, TSatOV, TSOV) - ! subcooled liquid case - ! tranferring the total mass to liquid - q_cons_vf(lp + contxb - 1)%sf(j, k, l) = (1.0_wp - mixM)*rM + ! subcooled liquid case + ! tranferring the total mass to liquid + q_cons_vf(lp + contxb - 1)%sf(j, k, l) = (1.0_wp - mixM)*rM - ! depleting the mass of vapor - q_cons_vf(vp + contxb - 1)%sf(j, k, l) = mixM*rM + ! depleting the mass of vapor + q_cons_vf(vp + contxb - 1)%sf(j, k, l) = mixM*rM - ! calling pT-equilibrium for subcooled liquid, which is MFL = 1 - call s_infinite_pt_relaxation_k(j, k, l, 1, pSSL, p_infSL, q_cons_vf, rhoe, TSSL) + ! calling pT-equilibrium for subcooled liquid, which is MFL = 1 + call s_infinite_pt_relaxation_k(j, k, l, 1, pSSL, p_infSL, q_cons_vf, rhoe, TSSL) - ! calculating Saturation temperature - call s_TSat(pSSL, TSatSL, TSSL) + ! calculating Saturation temperature + call s_TSat(pSSL, TSatSL, TSSL) - ! checking the conditions for overheated vapor and subcooled liquide - if (TSOV > TSatOV) then + ! checking the conditions for overheated vapor and subcooled liquide + if (TSOV > TSatOV) then - ! Assigning pressure - pS = pSOV + ! Assigning pressure + pS = pSOV - ! Assigning Temperature - TS = TSOV + ! Assigning Temperature + TS = TSOV - ! correcting the liquid partial density - q_cons_vf(lp + contxb - 1)%sf(j, k, l) = mixM*rM + ! correcting the liquid partial density + q_cons_vf(lp + contxb - 1)%sf(j, k, l) = mixM*rM - ! correcting the vapor partial density - q_cons_vf(vp + contxb - 1)%sf(j, k, l) = (1.0_wp - mixM)*rM + ! correcting the vapor partial density + q_cons_vf(vp + contxb - 1)%sf(j, k, l) = (1.0_wp - mixM)*rM - elseif (TSSL < TSatSL) then + elseif (TSSL < TSatSL) then - ! Assigning pressure - pS = pSSL + ! Assigning pressure + pS = pSSL - ! Assigning Temperature - TS = TSSL + ! Assigning Temperature + TS = TSSL - ! correcting the liquid partial density - q_cons_vf(lp + contxb - 1)%sf(j, k, l) = (1.0_wp - mixM)*rM + ! correcting the liquid partial density + q_cons_vf(lp + contxb - 1)%sf(j, k, l) = (1.0_wp - mixM)*rM - ! correcting the vapor partial density - q_cons_vf(vp + contxb - 1)%sf(j, k, l) = mixM*rM + ! correcting the vapor partial density + q_cons_vf(vp + contxb - 1)%sf(j, k, l) = mixM*rM - else + else - ! returning partial pressures to what they were from the homogeneous solver - ! liquid - q_cons_vf(lp + contxb - 1)%sf(j, k, l) = m1 + ! returning partial pressures to what they were from the homogeneous solver + ! liquid + q_cons_vf(lp + contxb - 1)%sf(j, k, l) = m1 - ! vapor - q_cons_vf(vp + contxb - 1)%sf(j, k, l) = m2 + ! vapor + q_cons_vf(vp + contxb - 1)%sf(j, k, l) = m2 - ! calling the pTg-equilibrium solver - call s_infinite_ptg_relaxation_k(j, k, l, pS, p_infpT, rhoe, q_cons_vf, TS) + ! calling the pTg-equilibrium solver + call s_infinite_ptg_relaxation_k(j, k, l, pS, p_infpT, rhoe, q_cons_vf, TS) - end if + end if - end if + end if - ! Calculations AFTER equilibrium + ! Calculations AFTER equilibrium - ! entropy - sk(1:num_fluids) = cvs(1:num_fluids)*log((TS**gs_min(1:num_fluids)) & - /((pS + ps_inf(1:num_fluids))**(gs_min(1:num_fluids) - 1.0_wp))) + qvps(1:num_fluids) + ! entropy + sk(1:num_fluids) = cvs(1:num_fluids)*log((TS**gs_min(1:num_fluids)) & + /((pS + ps_inf(1:num_fluids))**(gs_min(1:num_fluids) - 1.0_wp))) + qvps(1:num_fluids) - ! enthalpy - hk(1:num_fluids) = gs_min(1:num_fluids)*cvs(1:num_fluids)*TS & - + qvs(1:num_fluids) + ! enthalpy + hk(1:num_fluids) = gs_min(1:num_fluids)*cvs(1:num_fluids)*TS & + + qvs(1:num_fluids) - ! Gibbs-free energy - gk(1:num_fluids) = hk(1:num_fluids) - TS*sk(1:num_fluids) + ! Gibbs-free energy + gk(1:num_fluids) = hk(1:num_fluids) - TS*sk(1:num_fluids) - ! densities - rhok(1:num_fluids) = (pS + ps_inf(1:num_fluids)) & - /((gs_min(1:num_fluids) - 1)*cvs(1:num_fluids)*TS) + ! densities + rhok(1:num_fluids) = (pS + ps_inf(1:num_fluids)) & + /((gs_min(1:num_fluids) - 1)*cvs(1:num_fluids)*TS) - ! internal energy - ek(1:num_fluids) = (pS + gs_min(1:num_fluids) & - *ps_inf(1:num_fluids))/(pS + ps_inf(1:num_fluids)) & - *cvs(1:num_fluids)*TS + qvs(1:num_fluids) + ! internal energy + ek(1:num_fluids) = (pS + gs_min(1:num_fluids) & + *ps_inf(1:num_fluids))/(pS + ps_inf(1:num_fluids)) & + *cvs(1:num_fluids)*TS + qvs(1:num_fluids) - ! calculating volume fractions, internal energies, and total entropy - rhos = 0.0_wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids + ! calculating volume fractions, internal energies, and total entropy + rhos = 0.0_wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - ! volume fractions - q_cons_vf(i + advxb - 1)%sf(j, k, l) = q_cons_vf(i + contxb - 1)%sf(j, k, l)/rhok(i) + ! volume fractions + q_cons_vf(i + advxb - 1)%sf(j, k, l) = q_cons_vf(i + contxb - 1)%sf(j, k, l)/rhok(i) - ! alpha*rho*e - q_cons_vf(i + intxb - 1)%sf(j, k, l) = q_cons_vf(i + contxb - 1)%sf(j, k, l)*ek(i) + ! alpha*rho*e + q_cons_vf(i + intxb - 1)%sf(j, k, l) = q_cons_vf(i + contxb - 1)%sf(j, k, l)*ek(i) - ! Total entropy - rhos = rhos + q_cons_vf(i + contxb - 1)%sf(j, k, l)*sk(i) + ! Total entropy + rhos = rhos + q_cons_vf(i + contxb - 1)%sf(j, k, l)*sk(i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_infinite_relaxation_k diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index 33094bfb4f..1a49e7e5b6 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -465,9 +465,9 @@ contains end subroutine s_convert_species_to_mixture_variables subroutine s_convert_species_to_mixture_variables_acc(rho_K, & - gamma_K, pi_inf_K, qv_K, & - alpha_K, alpha_rho_K, Re_K, & - G_K, G) + gamma_K, pi_inf_K, qv_K, & + alpha_K, alpha_rho_K, Re_K, & + G_K, G) $:GPU_ROUTINE(function_name='s_convert_species_to_mixture_variables_acc', & & parallelism='[seq]', cray_inline=True) @@ -544,8 +544,8 @@ contains end subroutine s_convert_species_to_mixture_variables_acc subroutine s_convert_species_to_mixture_variables_bubbles_acc(rho_K, & - gamma_K, pi_inf_K, qv_K, & - alpha_K, alpha_rho_K, Re_K) + gamma_K, pi_inf_K, qv_K, & + alpha_K, alpha_rho_K, Re_K) $:GPU_ROUTINE(function_name='s_convert_species_to_mixture_variables_bubbles_acc', & & parallelism='[seq]', cray_inline=True) @@ -874,295 +874,295 @@ contains #:endif #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_K, alpha_rho_K, Re_K, nRtmp, rho_K, gamma_K, pi_inf_K,qv_K, dyn_pres_K, rhoYks, B]') - do l = ibounds(3)%beg, ibounds(3)%end - do k = ibounds(2)%beg, ibounds(2)%end - do j = ibounds(1)%beg, ibounds(1)%end - dyn_pres_K = 0._wp - - if (igr) then - if (num_fluids == 1) then - alpha_rho_K(1) = qK_cons_vf(contxb)%sf(j, k, l) - alpha_K(1) = qK_cons_vf(advxb)%sf(j, k, l) - else - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - alpha_rho_K(i) = qK_cons_vf(i)%sf(j, k, l) - alpha_K(i) = qK_cons_vf(advxb + i - 1)%sf(j, k, l) - end do - - alpha_rho_K(num_fluids) = qK_cons_vf(num_fluids)%sf(j, k, l) - alpha_K(num_fluids) = 1._wp - sum(alpha_K(1:num_fluids - 1)) - end if - else - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_K(i) = qK_cons_vf(i)%sf(j, k, l) - alpha_K(i) = qK_cons_vf(advxb + i - 1)%sf(j, k, l) - end do - end if + do l = ibounds(3)%beg, ibounds(3)%end + do k = ibounds(2)%beg, ibounds(2)%end + do j = ibounds(1)%beg, ibounds(1)%end + dyn_pres_K = 0._wp + + if (igr) then + if (num_fluids == 1) then + alpha_rho_K(1) = qK_cons_vf(contxb)%sf(j, k, l) + alpha_K(1) = qK_cons_vf(advxb)%sf(j, k, l) + else + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + alpha_rho_K(i) = qK_cons_vf(i)%sf(j, k, l) + alpha_K(i) = qK_cons_vf(advxb + i - 1)%sf(j, k, l) + end do + + alpha_rho_K(num_fluids) = qK_cons_vf(num_fluids)%sf(j, k, l) + alpha_K(num_fluids) = 1._wp - sum(alpha_K(1:num_fluids - 1)) + end if + else + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_K(i) = qK_cons_vf(i)%sf(j, k, l) + alpha_K(i) = qK_cons_vf(advxb + i - 1)%sf(j, k, l) + end do + end if - if (model_eqns /= 4) then + if (model_eqns /= 4) then #ifdef MFC_SIMULATION - ! If in simulation, use acc mixture subroutines - if (elasticity) then - call s_convert_species_to_mixture_variables_acc(rho_K, gamma_K, pi_inf_K, qv_K, alpha_K, & - alpha_rho_K, Re_K, G_K, Gs) - else if (bubbles_euler) then - call s_convert_species_to_mixture_variables_bubbles_acc(rho_K, gamma_K, pi_inf_K, qv_K, & - alpha_K, alpha_rho_K, Re_K) - else - call s_convert_species_to_mixture_variables_acc(rho_K, gamma_K, pi_inf_K, qv_K, & - alpha_K, alpha_rho_K, Re_K) - end if + ! If in simulation, use acc mixture subroutines + if (elasticity) then + call s_convert_species_to_mixture_variables_acc(rho_K, gamma_K, pi_inf_K, qv_K, alpha_K, & + alpha_rho_K, Re_K, G_K, Gs) + else if (bubbles_euler) then + call s_convert_species_to_mixture_variables_bubbles_acc(rho_K, gamma_K, pi_inf_K, qv_K, & + alpha_K, alpha_rho_K, Re_K) + else + call s_convert_species_to_mixture_variables_acc(rho_K, gamma_K, pi_inf_K, qv_K, & + alpha_K, alpha_rho_K, Re_K) + end if #else - ! If pre-processing, use non acc mixture subroutines - if (elasticity) then - call s_convert_to_mixture_variables(qK_cons_vf, j, k, l, & - rho_K, gamma_K, pi_inf_K, qv_K, Re_K, G_K, fluid_pp(:)%G) - else - call s_convert_to_mixture_variables(qK_cons_vf, j, k, l, & - rho_K, gamma_K, pi_inf_K, qv_K) - end if + ! If pre-processing, use non acc mixture subroutines + if (elasticity) then + call s_convert_to_mixture_variables(qK_cons_vf, j, k, l, & + rho_K, gamma_K, pi_inf_K, qv_K, Re_K, G_K, fluid_pp(:)%G) + else + call s_convert_to_mixture_variables(qK_cons_vf, j, k, l, & + rho_K, gamma_K, pi_inf_K, qv_K) + end if #endif - end if - - if (relativity) then - if (n == 0) then - B(1) = Bx0 - B(2) = qK_cons_vf(B_idx%beg)%sf(j, k, l) - B(3) = qK_cons_vf(B_idx%beg + 1)%sf(j, k, l) - else - B(1) = qK_cons_vf(B_idx%beg)%sf(j, k, l) - B(2) = qK_cons_vf(B_idx%beg + 1)%sf(j, k, l) - B(3) = qK_cons_vf(B_idx%beg + 2)%sf(j, k, l) end if - B2 = B(1)**2 + B(2)**2 + B(3)**2 - - m2 = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, momxe - m2 = m2 + qK_cons_vf(i)%sf(j, k, l)**2 - end do - S = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 3 - S = S + qK_cons_vf(momxb + i - 1)%sf(j, k, l)*B(i) - end do + if (relativity) then + if (n == 0) then + B(1) = Bx0 + B(2) = qK_cons_vf(B_idx%beg)%sf(j, k, l) + B(3) = qK_cons_vf(B_idx%beg + 1)%sf(j, k, l) + else + B(1) = qK_cons_vf(B_idx%beg)%sf(j, k, l) + B(2) = qK_cons_vf(B_idx%beg + 1)%sf(j, k, l) + B(3) = qK_cons_vf(B_idx%beg + 2)%sf(j, k, l) + end if + B2 = B(1)**2 + B(2)**2 + B(3)**2 - E = qK_cons_vf(E_idx)%sf(j, k, l) + m2 = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, momxe + m2 = m2 + qK_cons_vf(i)%sf(j, k, l)**2 + end do - D = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - D = D + qK_cons_vf(i)%sf(j, k, l) - end do + S = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 3 + S = S + qK_cons_vf(momxb + i - 1)%sf(j, k, l)*B(i) + end do - ! Newton-Raphson - W = E + D - $:GPU_LOOP(parallelism='[seq]') - do iter = 1, relativity_cons_to_prim_max_iter - Ga = (W + B2)*W/sqrt((W + B2)**2*W**2 - (m2*W**2 + S**2*(2*W + B2))) - pres = (W - D*Ga)/((gamma_K + 1)*Ga**2) ! Thermal pressure from EOS - f = W - pres + (1 - 1/(2*Ga**2))*B2 - S**2/(2*W**2) - E - D - - ! The first equation below corrects a typo in (Mignone & Bodo, 2006) - ! m2*W**2 → 2*m2*W**2, which would cancel with the 2* in other terms - ! This corrected version is not used as the second equation empirically converges faster. - ! First equation is kept for further investigation. - ! dGa_dW = -Ga**3 * ( S**2*(3*W**2+3*W*B2+B2**2) + m2*W**2 ) / (W**3 * (W+B2)**3) ! first (corrected) - dGa_dW = -Ga**3*(2*S**2*(3*W**2 + 3*W*B2 + B2**2) + m2*W**2)/(2*W**3*(W + B2)**3) ! second (in paper) - - dp_dW = (Ga*(1 + D*dGa_dW) - 2*W*dGa_dW)/((gamma_K + 1)*Ga**3) - df_dW = 1 - dp_dW + (B2/Ga**3)*dGa_dW + S**2/W**3 - - dW = -f/df_dW - W = W + dW - if (abs(dW) < 1.e-12_wp*W) exit - end do + E = qK_cons_vf(E_idx)%sf(j, k, l) - ! Recalculate pressure using converged W - Ga = (W + B2)*W/sqrt((W + B2)**2*W**2 - (m2*W**2 + S**2*(2*W + B2))) - qK_prim_vf(E_idx)%sf(j, k, l) = (W - D*Ga)/((gamma_K + 1)*Ga**2) + D = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + D = D + qK_cons_vf(i)%sf(j, k, l) + end do - ! Recover the other primitive variables - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 3 - qK_prim_vf(momxb + i - 1)%sf(j, k, l) = (qK_cons_vf(momxb + i - 1)%sf(j, k, l) + (S/W)*B(i))/(W + B2) - end do - qK_prim_vf(1)%sf(j, k, l) = D/Ga ! Hard-coded for single-component for now + ! Newton-Raphson + W = E + D + $:GPU_LOOP(parallelism='[seq]') + do iter = 1, relativity_cons_to_prim_max_iter + Ga = (W + B2)*W/sqrt((W + B2)**2*W**2 - (m2*W**2 + S**2*(2*W + B2))) + pres = (W - D*Ga)/((gamma_K + 1)*Ga**2) ! Thermal pressure from EOS + f = W - pres + (1 - 1/(2*Ga**2))*B2 - S**2/(2*W**2) - E - D + + ! The first equation below corrects a typo in (Mignone & Bodo, 2006) + ! m2*W**2 → 2*m2*W**2, which would cancel with the 2* in other terms + ! This corrected version is not used as the second equation empirically converges faster. + ! First equation is kept for further investigation. + ! dGa_dW = -Ga**3 * ( S**2*(3*W**2+3*W*B2+B2**2) + m2*W**2 ) / (W**3 * (W+B2)**3) ! first (corrected) + dGa_dW = -Ga**3*(2*S**2*(3*W**2 + 3*W*B2 + B2**2) + m2*W**2)/(2*W**3*(W + B2)**3) ! second (in paper) + + dp_dW = (Ga*(1 + D*dGa_dW) - 2*W*dGa_dW)/((gamma_K + 1)*Ga**3) + df_dW = 1 - dp_dW + (B2/Ga**3)*dGa_dW + S**2/W**3 + + dW = -f/df_dW + W = W + dW + if (abs(dW) < 1.e-12_wp*W) exit + end do - $:GPU_LOOP(parallelism='[seq]') - do i = B_idx%beg, B_idx%end - qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) - end do + ! Recalculate pressure using converged W + Ga = (W + B2)*W/sqrt((W + B2)**2*W**2 - (m2*W**2 + S**2*(2*W + B2))) + qK_prim_vf(E_idx)%sf(j, k, l) = (W - D*Ga)/((gamma_K + 1)*Ga**2) - cycle ! skip all the non-relativistic conversions below - end if + ! Recover the other primitive variables + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 3 + qK_prim_vf(momxb + i - 1)%sf(j, k, l) = (qK_cons_vf(momxb + i - 1)%sf(j, k, l) + (S/W)*B(i))/(W + B2) + end do + qK_prim_vf(1)%sf(j, k, l) = D/Ga ! Hard-coded for single-component for now - if (chemistry) then - rho_K = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = chemxb, chemxe - rho_K = rho_K + max(0._wp, qK_cons_vf(i)%sf(j, k, l)) - end do + $:GPU_LOOP(parallelism='[seq]') + do i = B_idx%beg, B_idx%end + qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - qK_prim_vf(i)%sf(j, k, l) = rho_K - end do + cycle ! skip all the non-relativistic conversions below + end if - $:GPU_LOOP(parallelism='[seq]') - do i = chemxb, chemxe - qK_prim_vf(i)%sf(j, k, l) = max(0._wp, qK_cons_vf(i)%sf(j, k, l)/rho_K) - end do - else - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) - end do - end if + if (chemistry) then + rho_K = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = chemxb, chemxe + rho_K = rho_K + max(0._wp, qK_cons_vf(i)%sf(j, k, l)) + end do -#ifdef MFC_SIMULATION - rho_K = max(rho_K, sgm_eps) -#endif + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + qK_prim_vf(i)%sf(j, k, l) = rho_K + end do - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, momxe - if (model_eqns /= 4) then - qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) & - /rho_K - dyn_pres_K = dyn_pres_K + 5.e-1_wp*qK_cons_vf(i)%sf(j, k, l) & - *qK_prim_vf(i)%sf(j, k, l) + $:GPU_LOOP(parallelism='[seq]') + do i = chemxb, chemxe + qK_prim_vf(i)%sf(j, k, l) = max(0._wp, qK_cons_vf(i)%sf(j, k, l)/rho_K) + end do else - qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) & - /qK_cons_vf(1)%sf(j, k, l) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) + end do end if - end do - if (chemistry) then +#ifdef MFC_SIMULATION + rho_K = max(rho_K, sgm_eps) +#endif + $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_species - rhoYks(i) = qK_cons_vf(chemxb + i - 1)%sf(j, k, l) + do i = momxb, momxe + if (model_eqns /= 4) then + qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) & + /rho_K + dyn_pres_K = dyn_pres_K + 5.e-1_wp*qK_cons_vf(i)%sf(j, k, l) & + *qK_prim_vf(i)%sf(j, k, l) + else + qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) & + /qK_cons_vf(1)%sf(j, k, l) + end if end do - T = q_T_sf%sf(j, k, l) - end if + if (chemistry) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_species + rhoYks(i) = qK_cons_vf(chemxb + i - 1)%sf(j, k, l) + end do - if (mhd) then - if (n == 0) then - pres_mag = 0.5_wp*(Bx0**2 + qK_cons_vf(B_idx%beg)%sf(j, k, l)**2 + qK_cons_vf(B_idx%beg + 1)%sf(j, k, l)**2) + T = q_T_sf%sf(j, k, l) + end if + + if (mhd) then + if (n == 0) then + pres_mag = 0.5_wp*(Bx0**2 + qK_cons_vf(B_idx%beg)%sf(j, k, l)**2 + qK_cons_vf(B_idx%beg + 1)%sf(j, k, l)**2) + else + pres_mag = 0.5_wp*(qK_cons_vf(B_idx%beg)%sf(j, k, l)**2 + qK_cons_vf(B_idx%beg + 1)%sf(j, k, l)**2 + qK_cons_vf(B_idx%beg + 2)%sf(j, k, l)**2) + end if else - pres_mag = 0.5_wp*(qK_cons_vf(B_idx%beg)%sf(j, k, l)**2 + qK_cons_vf(B_idx%beg + 1)%sf(j, k, l)**2 + qK_cons_vf(B_idx%beg + 2)%sf(j, k, l)**2) + pres_mag = 0._wp end if - else - pres_mag = 0._wp - end if - call s_compute_pressure(qK_cons_vf(E_idx)%sf(j, k, l), & - qK_cons_vf(alf_idx)%sf(j, k, l), & - dyn_pres_K, pi_inf_K, gamma_K, rho_K, & - qv_K, rhoYks, pres, T, pres_mag=pres_mag) + call s_compute_pressure(qK_cons_vf(E_idx)%sf(j, k, l), & + qK_cons_vf(alf_idx)%sf(j, k, l), & + dyn_pres_K, pi_inf_K, gamma_K, rho_K, & + qv_K, rhoYks, pres, T, pres_mag=pres_mag) - qK_prim_vf(E_idx)%sf(j, k, l) = pres + qK_prim_vf(E_idx)%sf(j, k, l) = pres - if (chemistry) then - q_T_sf%sf(j, k, l) = T - end if + if (chemistry) then + q_T_sf%sf(j, k, l) = T + end if - if (bubbles_euler) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, nb - nRtmp(i) = qK_cons_vf(bubrs(i))%sf(j, k, l) - end do + if (bubbles_euler) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, nb + nRtmp(i) = qK_cons_vf(bubrs(i))%sf(j, k, l) + end do - vftmp = qK_cons_vf(alf_idx)%sf(j, k, l) + vftmp = qK_cons_vf(alf_idx)%sf(j, k, l) - if (qbmm) then - !Get nb (constant across all R0 bins) - nbub_sc = qK_cons_vf(bubxb)%sf(j, k, l) + if (qbmm) then + !Get nb (constant across all R0 bins) + nbub_sc = qK_cons_vf(bubxb)%sf(j, k, l) - !Convert cons to prim - $:GPU_LOOP(parallelism='[seq]') - do i = bubxb, bubxe - qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l)/nbub_sc - end do - !Need to keep track of nb in the primitive variable list (converted back to true value before output) + !Convert cons to prim + $:GPU_LOOP(parallelism='[seq]') + do i = bubxb, bubxe + qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l)/nbub_sc + end do + !Need to keep track of nb in the primitive variable list (converted back to true value before output) #ifdef MFC_SIMULATION - qK_prim_vf(bubxb)%sf(j, k, l) = qK_cons_vf(bubxb)%sf(j, k, l) + qK_prim_vf(bubxb)%sf(j, k, l) = qK_cons_vf(bubxb)%sf(j, k, l) #endif - else - if (adv_n) then - qK_prim_vf(n_idx)%sf(j, k, l) = qK_cons_vf(n_idx)%sf(j, k, l) - nbub_sc = qK_prim_vf(n_idx)%sf(j, k, l) else - call s_comp_n_from_cons(vftmp, nRtmp, nbub_sc, weight) + if (adv_n) then + qK_prim_vf(n_idx)%sf(j, k, l) = qK_cons_vf(n_idx)%sf(j, k, l) + nbub_sc = qK_prim_vf(n_idx)%sf(j, k, l) + else + call s_comp_n_from_cons(vftmp, nRtmp, nbub_sc, weight) + end if + + $:GPU_LOOP(parallelism='[seq]') + do i = bubxb, bubxe + qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l)/nbub_sc + end do end if + end if + if (mhd) then $:GPU_LOOP(parallelism='[seq]') - do i = bubxb, bubxe - qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l)/nbub_sc + do i = B_idx%beg, B_idx%end + qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) end do end if - end if - - if (mhd) then - $:GPU_LOOP(parallelism='[seq]') - do i = B_idx%beg, B_idx%end - qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) - end do - end if - if (elasticity) then - $:GPU_LOOP(parallelism='[seq]') - do i = strxb, strxe - qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l)/rho_K - end do - end if + if (elasticity) then + $:GPU_LOOP(parallelism='[seq]') + do i = strxb, strxe + qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l)/rho_K + end do + end if - if (hypoelasticity) then - $:GPU_LOOP(parallelism='[seq]') - do i = strxb, strxe - ! subtracting elastic contribution for pressure calculation - if (G_K > verysmall) then - if (cont_damage) G_K = G_K*max((1._wp - qK_cons_vf(damage_idx)%sf(j, k, l)), 0._wp) - qK_prim_vf(E_idx)%sf(j, k, l) = qK_prim_vf(E_idx)%sf(j, k, l) - & - ((qK_prim_vf(i)%sf(j, k, l)**2._wp)/(4._wp*G_K))/gamma_K - ! Double for shear stresses - if (any(i == shear_indices)) then + if (hypoelasticity) then + $:GPU_LOOP(parallelism='[seq]') + do i = strxb, strxe + ! subtracting elastic contribution for pressure calculation + if (G_K > verysmall) then + if (cont_damage) G_K = G_K*max((1._wp - qK_cons_vf(damage_idx)%sf(j, k, l)), 0._wp) qK_prim_vf(E_idx)%sf(j, k, l) = qK_prim_vf(E_idx)%sf(j, k, l) - & ((qK_prim_vf(i)%sf(j, k, l)**2._wp)/(4._wp*G_K))/gamma_K + ! Double for shear stresses + if (any(i == shear_indices)) then + qK_prim_vf(E_idx)%sf(j, k, l) = qK_prim_vf(E_idx)%sf(j, k, l) - & + ((qK_prim_vf(i)%sf(j, k, l)**2._wp)/(4._wp*G_K))/gamma_K + end if end if - end if - end do - end if + end do + end if + + if (hyperelasticity) then + $:GPU_LOOP(parallelism='[seq]') + do i = xibeg, xiend + qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l)/rho_K + end do + end if - if (hyperelasticity) then $:GPU_LOOP(parallelism='[seq]') - do i = xibeg, xiend - qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l)/rho_K + do i = advxb, advxe + qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) end do - end if - - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - qK_prim_vf(i)%sf(j, k, l) = qK_cons_vf(i)%sf(j, k, l) - end do - if (surface_tension) then - qK_prim_vf(c_idx)%sf(j, k, l) = qK_cons_vf(c_idx)%sf(j, k, l) - end if + if (surface_tension) then + qK_prim_vf(c_idx)%sf(j, k, l) = qK_cons_vf(c_idx)%sf(j, k, l) + end if - if (cont_damage) qK_prim_vf(damage_idx)%sf(j, k, l) = qK_cons_vf(damage_idx)%sf(j, k, l) + if (cont_damage) qK_prim_vf(damage_idx)%sf(j, k, l) = qK_cons_vf(damage_idx)%sf(j, k, l) #ifdef MFC_POST_PROCESS - if (bubbles_lagrange) qK_prim_vf(beta_idx)%sf(j, k, l) = qK_cons_vf(beta_idx)%sf(j, k, l) + if (bubbles_lagrange) qK_prim_vf(beta_idx)%sf(j, k, l) = qK_cons_vf(beta_idx)%sf(j, k, l) #endif + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_convert_conservative_to_primitive_variables @@ -1489,111 +1489,111 @@ contains ! accounting for the contribution of either viscosity or capillarity #ifdef MFC_SIMULATION #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_K, vel_K, alpha_K, Re_K, Y_K]') - do l = is3b, is3e - do k = is2b, is2e - do j = is1b, is1e - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - alpha_rho_K(i) = qK_prim_vf(j, k, l, i) - end do - - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - alpha_K(i - E_idx) = qK_prim_vf(j, k, l, i) - end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_vels - vel_K(i) = qK_prim_vf(j, k, l, contxe + i) - end do + do l = is3b, is3e + do k = is2b, is2e + do j = is1b, is1e - vel_K_sum = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_vels - vel_K_sum = vel_K_sum + vel_K(i)**2._wp - end do - - pres_K = qK_prim_vf(j, k, l, E_idx) - if (elasticity) then - call s_convert_species_to_mixture_variables_acc(rho_K, gamma_K, pi_inf_K, qv_K, & - alpha_K, alpha_rho_K, Re_K, & - G_K, Gs) - else if (bubbles_euler) then - call s_convert_species_to_mixture_variables_bubbles_acc(rho_K, gamma_K, & - pi_inf_K, qv_K, alpha_K, alpha_rho_K, Re_K) - else - call s_convert_species_to_mixture_variables_acc(rho_K, gamma_K, pi_inf_K, qv_K, & - alpha_K, alpha_rho_K, Re_K) - end if + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + alpha_rho_K(i) = qK_prim_vf(j, k, l, i) + end do - ! Computing the energy from the pressure + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + alpha_K(i - E_idx) = qK_prim_vf(j, k, l, i) + end do + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_vels + vel_K(i) = qK_prim_vf(j, k, l, contxe + i) + end do - if (chemistry) then + vel_K_sum = 0._wp $:GPU_LOOP(parallelism='[seq]') - do i = chemxb, chemxe - Y_K(i - chemxb + 1) = qK_prim_vf(j, k, l, i) + do i = 1, num_vels + vel_K_sum = vel_K_sum + vel_K(i)**2._wp end do - !Computing the energy from the internal energy of the mixture - call get_mixture_molecular_weight(Y_k, mix_mol_weight) - R_gas = gas_constant/mix_mol_weight - T_K = pres_K/rho_K/R_gas - call get_mixture_energy_mass(T_K, Y_K, E_K) - E_K = rho_K*E_K + 5.e-1_wp*rho_K*vel_K_sum - else - ! Computing the energy from the pressure - E_K = gamma_K*pres_K + pi_inf_K & - + 5.e-1_wp*rho_K*vel_K_sum + qv_K - end if - ! mass flux, this should be \alpha_i \rho_i u_i - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - FK_vf(j, k, l, i) = alpha_rho_K(i)*vel_K(dir_idx(1)) - end do + pres_K = qK_prim_vf(j, k, l, E_idx) + if (elasticity) then + call s_convert_species_to_mixture_variables_acc(rho_K, gamma_K, pi_inf_K, qv_K, & + alpha_K, alpha_rho_K, Re_K, & + G_K, Gs) + else if (bubbles_euler) then + call s_convert_species_to_mixture_variables_bubbles_acc(rho_K, gamma_K, & + pi_inf_K, qv_K, alpha_K, alpha_rho_K, Re_K) + else + call s_convert_species_to_mixture_variables_acc(rho_K, gamma_K, pi_inf_K, qv_K, & + alpha_K, alpha_rho_K, Re_K) + end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_vels - FK_vf(j, k, l, contxe + dir_idx(i)) = & - rho_K*vel_K(dir_idx(1)) & - *vel_K(dir_idx(i)) & - + pres_K*dir_flg(dir_idx(i)) - end do + ! Computing the energy from the pressure - ! energy flux, u(E+p) - FK_vf(j, k, l, E_idx) = vel_K(dir_idx(1))*(E_K + pres_K) + if (chemistry) then + $:GPU_LOOP(parallelism='[seq]') + do i = chemxb, chemxe + Y_K(i - chemxb + 1) = qK_prim_vf(j, k, l, i) + end do + !Computing the energy from the internal energy of the mixture + call get_mixture_molecular_weight(Y_k, mix_mol_weight) + R_gas = gas_constant/mix_mol_weight + T_K = pres_K/rho_K/R_gas + call get_mixture_energy_mass(T_K, Y_K, E_K) + E_K = rho_K*E_K + 5.e-1_wp*rho_K*vel_K_sum + else + ! Computing the energy from the pressure + E_K = gamma_K*pres_K + pi_inf_K & + + 5.e-1_wp*rho_K*vel_K_sum + qv_K + end if - ! Species advection Flux, \rho*u*Y - if (chemistry) then + ! mass flux, this should be \alpha_i \rho_i u_i $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_species - FK_vf(j, k, l, i - 1 + chemxb) = vel_K(dir_idx(1))*(rho_K*Y_K(i)) + do i = 1, contxe + FK_vf(j, k, l, i) = alpha_rho_K(i)*vel_K(dir_idx(1)) end do - end if - if (riemann_solver == 1 .or. riemann_solver == 4) then $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - FK_vf(j, k, l, i) = 0._wp - FK_src_vf(j, k, l, i) = alpha_K(i - E_idx) + do i = 1, num_vels + FK_vf(j, k, l, contxe + dir_idx(i)) = & + rho_K*vel_K(dir_idx(1)) & + *vel_K(dir_idx(i)) & + + pres_K*dir_flg(dir_idx(i)) end do - else - ! Could be bubbles_euler! - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - FK_vf(j, k, l, i) = vel_K(dir_idx(1))*alpha_K(i - E_idx) - end do + ! energy flux, u(E+p) + FK_vf(j, k, l, E_idx) = vel_K(dir_idx(1))*(E_K + pres_K) - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - FK_src_vf(j, k, l, i) = vel_K(dir_idx(1)) - end do + ! Species advection Flux, \rho*u*Y + if (chemistry) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_species + FK_vf(j, k, l, i - 1 + chemxb) = vel_K(dir_idx(1))*(rho_K*Y_K(i)) + end do + end if - end if + if (riemann_solver == 1 .or. riemann_solver == 4) then + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + FK_vf(j, k, l, i) = 0._wp + FK_src_vf(j, k, l, i) = alpha_K(i - E_idx) + end do + + else + ! Could be bubbles_euler! + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + FK_vf(j, k, l, i) = vel_K(dir_idx(1))*alpha_K(i - E_idx) + end do + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + FK_src_vf(j, k, l, i) = vel_K(dir_idx(1)) + end do + + end if + + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #endif end subroutine s_convert_primitive_to_flux_variables diff --git a/src/simulation/m_acoustic_src.fpp b/src/simulation/m_acoustic_src.fpp index fe03b073d7..8b2efa6bcf 100644 --- a/src/simulation/m_acoustic_src.fpp +++ b/src/simulation/m_acoustic_src.fpp @@ -167,17 +167,17 @@ contains sim_time = t_step*dt #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - mass_src(j, k, l) = 0._wp - mom_src(1, j, k, l) = 0._wp - e_src(j, k, l) = 0._wp - if (n > 0) mom_src(2, j, k, l) = 0._wp - if (p > 0) mom_src(3, j, k, l) = 0._wp + do l = 0, p + do k = 0, n + do j = 0, m + mass_src(j, k, l) = 0._wp + mom_src(1, j, k, l) = 0._wp + e_src(j, k, l) = 0._wp + if (n > 0) mom_src(2, j, k, l) = 0._wp + if (p > 0) mom_src(3, j, k, l) = 0._wp + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP ! Keep outer loop sequel because different sources can have very different number of points @@ -222,122 +222,122 @@ contains deallocate (phi_rn) #:call GPU_PARALLEL_LOOP(private='[myalpha,myalpha_rho]') - do i = 1, num_points - j = source_spatials(ai)%coord(1, i) - k = source_spatials(ai)%coord(2, i) - l = source_spatials(ai)%coord(3, i) - - ! Compute speed of sound - myRho = 0._wp - B_tait = 0._wp - small_gamma = 0._wp - - $:GPU_LOOP(parallelism='[seq]') - do q = 1, num_fluids - myalpha_rho(q) = q_cons_vf(q)%sf(j, k, l) - myalpha(q) = q_cons_vf(advxb + q - 1)%sf(j, k, l) - end do + do i = 1, num_points + j = source_spatials(ai)%coord(1, i) + k = source_spatials(ai)%coord(2, i) + l = source_spatials(ai)%coord(3, i) + + ! Compute speed of sound + myRho = 0._wp + B_tait = 0._wp + small_gamma = 0._wp + + $:GPU_LOOP(parallelism='[seq]') + do q = 1, num_fluids + myalpha_rho(q) = q_cons_vf(q)%sf(j, k, l) + myalpha(q) = q_cons_vf(advxb + q - 1)%sf(j, k, l) + end do - if (bubbles_euler) then - if (num_fluids > 2) then + if (bubbles_euler) then + if (num_fluids > 2) then + $:GPU_LOOP(parallelism='[seq]') + do q = 1, num_fluids - 1 + myRho = myRho + myalpha_rho(q) + B_tait = B_tait + myalpha(q)*pi_infs(q) + small_gamma = small_gamma + myalpha(q)*gammas(q) + end do + else + myRho = myalpha_rho(1) + B_tait = pi_infs(1) + small_gamma = gammas(1) + end if + end if + + if ((.not. bubbles_euler) .or. (mpp_lim .and. (num_fluids > 2))) then $:GPU_LOOP(parallelism='[seq]') - do q = 1, num_fluids - 1 + do q = 1, num_fluids myRho = myRho + myalpha_rho(q) B_tait = B_tait + myalpha(q)*pi_infs(q) small_gamma = small_gamma + myalpha(q)*gammas(q) end do - else - myRho = myalpha_rho(1) - B_tait = pi_infs(1) - small_gamma = gammas(1) end if - end if - if ((.not. bubbles_euler) .or. (mpp_lim .and. (num_fluids > 2))) then - $:GPU_LOOP(parallelism='[seq]') - do q = 1, num_fluids - myRho = myRho + myalpha_rho(q) - B_tait = B_tait + myalpha(q)*pi_infs(q) - small_gamma = small_gamma + myalpha(q)*gammas(q) - end do - end if + small_gamma = 1._wp/small_gamma + 1._wp + c = sqrt(small_gamma*(q_prim_vf(E_idx)%sf(j, k, l) + ((small_gamma - 1._wp)/small_gamma)*B_tait)/myRho) - small_gamma = 1._wp/small_gamma + 1._wp - c = sqrt(small_gamma*(q_prim_vf(E_idx)%sf(j, k, l) + ((small_gamma - 1._wp)/small_gamma)*B_tait)/myRho) + ! Wavelength to frequency conversion + if (pulse(ai) == 1 .or. pulse(ai) == 3) frequency_local = f_frequency_local(freq_conv_flag, ai, c) + if (pulse(ai) == 2) gauss_sigma_time_local = f_gauss_sigma_time_local(gauss_conv_flag, ai, c) - ! Wavelength to frequency conversion - if (pulse(ai) == 1 .or. pulse(ai) == 3) frequency_local = f_frequency_local(freq_conv_flag, ai, c) - if (pulse(ai) == 2) gauss_sigma_time_local = f_gauss_sigma_time_local(gauss_conv_flag, ai, c) + ! Update momentum source term + call s_source_temporal(sim_time, c, ai, mom_label, frequency_local, gauss_sigma_time_local, source_temporal, sum_BB) + mom_src_diff = source_temporal*source_spatials(ai)%val(i) - ! Update momentum source term - call s_source_temporal(sim_time, c, ai, mom_label, frequency_local, gauss_sigma_time_local, source_temporal, sum_BB) - mom_src_diff = source_temporal*source_spatials(ai)%val(i) + if (dipole(ai)) then ! Double amplitude & No momentum source term (only works for Planar) + mass_src(j, k, l) = mass_src(j, k, l) + 2._wp*mom_src_diff/c + if (model_eqns /= 4) E_src(j, k, l) = E_src(j, k, l) + 2._wp*mom_src_diff*c/(small_gamma - 1._wp) + cycle + end if - if (dipole(ai)) then ! Double amplitude & No momentum source term (only works for Planar) - mass_src(j, k, l) = mass_src(j, k, l) + 2._wp*mom_src_diff/c - if (model_eqns /= 4) E_src(j, k, l) = E_src(j, k, l) + 2._wp*mom_src_diff*c/(small_gamma - 1._wp) - cycle - end if + if (n == 0) then ! 1D + mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*sign(1._wp, dir(ai)) ! Left or right-going wave - if (n == 0) then ! 1D - mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*sign(1._wp, dir(ai)) ! Left or right-going wave + elseif (p == 0) then ! 2D + if (support(ai) < 5) then ! Planar + mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(dir(ai)) + mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(dir(ai)) + else + mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(source_spatials(ai)%angle(i)) + mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(source_spatials(ai)%angle(i)) + end if - elseif (p == 0) then ! 2D - if (support(ai) < 5) then ! Planar - mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(dir(ai)) - mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(dir(ai)) - else - mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(source_spatials(ai)%angle(i)) - mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(source_spatials(ai)%angle(i)) + else ! 3D + if (support(ai) < 5) then ! Planar + mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(dir(ai)) + mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(dir(ai)) + else + mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(1, i) + mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(2, i) + mom_src(3, j, k, l) = mom_src(3, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(3, i) + end if end if - else ! 3D + ! Update mass source term if (support(ai) < 5) then ! Planar - mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(dir(ai)) - mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(dir(ai)) - else - mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(1, i) - mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(2, i) - mom_src(3, j, k, l) = mom_src(3, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(3, i) + mass_src_diff = mom_src_diff/c + else ! Spherical or cylindrical support + ! Mass source term must be calculated differently using a correction term for spherical and cylindrical support + call s_source_temporal(sim_time, c, ai, mass_label, frequency_local, gauss_sigma_time_local, source_temporal, sum_BB) + mass_src_diff = source_temporal*source_spatials(ai)%val(i) end if - end if - - ! Update mass source term - if (support(ai) < 5) then ! Planar - mass_src_diff = mom_src_diff/c - else ! Spherical or cylindrical support - ! Mass source term must be calculated differently using a correction term for spherical and cylindrical support - call s_source_temporal(sim_time, c, ai, mass_label, frequency_local, gauss_sigma_time_local, source_temporal, sum_BB) - mass_src_diff = source_temporal*source_spatials(ai)%val(i) - end if - mass_src(j, k, l) = mass_src(j, k, l) + mass_src_diff + mass_src(j, k, l) = mass_src(j, k, l) + mass_src_diff - ! Update energy source term - if (model_eqns /= 4) then - E_src(j, k, l) = E_src(j, k, l) + mass_src_diff*c**2._wp/(small_gamma - 1._wp) - end if + ! Update energy source term + if (model_eqns /= 4) then + E_src(j, k, l) = E_src(j, k, l) + mass_src_diff*c**2._wp/(small_gamma - 1._wp) + end if - end do + end do #:endcall GPU_PARALLEL_LOOP end do ! Update the rhs variables #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do q = contxb, contxe - rhs_vf(q)%sf(j, k, l) = rhs_vf(q)%sf(j, k, l) + mass_src(j, k, l) - end do - $:GPU_LOOP(parallelism='[seq]') - do q = momxb, momxe - rhs_vf(q)%sf(j, k, l) = rhs_vf(q)%sf(j, k, l) + mom_src(q - contxe, j, k, l) + do l = 0, p + do k = 0, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do q = contxb, contxe + rhs_vf(q)%sf(j, k, l) = rhs_vf(q)%sf(j, k, l) + mass_src(j, k, l) + end do + $:GPU_LOOP(parallelism='[seq]') + do q = momxb, momxe + rhs_vf(q)%sf(j, k, l) = rhs_vf(q)%sf(j, k, l) + mom_src(q - contxe, j, k, l) + end do + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + e_src(j, k, l) end do - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + e_src(j, k, l) end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_acoustic_src_calculations diff --git a/src/simulation/m_body_forces.fpp b/src/simulation/m_body_forces.fpp index 9bf2f5a022..213d9b7fc1 100644 --- a/src/simulation/m_body_forces.fpp +++ b/src/simulation/m_body_forces.fpp @@ -80,17 +80,17 @@ contains integer :: i, j, k, l !< standard iterators #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - rhoM(j, k, l) = 0._wp - do i = 1, num_fluids - rhoM(j, k, l) = rhoM(j, k, l) + & - q_cons_vf(contxb + i - 1)%sf(j, k, l) + do l = 0, p + do k = 0, n + do j = 0, m + rhoM(j, k, l) = 0._wp + do i = 1, num_fluids + rhoM(j, k, l) = rhoM(j, k, l) + & + q_cons_vf(contxb + i - 1)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_mixture_density @@ -111,62 +111,62 @@ contains call s_compute_mixture_density(q_cons_vf) #:call GPU_PARALLEL_LOOP(collapse=4) - do i = momxb, E_idx - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(i)%sf(j, k, l) = 0._wp + do i = momxb, E_idx + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(i)%sf(j, k, l) = 0._wp + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (bf_x) then ! x-direction body forces #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - rhoM(j, k, l)*accel_bf(1) - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - q_cons_vf(momxb)%sf(j, k, l)*accel_bf(1) + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & + rhoM(j, k, l)*accel_bf(1) + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + q_cons_vf(momxb)%sf(j, k, l)*accel_bf(1) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (bf_y) then ! y-direction body forces #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - rhoM(j, k, l)*accel_bf(2) - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - q_cons_vf(momxb + 1)%sf(j, k, l)*accel_bf(2) + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + rhoM(j, k, l)*accel_bf(2) + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + q_cons_vf(momxb + 1)%sf(j, k, l)*accel_bf(2) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (bf_z) then ! z-direction body forces #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(momxe)%sf(j, k, l) = rhs_vf(momxe)%sf(j, k, l) + & - (rhoM(j, k, l))*accel_bf(3) - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - q_cons_vf(momxe)%sf(j, k, l)*accel_bf(3) + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(momxe)%sf(j, k, l) = rhs_vf(momxe)%sf(j, k, l) + & + (rhoM(j, k, l))*accel_bf(3) + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + q_cons_vf(momxe)%sf(j, k, l)*accel_bf(3) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if diff --git a/src/simulation/m_bubbles.fpp b/src/simulation/m_bubbles.fpp index 549c38873c..7c6b84a37f 100644 --- a/src/simulation/m_bubbles.fpp +++ b/src/simulation/m_bubbles.fpp @@ -462,9 +462,9 @@ contains !! @param fCson Speed of sound (EL) !! @param adap_dt_stop Fail-safe exit if max iteration count reached subroutine s_advance_step(fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, & - fntait, fBtait, f_bub_adv_src, f_divu, & - bub_id, fmass_v, fmass_n, fbeta_c, & - fbeta_t, fCson, adap_dt_stop) + fntait, fBtait, f_bub_adv_src, f_divu, & + bub_id, fmass_v, fmass_n, fbeta_c, & + fbeta_t, fCson, adap_dt_stop) $:GPU_ROUTINE(function_name='s_advance_step',parallelism='[seq]', & & cray_inline=True) @@ -595,8 +595,8 @@ contains !! @param fCson Speed of sound (EL) !! @param h Time step size subroutine s_initial_substep_h(fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, & - fntait, fBtait, f_bub_adv_src, f_divu, & - fCson, h) + fntait, fBtait, f_bub_adv_src, f_divu, & + fCson, h) $:GPU_ROUTINE(function_name='s_initial_substep_h',parallelism='[seq]', & & cray_inline=True) @@ -677,10 +677,10 @@ contains !! @param myPb_tmp Internal bubble pressure at each stage (EL) !! @param myMv_tmp Mass of vapor in the bubble at each stage (EL) subroutine s_advance_substep(err, fRho, fP, fR, fV, fR0, fpb, fpbdot, alf, & - fntait, fBtait, f_bub_adv_src, f_divu, & - bub_id, fmass_v, fmass_n, fbeta_c, & - fbeta_t, fCson, h, & - myR_tmp, myV_tmp, myPb_tmp, myMv_tmp) + fntait, fBtait, f_bub_adv_src, f_divu, & + bub_id, fmass_v, fmass_n, fbeta_c, & + fbeta_t, fCson, h, & + myR_tmp, myV_tmp, myPb_tmp, myMv_tmp) $:GPU_ROUTINE(function_name='s_advance_substep',parallelism='[seq]', & & cray_inline=True) @@ -779,7 +779,7 @@ contains !! @param fdPbdt_tmp Rate of change of the internal bubble pressure !! @param fdMvdt_tmp Rate of change of the mass of vapor in the bubble elemental subroutine s_advance_EL(fR_tmp, fV_tmp, fPb_tmp, fMv_tmp, bub_id, & - fmass_n, fbeta_c, fbeta_t, fdPbdt_tmp, advance_EL) + fmass_n, fbeta_c, fbeta_t, fdPbdt_tmp, advance_EL) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(IN) :: fR_tmp, fV_tmp, fPb_tmp, fMv_tmp real(wp), intent(IN) :: fmass_n, fbeta_c, fbeta_t diff --git a/src/simulation/m_bubbles_EE.fpp b/src/simulation/m_bubbles_EE.fpp index 3e180d9585..f198d2e78c 100644 --- a/src/simulation/m_bubbles_EE.fpp +++ b/src/simulation/m_bubbles_EE.fpp @@ -77,18 +77,18 @@ contains integer(wp) :: i, j, k, l #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - nR3bar = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, nb - nR3bar = nR3bar + weight(i)*(q_cons_vf(rs(i))%sf(j, k, l))**3._wp + do l = 0, p + do k = 0, n + do j = 0, m + nR3bar = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, nb + nR3bar = nR3bar + weight(i)*(q_cons_vf(rs(i))%sf(j, k, l))**3._wp + end do + q_cons_vf(alf_idx)%sf(j, k, l) = (4._wp*pi*nR3bar)/(3._wp*q_cons_vf(n_idx)%sf(j, k, l)**2._wp) end do - q_cons_vf(alf_idx)%sf(j, k, l) = (4._wp*pi*nR3bar)/(3._wp*q_cons_vf(n_idx)%sf(j, k, l)**2._wp) end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_comp_alpha_from_n @@ -105,48 +105,48 @@ contains if (.not. qbmm) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - divu_in%sf(j, k, l) = 0._wp - divu_in%sf(j, k, l) = & - 5.e-1_wp/dx(j)*(q_prim_vf(contxe + idir)%sf(j + 1, k, l) - & - q_prim_vf(contxe + idir)%sf(j - 1, k, l)) + do l = 0, p + do k = 0, n + do j = 0, m + divu_in%sf(j, k, l) = 0._wp + divu_in%sf(j, k, l) = & + 5.e-1_wp/dx(j)*(q_prim_vf(contxe + idir)%sf(j + 1, k, l) - & + q_prim_vf(contxe + idir)%sf(j - 1, k, l)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if elseif (idir == 2) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - divu_in%sf(j, k, l) = divu_in%sf(j, k, l) + & - 5.e-1_wp/dy(k)*(q_prim_vf(contxe + idir)%sf(j, k + 1, l) - & - q_prim_vf(contxe + idir)%sf(j, k - 1, l)) + do l = 0, p + do k = 0, n + do j = 0, m + divu_in%sf(j, k, l) = divu_in%sf(j, k, l) + & + 5.e-1_wp/dy(k)*(q_prim_vf(contxe + idir)%sf(j, k + 1, l) - & + q_prim_vf(contxe + idir)%sf(j, k - 1, l)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (idir == 3) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - divu_in%sf(j, k, l) = divu_in%sf(j, k, l) + & - 5.e-1_wp/dz(l)*(q_prim_vf(contxe + idir)%sf(j, k, l + 1) - & - q_prim_vf(contxe + idir)%sf(j, k, l - 1)) + do l = 0, p + do k = 0, n + do j = 0, m + divu_in%sf(j, k, l) = divu_in%sf(j, k, l) + & + 5.e-1_wp/dz(l)*(q_prim_vf(contxe + idir)%sf(j, k, l + 1) - & + q_prim_vf(contxe + idir)%sf(j, k, l - 1)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -178,178 +178,178 @@ contains real(wp) :: dmMass_v, dmMass_n, dmBeta_c, dmBeta_t, dmCson #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - bub_adv_src(j, k, l) = 0._wp - - $:GPU_LOOP(parallelism='[seq]') - do q = 1, nb - bub_r_src(j, k, l, q) = 0._wp - bub_v_src(j, k, l, q) = 0._wp - bub_p_src(j, k, l, q) = 0._wp - bub_m_src(j, k, l, q) = 0._wp + do l = 0, p + do k = 0, n + do j = 0, m + bub_adv_src(j, k, l) = 0._wp + + $:GPU_LOOP(parallelism='[seq]') + do q = 1, nb + bub_r_src(j, k, l, q) = 0._wp + bub_v_src(j, k, l, q) = 0._wp + bub_p_src(j, k, l, q) = 0._wp + bub_m_src(j, k, l, q) = 0._wp + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP adap_dt_stop_max = 0 #:call GPU_PARALLEL_LOOP(collapse=3, private='[Rtmp, Vtmp, myalpha_rho, myalpha]', & & reduction='[[adap_dt_stop_max]]', reductionOp='[MAX]', & & copy='[adap_dt_stop_max]') - do l = 0, p - do k = 0, n - do j = 0, m - - if (adv_n) then - nbub = q_prim_vf(n_idx)%sf(j, k, l) - else - $:GPU_LOOP(parallelism='[seq]') - do q = 1, nb - Rtmp(q) = q_prim_vf(rs(q))%sf(j, k, l) - Vtmp(q) = q_prim_vf(vs(q))%sf(j, k, l) - end do + do l = 0, p + do k = 0, n + do j = 0, m - R3 = 0._wp + if (adv_n) then + nbub = q_prim_vf(n_idx)%sf(j, k, l) + else + $:GPU_LOOP(parallelism='[seq]') + do q = 1, nb + Rtmp(q) = q_prim_vf(rs(q))%sf(j, k, l) + Vtmp(q) = q_prim_vf(vs(q))%sf(j, k, l) + end do - $:GPU_LOOP(parallelism='[seq]') - do q = 1, nb - R3 = R3 + weight(q)*Rtmp(q)**3._wp - end do + R3 = 0._wp - nbub = (3._wp/(4._wp*pi))*q_prim_vf(alf_idx)%sf(j, k, l)/R3 - end if + $:GPU_LOOP(parallelism='[seq]') + do q = 1, nb + R3 = R3 + weight(q)*Rtmp(q)**3._wp + end do - if (.not. adap_dt) then - R2Vav = 0._wp + nbub = (3._wp/(4._wp*pi))*q_prim_vf(alf_idx)%sf(j, k, l)/R3 + end if - $:GPU_LOOP(parallelism='[seq]') - do q = 1, nb - R2Vav = R2Vav + weight(q)*Rtmp(q)**2._wp*Vtmp(q) - end do + if (.not. adap_dt) then + R2Vav = 0._wp - bub_adv_src(j, k, l) = 4._wp*pi*nbub*R2Vav - end if + $:GPU_LOOP(parallelism='[seq]') + do q = 1, nb + R2Vav = R2Vav + weight(q)*Rtmp(q)**2._wp*Vtmp(q) + end do - $:GPU_LOOP(parallelism='[seq]') - do q = 1, nb + bub_adv_src(j, k, l) = 4._wp*pi*nbub*R2Vav + end if $:GPU_LOOP(parallelism='[seq]') - do ii = 1, num_fluids - myalpha_rho(ii) = q_cons_vf(ii)%sf(j, k, l) - myalpha(ii) = q_cons_vf(advxb + ii - 1)%sf(j, k, l) - end do - - myRho = 0._wp - n_tait = 0._wp - B_tait = 0._wp + do q = 1, nb - if (mpp_lim .and. (num_fluids > 2)) then $:GPU_LOOP(parallelism='[seq]') do ii = 1, num_fluids - myRho = myRho + myalpha_rho(ii) - n_tait = n_tait + myalpha(ii)*gammas(ii) - B_tait = B_tait + myalpha(ii)*pi_infs(ii) - end do - else if (num_fluids > 2) then - $:GPU_LOOP(parallelism='[seq]') - do ii = 1, num_fluids - 1 - myRho = myRho + myalpha_rho(ii) - n_tait = n_tait + myalpha(ii)*gammas(ii) - B_tait = B_tait + myalpha(ii)*pi_infs(ii) + myalpha_rho(ii) = q_cons_vf(ii)%sf(j, k, l) + myalpha(ii) = q_cons_vf(advxb + ii - 1)%sf(j, k, l) end do - else - myRho = myalpha_rho(1) - n_tait = gammas(1) - B_tait = pi_infs(1)/pi_fac - end if - n_tait = 1._wp/n_tait + 1._wp !make this the usual little 'gamma' - B_tait = B_tait*(n_tait - 1)/n_tait ! make this the usual pi_inf + myRho = 0._wp + n_tait = 0._wp + B_tait = 0._wp + + if (mpp_lim .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do ii = 1, num_fluids + myRho = myRho + myalpha_rho(ii) + n_tait = n_tait + myalpha(ii)*gammas(ii) + B_tait = B_tait + myalpha(ii)*pi_infs(ii) + end do + else if (num_fluids > 2) then + $:GPU_LOOP(parallelism='[seq]') + do ii = 1, num_fluids - 1 + myRho = myRho + myalpha_rho(ii) + n_tait = n_tait + myalpha(ii)*gammas(ii) + B_tait = B_tait + myalpha(ii)*pi_infs(ii) + end do + else + myRho = myalpha_rho(1) + n_tait = gammas(1) + B_tait = pi_infs(1)/pi_fac + end if - myRho = q_prim_vf(1)%sf(j, k, l) - myP = q_prim_vf(E_idx)%sf(j, k, l) - alf = q_prim_vf(alf_idx)%sf(j, k, l) - myR = q_prim_vf(rs(q))%sf(j, k, l) - myV = q_prim_vf(vs(q))%sf(j, k, l) + n_tait = 1._wp/n_tait + 1._wp !make this the usual little 'gamma' + B_tait = B_tait*(n_tait - 1)/n_tait ! make this the usual pi_inf - if (.not. polytropic) then - pb_local = q_prim_vf(ps(q))%sf(j, k, l) - mv_local = q_prim_vf(ms(q))%sf(j, k, l) - call s_bwproperty(pb_local, q, chi_vw, k_mw, rho_mw) - call s_vflux(myR, myV, pb_local, mv_local, q, vflux) - pbdot = f_bpres_dot(vflux, myR, myV, pb_local, mv_local, q) + myRho = q_prim_vf(1)%sf(j, k, l) + myP = q_prim_vf(E_idx)%sf(j, k, l) + alf = q_prim_vf(alf_idx)%sf(j, k, l) + myR = q_prim_vf(rs(q))%sf(j, k, l) + myV = q_prim_vf(vs(q))%sf(j, k, l) - bub_p_src(j, k, l, q) = nbub*pbdot - bub_m_src(j, k, l, q) = nbub*vflux*4._wp*pi*(myR**2._wp) - else - pb_local = 0._wp; mv_local = 0._wp; vflux = 0._wp; pbdot = 0._wp - end if + if (.not. polytropic) then + pb_local = q_prim_vf(ps(q))%sf(j, k, l) + mv_local = q_prim_vf(ms(q))%sf(j, k, l) + call s_bwproperty(pb_local, q, chi_vw, k_mw, rho_mw) + call s_vflux(myR, myV, pb_local, mv_local, q, vflux) + pbdot = f_bpres_dot(vflux, myR, myV, pb_local, mv_local, q) + + bub_p_src(j, k, l, q) = nbub*pbdot + bub_m_src(j, k, l, q) = nbub*vflux*4._wp*pi*(myR**2._wp) + else + pb_local = 0._wp; mv_local = 0._wp; vflux = 0._wp; pbdot = 0._wp + end if - ! Adaptive time stepping - adap_dt_stop = 0 + ! Adaptive time stepping + adap_dt_stop = 0 - if (adap_dt) then + if (adap_dt) then - call s_advance_step(myRho, myP, myR, myV, R0(q), & - pb_local, pbdot, alf, n_tait, B_tait, & - bub_adv_src(j, k, l), divu_in%sf(j, k, l), & - dmBub_id, dmMass_v, dmMass_n, dmBeta_c, & - dmBeta_t, dmCson, adap_dt_stop) + call s_advance_step(myRho, myP, myR, myV, R0(q), & + pb_local, pbdot, alf, n_tait, B_tait, & + bub_adv_src(j, k, l), divu_in%sf(j, k, l), & + dmBub_id, dmMass_v, dmMass_n, dmBeta_c, & + dmBeta_t, dmCson, adap_dt_stop) - q_cons_vf(rs(q))%sf(j, k, l) = nbub*myR - q_cons_vf(vs(q))%sf(j, k, l) = nbub*myV + q_cons_vf(rs(q))%sf(j, k, l) = nbub*myR + q_cons_vf(vs(q))%sf(j, k, l) = nbub*myV - else - rddot = f_rddot(myRho, myP, myR, myV, R0(q), & - pb_local, pbdot, alf, n_tait, B_tait, & - bub_adv_src(j, k, l), divu_in%sf(j, k, l), & - dmCson) - bub_v_src(j, k, l, q) = nbub*rddot - bub_r_src(j, k, l, q) = q_cons_vf(vs(q))%sf(j, k, l) - end if + else + rddot = f_rddot(myRho, myP, myR, myV, R0(q), & + pb_local, pbdot, alf, n_tait, B_tait, & + bub_adv_src(j, k, l), divu_in%sf(j, k, l), & + dmCson) + bub_v_src(j, k, l, q) = nbub*rddot + bub_r_src(j, k, l, q) = q_cons_vf(vs(q))%sf(j, k, l) + end if - adap_dt_stop_max = max(adap_dt_stop_max, adap_dt_stop) + adap_dt_stop_max = max(adap_dt_stop_max, adap_dt_stop) - if (alf < 1.e-11_wp) then - bub_adv_src(j, k, l) = 0._wp - bub_r_src(j, k, l, q) = 0._wp - bub_v_src(j, k, l, q) = 0._wp - if (.not. polytropic) then - bub_p_src(j, k, l, q) = 0._wp - bub_m_src(j, k, l, q) = 0._wp + if (alf < 1.e-11_wp) then + bub_adv_src(j, k, l) = 0._wp + bub_r_src(j, k, l, q) = 0._wp + bub_v_src(j, k, l, q) = 0._wp + if (.not. polytropic) then + bub_p_src(j, k, l, q) = 0._wp + bub_m_src(j, k, l, q) = 0._wp + end if end if - end if + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (adap_dt .and. adap_dt_stop_max > 0) call s_mpi_abort("Adaptive time stepping failed to converge.") if (.not. adap_dt) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do q = 0, n - do i = 0, m - rhs_vf(alf_idx)%sf(i, q, l) = rhs_vf(alf_idx)%sf(i, q, l) + bub_adv_src(i, q, l) - if (num_fluids > 1) rhs_vf(advxb)%sf(i, q, l) = & - rhs_vf(advxb)%sf(i, q, l) - bub_adv_src(i, q, l) - $:GPU_LOOP(parallelism='[seq]') - do k = 1, nb - rhs_vf(rs(k))%sf(i, q, l) = rhs_vf(rs(k))%sf(i, q, l) + bub_r_src(i, q, l, k) - rhs_vf(vs(k))%sf(i, q, l) = rhs_vf(vs(k))%sf(i, q, l) + bub_v_src(i, q, l, k) - if (polytropic .neqv. .true.) then - rhs_vf(ps(k))%sf(i, q, l) = rhs_vf(ps(k))%sf(i, q, l) + bub_p_src(i, q, l, k) - rhs_vf(ms(k))%sf(i, q, l) = rhs_vf(ms(k))%sf(i, q, l) + bub_m_src(i, q, l, k) - end if + do l = 0, p + do q = 0, n + do i = 0, m + rhs_vf(alf_idx)%sf(i, q, l) = rhs_vf(alf_idx)%sf(i, q, l) + bub_adv_src(i, q, l) + if (num_fluids > 1) rhs_vf(advxb)%sf(i, q, l) = & + rhs_vf(advxb)%sf(i, q, l) - bub_adv_src(i, q, l) + $:GPU_LOOP(parallelism='[seq]') + do k = 1, nb + rhs_vf(rs(k))%sf(i, q, l) = rhs_vf(rs(k))%sf(i, q, l) + bub_r_src(i, q, l, k) + rhs_vf(vs(k))%sf(i, q, l) = rhs_vf(vs(k))%sf(i, q, l) + bub_v_src(i, q, l, k) + if (polytropic .neqv. .true.) then + rhs_vf(ps(k))%sf(i, q, l) = rhs_vf(ps(k))%sf(i, q, l) + bub_p_src(i, q, l, k) + rhs_vf(ms(k))%sf(i, q, l) = rhs_vf(ms(k))%sf(i, q, l) + bub_m_src(i, q, l, k) + end if + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end subroutine s_compute_bubble_EE_source diff --git a/src/simulation/m_bubbles_EL.fpp b/src/simulation/m_bubbles_EL.fpp index 3f4135dec3..9b3beb01a0 100644 --- a/src/simulation/m_bubbles_EL.fpp +++ b/src/simulation/m_bubbles_EL.fpp @@ -530,22 +530,22 @@ contains if (lag_params%pressure_corrector) then ! Calculate velocity potentials (valid for one bubble per cell) #:call GPU_PARALLEL_LOOP(private='[k,cell]') - do k = 1, nBubs - call s_get_pinf(k, q_prim_vf, 2, paux, cell, preterm1, term2, Romega) - myR0 = bub_R0(k) - myR = intfc_rad(k, 2) - myV = intfc_vel(k, 2) - myPb = gas_p(k, 2) - pint = f_cpbw_KM(myR0, myR, myV, myPb) - pint = pint + 0.5_wp*myV**2._wp - if (lag_params%cluster_type == 2) then - bub_dphidt(k) = (paux - pint) + term2 - ! Accounting for the potential induced by the bubble averaged over the control volume - ! Note that this is based on the incompressible flow assumption near the bubble. - term1_fac = 3._wp/2._wp*(myR*(Romega**2._wp - myR**2._wp))/(Romega**3._wp - myR**3._wp) - bub_dphidt(k) = bub_dphidt(k)/(1._wp - term1_fac) - end if - end do + do k = 1, nBubs + call s_get_pinf(k, q_prim_vf, 2, paux, cell, preterm1, term2, Romega) + myR0 = bub_R0(k) + myR = intfc_rad(k, 2) + myV = intfc_vel(k, 2) + myPb = gas_p(k, 2) + pint = f_cpbw_KM(myR0, myR, myV, myPb) + pint = pint + 0.5_wp*myV**2._wp + if (lag_params%cluster_type == 2) then + bub_dphidt(k) = (paux - pint) + term2 + ! Accounting for the potential induced by the bubble averaged over the control volume + ! Note that this is based on the incompressible flow assumption near the bubble. + term1_fac = 3._wp/2._wp*(myR*(Romega**2._wp - myR**2._wp))/(Romega**3._wp - myR**3._wp) + bub_dphidt(k) = bub_dphidt(k)/(1._wp - term1_fac) + end if + end do #:endcall GPU_PARALLEL_LOOP end if @@ -554,81 +554,81 @@ contains #:call GPU_PARALLEL_LOOP(private='[k,myalpha_rho,myalpha,Re,cell]', & & reduction='[[adap_dt_stop_max]]',reductionOp='[MAX]', & & copy='[adap_dt_stop_max]',copyin='[stage]') - do k = 1, nBubs - ! Keller-Miksis model - - ! Current bubble state - myPb = gas_p(k, 2) - myMass_n = gas_mg(k) - myMass_v = gas_mv(k, 2) - myR = intfc_rad(k, 2) - myV = intfc_vel(k, 2) - myBeta_c = gas_betaC(k) - myBeta_t = gas_betaT(k) - myR0 = bub_R0(k) - - ! Vapor and heat fluxes - call s_vflux(myR, myV, myPb, myMass_v, k, myVapFlux, myMass_n, myBeta_c, myR_m, mygamma_m) - myPbdot = f_bpres_dot(myVapFlux, myR, myV, myPb, myMass_v, k, myBeta_t, myR_m, mygamma_m) - myMvdot = 4._wp*pi*myR**2._wp*myVapFlux - - ! Obtaining driving pressure - call s_get_pinf(k, q_prim_vf, 1, myPinf, cell, aux1, aux2) - - ! Obtain liquid density and computing speed of sound from pinf - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - myalpha_rho(i) = q_prim_vf(i)%sf(cell(1), cell(2), cell(3)) - myalpha(i) = q_prim_vf(E_idx + i)%sf(cell(1), cell(2), cell(3)) - end do - call s_convert_species_to_mixture_variables_acc(myRho, gamma, pi_inf, qv, myalpha, & - myalpha_rho, Re) - call s_compute_cson_from_pinf(q_prim_vf, myPinf, cell, myRho, gamma, pi_inf, myCson) + do k = 1, nBubs + ! Keller-Miksis model + + ! Current bubble state + myPb = gas_p(k, 2) + myMass_n = gas_mg(k) + myMass_v = gas_mv(k, 2) + myR = intfc_rad(k, 2) + myV = intfc_vel(k, 2) + myBeta_c = gas_betaC(k) + myBeta_t = gas_betaT(k) + myR0 = bub_R0(k) - ! Adaptive time stepping - adap_dt_stop = 0 + ! Vapor and heat fluxes + call s_vflux(myR, myV, myPb, myMass_v, k, myVapFlux, myMass_n, myBeta_c, myR_m, mygamma_m) + myPbdot = f_bpres_dot(myVapFlux, myR, myV, myPb, myMass_v, k, myBeta_t, myR_m, mygamma_m) + myMvdot = 4._wp*pi*myR**2._wp*myVapFlux - if (adap_dt) then + ! Obtaining driving pressure + call s_get_pinf(k, q_prim_vf, 1, myPinf, cell, aux1, aux2) - call s_advance_step(myRho, myPinf, myR, myV, myR0, myPb, myPbdot, dmalf, & - dmntait, dmBtait, dm_bub_adv_src, dm_divu, & - k, myMass_v, myMass_n, myBeta_c, & - myBeta_t, myCson, adap_dt_stop) + ! Obtain liquid density and computing speed of sound from pinf + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + myalpha_rho(i) = q_prim_vf(i)%sf(cell(1), cell(2), cell(3)) + myalpha(i) = q_prim_vf(E_idx + i)%sf(cell(1), cell(2), cell(3)) + end do + call s_convert_species_to_mixture_variables_acc(myRho, gamma, pi_inf, qv, myalpha, & + myalpha_rho, Re) + call s_compute_cson_from_pinf(q_prim_vf, myPinf, cell, myRho, gamma, pi_inf, myCson) - ! Update bubble state - intfc_rad(k, 1) = myR - intfc_vel(k, 1) = myV - gas_p(k, 1) = myPb - gas_mv(k, 1) = myMass_v + ! Adaptive time stepping + adap_dt_stop = 0 - else + if (adap_dt) then - ! Radial acceleration from bubble models - intfc_dveldt(k, stage) = f_rddot(myRho, myPinf, myR, myV, myR0, & - myPb, myPbdot, dmalf, dmntait, dmBtait, & - dm_bub_adv_src, dm_divu, & - myCson) - intfc_draddt(k, stage) = myV - gas_dmvdt(k, stage) = myMvdot - gas_dpdt(k, stage) = myPbdot + call s_advance_step(myRho, myPinf, myR, myV, myR0, myPb, myPbdot, dmalf, & + dmntait, dmBtait, dm_bub_adv_src, dm_divu, & + k, myMass_v, myMass_n, myBeta_c, & + myBeta_t, myCson, adap_dt_stop) - end if + ! Update bubble state + intfc_rad(k, 1) = myR + intfc_vel(k, 1) = myV + gas_p(k, 1) = myPb + gas_mv(k, 1) = myMass_v + + else - adap_dt_stop_max = max(adap_dt_stop_max, adap_dt_stop) + ! Radial acceleration from bubble models + intfc_dveldt(k, stage) = f_rddot(myRho, myPinf, myR, myV, myR0, & + myPb, myPbdot, dmalf, dmntait, dmBtait, & + dm_bub_adv_src, dm_divu, & + myCson) + intfc_draddt(k, stage) = myV + gas_dmvdt(k, stage) = myMvdot + gas_dpdt(k, stage) = myPbdot - end do + end if + + adap_dt_stop_max = max(adap_dt_stop_max, adap_dt_stop) + + end do #:endcall GPU_PARALLEL_LOOP if (adap_dt .and. adap_dt_stop_max > 0) call s_mpi_abort("Adaptive time stepping failed to converge.") ! Bubbles remain in a fixed position #:call GPU_PARALLEL_LOOP(collapse=2, private='[k]', copyin='[stage]') - do k = 1, nBubs - do l = 1, 3 - mtn_dposdt(k, l, stage) = 0._wp - mtn_dveldt(k, l, stage) = 0._wp + do k = 1, nBubs + do l = 1, 3 + mtn_dposdt(k, l, stage) = 0._wp + mtn_dveldt(k, l, stage) = 0._wp + end do end do - end do #:endcall GPU_PARALLEL_LOOP call nvtxEndRange @@ -654,36 +654,36 @@ contains if (p == 0) then #:call GPU_PARALLEL_LOOP(collapse=4) - do k = 0, p - do j = 0, n - do i = 0, m - do l = 1, E_idx - if (q_beta%vf(1)%sf(i, j, k) > (1._wp - lag_params%valmaxvoid)) then - rhs_vf(l)%sf(i, j, k) = rhs_vf(l)%sf(i, j, k) + & - q_cons_vf(l)%sf(i, j, k)*(q_beta%vf(2)%sf(i, j, k) + & - q_beta%vf(5)%sf(i, j, k)) - - end if + do k = 0, p + do j = 0, n + do i = 0, m + do l = 1, E_idx + if (q_beta%vf(1)%sf(i, j, k) > (1._wp - lag_params%valmaxvoid)) then + rhs_vf(l)%sf(i, j, k) = rhs_vf(l)%sf(i, j, k) + & + q_cons_vf(l)%sf(i, j, k)*(q_beta%vf(2)%sf(i, j, k) + & + q_beta%vf(5)%sf(i, j, k)) + + end if + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else #:call GPU_PARALLEL_LOOP(collapse=4) - do k = 0, p - do j = 0, n - do i = 0, m - do l = 1, E_idx - if (q_beta%vf(1)%sf(i, j, k) > (1._wp - lag_params%valmaxvoid)) then - rhs_vf(l)%sf(i, j, k) = rhs_vf(l)%sf(i, j, k) + & - q_cons_vf(l)%sf(i, j, k)/q_beta%vf(1)%sf(i, j, k)* & - q_beta%vf(2)%sf(i, j, k) - end if + do k = 0, p + do j = 0, n + do i = 0, m + do l = 1, E_idx + if (q_beta%vf(1)%sf(i, j, k) > (1._wp - lag_params%valmaxvoid)) then + rhs_vf(l)%sf(i, j, k) = rhs_vf(l)%sf(i, j, k) + & + q_cons_vf(l)%sf(i, j, k)/q_beta%vf(1)%sf(i, j, k)* & + q_beta%vf(2)%sf(i, j, k) + end if + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -692,45 +692,45 @@ contains call s_gradient_dir(q_prim_vf(E_idx), q_beta%vf(3), l) #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 0, p - do j = 0, n - do i = 0, m - if (q_beta%vf(1)%sf(i, j, k) > (1._wp - lag_params%valmaxvoid)) then - rhs_vf(contxe + l)%sf(i, j, k) = rhs_vf(contxe + l)%sf(i, j, k) - & - (1._wp - q_beta%vf(1)%sf(i, j, k))/ & - q_beta%vf(1)%sf(i, j, k)* & - q_beta%vf(3)%sf(i, j, k) - end if + do k = 0, p + do j = 0, n + do i = 0, m + if (q_beta%vf(1)%sf(i, j, k) > (1._wp - lag_params%valmaxvoid)) then + rhs_vf(contxe + l)%sf(i, j, k) = rhs_vf(contxe + l)%sf(i, j, k) - & + (1._wp - q_beta%vf(1)%sf(i, j, k))/ & + q_beta%vf(1)%sf(i, j, k)* & + q_beta%vf(3)%sf(i, j, k) + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP !source in energy #:call GPU_PARALLEL_LOOP(collapse=3) - do k = idwbuff(3)%beg, idwbuff(3)%end - do j = idwbuff(2)%beg, idwbuff(2)%end - do i = idwbuff(1)%beg, idwbuff(1)%end - q_beta%vf(3)%sf(i, j, k) = q_prim_vf(E_idx)%sf(i, j, k)*q_prim_vf(contxe + l)%sf(i, j, k) + do k = idwbuff(3)%beg, idwbuff(3)%end + do j = idwbuff(2)%beg, idwbuff(2)%end + do i = idwbuff(1)%beg, idwbuff(1)%end + q_beta%vf(3)%sf(i, j, k) = q_prim_vf(E_idx)%sf(i, j, k)*q_prim_vf(contxe + l)%sf(i, j, k) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP call s_gradient_dir(q_beta%vf(3), q_beta%vf(4), l) #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 0, p - do j = 0, n - do i = 0, m - if (q_beta%vf(1)%sf(i, j, k) > (1._wp - lag_params%valmaxvoid)) then - rhs_vf(E_idx)%sf(i, j, k) = rhs_vf(E_idx)%sf(i, j, k) - & - q_beta%vf(4)%sf(i, j, k)*(1._wp - q_beta%vf(1)%sf(i, j, k))/ & - q_beta%vf(1)%sf(i, j, k) - end if + do k = 0, p + do j = 0, n + do i = 0, m + if (q_beta%vf(1)%sf(i, j, k) > (1._wp - lag_params%valmaxvoid)) then + rhs_vf(E_idx)%sf(i, j, k) = rhs_vf(E_idx)%sf(i, j, k) - & + q_beta%vf(4)%sf(i, j, k)*(1._wp - q_beta%vf(1)%sf(i, j, k))/ & + q_beta%vf(1)%sf(i, j, k) + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end do @@ -778,15 +778,15 @@ contains call nvtxStartRange("BUBBLES-LAGRANGE-KERNELS") #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, q_beta_idx - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - q_beta%vf(i)%sf(j, k, l) = 0._wp + do i = 1, q_beta_idx + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + q_beta%vf(i)%sf(j, k, l) = 0._wp + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP call s_smoothfunction(nBubs, intfc_rad, intfc_vel, & @@ -794,16 +794,16 @@ contains !Store 1-beta #:call GPU_PARALLEL_LOOP(collapse=3) - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - q_beta%vf(1)%sf(j, k, l) = 1._wp - q_beta%vf(1)%sf(j, k, l) - ! Limiting void fraction given max value - q_beta%vf(1)%sf(j, k, l) = max(q_beta%vf(1)%sf(j, k, l), & - 1._wp - lag_params%valmaxvoid) + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + q_beta%vf(1)%sf(j, k, l) = 1._wp - q_beta%vf(1)%sf(j, k, l) + ! Limiting void fraction given max value + q_beta%vf(1)%sf(j, k, l) = max(q_beta%vf(1)%sf(j, k, l), & + 1._wp - lag_params%valmaxvoid) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP call nvtxEndRange @@ -1036,15 +1036,15 @@ contains if (time_stepper == 1) then ! 1st order TVD RK #:call GPU_PARALLEL_LOOP(private='[k]') - do k = 1, nBubs - !u{1} = u{n} + dt * RHS{n} - intfc_rad(k, 1) = intfc_rad(k, 1) + dt*intfc_draddt(k, 1) - intfc_vel(k, 1) = intfc_vel(k, 1) + dt*intfc_dveldt(k, 1) - mtn_pos(k, 1:3, 1) = mtn_pos(k, 1:3, 1) + dt*mtn_dposdt(k, 1:3, 1) - mtn_vel(k, 1:3, 1) = mtn_vel(k, 1:3, 1) + dt*mtn_dveldt(k, 1:3, 1) - gas_p(k, 1) = gas_p(k, 1) + dt*gas_dpdt(k, 1) - gas_mv(k, 1) = gas_mv(k, 1) + dt*gas_dmvdt(k, 1) - end do + do k = 1, nBubs + !u{1} = u{n} + dt * RHS{n} + intfc_rad(k, 1) = intfc_rad(k, 1) + dt*intfc_draddt(k, 1) + intfc_vel(k, 1) = intfc_vel(k, 1) + dt*intfc_dveldt(k, 1) + mtn_pos(k, 1:3, 1) = mtn_pos(k, 1:3, 1) + dt*mtn_dposdt(k, 1:3, 1) + mtn_vel(k, 1:3, 1) = mtn_vel(k, 1:3, 1) + dt*mtn_dveldt(k, 1:3, 1) + gas_p(k, 1) = gas_p(k, 1) + dt*gas_dpdt(k, 1) + gas_mv(k, 1) = gas_mv(k, 1) + dt*gas_dmvdt(k, 1) + end do #:endcall GPU_PARALLEL_LOOP call s_transfer_data_to_tmp() @@ -1059,28 +1059,28 @@ contains elseif (time_stepper == 2) then ! 2nd order TVD RK if (stage == 1) then #:call GPU_PARALLEL_LOOP(private='[k]') - do k = 1, nBubs - !u{1} = u{n} + dt * RHS{n} - intfc_rad(k, 2) = intfc_rad(k, 1) + dt*intfc_draddt(k, 1) - intfc_vel(k, 2) = intfc_vel(k, 1) + dt*intfc_dveldt(k, 1) - mtn_pos(k, 1:3, 2) = mtn_pos(k, 1:3, 1) + dt*mtn_dposdt(k, 1:3, 1) - mtn_vel(k, 1:3, 2) = mtn_vel(k, 1:3, 1) + dt*mtn_dveldt(k, 1:3, 1) - gas_p(k, 2) = gas_p(k, 1) + dt*gas_dpdt(k, 1) - gas_mv(k, 2) = gas_mv(k, 1) + dt*gas_dmvdt(k, 1) - end do + do k = 1, nBubs + !u{1} = u{n} + dt * RHS{n} + intfc_rad(k, 2) = intfc_rad(k, 1) + dt*intfc_draddt(k, 1) + intfc_vel(k, 2) = intfc_vel(k, 1) + dt*intfc_dveldt(k, 1) + mtn_pos(k, 1:3, 2) = mtn_pos(k, 1:3, 1) + dt*mtn_dposdt(k, 1:3, 1) + mtn_vel(k, 1:3, 2) = mtn_vel(k, 1:3, 1) + dt*mtn_dveldt(k, 1:3, 1) + gas_p(k, 2) = gas_p(k, 1) + dt*gas_dpdt(k, 1) + gas_mv(k, 2) = gas_mv(k, 1) + dt*gas_dmvdt(k, 1) + end do #:endcall GPU_PARALLEL_LOOP elseif (stage == 2) then #:call GPU_PARALLEL_LOOP(private='[k]') - do k = 1, nBubs - !u{1} = u{n} + (1/2) * dt * (RHS{n} + RHS{1}) - intfc_rad(k, 1) = intfc_rad(k, 1) + dt*(intfc_draddt(k, 1) + intfc_draddt(k, 2))/2._wp - intfc_vel(k, 1) = intfc_vel(k, 1) + dt*(intfc_dveldt(k, 1) + intfc_dveldt(k, 2))/2._wp - mtn_pos(k, 1:3, 1) = mtn_pos(k, 1:3, 1) + dt*(mtn_dposdt(k, 1:3, 1) + mtn_dposdt(k, 1:3, 2))/2._wp - mtn_vel(k, 1:3, 1) = mtn_vel(k, 1:3, 1) + dt*(mtn_dveldt(k, 1:3, 1) + mtn_dveldt(k, 1:3, 2))/2._wp - gas_p(k, 1) = gas_p(k, 1) + dt*(gas_dpdt(k, 1) + gas_dpdt(k, 2))/2._wp - gas_mv(k, 1) = gas_mv(k, 1) + dt*(gas_dmvdt(k, 1) + gas_dmvdt(k, 2))/2._wp - end do + do k = 1, nBubs + !u{1} = u{n} + (1/2) * dt * (RHS{n} + RHS{1}) + intfc_rad(k, 1) = intfc_rad(k, 1) + dt*(intfc_draddt(k, 1) + intfc_draddt(k, 2))/2._wp + intfc_vel(k, 1) = intfc_vel(k, 1) + dt*(intfc_dveldt(k, 1) + intfc_dveldt(k, 2))/2._wp + mtn_pos(k, 1:3, 1) = mtn_pos(k, 1:3, 1) + dt*(mtn_dposdt(k, 1:3, 1) + mtn_dposdt(k, 1:3, 2))/2._wp + mtn_vel(k, 1:3, 1) = mtn_vel(k, 1:3, 1) + dt*(mtn_dveldt(k, 1:3, 1) + mtn_dveldt(k, 1:3, 2))/2._wp + gas_p(k, 1) = gas_p(k, 1) + dt*(gas_dpdt(k, 1) + gas_dpdt(k, 2))/2._wp + gas_mv(k, 1) = gas_mv(k, 1) + dt*(gas_dmvdt(k, 1) + gas_dmvdt(k, 2))/2._wp + end do #:endcall GPU_PARALLEL_LOOP call s_transfer_data_to_tmp() @@ -1097,40 +1097,40 @@ contains elseif (time_stepper == 3) then ! 3rd order TVD RK if (stage == 1) then #:call GPU_PARALLEL_LOOP(private='[k]') - do k = 1, nBubs - !u{1} = u{n} + dt * RHS{n} - intfc_rad(k, 2) = intfc_rad(k, 1) + dt*intfc_draddt(k, 1) - intfc_vel(k, 2) = intfc_vel(k, 1) + dt*intfc_dveldt(k, 1) - mtn_pos(k, 1:3, 2) = mtn_pos(k, 1:3, 1) + dt*mtn_dposdt(k, 1:3, 1) - mtn_vel(k, 1:3, 2) = mtn_vel(k, 1:3, 1) + dt*mtn_dveldt(k, 1:3, 1) - gas_p(k, 2) = gas_p(k, 1) + dt*gas_dpdt(k, 1) - gas_mv(k, 2) = gas_mv(k, 1) + dt*gas_dmvdt(k, 1) - end do + do k = 1, nBubs + !u{1} = u{n} + dt * RHS{n} + intfc_rad(k, 2) = intfc_rad(k, 1) + dt*intfc_draddt(k, 1) + intfc_vel(k, 2) = intfc_vel(k, 1) + dt*intfc_dveldt(k, 1) + mtn_pos(k, 1:3, 2) = mtn_pos(k, 1:3, 1) + dt*mtn_dposdt(k, 1:3, 1) + mtn_vel(k, 1:3, 2) = mtn_vel(k, 1:3, 1) + dt*mtn_dveldt(k, 1:3, 1) + gas_p(k, 2) = gas_p(k, 1) + dt*gas_dpdt(k, 1) + gas_mv(k, 2) = gas_mv(k, 1) + dt*gas_dmvdt(k, 1) + end do #:endcall GPU_PARALLEL_LOOP elseif (stage == 2) then #:call GPU_PARALLEL_LOOP(private='[k]') - do k = 1, nBubs - !u{2} = u{n} + (1/4) * dt * [RHS{n} + RHS{1}] - intfc_rad(k, 2) = intfc_rad(k, 1) + dt*(intfc_draddt(k, 1) + intfc_draddt(k, 2))/4._wp - intfc_vel(k, 2) = intfc_vel(k, 1) + dt*(intfc_dveldt(k, 1) + intfc_dveldt(k, 2))/4._wp - mtn_pos(k, 1:3, 2) = mtn_pos(k, 1:3, 1) + dt*(mtn_dposdt(k, 1:3, 1) + mtn_dposdt(k, 1:3, 2))/4._wp - mtn_vel(k, 1:3, 2) = mtn_vel(k, 1:3, 1) + dt*(mtn_dveldt(k, 1:3, 1) + mtn_dveldt(k, 1:3, 2))/4._wp - gas_p(k, 2) = gas_p(k, 1) + dt*(gas_dpdt(k, 1) + gas_dpdt(k, 2))/4._wp - gas_mv(k, 2) = gas_mv(k, 1) + dt*(gas_dmvdt(k, 1) + gas_dmvdt(k, 2))/4._wp - end do + do k = 1, nBubs + !u{2} = u{n} + (1/4) * dt * [RHS{n} + RHS{1}] + intfc_rad(k, 2) = intfc_rad(k, 1) + dt*(intfc_draddt(k, 1) + intfc_draddt(k, 2))/4._wp + intfc_vel(k, 2) = intfc_vel(k, 1) + dt*(intfc_dveldt(k, 1) + intfc_dveldt(k, 2))/4._wp + mtn_pos(k, 1:3, 2) = mtn_pos(k, 1:3, 1) + dt*(mtn_dposdt(k, 1:3, 1) + mtn_dposdt(k, 1:3, 2))/4._wp + mtn_vel(k, 1:3, 2) = mtn_vel(k, 1:3, 1) + dt*(mtn_dveldt(k, 1:3, 1) + mtn_dveldt(k, 1:3, 2))/4._wp + gas_p(k, 2) = gas_p(k, 1) + dt*(gas_dpdt(k, 1) + gas_dpdt(k, 2))/4._wp + gas_mv(k, 2) = gas_mv(k, 1) + dt*(gas_dmvdt(k, 1) + gas_dmvdt(k, 2))/4._wp + end do #:endcall GPU_PARALLEL_LOOP elseif (stage == 3) then #:call GPU_PARALLEL_LOOP(private='[k]') - do k = 1, nBubs - !u{n+1} = u{n} + (2/3) * dt * [(1/4)* RHS{n} + (1/4)* RHS{1} + RHS{2}] - intfc_rad(k, 1) = intfc_rad(k, 1) + (2._wp/3._wp)*dt*(intfc_draddt(k, 1)/4._wp + intfc_draddt(k, 2)/4._wp + intfc_draddt(k, 3)) - intfc_vel(k, 1) = intfc_vel(k, 1) + (2._wp/3._wp)*dt*(intfc_dveldt(k, 1)/4._wp + intfc_dveldt(k, 2)/4._wp + intfc_dveldt(k, 3)) - mtn_pos(k, 1:3, 1) = mtn_pos(k, 1:3, 1) + (2._wp/3._wp)*dt*(mtn_dposdt(k, 1:3, 1)/4._wp + mtn_dposdt(k, 1:3, 2)/4._wp + mtn_dposdt(k, 1:3, 3)) - mtn_vel(k, 1:3, 1) = mtn_vel(k, 1:3, 1) + (2._wp/3._wp)*dt*(mtn_dveldt(k, 1:3, 1)/4._wp + mtn_dveldt(k, 1:3, 2)/4._wp + mtn_dveldt(k, 1:3, 3)) - gas_p(k, 1) = gas_p(k, 1) + (2._wp/3._wp)*dt*(gas_dpdt(k, 1)/4._wp + gas_dpdt(k, 2)/4._wp + gas_dpdt(k, 3)) - gas_mv(k, 1) = gas_mv(k, 1) + (2._wp/3._wp)*dt*(gas_dmvdt(k, 1)/4._wp + gas_dmvdt(k, 2)/4._wp + gas_dmvdt(k, 3)) - end do + do k = 1, nBubs + !u{n+1} = u{n} + (2/3) * dt * [(1/4)* RHS{n} + (1/4)* RHS{1} + RHS{2}] + intfc_rad(k, 1) = intfc_rad(k, 1) + (2._wp/3._wp)*dt*(intfc_draddt(k, 1)/4._wp + intfc_draddt(k, 2)/4._wp + intfc_draddt(k, 3)) + intfc_vel(k, 1) = intfc_vel(k, 1) + (2._wp/3._wp)*dt*(intfc_dveldt(k, 1)/4._wp + intfc_dveldt(k, 2)/4._wp + intfc_dveldt(k, 3)) + mtn_pos(k, 1:3, 1) = mtn_pos(k, 1:3, 1) + (2._wp/3._wp)*dt*(mtn_dposdt(k, 1:3, 1)/4._wp + mtn_dposdt(k, 1:3, 2)/4._wp + mtn_dposdt(k, 1:3, 3)) + mtn_vel(k, 1:3, 1) = mtn_vel(k, 1:3, 1) + (2._wp/3._wp)*dt*(mtn_dveldt(k, 1:3, 1)/4._wp + mtn_dveldt(k, 1:3, 2)/4._wp + mtn_dveldt(k, 1:3, 3)) + gas_p(k, 1) = gas_p(k, 1) + (2._wp/3._wp)*dt*(gas_dpdt(k, 1)/4._wp + gas_dpdt(k, 2)/4._wp + gas_dpdt(k, 3)) + gas_mv(k, 1) = gas_mv(k, 1) + (2._wp/3._wp)*dt*(gas_dmvdt(k, 1)/4._wp + gas_dmvdt(k, 2)/4._wp + gas_dmvdt(k, 3)) + end do #:endcall GPU_PARALLEL_LOOP call s_transfer_data_to_tmp() @@ -1209,16 +1209,16 @@ contains integer :: k #:call GPU_PARALLEL_LOOP(private='[k]') - do k = 1, nBubs - gas_p(k, 2) = gas_p(k, 1) - gas_mv(k, 2) = gas_mv(k, 1) - intfc_rad(k, 2) = intfc_rad(k, 1) - intfc_vel(k, 2) = intfc_vel(k, 1) - mtn_pos(k, 1:3, 2) = mtn_pos(k, 1:3, 1) - mtn_posPrev(k, 1:3, 2) = mtn_posPrev(k, 1:3, 1) - mtn_vel(k, 1:3, 2) = mtn_vel(k, 1:3, 1) - mtn_s(k, 1:3, 2) = mtn_s(k, 1:3, 1) - end do + do k = 1, nBubs + gas_p(k, 2) = gas_p(k, 1) + gas_mv(k, 2) = gas_mv(k, 1) + intfc_rad(k, 2) = intfc_rad(k, 1) + intfc_vel(k, 2) = intfc_vel(k, 1) + mtn_pos(k, 1:3, 2) = mtn_pos(k, 1:3, 1) + mtn_posPrev(k, 1:3, 2) = mtn_posPrev(k, 1:3, 1) + mtn_vel(k, 1:3, 2) = mtn_vel(k, 1:3, 1) + mtn_s(k, 1:3, 2) = mtn_s(k, 1:3, 1) + end do #:endcall GPU_PARALLEL_LOOP end subroutine s_transfer_data_to_tmp @@ -1309,48 +1309,48 @@ contains if (dir == 1) then ! Gradient in x dir. #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 0, p - do j = 0, n - do i = 0, m - dq%sf(i, j, k) = q%sf(i, j, k)*(dx(i + 1) - dx(i - 1)) & - + q%sf(i + 1, j, k)*(dx(i) + dx(i - 1)) & - - q%sf(i - 1, j, k)*(dx(i) + dx(i + 1)) - dq%sf(i, j, k) = dq%sf(i, j, k)/ & - ((dx(i) + dx(i - 1))*(dx(i) + dx(i + 1))) + do k = 0, p + do j = 0, n + do i = 0, m + dq%sf(i, j, k) = q%sf(i, j, k)*(dx(i + 1) - dx(i - 1)) & + + q%sf(i + 1, j, k)*(dx(i) + dx(i - 1)) & + - q%sf(i - 1, j, k)*(dx(i) + dx(i + 1)) + dq%sf(i, j, k) = dq%sf(i, j, k)/ & + ((dx(i) + dx(i - 1))*(dx(i) + dx(i + 1))) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else if (dir == 2) then ! Gradient in y dir. #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 0, p - do j = 0, n - do i = 0, m - dq%sf(i, j, k) = q%sf(i, j, k)*(dy(j + 1) - dy(j - 1)) & - + q%sf(i, j + 1, k)*(dy(j) + dy(j - 1)) & - - q%sf(i, j - 1, k)*(dy(j) + dy(j + 1)) - dq%sf(i, j, k) = dq%sf(i, j, k)/ & - ((dy(j) + dy(j - 1))*(dy(j) + dy(j + 1))) + do k = 0, p + do j = 0, n + do i = 0, m + dq%sf(i, j, k) = q%sf(i, j, k)*(dy(j + 1) - dy(j - 1)) & + + q%sf(i, j + 1, k)*(dy(j) + dy(j - 1)) & + - q%sf(i, j - 1, k)*(dy(j) + dy(j + 1)) + dq%sf(i, j, k) = dq%sf(i, j, k)/ & + ((dy(j) + dy(j - 1))*(dy(j) + dy(j + 1))) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else ! Gradient in z dir. #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 0, p - do j = 0, n - do i = 0, m - dq%sf(i, j, k) = q%sf(i, j, k)*(dz(k + 1) - dz(k - 1)) & - + q%sf(i, j, k + 1)*(dz(k) + dz(k - 1)) & - - q%sf(i, j, k - 1)*(dz(k) + dz(k + 1)) - dq%sf(i, j, k) = dq%sf(i, j, k)/ & - ((dz(k) + dz(k - 1))*(dz(k) + dz(k + 1))) + do k = 0, p + do j = 0, n + do i = 0, m + dq%sf(i, j, k) = q%sf(i, j, k)*(dz(k + 1) - dz(k - 1)) & + + q%sf(i, j, k + 1)*(dz(k) + dz(k - 1)) & + - q%sf(i, j, k - 1)*(dz(k) + dz(k + 1)) + dq%sf(i, j, k) = dq%sf(i, j, k)/ & + ((dz(k) + dz(k - 1))*(dz(k) + dz(k + 1))) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if @@ -1435,18 +1435,18 @@ contains lag_void_avg = 0._wp lag_vol = 0._wp #:call GPU_PARALLEL_LOOP(collapse=3, reduction='[[lag_vol, lag_void_avg], [lag_void_max]]', reductionOp='[+, MAX]', copy='[lag_vol, lag_void_avg, lag_void_max]') - do k = 0, p - do j = 0, n - do i = 0, m - lag_void_max = max(lag_void_max, 1._wp - q_beta%vf(1)%sf(i, j, k)) - call s_get_char_vol(i, j, k, volcell) - if ((1._wp - q_beta%vf(1)%sf(i, j, k)) > 5.0d-11) then - lag_void_avg = lag_void_avg + (1._wp - q_beta%vf(1)%sf(i, j, k))*volcell - lag_vol = lag_vol + volcell - end if + do k = 0, p + do j = 0, n + do i = 0, m + lag_void_max = max(lag_void_max, 1._wp - q_beta%vf(1)%sf(i, j, k)) + call s_get_char_vol(i, j, k, volcell) + if ((1._wp - q_beta%vf(1)%sf(i, j, k)) > 5.0d-11) then + lag_void_avg = lag_void_avg + (1._wp - q_beta%vf(1)%sf(i, j, k))*volcell + lag_vol = lag_vol + volcell + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #ifdef MFC_MPI @@ -1621,12 +1621,12 @@ contains #:call GPU_PARALLEL_LOOP(reduction='[[Rmax_glb], [Rmin_glb]]', & & reductionOp='[MAX, MIN]', copy='[Rmax_glb,Rmin_glb]') - do k = 1, nBubs - Rmax_glb = max(Rmax_glb, intfc_rad(k, 1)/bub_R0(k)) - Rmin_glb = min(Rmin_glb, intfc_rad(k, 1)/bub_R0(k)) - Rmax_stats(k) = max(Rmax_stats(k), intfc_rad(k, 1)/bub_R0(k)) - Rmin_stats(k) = min(Rmin_stats(k), intfc_rad(k, 1)/bub_R0(k)) - end do + do k = 1, nBubs + Rmax_glb = max(Rmax_glb, intfc_rad(k, 1)/bub_R0(k)) + Rmin_glb = min(Rmin_glb, intfc_rad(k, 1)/bub_R0(k)) + Rmax_stats(k) = max(Rmax_stats(k), intfc_rad(k, 1)/bub_R0(k)) + Rmin_stats(k) = min(Rmin_stats(k), intfc_rad(k, 1)/bub_R0(k)) + end do #:endcall GPU_PARALLEL_LOOP end subroutine s_calculate_lag_bubble_stats diff --git a/src/simulation/m_bubbles_EL_kernels.fpp b/src/simulation/m_bubbles_EL_kernels.fpp index 529b08bfd9..218eaa6ea6 100644 --- a/src/simulation/m_bubbles_EL_kernels.fpp +++ b/src/simulation/m_bubbles_EL_kernels.fpp @@ -56,40 +56,40 @@ contains integer :: l #:call GPU_PARALLEL_LOOP(private='[l,s_coord,cell]') - do l = 1, nBubs + do l = 1, nBubs - volpart = 4._wp/3._wp*pi*lbk_rad(l, 2)**3._wp - s_coord(1:3) = lbk_s(l, 1:3, 2) - call s_get_cell(s_coord, cell) + volpart = 4._wp/3._wp*pi*lbk_rad(l, 2)**3._wp + s_coord(1:3) = lbk_s(l, 1:3, 2) + call s_get_cell(s_coord, cell) - strength_vol = volpart - strength_vel = 4._wp*pi*lbk_rad(l, 2)**2._wp*lbk_vel(l, 2) + strength_vol = volpart + strength_vel = 4._wp*pi*lbk_rad(l, 2)**2._wp*lbk_vel(l, 2) - if (num_dims == 2) then - Vol = dx(cell(1))*dy(cell(2))*lag_params%charwidth - if (cyl_coord) Vol = dx(cell(1))*dy(cell(2))*y_cc(cell(2))*2._wp*pi - else - Vol = dx(cell(1))*dy(cell(2))*dz(cell(3)) - end if + if (num_dims == 2) then + Vol = dx(cell(1))*dy(cell(2))*lag_params%charwidth + if (cyl_coord) Vol = dx(cell(1))*dy(cell(2))*y_cc(cell(2))*2._wp*pi + else + Vol = dx(cell(1))*dy(cell(2))*dz(cell(3)) + end if - !Update void fraction field - addFun1 = strength_vol/Vol - $:GPU_ATOMIC(atomic='update') - updatedvar%vf(1)%sf(cell(1), cell(2), cell(3)) = updatedvar%vf(1)%sf(cell(1), cell(2), cell(3)) + addFun1 - - !Update time derivative of void fraction - addFun2 = strength_vel/Vol - $:GPU_ATOMIC(atomic='update') - updatedvar%vf(2)%sf(cell(1), cell(2), cell(3)) = updatedvar%vf(2)%sf(cell(1), cell(2), cell(3)) + addFun2 + !Update void fraction field + addFun1 = strength_vol/Vol + $:GPU_ATOMIC(atomic='update') + updatedvar%vf(1)%sf(cell(1), cell(2), cell(3)) = updatedvar%vf(1)%sf(cell(1), cell(2), cell(3)) + addFun1 - !Product of two smeared functions - !Update void fraction * time derivative of void fraction - if (lag_params%cluster_type >= 4) then - addFun3 = (strength_vol*strength_vel)/Vol + !Update time derivative of void fraction + addFun2 = strength_vel/Vol $:GPU_ATOMIC(atomic='update') - updatedvar%vf(5)%sf(cell(1), cell(2), cell(3)) = updatedvar%vf(5)%sf(cell(1), cell(2), cell(3)) + addFun3 - end if - end do + updatedvar%vf(2)%sf(cell(1), cell(2), cell(3)) = updatedvar%vf(2)%sf(cell(1), cell(2), cell(3)) + addFun2 + + !Product of two smeared functions + !Update void fraction * time derivative of void fraction + if (lag_params%cluster_type >= 4) then + addFun3 = (strength_vol*strength_vel)/Vol + $:GPU_ATOMIC(atomic='update') + updatedvar%vf(5)%sf(cell(1), cell(2), cell(3)) = updatedvar%vf(5)%sf(cell(1), cell(2), cell(3)) + addFun3 + end if + end do #:endcall GPU_PARALLEL_LOOP end subroutine s_deltafunc @@ -122,80 +122,80 @@ contains if (p == 0) smearGridz = 1 #:call GPU_PARALLEL_LOOP(private='[nodecoord,l,s_coord,cell,center]', copyin='[smearGrid,smearGridz]') - do l = 1, nBubs - nodecoord(1:3) = 0 - center(1:3) = 0._wp - volpart = 4._wp/3._wp*pi*lbk_rad(l, 2)**3._wp - s_coord(1:3) = lbk_s(l, 1:3, 2) - center(1:2) = lbk_pos(l, 1:2, 2) - if (p > 0) center(3) = lbk_pos(l, 3, 2) - call s_get_cell(s_coord, cell) - call s_compute_stddsv(cell, volpart, stddsv) - - strength_vol = volpart - strength_vel = 4._wp*pi*lbk_rad(l, 2)**2._wp*lbk_vel(l, 2) - - $:GPU_LOOP(collapse=3,private='[cellaux,nodecoord]') - do i = 1, smearGrid - do j = 1, smearGrid - do k = 1, smearGridz - cellaux(1) = cell(1) + i - (mapCells + 1) - cellaux(2) = cell(2) + j - (mapCells + 1) - cellaux(3) = cell(3) + k - (mapCells + 1) - if (p == 0) cellaux(3) = 0 - - !Check if the cells intended to smear the bubbles in are in the computational domain - !and redefine the cells for symmetric boundary - call s_check_celloutside(cellaux, celloutside) - - if (.not. celloutside) then - - nodecoord(1) = x_cc(cellaux(1)) - nodecoord(2) = y_cc(cellaux(2)) - if (p > 0) nodecoord(3) = z_cc(cellaux(3)) - call s_applygaussian(center, cellaux, nodecoord, stddsv, 0._wp, func) - if (lag_params%cluster_type >= 4) call s_applygaussian(center, cellaux, nodecoord, stddsv, 1._wp, func2) - - ! Relocate cells for bubbles intersecting symmetric boundaries - if (any((/bc_x%beg, bc_x%end, bc_y%beg, bc_y%end, bc_z%beg, bc_z%end/) == BC_REFLECTIVE)) then - call s_shift_cell_symmetric_bc(cellaux, cell) - end if - else - func = 0._wp - func2 = 0._wp - cellaux(1) = cell(1) - cellaux(2) = cell(2) - cellaux(3) = cell(3) + do l = 1, nBubs + nodecoord(1:3) = 0 + center(1:3) = 0._wp + volpart = 4._wp/3._wp*pi*lbk_rad(l, 2)**3._wp + s_coord(1:3) = lbk_s(l, 1:3, 2) + center(1:2) = lbk_pos(l, 1:2, 2) + if (p > 0) center(3) = lbk_pos(l, 3, 2) + call s_get_cell(s_coord, cell) + call s_compute_stddsv(cell, volpart, stddsv) + + strength_vol = volpart + strength_vel = 4._wp*pi*lbk_rad(l, 2)**2._wp*lbk_vel(l, 2) + + $:GPU_LOOP(collapse=3,private='[cellaux,nodecoord]') + do i = 1, smearGrid + do j = 1, smearGrid + do k = 1, smearGridz + cellaux(1) = cell(1) + i - (mapCells + 1) + cellaux(2) = cell(2) + j - (mapCells + 1) + cellaux(3) = cell(3) + k - (mapCells + 1) if (p == 0) cellaux(3) = 0 - end if - - !Update void fraction field - addFun1 = func*strength_vol - $:GPU_ATOMIC(atomic='update') - updatedvar%vf(1)%sf(cellaux(1), cellaux(2), cellaux(3)) = & - updatedvar%vf(1)%sf(cellaux(1), cellaux(2), cellaux(3)) & - + addFun1 - - !Update time derivative of void fraction - addFun2 = func*strength_vel - $:GPU_ATOMIC(atomic='update') - updatedvar%vf(2)%sf(cellaux(1), cellaux(2), cellaux(3)) = & - updatedvar%vf(2)%sf(cellaux(1), cellaux(2), cellaux(3)) & - + addFun2 - - !Product of two smeared functions - !Update void fraction * time derivative of void fraction - if (lag_params%cluster_type >= 4) then - addFun3 = func2*strength_vol*strength_vel + + !Check if the cells intended to smear the bubbles in are in the computational domain + !and redefine the cells for symmetric boundary + call s_check_celloutside(cellaux, celloutside) + + if (.not. celloutside) then + + nodecoord(1) = x_cc(cellaux(1)) + nodecoord(2) = y_cc(cellaux(2)) + if (p > 0) nodecoord(3) = z_cc(cellaux(3)) + call s_applygaussian(center, cellaux, nodecoord, stddsv, 0._wp, func) + if (lag_params%cluster_type >= 4) call s_applygaussian(center, cellaux, nodecoord, stddsv, 1._wp, func2) + + ! Relocate cells for bubbles intersecting symmetric boundaries + if (any((/bc_x%beg, bc_x%end, bc_y%beg, bc_y%end, bc_z%beg, bc_z%end/) == BC_REFLECTIVE)) then + call s_shift_cell_symmetric_bc(cellaux, cell) + end if + else + func = 0._wp + func2 = 0._wp + cellaux(1) = cell(1) + cellaux(2) = cell(2) + cellaux(3) = cell(3) + if (p == 0) cellaux(3) = 0 + end if + + !Update void fraction field + addFun1 = func*strength_vol $:GPU_ATOMIC(atomic='update') - updatedvar%vf(5)%sf(cellaux(1), cellaux(2), cellaux(3)) = & - updatedvar%vf(5)%sf(cellaux(1), cellaux(2), cellaux(3)) & - + addFun3 - end if + updatedvar%vf(1)%sf(cellaux(1), cellaux(2), cellaux(3)) = & + updatedvar%vf(1)%sf(cellaux(1), cellaux(2), cellaux(3)) & + + addFun1 + + !Update time derivative of void fraction + addFun2 = func*strength_vel + $:GPU_ATOMIC(atomic='update') + updatedvar%vf(2)%sf(cellaux(1), cellaux(2), cellaux(3)) = & + updatedvar%vf(2)%sf(cellaux(1), cellaux(2), cellaux(3)) & + + addFun2 + + !Product of two smeared functions + !Update void fraction * time derivative of void fraction + if (lag_params%cluster_type >= 4) then + addFun3 = func2*strength_vol*strength_vel + $:GPU_ATOMIC(atomic='update') + updatedvar%vf(5)%sf(cellaux(1), cellaux(2), cellaux(3)) = & + updatedvar%vf(5)%sf(cellaux(1), cellaux(2), cellaux(3)) & + + addFun3 + end if + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_gaussian diff --git a/src/simulation/m_cbc.fpp b/src/simulation/m_cbc.fpp index e4682c575d..14d81fdf31 100644 --- a/src/simulation/m_cbc.fpp +++ b/src/simulation/m_cbc.fpp @@ -696,29 +696,29 @@ contains is1, is2, is3, idwbuff(2)%beg, idwbuff(3)%beg) #:call GPU_PARALLEL_LOOP(collapse=3) - do i = 1, flux_cbc_index - do r = is3%beg, is3%end - do k = is2%beg, is2%end - flux_rs${XYZ}$_vf_l(0, k, r, i) = F_rs${XYZ}$_vf(0, k, r, i) & - + pi_coef_${XYZ}$ (0, 0, cbc_loc)* & - (F_rs${XYZ}$_vf(1, k, r, i) - & - F_rs${XYZ}$_vf(0, k, r, i)) + do i = 1, flux_cbc_index + do r = is3%beg, is3%end + do k = is2%beg, is2%end + flux_rs${XYZ}$_vf_l(0, k, r, i) = F_rs${XYZ}$_vf(0, k, r, i) & + + pi_coef_${XYZ}$ (0, 0, cbc_loc)* & + (F_rs${XYZ}$_vf(1, k, r, i) - & + F_rs${XYZ}$_vf(0, k, r, i)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do i = advxb, advxe - do r = is3%beg, is3%end - do k = is2%beg, is2%end - flux_src_rs${XYZ}$_vf_l(0, k, r, i) = F_src_rs${XYZ}$_vf(0, k, r, i) + & - (F_src_rs${XYZ}$_vf(1, k, r, i) - & - F_src_rs${XYZ}$_vf(0, k, r, i)) & - *pi_coef_${XYZ}$ (0, 0, cbc_loc) + do i = advxb, advxe + do r = is3%beg, is3%end + do k = is2%beg, is2%end + flux_src_rs${XYZ}$_vf_l(0, k, r, i) = F_src_rs${XYZ}$_vf(0, k, r, i) + & + (F_src_rs${XYZ}$_vf(1, k, r, i) - & + F_src_rs${XYZ}$_vf(0, k, r, i)) & + *pi_coef_${XYZ}$ (0, 0, cbc_loc) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP ! PI4 of flux_rs_vf and flux_src_rs_vf at j = 1/2, 3/2 @@ -729,381 +729,381 @@ contains is1, is2, is3, idwbuff(2)%beg, idwbuff(3)%beg) #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, flux_cbc_index - do j = 0, 1 - do r = is3%beg, is3%end - do k = is2%beg, is2%end - flux_rs${XYZ}$_vf_l(j, k, r, i) = F_rs${XYZ}$_vf(j, k, r, i) & - + pi_coef_${XYZ}$ (j, 0, cbc_loc)* & - (F_rs${XYZ}$_vf(3, k, r, i) - & - F_rs${XYZ}$_vf(2, k, r, i)) & - + pi_coef_${XYZ}$ (j, 1, cbc_loc)* & - (F_rs${XYZ}$_vf(2, k, r, i) - & - F_rs${XYZ}$_vf(1, k, r, i)) & - + pi_coef_${XYZ}$ (j, 2, cbc_loc)* & - (F_rs${XYZ}$_vf(1, k, r, i) - & - F_rs${XYZ}$_vf(0, k, r, i)) + do i = 1, flux_cbc_index + do j = 0, 1 + do r = is3%beg, is3%end + do k = is2%beg, is2%end + flux_rs${XYZ}$_vf_l(j, k, r, i) = F_rs${XYZ}$_vf(j, k, r, i) & + + pi_coef_${XYZ}$ (j, 0, cbc_loc)* & + (F_rs${XYZ}$_vf(3, k, r, i) - & + F_rs${XYZ}$_vf(2, k, r, i)) & + + pi_coef_${XYZ}$ (j, 1, cbc_loc)* & + (F_rs${XYZ}$_vf(2, k, r, i) - & + F_rs${XYZ}$_vf(1, k, r, i)) & + + pi_coef_${XYZ}$ (j, 2, cbc_loc)* & + (F_rs${XYZ}$_vf(1, k, r, i) - & + F_rs${XYZ}$_vf(0, k, r, i)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=4) - do i = advxb, advxe - do j = 0, 1 - do r = is3%beg, is3%end - do k = is2%beg, is2%end - flux_src_rs${XYZ}$_vf_l(j, k, r, i) = F_src_rs${XYZ}$_vf(j, k, r, i) + & - (F_src_rs${XYZ}$_vf(3, k, r, i) - & - F_src_rs${XYZ}$_vf(2, k, r, i)) & - *pi_coef_${XYZ}$ (j, 0, cbc_loc) + & - (F_src_rs${XYZ}$_vf(2, k, r, i) - & - F_src_rs${XYZ}$_vf(1, k, r, i)) & - *pi_coef_${XYZ}$ (j, 1, cbc_loc) + & - (F_src_rs${XYZ}$_vf(1, k, r, i) - & - F_src_rs${XYZ}$_vf(0, k, r, i)) & - *pi_coef_${XYZ}$ (j, 2, cbc_loc) + do i = advxb, advxe + do j = 0, 1 + do r = is3%beg, is3%end + do k = is2%beg, is2%end + flux_src_rs${XYZ}$_vf_l(j, k, r, i) = F_src_rs${XYZ}$_vf(j, k, r, i) + & + (F_src_rs${XYZ}$_vf(3, k, r, i) - & + F_src_rs${XYZ}$_vf(2, k, r, i)) & + *pi_coef_${XYZ}$ (j, 0, cbc_loc) + & + (F_src_rs${XYZ}$_vf(2, k, r, i) - & + F_src_rs${XYZ}$_vf(1, k, r, i)) & + *pi_coef_${XYZ}$ (j, 1, cbc_loc) + & + (F_src_rs${XYZ}$_vf(1, k, r, i) - & + F_src_rs${XYZ}$_vf(0, k, r, i)) & + *pi_coef_${XYZ}$ (j, 2, cbc_loc) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if ! FD2 or FD4 of RHS at j = 0 #:call GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, dYs_ds, h_k, Cp_i, Gamma_i, Xs]') - do r = is3%beg, is3%end - do k = is2%beg, is2%end - - ! Transferring the Primitive Variables - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - alpha_rho(i) = q_prim_rs${XYZ}$_vf(0, k, r, i) - end do - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel(i) = q_prim_rs${XYZ}$_vf(0, k, r, contxe + i) - end do - - vel_K_sum = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_K_sum = vel_K_sum + vel(i)**2._wp - end do + do r = is3%beg, is3%end + do k = is2%beg, is2%end - pres = q_prim_rs${XYZ}$_vf(0, k, r, E_idx) + ! Transferring the Primitive Variables + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + alpha_rho(i) = q_prim_rs${XYZ}$_vf(0, k, r, i) + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, advxe - E_idx - adv_local(i) = q_prim_rs${XYZ}$_vf(0, k, r, E_idx + i) - end do + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + vel(i) = q_prim_rs${XYZ}$_vf(0, k, r, contxe + i) + end do - if (bubbles_euler) then - call s_convert_species_to_mixture_variables_bubbles_acc(rho, gamma, pi_inf, qv, adv_local, alpha_rho, Re_cbc) - else - call s_convert_species_to_mixture_variables_acc(rho, gamma, pi_inf, qv, adv_local, alpha_rho, Re_cbc) - end if + vel_K_sum = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + vel_K_sum = vel_K_sum + vel(i)**2._wp + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - mf(i) = alpha_rho(i)/rho - end do + pres = q_prim_rs${XYZ}$_vf(0, k, r, E_idx) - if (chemistry) then $:GPU_LOOP(parallelism='[seq]') - do i = chemxb, chemxe - Ys(i - chemxb + 1) = q_prim_rs${XYZ}$_vf(0, k, r, i) + do i = 1, advxe - E_idx + adv_local(i) = q_prim_rs${XYZ}$_vf(0, k, r, E_idx + i) end do - call get_mixture_molecular_weight(Ys, Mw) - R_gas = gas_constant/Mw - T = pres/rho/R_gas - call get_mixture_specific_heat_cp_mass(T, Ys, Cp) - call get_mixture_energy_mass(T, Ys, e_mix) - E = rho*e_mix + 5.e-1_wp*rho*vel_K_sum - if (chem_params%gamma_method == 1) then - !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. - call get_mole_fractions(Mw, Ys, Xs) - call get_species_specific_heats_r(T, Cp_i) - Gamma_i = Cp_i/(Cp_i - 1.0_wp) - gamma = sum(Xs(:)/(Gamma_i(:) - 1.0_wp)) - else if (chem_params%gamma_method == 2) then - !> gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. - call get_mixture_specific_heat_cv_mass(T, Ys, Cv) - gamma = 1.0_wp/(Cp/Cv - 1.0_wp) + if (bubbles_euler) then + call s_convert_species_to_mixture_variables_bubbles_acc(rho, gamma, pi_inf, qv, adv_local, alpha_rho, Re_cbc) + else + call s_convert_species_to_mixture_variables_acc(rho, gamma, pi_inf, qv, adv_local, alpha_rho, Re_cbc) end if - else - E = gamma*pres + pi_inf + 5.e-1_wp*rho*vel_K_sum - end if - H = (E + pres)/rho - - ! Compute mixture sound speed - call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, adv_local, vel_K_sum, 0._wp, c) - - ! First-Order Spatial Derivatives of Primitive Variables + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + mf(i) = alpha_rho(i)/rho + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - dalpha_rho_ds(i) = 0._wp - end do + if (chemistry) then + $:GPU_LOOP(parallelism='[seq]') + do i = chemxb, chemxe + Ys(i - chemxb + 1) = q_prim_rs${XYZ}$_vf(0, k, r, i) + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - dvel_ds(i) = 0._wp - end do + call get_mixture_molecular_weight(Ys, Mw) + R_gas = gas_constant/Mw + T = pres/rho/R_gas + call get_mixture_specific_heat_cp_mass(T, Ys, Cp) + call get_mixture_energy_mass(T, Ys, e_mix) + E = rho*e_mix + 5.e-1_wp*rho*vel_K_sum + if (chem_params%gamma_method == 1) then + !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. + call get_mole_fractions(Mw, Ys, Xs) + call get_species_specific_heats_r(T, Cp_i) + Gamma_i = Cp_i/(Cp_i - 1.0_wp) + gamma = sum(Xs(:)/(Gamma_i(:) - 1.0_wp)) + else if (chem_params%gamma_method == 2) then + !> gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. + call get_mixture_specific_heat_cv_mass(T, Ys, Cv) + gamma = 1.0_wp/(Cp/Cv - 1.0_wp) + end if + else + E = gamma*pres + pi_inf + 5.e-1_wp*rho*vel_K_sum + end if - dpres_ds = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, advxe - E_idx - dadv_ds(i) = 0._wp - end do + H = (E + pres)/rho - if (chemistry) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_species - dYs_ds(i) = 0._wp - end do - end if + ! Compute mixture sound speed + call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, adv_local, vel_K_sum, 0._wp, c) - $:GPU_LOOP(parallelism='[seq]') - do j = 0, buff_size + ! First-Order Spatial Derivatives of Primitive Variables $:GPU_LOOP(parallelism='[seq]') do i = 1, contxe - dalpha_rho_ds(i) = q_prim_rs${XYZ}$_vf(j, k, r, i)* & - fd_coef_${XYZ}$ (j, cbc_loc) + & - dalpha_rho_ds(i) + dalpha_rho_ds(i) = 0._wp end do + $:GPU_LOOP(parallelism='[seq]') do i = 1, num_dims - dvel_ds(i) = q_prim_rs${XYZ}$_vf(j, k, r, contxe + i)* & - fd_coef_${XYZ}$ (j, cbc_loc) + & - dvel_ds(i) + dvel_ds(i) = 0._wp end do - dpres_ds = q_prim_rs${XYZ}$_vf(j, k, r, E_idx)* & - fd_coef_${XYZ}$ (j, cbc_loc) + & - dpres_ds + dpres_ds = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, advxe - E_idx - dadv_ds(i) = q_prim_rs${XYZ}$_vf(j, k, r, E_idx + i)* & - fd_coef_${XYZ}$ (j, cbc_loc) + & - dadv_ds(i) + dadv_ds(i) = 0._wp end do if (chemistry) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_species - dYs_ds(i) = q_prim_rs${XYZ}$_vf(j, k, r, chemxb - 1 + i)* & - fd_coef_${XYZ}$ (j, cbc_loc) + & - dYs_ds(i) + dYs_ds(i) = 0._wp end do end if - end do - ! First-Order Temporal Derivatives of Primitive Variables - lambda(1) = vel(dir_idx(1)) - c - lambda(2) = vel(dir_idx(1)) - lambda(3) = vel(dir_idx(1)) + c - - Ma = vel(dir_idx(1))/c - - if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_SLIP_WALL) .or. & - (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_SLIP_WALL)) then - call s_compute_slip_wall_L(lambda, L, rho, c, dpres_ds, dvel_ds) - else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_BUFFER) .or. & - (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_BUFFER)) then - call s_compute_nonreflecting_subsonic_buffer_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) - else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_INFLOW) .or. & - (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_INFLOW)) then - call s_compute_nonreflecting_subsonic_inflow_L(lambda, L, rho, c, dpres_ds, dvel_ds) - ! Add GRCBC for Subsonic Inflow - if (bc_${XYZ}$%grcbc_in) then + $:GPU_LOOP(parallelism='[seq]') + do j = 0, buff_size + $:GPU_LOOP(parallelism='[seq]') - do i = 2, momxb - L(2) = c**3._wp*Ma*(alpha_rho(i - 1) - alpha_rho_in(i - 1, ${CBC_DIR}$))/Del_in(${CBC_DIR}$) - c*Ma*(pres - pres_in(${CBC_DIR}$))/Del_in(${CBC_DIR}$) + do i = 1, contxe + dalpha_rho_ds(i) = q_prim_rs${XYZ}$_vf(j, k, r, i)* & + fd_coef_${XYZ}$ (j, cbc_loc) + & + dalpha_rho_ds(i) end do - if (n > 0) then - L(momxb + 1) = c*Ma*(vel(dir_idx(2)) - vel_in(${CBC_DIR}$, dir_idx(2)))/Del_in(${CBC_DIR}$) - if (p > 0) then - L(momxb + 2) = c*Ma*(vel(dir_idx(3)) - vel_in(${CBC_DIR}$, dir_idx(3)))/Del_in(${CBC_DIR}$) - end if - end if $:GPU_LOOP(parallelism='[seq]') - do i = E_idx, advxe - 1 - L(i) = c*Ma*(adv_local(i + 1 - E_idx) - alpha_in(i + 1 - E_idx, ${CBC_DIR}$))/Del_in(${CBC_DIR}$) + do i = 1, num_dims + dvel_ds(i) = q_prim_rs${XYZ}$_vf(j, k, r, contxe + i)* & + fd_coef_${XYZ}$ (j, cbc_loc) + & + dvel_ds(i) end do - L(advxe) = rho*c**2._wp*(1._wp + Ma)*(vel(dir_idx(1)) + vel_in(${CBC_DIR}$, dir_idx(1))*sign(1, cbc_loc))/Del_in(${CBC_DIR}$) + c*(1._wp + Ma)*(pres - pres_in(${CBC_DIR}$))/Del_in(${CBC_DIR}$) - end if - else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_OUTFLOW) .or. & - (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_OUTFLOW)) then - call s_compute_nonreflecting_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) - ! Add GRCBC for Subsonic Outflow (Pressure) - if (bc_${XYZ}$%grcbc_out) then - L(advxe) = c*(1._wp - Ma)*(pres - pres_out(${CBC_DIR}$))/Del_out(${CBC_DIR}$) - - ! Add GRCBC for Subsonic Outflow (Normal Velocity) - if (bc_${XYZ}$%grcbc_vel_out) then - L(advxe) = L(advxe) + rho*c**2._wp*(1._wp - Ma)*(vel(dir_idx(1)) + vel_out(${CBC_DIR}$, dir_idx(1))*sign(1, cbc_loc))/Del_out(${CBC_DIR}$) + + dpres_ds = q_prim_rs${XYZ}$_vf(j, k, r, E_idx)* & + fd_coef_${XYZ}$ (j, cbc_loc) + & + dpres_ds + $:GPU_LOOP(parallelism='[seq]') + do i = 1, advxe - E_idx + dadv_ds(i) = q_prim_rs${XYZ}$_vf(j, k, r, E_idx + i)* & + fd_coef_${XYZ}$ (j, cbc_loc) + & + dadv_ds(i) + end do + + if (chemistry) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_species + dYs_ds(i) = q_prim_rs${XYZ}$_vf(j, k, r, chemxb - 1 + i)* & + fd_coef_${XYZ}$ (j, cbc_loc) + & + dYs_ds(i) + end do end if - end if - else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_FF_SUB_OUTFLOW) .or. & - (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_FF_SUB_OUTFLOW)) then - call s_compute_force_free_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds) - else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_CP_SUB_OUTFLOW) .or. & - (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_CP_SUB_OUTFLOW)) then - call s_compute_constant_pressure_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds) - else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_SUP_INFLOW) .or. & - (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_SUP_INFLOW)) then - call s_compute_supersonic_inflow_L(L) - else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_SUP_OUTFLOW) .or. & - (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_SUP_OUTFLOW)) then - call s_compute_supersonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) - end if - - ! Be careful about the cylindrical coordinate! - if (cyl_coord .and. cbc_dir == 2 .and. cbc_loc == 1) then - dpres_dt = -5.e-1_wp*(L(advxe) + L(1)) + rho*c*c*vel(dir_idx(1)) & - /y_cc(n) - else - dpres_dt = -5.e-1_wp*(L(advxe) + L(1)) - end if - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - dalpha_rho_dt(i) = & - -(L(i + 1) - mf(i)*dpres_dt)/(c*c) - end do + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - dvel_dt(dir_idx(i)) = dir_flg(dir_idx(i))* & - (L(1) - L(advxe))/(2._wp*rho*c) + & - (dir_flg(dir_idx(i)) - 1._wp)* & - L(momxb + i - 1) - end do + ! First-Order Temporal Derivatives of Primitive Variables + lambda(1) = vel(dir_idx(1)) - c + lambda(2) = vel(dir_idx(1)) + lambda(3) = vel(dir_idx(1)) + c + + Ma = vel(dir_idx(1))/c + + if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_SLIP_WALL) .or. & + (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_SLIP_WALL)) then + call s_compute_slip_wall_L(lambda, L, rho, c, dpres_ds, dvel_ds) + else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_BUFFER) .or. & + (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_BUFFER)) then + call s_compute_nonreflecting_subsonic_buffer_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) + else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_INFLOW) .or. & + (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_INFLOW)) then + call s_compute_nonreflecting_subsonic_inflow_L(lambda, L, rho, c, dpres_ds, dvel_ds) + ! Add GRCBC for Subsonic Inflow + if (bc_${XYZ}$%grcbc_in) then + $:GPU_LOOP(parallelism='[seq]') + do i = 2, momxb + L(2) = c**3._wp*Ma*(alpha_rho(i - 1) - alpha_rho_in(i - 1, ${CBC_DIR}$))/Del_in(${CBC_DIR}$) - c*Ma*(pres - pres_in(${CBC_DIR}$))/Del_in(${CBC_DIR}$) + end do + if (n > 0) then + L(momxb + 1) = c*Ma*(vel(dir_idx(2)) - vel_in(${CBC_DIR}$, dir_idx(2)))/Del_in(${CBC_DIR}$) + if (p > 0) then + L(momxb + 2) = c*Ma*(vel(dir_idx(3)) - vel_in(${CBC_DIR}$, dir_idx(3)))/Del_in(${CBC_DIR}$) + end if + end if + $:GPU_LOOP(parallelism='[seq]') + do i = E_idx, advxe - 1 + L(i) = c*Ma*(adv_local(i + 1 - E_idx) - alpha_in(i + 1 - E_idx, ${CBC_DIR}$))/Del_in(${CBC_DIR}$) + end do + L(advxe) = rho*c**2._wp*(1._wp + Ma)*(vel(dir_idx(1)) + vel_in(${CBC_DIR}$, dir_idx(1))*sign(1, cbc_loc))/Del_in(${CBC_DIR}$) + c*(1._wp + Ma)*(pres - pres_in(${CBC_DIR}$))/Del_in(${CBC_DIR}$) + end if + else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_OUTFLOW) .or. & + (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_OUTFLOW)) then + call s_compute_nonreflecting_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) + ! Add GRCBC for Subsonic Outflow (Pressure) + if (bc_${XYZ}$%grcbc_out) then + L(advxe) = c*(1._wp - Ma)*(pres - pres_out(${CBC_DIR}$))/Del_out(${CBC_DIR}$) + + ! Add GRCBC for Subsonic Outflow (Normal Velocity) + if (bc_${XYZ}$%grcbc_vel_out) then + L(advxe) = L(advxe) + rho*c**2._wp*(1._wp - Ma)*(vel(dir_idx(1)) + vel_out(${CBC_DIR}$, dir_idx(1))*sign(1, cbc_loc))/Del_out(${CBC_DIR}$) + end if + end if + else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_FF_SUB_OUTFLOW) .or. & + (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_FF_SUB_OUTFLOW)) then + call s_compute_force_free_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds) + else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_CP_SUB_OUTFLOW) .or. & + (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_CP_SUB_OUTFLOW)) then + call s_compute_constant_pressure_subsonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds) + else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_SUP_INFLOW) .or. & + (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_SUP_INFLOW)) then + call s_compute_supersonic_inflow_L(L) + else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_SUP_OUTFLOW) .or. & + (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_SUP_OUTFLOW)) then + call s_compute_supersonic_outflow_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, dvel_ds, dadv_ds, dYs_ds) + end if - vel_dv_dt_sum = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_dv_dt_sum = vel_dv_dt_sum + vel(i)*dvel_dt(i) - end do + ! Be careful about the cylindrical coordinate! + if (cyl_coord .and. cbc_dir == 2 .and. cbc_loc == 1) then + dpres_dt = -5.e-1_wp*(L(advxe) + L(1)) + rho*c*c*vel(dir_idx(1)) & + /y_cc(n) + else + dpres_dt = -5.e-1_wp*(L(advxe) + L(1)) + end if - if (chemistry) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_species - dYs_dt(i) = -1._wp*L(chemxb + i - 1) + do i = 1, contxe + dalpha_rho_dt(i) = & + -(L(i + 1) - mf(i)*dpres_dt)/(c*c) end do - end if - ! The treatment of void fraction source is unclear - if (cyl_coord .and. cbc_dir == 2 .and. cbc_loc == 1) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, advxe - E_idx - dadv_dt(i) = -L(momxe + i) !+ adv_local(i) * vel(dir_idx(1))/y_cc(n) + do i = 1, num_dims + dvel_dt(dir_idx(i)) = dir_flg(dir_idx(i))* & + (L(1) - L(advxe))/(2._wp*rho*c) + & + (dir_flg(dir_idx(i)) - 1._wp)* & + L(momxb + i - 1) end do - else + + vel_dv_dt_sum = 0._wp $:GPU_LOOP(parallelism='[seq]') - do i = 1, advxe - E_idx - dadv_dt(i) = -L(momxe + i) + do i = 1, num_dims + vel_dv_dt_sum = vel_dv_dt_sum + vel(i)*dvel_dt(i) end do - end if - drho_dt = 0._wp; dgamma_dt = 0._wp; dpi_inf_dt = 0._wp; dqv_dt = 0._wp + if (chemistry) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_species + dYs_dt(i) = -1._wp*L(chemxb + i - 1) + end do + end if - if (model_eqns == 1) then - drho_dt = dalpha_rho_dt(1) - dgamma_dt = dadv_dt(1) - dpi_inf_dt = dadv_dt(2) - else - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - drho_dt = drho_dt + dalpha_rho_dt(i) - dgamma_dt = dgamma_dt + dadv_dt(i)*gammas(i) - dpi_inf_dt = dpi_inf_dt + dadv_dt(i)*pi_infs(i) - dqv_dt = dqv_dt + dalpha_rho_dt(i)*qvs(i) - end do - end if + ! The treatment of void fraction source is unclear + if (cyl_coord .and. cbc_dir == 2 .and. cbc_loc == 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, advxe - E_idx + dadv_dt(i) = -L(momxe + i) !+ adv_local(i) * vel(dir_idx(1))/y_cc(n) + end do + else + $:GPU_LOOP(parallelism='[seq]') + do i = 1, advxe - E_idx + dadv_dt(i) = -L(momxe + i) + end do + end if - ! flux_rs_vf_l and flux_src_rs_vf_l at j = -1/2 - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - flux_rs${XYZ}$_vf_l(-1, k, r, i) = flux_rs${XYZ}$_vf_l(0, k, r, i) & - + ds(0)*dalpha_rho_dt(i) - end do + drho_dt = 0._wp; dgamma_dt = 0._wp; dpi_inf_dt = 0._wp; dqv_dt = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, momxe - flux_rs${XYZ}$_vf_l(-1, k, r, i) = flux_rs${XYZ}$_vf_l(0, k, r, i) & - + ds(0)*(vel(i - contxe)*drho_dt & - + rho*dvel_dt(i - contxe)) - end do + if (model_eqns == 1) then + drho_dt = dalpha_rho_dt(1) + dgamma_dt = dadv_dt(1) + dpi_inf_dt = dadv_dt(2) + else + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + drho_dt = drho_dt + dalpha_rho_dt(i) + dgamma_dt = dgamma_dt + dadv_dt(i)*gammas(i) + dpi_inf_dt = dpi_inf_dt + dadv_dt(i)*pi_infs(i) + dqv_dt = dqv_dt + dalpha_rho_dt(i)*qvs(i) + end do + end if - if (chemistry) then - ! Evolution of LODI equation of energy for real gases adjusted to perfect gas, doi:10.1006/jcph.2002.6990 - call get_species_enthalpies_rt(T, h_k) - sum_Enthalpies = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_species - h_k(i) = h_k(i)*gas_constant/molecular_weights(i)*T - sum_Enthalpies = sum_Enthalpies + (rho*h_k(i) - pres*Mw/molecular_weights(i)*Cp/R_gas)*dYs_dt(i) - end do - flux_rs${XYZ}$_vf_l(-1, k, r, E_idx) = flux_rs${XYZ}$_vf_l(0, k, r, E_idx) & - + ds(0)*((E/rho + pres/rho)*drho_dt + rho*vel_dv_dt_sum + Cp*T*L(2)/(c*c) + sum_Enthalpies) + ! flux_rs_vf_l and flux_src_rs_vf_l at j = -1/2 $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_species - flux_rs${XYZ}$_vf_l(-1, k, r, i - 1 + chemxb) = flux_rs${XYZ}$_vf_l(0, k, r, chemxb + i - 1) & - + ds(0)*(drho_dt*Ys(i) + rho*dYs_dt(i)) - end do - else - flux_rs${XYZ}$_vf_l(-1, k, r, E_idx) = flux_rs${XYZ}$_vf_l(0, k, r, E_idx) & - + ds(0)*(pres*dgamma_dt & - + gamma*dpres_dt & - + dpi_inf_dt & - + dqv_dt & - + rho*vel_dv_dt_sum & - + 5.e-1_wp*drho_dt*vel_K_sum) - end if - - if (riemann_solver == 1) then - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_rs${XYZ}$_vf_l(-1, k, r, i) = 0._wp + do i = 1, contxe + flux_rs${XYZ}$_vf_l(-1, k, r, i) = flux_rs${XYZ}$_vf_l(0, k, r, i) & + + ds(0)*dalpha_rho_dt(i) end do $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_src_rs${XYZ}$_vf_l(-1, k, r, i) = & - 1._wp/max(abs(vel(dir_idx(1))), sgm_eps) & - *sign(1._wp, vel(dir_idx(1))) & - *(flux_rs${XYZ}$_vf_l(0, k, r, i) & - + vel(dir_idx(1)) & - *flux_src_rs${XYZ}$_vf_l(0, k, r, i) & - + ds(0)*dadv_dt(i - E_idx)) + do i = momxb, momxe + flux_rs${XYZ}$_vf_l(-1, k, r, i) = flux_rs${XYZ}$_vf_l(0, k, r, i) & + + ds(0)*(vel(i - contxe)*drho_dt & + + rho*dvel_dt(i - contxe)) end do - else + if (chemistry) then + ! Evolution of LODI equation of energy for real gases adjusted to perfect gas, doi:10.1006/jcph.2002.6990 + call get_species_enthalpies_rt(T, h_k) + sum_Enthalpies = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_species + h_k(i) = h_k(i)*gas_constant/molecular_weights(i)*T + sum_Enthalpies = sum_Enthalpies + (rho*h_k(i) - pres*Mw/molecular_weights(i)*Cp/R_gas)*dYs_dt(i) + end do + flux_rs${XYZ}$_vf_l(-1, k, r, E_idx) = flux_rs${XYZ}$_vf_l(0, k, r, E_idx) & + + ds(0)*((E/rho + pres/rho)*drho_dt + rho*vel_dv_dt_sum + Cp*T*L(2)/(c*c) + sum_Enthalpies) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_species + flux_rs${XYZ}$_vf_l(-1, k, r, i - 1 + chemxb) = flux_rs${XYZ}$_vf_l(0, k, r, chemxb + i - 1) & + + ds(0)*(drho_dt*Ys(i) + rho*dYs_dt(i)) + end do + else + flux_rs${XYZ}$_vf_l(-1, k, r, E_idx) = flux_rs${XYZ}$_vf_l(0, k, r, E_idx) & + + ds(0)*(pres*dgamma_dt & + + gamma*dpres_dt & + + dpi_inf_dt & + + dqv_dt & + + rho*vel_dv_dt_sum & + + 5.e-1_wp*drho_dt*vel_K_sum) + end if - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_rs${XYZ}$_vf_l(-1, k, r, i) = flux_rs${XYZ}$_vf_l(0, k, r, i) + & - ds(0)*dadv_dt(i - E_idx) - end do + if (riemann_solver == 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_rs${XYZ}$_vf_l(-1, k, r, i) = 0._wp + end do - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_src_rs${XYZ}$_vf_l(-1, k, r, i) = flux_src_rs${XYZ}$_vf_l(0, k, r, i) - end do + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_src_rs${XYZ}$_vf_l(-1, k, r, i) = & + 1._wp/max(abs(vel(dir_idx(1))), sgm_eps) & + *sign(1._wp, vel(dir_idx(1))) & + *(flux_rs${XYZ}$_vf_l(0, k, r, i) & + + vel(dir_idx(1)) & + *flux_src_rs${XYZ}$_vf_l(0, k, r, i) & + + ds(0)*dadv_dt(i - E_idx)) + end do - end if - ! END: flux_rs_vf_l and flux_src_rs_vf_l at j = -1/2 + else + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_rs${XYZ}$_vf_l(-1, k, r, i) = flux_rs${XYZ}$_vf_l(0, k, r, i) + & + ds(0)*dadv_dt(i - E_idx) + end do + + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_src_rs${XYZ}$_vf_l(-1, k, r, i) = flux_src_rs${XYZ}$_vf_l(0, k, r, i) + end do + + end if + ! END: flux_rs_vf_l and flux_src_rs_vf_l at j = -1/2 + + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:endfor @@ -1166,79 +1166,79 @@ contains if (cbc_dir == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = 0, buff_size - q_prim_rsx_vf(j, k, r, i) = & - q_prim_vf(i)%sf(dj*(m - 2*j) + j, k, r) + do i = 1, sys_size + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = 0, buff_size + q_prim_rsx_vf(j, k, r, i) = & + q_prim_vf(i)%sf(dj*(m - 2*j) + j, k, r) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = 0, buff_size - q_prim_rsx_vf(j, k, r, momxb) = & - q_prim_vf(momxb)%sf(dj*(m - 2*j) + j, k, r)* & - sign(1._wp, -1._wp*cbc_loc) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = 0, buff_size + q_prim_rsx_vf(j, k, r, momxb) = & + q_prim_vf(momxb)%sf(dj*(m - 2*j) + j, k, r)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, flux_cbc_index - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_rsx_vf_l(j, k, r, i) = & - flux_vf(i)%sf(dj*((m - 1) - 2*j) + j, k, r)* & - sign(1._wp, -1._wp*cbc_loc) + do i = 1, flux_cbc_index + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_rsx_vf_l(j, k, r, i) = & + flux_vf(i)%sf(dj*((m - 1) - 2*j) + j, k, r)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_rsx_vf_l(j, k, r, momxb) = & - flux_vf(momxb)%sf(dj*((m - 1) - 2*j) + j, k, r) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_rsx_vf_l(j, k, r, momxb) = & + flux_vf(momxb)%sf(dj*((m - 1) - 2*j) + j, k, r) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = advxb, advxe - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_rsx_vf_l(j, k, r, i) = & - flux_src_vf(i)%sf(dj*((m - 1) - 2*j) + j, k, r) + do i = advxb, advxe + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_rsx_vf_l(j, k, r, i) = & + flux_src_vf(i)%sf(dj*((m - 1) - 2*j) + j, k, r) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_rsx_vf_l(j, k, r, advxb) = & - flux_src_vf(advxb)%sf(dj*((m - 1) - 2*j) + j, k, r)* & - sign(1._wp, -1._wp*cbc_loc) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_rsx_vf_l(j, k, r, advxb) = & + flux_src_vf(advxb)%sf(dj*((m - 1) - 2*j) + j, k, r)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1248,79 +1248,79 @@ contains elseif (cbc_dir == 2) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = 0, buff_size - q_prim_rsy_vf(j, k, r, i) = & - q_prim_vf(i)%sf(k, dj*(n - 2*j) + j, r) + do i = 1, sys_size + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = 0, buff_size + q_prim_rsy_vf(j, k, r, i) = & + q_prim_vf(i)%sf(k, dj*(n - 2*j) + j, r) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = 0, buff_size - q_prim_rsy_vf(j, k, r, momxb + 1) = & - q_prim_vf(momxb + 1)%sf(k, dj*(n - 2*j) + j, r)* & - sign(1._wp, -1._wp*cbc_loc) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = 0, buff_size + q_prim_rsy_vf(j, k, r, momxb + 1) = & + q_prim_vf(momxb + 1)%sf(k, dj*(n - 2*j) + j, r)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, flux_cbc_index - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_rsy_vf_l(j, k, r, i) = & - flux_vf(i)%sf(k, dj*((n - 1) - 2*j) + j, r)* & - sign(1._wp, -1._wp*cbc_loc) + do i = 1, flux_cbc_index + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_rsy_vf_l(j, k, r, i) = & + flux_vf(i)%sf(k, dj*((n - 1) - 2*j) + j, r)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_rsy_vf_l(j, k, r, momxb + 1) = & - flux_vf(momxb + 1)%sf(k, dj*((n - 1) - 2*j) + j, r) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_rsy_vf_l(j, k, r, momxb + 1) = & + flux_vf(momxb + 1)%sf(k, dj*((n - 1) - 2*j) + j, r) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = advxb, advxe - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_rsy_vf_l(j, k, r, i) = & - flux_src_vf(i)%sf(k, dj*((n - 1) - 2*j) + j, r) + do i = advxb, advxe + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_rsy_vf_l(j, k, r, i) = & + flux_src_vf(i)%sf(k, dj*((n - 1) - 2*j) + j, r) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_rsy_vf_l(j, k, r, advxb) = & - flux_src_vf(advxb)%sf(k, dj*((n - 1) - 2*j) + j, r)* & - sign(1._wp, -1._wp*cbc_loc) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_rsy_vf_l(j, k, r, advxb) = & + flux_src_vf(advxb)%sf(k, dj*((n - 1) - 2*j) + j, r)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1330,79 +1330,79 @@ contains else #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = 0, buff_size - q_prim_rsz_vf(j, k, r, i) = & - q_prim_vf(i)%sf(r, k, dj*(p - 2*j) + j) + do i = 1, sys_size + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = 0, buff_size + q_prim_rsz_vf(j, k, r, i) = & + q_prim_vf(i)%sf(r, k, dj*(p - 2*j) + j) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = 0, buff_size - q_prim_rsz_vf(j, k, r, momxe) = & - q_prim_vf(momxe)%sf(r, k, dj*(p - 2*j) + j)* & - sign(1._wp, -1._wp*cbc_loc) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = 0, buff_size + q_prim_rsz_vf(j, k, r, momxe) = & + q_prim_vf(momxe)%sf(r, k, dj*(p - 2*j) + j)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, flux_cbc_index - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_rsz_vf_l(j, k, r, i) = & - flux_vf(i)%sf(r, k, dj*((p - 1) - 2*j) + j)* & - sign(1._wp, -1._wp*cbc_loc) + do i = 1, flux_cbc_index + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_rsz_vf_l(j, k, r, i) = & + flux_vf(i)%sf(r, k, dj*((p - 1) - 2*j) + j)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_rsz_vf_l(j, k, r, momxe) = & - flux_vf(momxe)%sf(r, k, dj*((p - 1) - 2*j) + j) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_rsz_vf_l(j, k, r, momxe) = & + flux_vf(momxe)%sf(r, k, dj*((p - 1) - 2*j) + j) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = advxb, advxe - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_rsz_vf_l(j, k, r, i) = & - flux_src_vf(i)%sf(r, k, dj*((p - 1) - 2*j) + j) + do i = advxb, advxe + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_rsz_vf_l(j, k, r, i) = & + flux_src_vf(i)%sf(r, k, dj*((p - 1) - 2*j) + j) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_rsz_vf_l(j, k, r, advxb) = & - flux_src_vf(advxb)%sf(r, k, dj*((p - 1) - 2*j) + j)* & - sign(1._wp, -1._wp*cbc_loc) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_rsz_vf_l(j, k, r, advxb) = & + flux_src_vf(advxb)%sf(r, k, dj*((p - 1) - 2*j) + j)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1434,53 +1434,53 @@ contains if (cbc_dir == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, flux_cbc_index - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_vf(i)%sf(dj*((m - 1) - 2*j) + j, k, r) = & - flux_rsx_vf_l(j, k, r, i)* & - sign(1._wp, -1._wp*cbc_loc) + do i = 1, flux_cbc_index + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_vf(i)%sf(dj*((m - 1) - 2*j) + j, k, r) = & + flux_rsx_vf_l(j, k, r, i)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_vf(momxb)%sf(dj*((m - 1) - 2*j) + j, k, r) = & - flux_rsx_vf_l(j, k, r, momxb) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_vf(momxb)%sf(dj*((m - 1) - 2*j) + j, k, r) = & + flux_rsx_vf_l(j, k, r, momxb) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = advxb, advxe - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_vf(i)%sf(dj*((m - 1) - 2*j) + j, k, r) = & - flux_src_rsx_vf_l(j, k, r, i) + do i = advxb, advxe + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_vf(i)%sf(dj*((m - 1) - 2*j) + j, k, r) = & + flux_src_rsx_vf_l(j, k, r, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_vf(advxb)%sf(dj*((m - 1) - 2*j) + j, k, r) = & - flux_src_rsx_vf_l(j, k, r, advxb)* & - sign(1._wp, -1._wp*cbc_loc) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_vf(advxb)%sf(dj*((m - 1) - 2*j) + j, k, r) = & + flux_src_rsx_vf_l(j, k, r, advxb)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if ! END: Reshaping Outputted Data in x-direction @@ -1489,54 +1489,54 @@ contains elseif (cbc_dir == 2) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, flux_cbc_index - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_vf(i)%sf(k, dj*((n - 1) - 2*j) + j, r) = & - flux_rsy_vf_l(j, k, r, i)* & - sign(1._wp, -1._wp*cbc_loc) + do i = 1, flux_cbc_index + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_vf(i)%sf(k, dj*((n - 1) - 2*j) + j, r) = & + flux_rsy_vf_l(j, k, r, i)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_vf(momxb + 1)%sf(k, dj*((n - 1) - 2*j) + j, r) = & - flux_rsy_vf_l(j, k, r, momxb + 1) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_vf(momxb + 1)%sf(k, dj*((n - 1) - 2*j) + j, r) = & + flux_rsy_vf_l(j, k, r, momxb + 1) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = advxb, advxe - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_vf(i)%sf(k, dj*((n - 1) - 2*j) + j, r) = & - flux_src_rsy_vf_l(j, k, r, i) + do i = advxb, advxe + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_vf(i)%sf(k, dj*((n - 1) - 2*j) + j, r) = & + flux_src_rsy_vf_l(j, k, r, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_vf(advxb)%sf(k, dj*((n - 1) - 2*j) + j, r) = & - flux_src_rsy_vf_l(j, k, r, advxb)* & - sign(1._wp, -1._wp*cbc_loc) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_vf(advxb)%sf(k, dj*((n - 1) - 2*j) + j, r) = & + flux_src_rsy_vf_l(j, k, r, advxb)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1546,54 +1546,54 @@ contains else #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, flux_cbc_index - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_vf(i)%sf(r, k, dj*((p - 1) - 2*j) + j) = & - flux_rsz_vf_l(j, k, r, i)* & - sign(1._wp, -1._wp*cbc_loc) + do i = 1, flux_cbc_index + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_vf(i)%sf(r, k, dj*((p - 1) - 2*j) + j) = & + flux_rsz_vf_l(j, k, r, i)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_vf(momxe)%sf(r, k, dj*((p - 1) - 2*j) + j) = & - flux_rsz_vf_l(j, k, r, momxe) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_vf(momxe)%sf(r, k, dj*((p - 1) - 2*j) + j) = & + flux_rsz_vf_l(j, k, r, momxe) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = advxb, advxe - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_vf(i)%sf(r, k, dj*((p - 1) - 2*j) + j) = & - flux_src_rsz_vf_l(j, k, r, i) + do i = advxb, advxe + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_vf(i)%sf(r, k, dj*((p - 1) - 2*j) + j) = & + flux_src_rsz_vf_l(j, k, r, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else #:call GPU_PARALLEL_LOOP(collapse=3) - do r = is3%beg, is3%end - do k = is2%beg, is2%end - do j = -1, buff_size - flux_src_vf(advxb)%sf(r, k, dj*((p - 1) - 2*j) + j) = & - flux_src_rsz_vf_l(j, k, r, advxb)* & - sign(1._wp, -1._wp*cbc_loc) + do r = is3%beg, is3%end + do k = is2%beg, is2%end + do j = -1, buff_size + flux_src_vf(advxb)%sf(r, k, dj*((p - 1) - 2*j) + j) = & + flux_src_rsz_vf_l(j, k, r, advxb)* & + sign(1._wp, -1._wp*cbc_loc) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if diff --git a/src/simulation/m_data_output.fpp b/src/simulation/m_data_output.fpp index 9f80df014e..ecae911da3 100644 --- a/src/simulation/m_data_output.fpp +++ b/src/simulation/m_data_output.fpp @@ -280,22 +280,22 @@ contains ! Computing Stability Criteria at Current Time-step #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') - do l = 0, p - do k = 0, n - do j = 0, m - call s_compute_enthalpy(q_prim_vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) + do l = 0, p + do k = 0, n + do j = 0, m + call s_compute_enthalpy(q_prim_vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) - call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, alpha, vel_sum, 0._wp, c) + call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, alpha, vel_sum, 0._wp, c) - if (viscous) then - call s_compute_stability_from_dt(vel, c, rho, Re, j, k, l, icfl_sf, vcfl_sf, Rc_sf) - else - call s_compute_stability_from_dt(vel, c, rho, Re, j, k, l, icfl_sf) - end if + if (viscous) then + call s_compute_stability_from_dt(vel, c, rho, Re, j, k, l, icfl_sf, vcfl_sf, Rc_sf) + else + call s_compute_stability_from_dt(vel, c, rho, Re, j, k, l, icfl_sf) + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP ! end: Computing Stability Criteria at Current Time-step diff --git a/src/simulation/m_derived_variables.fpp b/src/simulation/m_derived_variables.fpp index 467737937e..18c88f85c3 100644 --- a/src/simulation/m_derived_variables.fpp +++ b/src/simulation/m_derived_variables.fpp @@ -188,7 +188,7 @@ contains !! @param q_prim_vf3 Primitive variables !! @param q_sf Acceleration component subroutine s_derive_acceleration_component(i, q_prim_vf0, q_prim_vf1, & - q_prim_vf2, q_prim_vf3, q_sf) + q_prim_vf2, q_prim_vf3, q_sf) integer, intent(in) :: i diff --git a/src/simulation/m_fftw.fpp b/src/simulation/m_fftw.fpp index d6eb430dcc..be081f44d9 100644 --- a/src/simulation/m_fftw.fpp +++ b/src/simulation/m_fftw.fpp @@ -142,23 +142,23 @@ contains #if defined(MFC_GPU) #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 1, sys_size - do j = 0, m - do l = 1, cmplx_size - data_fltr_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) = (0_dp, 0_dp) + do k = 1, sys_size + do j = 0, m + do l = 1, cmplx_size + data_fltr_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) = (0_dp, 0_dp) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 1, sys_size - do j = 0, m - do l = 0, p - data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) = q_cons_vf(k)%sf(j, 0, l) + do k = 1, sys_size + do j = 0, m + do l = 0, p + data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) = q_cons_vf(k)%sf(j, 0, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP p_real => data_real_gpu @@ -178,13 +178,13 @@ contains $:GPU_UPDATE(device='[Nfq]') #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 1, sys_size - do j = 0, m - do l = 1, Nfq - data_fltr_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) = data_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) + do k = 1, sys_size + do j = 0, m + do l = 1, Nfq + data_fltr_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) = data_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_HOST_DATA(use_device='[p_real, p_fltr_cmplx]') @@ -197,36 +197,36 @@ contains #:endcall GPU_HOST_DATA #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 1, sys_size - do j = 0, m - do l = 0, p - data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) = data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size)/real(real_size, dp) - q_cons_vf(k)%sf(j, 0, l) = data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) + do k = 1, sys_size + do j = 0, m + do l = 0, p + data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) = data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size)/real(real_size, dp) + q_cons_vf(k)%sf(j, 0, l) = data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP do i = 1, fourier_rings #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 1, sys_size - do j = 0, m - do l = 1, cmplx_size - data_fltr_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) = (0_dp, 0_dp) + do k = 1, sys_size + do j = 0, m + do l = 1, cmplx_size + data_fltr_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) = (0_dp, 0_dp) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3, firstprivate='[i]') - do k = 1, sys_size - do j = 0, m - do l = 0, p - data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) = q_cons_vf(k)%sf(j, i, l) + do k = 1, sys_size + do j = 0, m + do l = 0, p + data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) = q_cons_vf(k)%sf(j, i, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_HOST_DATA(use_device='[p_real, p_cmplx]') @@ -242,13 +242,13 @@ contains $:GPU_UPDATE(device='[Nfq]') #:call GPU_PARALLEL_LOOP(collapse=3) - do k = 1, sys_size - do j = 0, m - do l = 1, Nfq - data_fltr_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) = data_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) + do k = 1, sys_size + do j = 0, m + do l = 1, Nfq + data_fltr_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) = data_cmplx_gpu(l + j*cmplx_size + (k - 1)*cmplx_size*x_size) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_HOST_DATA(use_device='[p_real, p_fltr_cmplx]') @@ -261,48 +261,48 @@ contains #:endcall GPU_HOST_DATA #:call GPU_PARALLEL_LOOP(collapse=3, firstprivate='[i]') - do k = 1, sys_size - do j = 0, m - do l = 0, p - data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) = data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size)/real(real_size, dp) - q_cons_vf(k)%sf(j, i, l) = data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) + do k = 1, sys_size + do j = 0, m + do l = 0, p + data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) = data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size)/real(real_size, dp) + q_cons_vf(k)%sf(j, i, l) = data_real_gpu(l + j*real_size + 1 + (k - 1)*real_size*x_size) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end do #:endcall GPU_DATA #else - Nfq = 3 + Nfq = 3 + do j = 0, m + do k = 1, sys_size + data_fltr_cmplx(:) = (0_dp, 0_dp) + data_real(1:p + 1) = q_cons_vf(k)%sf(j, 0, 0:p) + call fftw_execute_dft_r2c(fwd_plan, data_real, data_cmplx) + data_fltr_cmplx(1:Nfq) = data_cmplx(1:Nfq) + call fftw_execute_dft_c2r(bwd_plan, data_fltr_cmplx, data_real) + data_real(:) = data_real(:)/real(real_size, dp) + q_cons_vf(k)%sf(j, 0, 0:p) = data_real(1:p + 1) + end do + end do + + ! Apply Fourier filter to additional rings + do i = 1, fourier_rings + Nfq = min(floor(2_dp*real(i, dp)*pi), cmplx_size) do j = 0, m do k = 1, sys_size data_fltr_cmplx(:) = (0_dp, 0_dp) - data_real(1:p + 1) = q_cons_vf(k)%sf(j, 0, 0:p) + data_real(1:p + 1) = q_cons_vf(k)%sf(j, i, 0:p) call fftw_execute_dft_r2c(fwd_plan, data_real, data_cmplx) data_fltr_cmplx(1:Nfq) = data_cmplx(1:Nfq) call fftw_execute_dft_c2r(bwd_plan, data_fltr_cmplx, data_real) data_real(:) = data_real(:)/real(real_size, dp) - q_cons_vf(k)%sf(j, 0, 0:p) = data_real(1:p + 1) - end do - end do - - ! Apply Fourier filter to additional rings - do i = 1, fourier_rings - Nfq = min(floor(2_dp*real(i, dp)*pi), cmplx_size) - do j = 0, m - do k = 1, sys_size - data_fltr_cmplx(:) = (0_dp, 0_dp) - data_real(1:p + 1) = q_cons_vf(k)%sf(j, i, 0:p) - call fftw_execute_dft_r2c(fwd_plan, data_real, data_cmplx) - data_fltr_cmplx(1:Nfq) = data_cmplx(1:Nfq) - call fftw_execute_dft_c2r(bwd_plan, data_fltr_cmplx, data_real) - data_real(:) = data_real(:)/real(real_size, dp) - q_cons_vf(k)%sf(j, i, 0:p) = data_real(1:p + 1) - end do + q_cons_vf(k)%sf(j, i, 0:p) = data_real(1:p + 1) end do end do + end do #endif end subroutine s_apply_fourier_filter diff --git a/src/simulation/m_hyperelastic.fpp b/src/simulation/m_hyperelastic.fpp index 9cb7bd4c43..bd79e0f7fb 100644 --- a/src/simulation/m_hyperelastic.fpp +++ b/src/simulation/m_hyperelastic.fpp @@ -107,106 +107,106 @@ contains integer :: j, k, l, i, r #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_K, alpha_rho_K, rho, gamma, pi_inf, qv, G_local, Re, tensora, tensorb]') - do l = 0, p - do k = 0, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_k(i) = q_cons_vf(i)%sf(j, k, l) - alpha_k(i) = q_cons_vf(advxb + i - 1)%sf(j, k, l) - end do - ! If in simulation, use acc mixture subroutines - call s_convert_species_to_mixture_variables_acc(rho, gamma, pi_inf, qv, alpha_k, & - alpha_rho_k, Re, G_local, Gs) - rho = max(rho, sgm_eps) - G_local = max(G_local, sgm_eps) - !if ( G_local <= verysmall ) G_K = 0._wp - - if (G_local > verysmall) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, tensor_size - tensora(i) = 0._wp - end do - ! STEP 1: computing the grad_xi tensor using finite differences - ! grad_xi definition / organization - ! number for the tensor 1-3: dxix_dx, dxiy_dx, dxiz_dx - ! 4-6 : dxix_dy, dxiy_dy, dxiz_dy - ! 7-9 : dxix_dz, dxiy_dz, dxiz_dz + do l = 0, p + do k = 0, n + do j = 0, m $:GPU_LOOP(parallelism='[seq]') - do r = -fd_number, fd_number - ! derivatives in the x-direction - tensora(1) = tensora(1) + q_prim_vf(xibeg)%sf(j + r, k, l)*fd_coeff_x(r, j) - tensora(2) = tensora(2) + q_prim_vf(xibeg + 1)%sf(j + r, k, l)*fd_coeff_x(r, j) - tensora(3) = tensora(3) + q_prim_vf(xiend)%sf(j + r, k, l)*fd_coeff_x(r, j) - ! derivatives in the y-direction - tensora(4) = tensora(4) + q_prim_vf(xibeg)%sf(j, k + r, l)*fd_coeff_y(r, k) - tensora(5) = tensora(5) + q_prim_vf(xibeg + 1)%sf(j, k + r, l)*fd_coeff_y(r, k) - tensora(6) = tensora(6) + q_prim_vf(xiend)%sf(j, k + r, l)*fd_coeff_y(r, k) - ! derivatives in the z-direction - tensora(7) = tensora(7) + q_prim_vf(xibeg)%sf(j, k, l + r)*fd_coeff_z(r, l) - tensora(8) = tensora(8) + q_prim_vf(xibeg + 1)%sf(j, k, l + r)*fd_coeff_z(r, l) - tensora(9) = tensora(9) + q_prim_vf(xiend)%sf(j, k, l + r)*fd_coeff_z(r, l) + do i = 1, num_fluids + alpha_rho_k(i) = q_cons_vf(i)%sf(j, k, l) + alpha_k(i) = q_cons_vf(advxb + i - 1)%sf(j, k, l) end do - ! STEP 2a: computing the adjoint of the grad_xi tensor for the inverse - tensorb(1) = tensora(5)*tensora(9) - tensora(6)*tensora(8) - tensorb(2) = -(tensora(2)*tensora(9) - tensora(3)*tensora(8)) - tensorb(3) = tensora(2)*tensora(6) - tensora(3)*tensora(5) - tensorb(4) = -(tensora(4)*tensora(9) - tensora(6)*tensora(7)) - tensorb(5) = tensora(1)*tensora(9) - tensora(3)*tensora(7) - tensorb(6) = -(tensora(1)*tensora(6) - tensora(4)*tensora(3)) - tensorb(7) = tensora(4)*tensora(8) - tensora(5)*tensora(7) - tensorb(8) = -(tensora(1)*tensora(8) - tensora(2)*tensora(7)) - tensorb(9) = tensora(1)*tensora(5) - tensora(2)*tensora(4) - - ! STEP 2b: computing the determinant of the grad_xi tensor - tensorb(tensor_size) = tensora(1)*(tensora(5)*tensora(9) - tensora(6)*tensora(8)) & - - tensora(2)*(tensora(4)*tensora(9) - tensora(6)*tensora(7)) & - + tensora(3)*(tensora(4)*tensora(8) - tensora(5)*tensora(7)) - - if (tensorb(tensor_size) > verysmall) then - ! STEP 2c: computing the inverse of grad_xi tensor = F - ! tensorb is the adjoint, tensora becomes F + ! If in simulation, use acc mixture subroutines + call s_convert_species_to_mixture_variables_acc(rho, gamma, pi_inf, qv, alpha_k, & + alpha_rho_k, Re, G_local, Gs) + rho = max(rho, sgm_eps) + G_local = max(G_local, sgm_eps) + !if ( G_local <= verysmall ) G_K = 0._wp + + if (G_local > verysmall) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, tensor_size - 1 - tensora(i) = tensorb(i)/tensorb(tensor_size) + do i = 1, tensor_size + tensora(i) = 0._wp end do - - ! STEP 2d: computing the J = det(F) = 1/det(\grad{\xi}) - tensorb(tensor_size) = 1._wp/tensorb(tensor_size) - - ! STEP 3: computing F transpose F - tensorb(1) = tensora(1)**2 + tensora(2)**2 + tensora(3)**2 - tensorb(5) = tensora(4)**2 + tensora(5)**2 + tensora(6)**2 - tensorb(9) = tensora(7)**2 + tensora(8)**2 + tensora(9)**2 - tensorb(2) = tensora(1)*tensora(4) + tensora(2)*tensora(5) + tensora(3)*tensora(6) - tensorb(3) = tensora(1)*tensora(7) + tensora(2)*tensora(8) + tensora(3)*tensora(9) - tensorb(6) = tensora(4)*tensora(7) + tensora(5)*tensora(8) + tensora(6)*tensora(9) - ! STEP 4: update the btensor, this is consistent with Riemann solvers - #:for BIJ, TXY in [(1,1),(2,2),(3,5),(4,3),(5,6),(6,9)] - btensor%vf(${BIJ}$)%sf(j, k, l) = tensorb(${TXY}$) - #:endfor - ! store the determinant at the last entry of the btensor - btensor%vf(b_size)%sf(j, k, l) = tensorb(tensor_size) - ! STEP 5a: updating the Cauchy stress primitive scalar field - if (hyper_model == 1) then - call s_neoHookean_cauchy_solver(btensor%vf, q_prim_vf, G_local, j, k, l) - elseif (hyper_model == 2) then - call s_Mooney_Rivlin_cauchy_solver(btensor%vf, q_prim_vf, G_local, j, k, l) - end if - ! STEP 5b: updating the pressure field - q_prim_vf(E_idx)%sf(j, k, l) = q_prim_vf(E_idx)%sf(j, k, l) - & - G_local*q_prim_vf(xiend + 1)%sf(j, k, l)/gamma - ! STEP 5c: updating the Cauchy stress conservative scalar field + ! STEP 1: computing the grad_xi tensor using finite differences + ! grad_xi definition / organization + ! number for the tensor 1-3: dxix_dx, dxiy_dx, dxiz_dx + ! 4-6 : dxix_dy, dxiy_dy, dxiz_dy + ! 7-9 : dxix_dz, dxiy_dz, dxiz_dz $:GPU_LOOP(parallelism='[seq]') - do i = 1, b_size - 1 - q_cons_vf(strxb + i - 1)%sf(j, k, l) = & - rho*q_prim_vf(strxb + i - 1)%sf(j, k, l) + do r = -fd_number, fd_number + ! derivatives in the x-direction + tensora(1) = tensora(1) + q_prim_vf(xibeg)%sf(j + r, k, l)*fd_coeff_x(r, j) + tensora(2) = tensora(2) + q_prim_vf(xibeg + 1)%sf(j + r, k, l)*fd_coeff_x(r, j) + tensora(3) = tensora(3) + q_prim_vf(xiend)%sf(j + r, k, l)*fd_coeff_x(r, j) + ! derivatives in the y-direction + tensora(4) = tensora(4) + q_prim_vf(xibeg)%sf(j, k + r, l)*fd_coeff_y(r, k) + tensora(5) = tensora(5) + q_prim_vf(xibeg + 1)%sf(j, k + r, l)*fd_coeff_y(r, k) + tensora(6) = tensora(6) + q_prim_vf(xiend)%sf(j, k + r, l)*fd_coeff_y(r, k) + ! derivatives in the z-direction + tensora(7) = tensora(7) + q_prim_vf(xibeg)%sf(j, k, l + r)*fd_coeff_z(r, l) + tensora(8) = tensora(8) + q_prim_vf(xibeg + 1)%sf(j, k, l + r)*fd_coeff_z(r, l) + tensora(9) = tensora(9) + q_prim_vf(xiend)%sf(j, k, l + r)*fd_coeff_z(r, l) end do + ! STEP 2a: computing the adjoint of the grad_xi tensor for the inverse + tensorb(1) = tensora(5)*tensora(9) - tensora(6)*tensora(8) + tensorb(2) = -(tensora(2)*tensora(9) - tensora(3)*tensora(8)) + tensorb(3) = tensora(2)*tensora(6) - tensora(3)*tensora(5) + tensorb(4) = -(tensora(4)*tensora(9) - tensora(6)*tensora(7)) + tensorb(5) = tensora(1)*tensora(9) - tensora(3)*tensora(7) + tensorb(6) = -(tensora(1)*tensora(6) - tensora(4)*tensora(3)) + tensorb(7) = tensora(4)*tensora(8) - tensora(5)*tensora(7) + tensorb(8) = -(tensora(1)*tensora(8) - tensora(2)*tensora(7)) + tensorb(9) = tensora(1)*tensora(5) - tensora(2)*tensora(4) + + ! STEP 2b: computing the determinant of the grad_xi tensor + tensorb(tensor_size) = tensora(1)*(tensora(5)*tensora(9) - tensora(6)*tensora(8)) & + - tensora(2)*(tensora(4)*tensora(9) - tensora(6)*tensora(7)) & + + tensora(3)*(tensora(4)*tensora(8) - tensora(5)*tensora(7)) + + if (tensorb(tensor_size) > verysmall) then + ! STEP 2c: computing the inverse of grad_xi tensor = F + ! tensorb is the adjoint, tensora becomes F + $:GPU_LOOP(parallelism='[seq]') + do i = 1, tensor_size - 1 + tensora(i) = tensorb(i)/tensorb(tensor_size) + end do + + ! STEP 2d: computing the J = det(F) = 1/det(\grad{\xi}) + tensorb(tensor_size) = 1._wp/tensorb(tensor_size) + + ! STEP 3: computing F transpose F + tensorb(1) = tensora(1)**2 + tensora(2)**2 + tensora(3)**2 + tensorb(5) = tensora(4)**2 + tensora(5)**2 + tensora(6)**2 + tensorb(9) = tensora(7)**2 + tensora(8)**2 + tensora(9)**2 + tensorb(2) = tensora(1)*tensora(4) + tensora(2)*tensora(5) + tensora(3)*tensora(6) + tensorb(3) = tensora(1)*tensora(7) + tensora(2)*tensora(8) + tensora(3)*tensora(9) + tensorb(6) = tensora(4)*tensora(7) + tensora(5)*tensora(8) + tensora(6)*tensora(9) + ! STEP 4: update the btensor, this is consistent with Riemann solvers + #:for BIJ, TXY in [(1,1),(2,2),(3,5),(4,3),(5,6),(6,9)] + btensor%vf(${BIJ}$)%sf(j, k, l) = tensorb(${TXY}$) + #:endfor + ! store the determinant at the last entry of the btensor + btensor%vf(b_size)%sf(j, k, l) = tensorb(tensor_size) + ! STEP 5a: updating the Cauchy stress primitive scalar field + if (hyper_model == 1) then + call s_neoHookean_cauchy_solver(btensor%vf, q_prim_vf, G_local, j, k, l) + elseif (hyper_model == 2) then + call s_Mooney_Rivlin_cauchy_solver(btensor%vf, q_prim_vf, G_local, j, k, l) + end if + ! STEP 5b: updating the pressure field + q_prim_vf(E_idx)%sf(j, k, l) = q_prim_vf(E_idx)%sf(j, k, l) - & + G_local*q_prim_vf(xiend + 1)%sf(j, k, l)/gamma + ! STEP 5c: updating the Cauchy stress conservative scalar field + $:GPU_LOOP(parallelism='[seq]') + do i = 1, b_size - 1 + q_cons_vf(strxb + i - 1)%sf(j, k, l) = & + rho*q_prim_vf(strxb + i - 1)%sf(j, k, l) + end do + end if end if - end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_hyperelastic_rmt_stress_update diff --git a/src/simulation/m_hypoelastic.fpp b/src/simulation/m_hypoelastic.fpp index 84be088fae..e4c781ebe9 100644 --- a/src/simulation/m_hypoelastic.fpp +++ b/src/simulation/m_hypoelastic.fpp @@ -105,270 +105,270 @@ contains ! TODO: re-organize these loops one by one for GPU efficiency if possible? #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - du_dx(k, l, q) = 0._wp + do q = 0, p + do l = 0, n + do k = 0, m + du_dx(k, l, q) = 0._wp + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - $:GPU_LOOP(parallelism='[seq]') - do r = -fd_number, fd_number - du_dx(k, l, q) = du_dx(k, l, q) & - + q_prim_vf(momxb)%sf(k + r, l, q)*fd_coeff_x_h(r, k) - end do + do q = 0, p + do l = 0, n + do k = 0, m + $:GPU_LOOP(parallelism='[seq]') + do r = -fd_number, fd_number + du_dx(k, l, q) = du_dx(k, l, q) & + + q_prim_vf(momxb)%sf(k + r, l, q)*fd_coeff_x_h(r, k) + end do + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (ndirs > 1) then #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - du_dy(k, l, q) = 0._wp; dv_dx(k, l, q) = 0._wp; dv_dy(k, l, q) = 0._wp + do q = 0, p + do l = 0, n + do k = 0, m + du_dy(k, l, q) = 0._wp; dv_dx(k, l, q) = 0._wp; dv_dy(k, l, q) = 0._wp + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - $:GPU_LOOP(parallelism='[seq]') - do r = -fd_number, fd_number - du_dy(k, l, q) = du_dy(k, l, q) & - + q_prim_vf(momxb)%sf(k, l + r, q)*fd_coeff_y_h(r, l) - dv_dx(k, l, q) = dv_dx(k, l, q) & - + q_prim_vf(momxb + 1)%sf(k + r, l, q)*fd_coeff_x_h(r, k) - dv_dy(k, l, q) = dv_dy(k, l, q) & - + q_prim_vf(momxb + 1)%sf(k, l + r, q)*fd_coeff_y_h(r, l) + do q = 0, p + do l = 0, n + do k = 0, m + $:GPU_LOOP(parallelism='[seq]') + do r = -fd_number, fd_number + du_dy(k, l, q) = du_dy(k, l, q) & + + q_prim_vf(momxb)%sf(k, l + r, q)*fd_coeff_y_h(r, l) + dv_dx(k, l, q) = dv_dx(k, l, q) & + + q_prim_vf(momxb + 1)%sf(k + r, l, q)*fd_coeff_x_h(r, k) + dv_dy(k, l, q) = dv_dy(k, l, q) & + + q_prim_vf(momxb + 1)%sf(k, l + r, q)*fd_coeff_y_h(r, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP ! 3D if (ndirs == 3) then #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - du_dz(k, l, q) = 0._wp; dv_dz(k, l, q) = 0._wp; dw_dx(k, l, q) = 0._wp; - dw_dy(k, l, q) = 0._wp; dw_dz(k, l, q) = 0._wp; + do q = 0, p + do l = 0, n + do k = 0, m + du_dz(k, l, q) = 0._wp; dv_dz(k, l, q) = 0._wp; dw_dx(k, l, q) = 0._wp; + dw_dy(k, l, q) = 0._wp; dw_dz(k, l, q) = 0._wp; + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - $:GPU_LOOP(parallelism='[seq]') - do r = -fd_number, fd_number - du_dz(k, l, q) = du_dz(k, l, q) & - + q_prim_vf(momxb)%sf(k, l, q + r)*fd_coeff_z_h(r, q) - dv_dz(k, l, q) = dv_dz(k, l, q) & - + q_prim_vf(momxb + 1)%sf(k, l, q + r)*fd_coeff_z_h(r, q) - dw_dx(k, l, q) = dw_dx(k, l, q) & - + q_prim_vf(momxe)%sf(k + r, l, q)*fd_coeff_x_h(r, k) - dw_dy(k, l, q) = dw_dy(k, l, q) & - + q_prim_vf(momxe)%sf(k, l + r, q)*fd_coeff_y_h(r, l) - dw_dz(k, l, q) = dw_dz(k, l, q) & - + q_prim_vf(momxe)%sf(k, l, q + r)*fd_coeff_z_h(r, q) + do q = 0, p + do l = 0, n + do k = 0, m + $:GPU_LOOP(parallelism='[seq]') + do r = -fd_number, fd_number + du_dz(k, l, q) = du_dz(k, l, q) & + + q_prim_vf(momxb)%sf(k, l, q + r)*fd_coeff_z_h(r, q) + dv_dz(k, l, q) = dv_dz(k, l, q) & + + q_prim_vf(momxb + 1)%sf(k, l, q + r)*fd_coeff_z_h(r, q) + dw_dx(k, l, q) = dw_dx(k, l, q) & + + q_prim_vf(momxe)%sf(k + r, l, q)*fd_coeff_x_h(r, k) + dw_dy(k, l, q) = dw_dy(k, l, q) & + + q_prim_vf(momxe)%sf(k, l + r, q)*fd_coeff_y_h(r, l) + dw_dz(k, l, q) = dw_dz(k, l, q) & + + q_prim_vf(momxe)%sf(k, l, q + r)*fd_coeff_z_h(r, q) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - rho_K = 0._wp; G_K = 0._wp - do i = 1, num_fluids - rho_K = rho_K + q_prim_vf(i)%sf(k, l, q) !alpha_rho_K(1) - G_K = G_K + q_prim_vf(advxb - 1 + i)%sf(k, l, q)*Gs(i) !alpha_K(1) * Gs(1) - end do + do q = 0, p + do l = 0, n + do k = 0, m + rho_K = 0._wp; G_K = 0._wp + do i = 1, num_fluids + rho_K = rho_K + q_prim_vf(i)%sf(k, l, q) !alpha_rho_K(1) + G_K = G_K + q_prim_vf(advxb - 1 + i)%sf(k, l, q)*Gs(i) !alpha_K(1) * Gs(1) + end do - if (cont_damage) G_K = G_K*max((1._wp - q_prim_vf(damage_idx)%sf(k, l, q)), 0._wp) + if (cont_damage) G_K = G_K*max((1._wp - q_prim_vf(damage_idx)%sf(k, l, q)), 0._wp) - rho_K_field(k, l, q) = rho_K - G_K_field(k, l, q) = G_K + rho_K_field(k, l, q) = rho_K + G_K_field(k, l, q) = G_K - !TODO: take this out if not needed - if (G_K < verysmall) then - G_K_field(k, l, q) = 0 - end if + !TODO: take this out if not needed + if (G_K < verysmall) then + G_K_field(k, l, q) = 0 + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP ! apply rhs source term to elastic stress equation #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - rhs_vf(strxb)%sf(k, l, q) = & - rhs_vf(strxb)%sf(k, l, q) + rho_K_field(k, l, q)* & - ((4._wp*G_K_field(k, l, q)/3._wp) + & - q_prim_vf(strxb)%sf(k, l, q))* & - du_dx(k, l, q) + do q = 0, p + do l = 0, n + do k = 0, m + rhs_vf(strxb)%sf(k, l, q) = & + rhs_vf(strxb)%sf(k, l, q) + rho_K_field(k, l, q)* & + ((4._wp*G_K_field(k, l, q)/3._wp) + & + q_prim_vf(strxb)%sf(k, l, q))* & + du_dx(k, l, q) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (idir == 2) then #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - rhs_vf(strxb)%sf(k, l, q) = rhs_vf(strxb)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 1)%sf(k, l, q)*du_dy(k, l, q) + & - q_prim_vf(strxb + 1)%sf(k, l, q)*du_dy(k, l, q) - & - q_prim_vf(strxb)%sf(k, l, q)*dv_dy(k, l, q) - & - 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dv_dy(k, l, q)) - - rhs_vf(strxb + 1)%sf(k, l, q) = rhs_vf(strxb + 1)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 1)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb)%sf(k, l, q)*dv_dx(k, l, q) - & - q_prim_vf(strxb + 1)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb + 2)%sf(k, l, q)*du_dy(k, l, q) + & - q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dy(k, l, q) - & - q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dy(k, l, q) + & - 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(du_dy(k, l, q) + & - dv_dx(k, l, q))) - - rhs_vf(strxb + 2)%sf(k, l, q) = rhs_vf(strxb + 2)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dx(k, l, q) + & - q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dx(k, l, q) - & - q_prim_vf(strxb + 2)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy(k, l, q) + & - q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy(k, l, q) - & - q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy(k, l, q) + & - 2._wp*G_K_field(k, l, q)*(dv_dy(k, l, q) - (1._wp/3._wp)* & - (du_dx(k, l, q) + & - dv_dy(k, l, q)))) + do q = 0, p + do l = 0, n + do k = 0, m + rhs_vf(strxb)%sf(k, l, q) = rhs_vf(strxb)%sf(k, l, q) + rho_K_field(k, l, q)* & + (q_prim_vf(strxb + 1)%sf(k, l, q)*du_dy(k, l, q) + & + q_prim_vf(strxb + 1)%sf(k, l, q)*du_dy(k, l, q) - & + q_prim_vf(strxb)%sf(k, l, q)*dv_dy(k, l, q) - & + 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dv_dy(k, l, q)) + + rhs_vf(strxb + 1)%sf(k, l, q) = rhs_vf(strxb + 1)%sf(k, l, q) + rho_K_field(k, l, q)* & + (q_prim_vf(strxb + 1)%sf(k, l, q)*du_dx(k, l, q) + & + q_prim_vf(strxb)%sf(k, l, q)*dv_dx(k, l, q) - & + q_prim_vf(strxb + 1)%sf(k, l, q)*du_dx(k, l, q) + & + q_prim_vf(strxb + 2)%sf(k, l, q)*du_dy(k, l, q) + & + q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dy(k, l, q) - & + q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dy(k, l, q) + & + 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(du_dy(k, l, q) + & + dv_dx(k, l, q))) + + rhs_vf(strxb + 2)%sf(k, l, q) = rhs_vf(strxb + 2)%sf(k, l, q) + rho_K_field(k, l, q)* & + (q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dx(k, l, q) + & + q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dx(k, l, q) - & + q_prim_vf(strxb + 2)%sf(k, l, q)*du_dx(k, l, q) + & + q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy(k, l, q) + & + q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy(k, l, q) - & + q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy(k, l, q) + & + 2._wp*G_K_field(k, l, q)*(dv_dy(k, l, q) - (1._wp/3._wp)* & + (du_dx(k, l, q) + & + dv_dy(k, l, q)))) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (idir == 3) then #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - rhs_vf(strxb)%sf(k, l, q) = rhs_vf(strxb)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 3)%sf(k, l, q)*du_dz(k, l, q) + & - q_prim_vf(strxb + 3)%sf(k, l, q)*du_dz(k, l, q) - & - q_prim_vf(strxb)%sf(k, l, q)*dw_dz(k, l, q) - & - 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dw_dz(k, l, q)) - - rhs_vf(strxb + 1)%sf(k, l, q) = rhs_vf(strxb + 1)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 4)%sf(k, l, q)*du_dz(k, l, q) + & - q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dz(k, l, q) - & - q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dz(k, l, q)) - - rhs_vf(strxb + 2)%sf(k, l, q) = rhs_vf(strxb + 2)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dz(k, l, q) + & - q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dz(k, l, q) - & - q_prim_vf(strxb + 2)%sf(k, l, q)*dw_dz(k, l, q) - & + do q = 0, p + do l = 0, n + do k = 0, m + rhs_vf(strxb)%sf(k, l, q) = rhs_vf(strxb)%sf(k, l, q) + rho_K_field(k, l, q)* & + (q_prim_vf(strxb + 3)%sf(k, l, q)*du_dz(k, l, q) + & + q_prim_vf(strxb + 3)%sf(k, l, q)*du_dz(k, l, q) - & + q_prim_vf(strxb)%sf(k, l, q)*dw_dz(k, l, q) - & 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dw_dz(k, l, q)) - rhs_vf(strxb + 3)%sf(k, l, q) = rhs_vf(strxb + 3)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 3)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb)%sf(k, l, q)*dw_dx(k, l, q) - & - q_prim_vf(strxb + 3)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb + 4)%sf(k, l, q)*du_dy(k, l, q) + & - q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dy(k, l, q) - & - q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dy(k, l, q) + & - q_prim_vf(strxb + 5)%sf(k, l, q)*du_dz(k, l, q) + & - q_prim_vf(strxb + 3)%sf(k, l, q)*dw_dz(k, l, q) - & - q_prim_vf(strxb + 3)%sf(k, l, q)*dw_dz(k, l, q) + & - 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(du_dz(k, l, q) + & - dw_dx(k, l, q))) - - rhs_vf(strxb + 4)%sf(k, l, q) = rhs_vf(strxb + 4)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dx(k, l, q) + & - q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dx(k, l, q) - & - q_prim_vf(strxb + 4)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dy(k, l, q) + & - q_prim_vf(strxb + 2)%sf(k, l, q)*dw_dy(k, l, q) - & - q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dy(k, l, q) + & - q_prim_vf(strxb + 5)%sf(k, l, q)*dv_dz(k, l, q) + & - q_prim_vf(strxb + 4)%sf(k, l, q)*dw_dz(k, l, q) - & - q_prim_vf(strxb + 4)%sf(k, l, q)*dw_dz(k, l, q) + & - 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(dv_dz(k, l, q) + & - dw_dy(k, l, q))) - - rhs_vf(strxe)%sf(k, l, q) = rhs_vf(strxe)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxe - 2)%sf(k, l, q)*dw_dx(k, l, q) + & - q_prim_vf(strxe - 2)%sf(k, l, q)*dw_dx(k, l, q) - & - q_prim_vf(strxe)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxe - 1)%sf(k, l, q)*dw_dy(k, l, q) + & - q_prim_vf(strxe - 1)%sf(k, l, q)*dw_dy(k, l, q) - & - q_prim_vf(strxe)%sf(k, l, q)*dv_dy(k, l, q) + & - q_prim_vf(strxe)%sf(k, l, q)*dw_dz(k, l, q) + & - q_prim_vf(strxe)%sf(k, l, q)*dw_dz(k, l, q) - & - q_prim_vf(strxe)%sf(k, l, q)*dw_dz(k, l, q) + & - 2._wp*G_K_field(k, l, q)*(dw_dz(k, l, q) - (1._wp/3._wp)* & - (du_dx(k, l, q) + & - dv_dy(k, l, q) + & - dw_dz(k, l, q)))) + rhs_vf(strxb + 1)%sf(k, l, q) = rhs_vf(strxb + 1)%sf(k, l, q) + rho_K_field(k, l, q)* & + (q_prim_vf(strxb + 4)%sf(k, l, q)*du_dz(k, l, q) + & + q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dz(k, l, q) - & + q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dz(k, l, q)) + + rhs_vf(strxb + 2)%sf(k, l, q) = rhs_vf(strxb + 2)%sf(k, l, q) + rho_K_field(k, l, q)* & + (q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dz(k, l, q) + & + q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dz(k, l, q) - & + q_prim_vf(strxb + 2)%sf(k, l, q)*dw_dz(k, l, q) - & + 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dw_dz(k, l, q)) + + rhs_vf(strxb + 3)%sf(k, l, q) = rhs_vf(strxb + 3)%sf(k, l, q) + rho_K_field(k, l, q)* & + (q_prim_vf(strxb + 3)%sf(k, l, q)*du_dx(k, l, q) + & + q_prim_vf(strxb)%sf(k, l, q)*dw_dx(k, l, q) - & + q_prim_vf(strxb + 3)%sf(k, l, q)*du_dx(k, l, q) + & + q_prim_vf(strxb + 4)%sf(k, l, q)*du_dy(k, l, q) + & + q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dy(k, l, q) - & + q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dy(k, l, q) + & + q_prim_vf(strxb + 5)%sf(k, l, q)*du_dz(k, l, q) + & + q_prim_vf(strxb + 3)%sf(k, l, q)*dw_dz(k, l, q) - & + q_prim_vf(strxb + 3)%sf(k, l, q)*dw_dz(k, l, q) + & + 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(du_dz(k, l, q) + & + dw_dx(k, l, q))) + + rhs_vf(strxb + 4)%sf(k, l, q) = rhs_vf(strxb + 4)%sf(k, l, q) + rho_K_field(k, l, q)* & + (q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dx(k, l, q) + & + q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dx(k, l, q) - & + q_prim_vf(strxb + 4)%sf(k, l, q)*du_dx(k, l, q) + & + q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dy(k, l, q) + & + q_prim_vf(strxb + 2)%sf(k, l, q)*dw_dy(k, l, q) - & + q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dy(k, l, q) + & + q_prim_vf(strxb + 5)%sf(k, l, q)*dv_dz(k, l, q) + & + q_prim_vf(strxb + 4)%sf(k, l, q)*dw_dz(k, l, q) - & + q_prim_vf(strxb + 4)%sf(k, l, q)*dw_dz(k, l, q) + & + 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(dv_dz(k, l, q) + & + dw_dy(k, l, q))) + + rhs_vf(strxe)%sf(k, l, q) = rhs_vf(strxe)%sf(k, l, q) + rho_K_field(k, l, q)* & + (q_prim_vf(strxe - 2)%sf(k, l, q)*dw_dx(k, l, q) + & + q_prim_vf(strxe - 2)%sf(k, l, q)*dw_dx(k, l, q) - & + q_prim_vf(strxe)%sf(k, l, q)*du_dx(k, l, q) + & + q_prim_vf(strxe - 1)%sf(k, l, q)*dw_dy(k, l, q) + & + q_prim_vf(strxe - 1)%sf(k, l, q)*dw_dy(k, l, q) - & + q_prim_vf(strxe)%sf(k, l, q)*dv_dy(k, l, q) + & + q_prim_vf(strxe)%sf(k, l, q)*dw_dz(k, l, q) + & + q_prim_vf(strxe)%sf(k, l, q)*dw_dz(k, l, q) - & + q_prim_vf(strxe)%sf(k, l, q)*dw_dz(k, l, q) + & + 2._wp*G_K_field(k, l, q)*(dw_dz(k, l, q) - (1._wp/3._wp)* & + (du_dx(k, l, q) + & + dv_dy(k, l, q) + & + dw_dz(k, l, q)))) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (cyl_coord .and. idir == 2) then #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p - do l = 0, n - do k = 0, m - ! S_xx -= rho * v/r * (tau_xx + 2/3*G) - rhs_vf(strxb)%sf(k, l, q) = rhs_vf(strxb)%sf(k, l, q) - & - rho_K_field(k, l, q)*q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)* & - (q_prim_vf(strxb)%sf(k, l, q) + (2._wp/3._wp)*G_K_field(k, l, q)) ! tau_xx + 2/3*G - - ! S_xr -= rho * v/r * tau_xr - rhs_vf(strxb + 1)%sf(k, l, q) = rhs_vf(strxb + 1)%sf(k, l, q) - & - rho_K_field(k, l, q)*q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)* & - q_prim_vf(strxb + 1)%sf(k, l, q) ! tau_xx - - ! S_rr -= rho * v/r * (tau_rr + 2/3*G) - rhs_vf(strxb + 2)%sf(k, l, q) = rhs_vf(strxb + 2)%sf(k, l, q) - & + do q = 0, p + do l = 0, n + do k = 0, m + ! S_xx -= rho * v/r * (tau_xx + 2/3*G) + rhs_vf(strxb)%sf(k, l, q) = rhs_vf(strxb)%sf(k, l, q) - & rho_K_field(k, l, q)*q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)* & - (q_prim_vf(strxb + 2)%sf(k, l, q) + (2._wp/3._wp)*G_K_field(k, l, q)) ! tau_rr + 2/3*G - - ! S_thetatheta += rho * ( -(tau_thetatheta + 2/3*G)*(du/dx + dv/dr + v/r) + 2*(tau_thetatheta + G)*v/r ) - rhs_vf(strxb + 3)%sf(k, l, q) = rhs_vf(strxb + 3)%sf(k, l, q) + & - rho_K_field(k, l, q)*( & - -(q_prim_vf(strxb + 3)%sf(k, l, q) + (2._wp/3._wp)*G_K_field(k, l, q))* & - (du_dx(k, l, q) + dv_dy(k, l, q) + q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)) & - + 2._wp*(q_prim_vf(strxb + 3)%sf(k, l, q) + G_K_field(k, l, q))*q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)) + (q_prim_vf(strxb)%sf(k, l, q) + (2._wp/3._wp)*G_K_field(k, l, q)) ! tau_xx + 2/3*G + + ! S_xr -= rho * v/r * tau_xr + rhs_vf(strxb + 1)%sf(k, l, q) = rhs_vf(strxb + 1)%sf(k, l, q) - & + rho_K_field(k, l, q)*q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)* & + q_prim_vf(strxb + 1)%sf(k, l, q) ! tau_xx + + ! S_rr -= rho * v/r * (tau_rr + 2/3*G) + rhs_vf(strxb + 2)%sf(k, l, q) = rhs_vf(strxb + 2)%sf(k, l, q) - & + rho_K_field(k, l, q)*q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)* & + (q_prim_vf(strxb + 2)%sf(k, l, q) + (2._wp/3._wp)*G_K_field(k, l, q)) ! tau_rr + 2/3*G + + ! S_thetatheta += rho * ( -(tau_thetatheta + 2/3*G)*(du/dx + dv/dr + v/r) + 2*(tau_thetatheta + G)*v/r ) + rhs_vf(strxb + 3)%sf(k, l, q) = rhs_vf(strxb + 3)%sf(k, l, q) + & + rho_K_field(k, l, q)*( & + -(q_prim_vf(strxb + 3)%sf(k, l, q) + (2._wp/3._wp)*G_K_field(k, l, q))* & + (du_dx(k, l, q) + dv_dy(k, l, q) + q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)) & + + 2._wp*(q_prim_vf(strxb + 3)%sf(k, l, q) + G_K_field(k, l, q))*q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -405,64 +405,64 @@ contains if (n == 0) then l = 0; q = 0 #:call GPU_PARALLEL_LOOP() - do k = 0, m - rhs_vf(damage_idx)%sf(k, l, q) = (alpha_bar*max(abs(q_cons_vf(stress_idx%beg)%sf(k, l, q)) - tau_star, 0._wp))**cont_damage_s - end do + do k = 0, m + rhs_vf(damage_idx)%sf(k, l, q) = (alpha_bar*max(abs(q_cons_vf(stress_idx%beg)%sf(k, l, q)) - tau_star, 0._wp))**cont_damage_s + end do #:endcall GPU_PARALLEL_LOOP elseif (p == 0) then q = 0 #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, n - do k = 0, m - ! Maximum principal stress - tau_p = 0.5_wp*(q_cons_vf(stress_idx%beg)%sf(k, l, q) + & - q_cons_vf(stress_idx%beg + 2)%sf(k, l, q)) + & - sqrt((q_cons_vf(stress_idx%beg)%sf(k, l, q) - & - q_cons_vf(stress_idx%beg + 2)%sf(k, l, q))**2.0_wp + & - 4._wp*q_cons_vf(stress_idx%beg + 1)%sf(k, l, q)**2.0_wp)/2._wp - - rhs_vf(damage_idx)%sf(k, l, q) = (alpha_bar*max(tau_p - tau_star, 0._wp))**cont_damage_s - end do - end do - #:endcall GPU_PARALLEL_LOOP - else - #:call GPU_PARALLEL_LOOP(collapse=3) - do q = 0, p do l = 0, n do k = 0, m - tau_xx = q_cons_vf(stress_idx%beg)%sf(k, l, q) - tau_xy = q_cons_vf(stress_idx%beg + 1)%sf(k, l, q) - tau_yy = q_cons_vf(stress_idx%beg + 2)%sf(k, l, q) - tau_xz = q_cons_vf(stress_idx%beg + 3)%sf(k, l, q) - tau_yz = q_cons_vf(stress_idx%beg + 4)%sf(k, l, q) - tau_zz = q_cons_vf(stress_idx%beg + 5)%sf(k, l, q) - - ! Invariants of the stress tensor - I1 = tau_xx + tau_yy + tau_zz - I2 = tau_xx*tau_yy + tau_xx*tau_zz + tau_yy*tau_zz - & - (tau_xy**2.0_wp + tau_xz**2.0_wp + tau_yz**2.0_wp) - I3 = tau_xx*tau_yy*tau_zz + 2.0_wp*tau_xy*tau_xz*tau_yz - & - tau_xx*tau_yz**2.0_wp - tau_yy*tau_xz**2.0_wp - tau_zz*tau_xy**2.0_wp - ! Maximum principal stress - temp = I1**2.0_wp - 3.0_wp*I2 - sqrt_term_1 = sqrt(max(temp, 0.0_wp)) - if (sqrt_term_1 > verysmall) then ! Avoid 0/0 - argument = (2.0_wp*I1*I1*I1 - 9.0_wp*I1*I2 + 27.0_wp*I3)/ & - (2.0_wp*sqrt_term_1*sqrt_term_1*sqrt_term_1) - if (argument > 1.0_wp) argument = 1.0_wp - if (argument < -1.0_wp) argument = -1.0_wp - phi = acos(argument) - sqrt_term_2 = sqrt(max(I1**2.0_wp - 3.0_wp*I2, 0.0_wp)) - tau_p = I1/3.0_wp + 2.0_wp/sqrt(3.0_wp)*sqrt_term_2*cos(phi/3.0_wp) - else - tau_p = I1/3.0_wp - end if + tau_p = 0.5_wp*(q_cons_vf(stress_idx%beg)%sf(k, l, q) + & + q_cons_vf(stress_idx%beg + 2)%sf(k, l, q)) + & + sqrt((q_cons_vf(stress_idx%beg)%sf(k, l, q) - & + q_cons_vf(stress_idx%beg + 2)%sf(k, l, q))**2.0_wp + & + 4._wp*q_cons_vf(stress_idx%beg + 1)%sf(k, l, q)**2.0_wp)/2._wp rhs_vf(damage_idx)%sf(k, l, q) = (alpha_bar*max(tau_p - tau_star, 0._wp))**cont_damage_s end do end do - end do + #:endcall GPU_PARALLEL_LOOP + else + #:call GPU_PARALLEL_LOOP(collapse=3) + do q = 0, p + do l = 0, n + do k = 0, m + tau_xx = q_cons_vf(stress_idx%beg)%sf(k, l, q) + tau_xy = q_cons_vf(stress_idx%beg + 1)%sf(k, l, q) + tau_yy = q_cons_vf(stress_idx%beg + 2)%sf(k, l, q) + tau_xz = q_cons_vf(stress_idx%beg + 3)%sf(k, l, q) + tau_yz = q_cons_vf(stress_idx%beg + 4)%sf(k, l, q) + tau_zz = q_cons_vf(stress_idx%beg + 5)%sf(k, l, q) + + ! Invariants of the stress tensor + I1 = tau_xx + tau_yy + tau_zz + I2 = tau_xx*tau_yy + tau_xx*tau_zz + tau_yy*tau_zz - & + (tau_xy**2.0_wp + tau_xz**2.0_wp + tau_yz**2.0_wp) + I3 = tau_xx*tau_yy*tau_zz + 2.0_wp*tau_xy*tau_xz*tau_yz - & + tau_xx*tau_yz**2.0_wp - tau_yy*tau_xz**2.0_wp - tau_zz*tau_xy**2.0_wp + + ! Maximum principal stress + temp = I1**2.0_wp - 3.0_wp*I2 + sqrt_term_1 = sqrt(max(temp, 0.0_wp)) + if (sqrt_term_1 > verysmall) then ! Avoid 0/0 + argument = (2.0_wp*I1*I1*I1 - 9.0_wp*I1*I2 + 27.0_wp*I3)/ & + (2.0_wp*sqrt_term_1*sqrt_term_1*sqrt_term_1) + if (argument > 1.0_wp) argument = 1.0_wp + if (argument < -1.0_wp) argument = -1.0_wp + phi = acos(argument) + sqrt_term_2 = sqrt(max(I1**2.0_wp - 3.0_wp*I2, 0.0_wp)) + tau_p = I1/3.0_wp + 2.0_wp/sqrt(3.0_wp)*sqrt_term_2*cos(phi/3.0_wp) + else + tau_p = I1/3.0_wp + end if + + rhs_vf(damage_idx)%sf(k, l, q) = (alpha_bar*max(tau_p - tau_star, 0._wp))**cont_damage_s + end do + end do + end do #:endcall GPU_PARALLEL_LOOP end if diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index 97d31f9bc8..668a15d41e 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -170,163 +170,163 @@ contains type(ghost_point) :: innerp #:call GPU_PARALLEL_LOOP(private='[physical_loc,dyn_pres,alpha_rho_IP, alpha_IP,pres_IP,vel_IP,vel_g,vel_norm_IP,r_IP, v_IP,pb_IP,mv_IP,nmom_IP,presb_IP,massv_IP,rho, gamma,pi_inf,Re_K,G_K,Gs,gp,innerp,norm,buf, j,k,l,q]') - do i = 1, num_gps - - gp = ghost_points(i) - j = gp%loc(1) - k = gp%loc(2) - l = gp%loc(3) - patch_id = ghost_points(i)%ib_patch_id + do i = 1, num_gps - ! Calculate physical location of GP - if (p > 0) then - physical_loc = [x_cc(j), y_cc(k), z_cc(l)] - else - physical_loc = [x_cc(j), y_cc(k), 0._wp] - end if + gp = ghost_points(i) + j = gp%loc(1) + k = gp%loc(2) + l = gp%loc(3) + patch_id = ghost_points(i)%ib_patch_id - !Interpolate primitive variables at image point associated w/ GP - if (bubbles_euler .and. .not. qbmm) then - call s_interpolate_image_point(q_prim_vf, gp, & - alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP, & - r_IP, v_IP, pb_IP, mv_IP) - else if (qbmm .and. polytropic) then - call s_interpolate_image_point(q_prim_vf, gp, & - alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP, & - r_IP, v_IP, pb_IP, mv_IP, nmom_IP) - else if (qbmm .and. .not. polytropic) then - call s_interpolate_image_point(q_prim_vf, gp, & - alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP, & - r_IP, v_IP, pb_IP, mv_IP, nmom_IP, pb_in, mv_in, presb_IP, massv_IP) - else - call s_interpolate_image_point(q_prim_vf, gp, & - alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP) - end if + ! Calculate physical location of GP + if (p > 0) then + physical_loc = [x_cc(j), y_cc(k), z_cc(l)] + else + physical_loc = [x_cc(j), y_cc(k), 0._wp] + end if - dyn_pres = 0._wp + !Interpolate primitive variables at image point associated w/ GP + if (bubbles_euler .and. .not. qbmm) then + call s_interpolate_image_point(q_prim_vf, gp, & + alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP, & + r_IP, v_IP, pb_IP, mv_IP) + else if (qbmm .and. polytropic) then + call s_interpolate_image_point(q_prim_vf, gp, & + alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP, & + r_IP, v_IP, pb_IP, mv_IP, nmom_IP) + else if (qbmm .and. .not. polytropic) then + call s_interpolate_image_point(q_prim_vf, gp, & + alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP, & + r_IP, v_IP, pb_IP, mv_IP, nmom_IP, pb_in, mv_in, presb_IP, massv_IP) + else + call s_interpolate_image_point(q_prim_vf, gp, & + alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP) + end if - ! Set q_prim_vf params at GP so that mixture vars calculated properly - $:GPU_LOOP(parallelism='[seq]') - do q = 1, num_fluids - q_prim_vf(q)%sf(j, k, l) = alpha_rho_IP(q) - q_prim_vf(advxb + q - 1)%sf(j, k, l) = alpha_IP(q) - end do + dyn_pres = 0._wp - if (surface_tension) then - q_prim_vf(c_idx)%sf(j, k, l) = c_IP - end if + ! Set q_prim_vf params at GP so that mixture vars calculated properly + $:GPU_LOOP(parallelism='[seq]') + do q = 1, num_fluids + q_prim_vf(q)%sf(j, k, l) = alpha_rho_IP(q) + q_prim_vf(advxb + q - 1)%sf(j, k, l) = alpha_IP(q) + end do - if (model_eqns /= 4) then - ! If in simulation, use acc mixture subroutines - if (elasticity) then - call s_convert_species_to_mixture_variables_acc(rho, gamma, pi_inf, qv_K, alpha_IP, & - alpha_rho_IP, Re_K, G_K, Gs) - else if (bubbles_euler) then - call s_convert_species_to_mixture_variables_bubbles_acc(rho, gamma, pi_inf, qv_K, alpha_IP, & - alpha_rho_IP, Re_K) - else - call s_convert_species_to_mixture_variables_acc(rho, gamma, pi_inf, qv_K, alpha_IP, & - alpha_rho_IP, Re_K) + if (surface_tension) then + q_prim_vf(c_idx)%sf(j, k, l) = c_IP end if - end if - ! Calculate velocity of ghost cell - if (gp%slip) then - norm(1:3) = levelset_norm%sf(gp%loc(1), gp%loc(2), gp%loc(3), gp%ib_patch_id, 1:3) - buf = sqrt(sum(norm**2)) - norm = norm/buf - vel_norm_IP = sum(vel_IP*norm)*norm - vel_g = vel_IP - vel_norm_IP - else - vel_g = 0._wp - end if + if (model_eqns /= 4) then + ! If in simulation, use acc mixture subroutines + if (elasticity) then + call s_convert_species_to_mixture_variables_acc(rho, gamma, pi_inf, qv_K, alpha_IP, & + alpha_rho_IP, Re_K, G_K, Gs) + else if (bubbles_euler) then + call s_convert_species_to_mixture_variables_bubbles_acc(rho, gamma, pi_inf, qv_K, alpha_IP, & + alpha_rho_IP, Re_K) + else + call s_convert_species_to_mixture_variables_acc(rho, gamma, pi_inf, qv_K, alpha_IP, & + alpha_rho_IP, Re_K) + end if + end if - ! Set momentum - $:GPU_LOOP(parallelism='[seq]') - do q = momxb, momxe - q_cons_vf(q)%sf(j, k, l) = rho*vel_g(q - momxb + 1) - dyn_pres = dyn_pres + q_cons_vf(q)%sf(j, k, l)* & - vel_g(q - momxb + 1)/2._wp - end do + ! Calculate velocity of ghost cell + if (gp%slip) then + norm(1:3) = levelset_norm%sf(gp%loc(1), gp%loc(2), gp%loc(3), gp%ib_patch_id, 1:3) + buf = sqrt(sum(norm**2)) + norm = norm/buf + vel_norm_IP = sum(vel_IP*norm)*norm + vel_g = vel_IP - vel_norm_IP + else + vel_g = 0._wp + end if - ! Set continuity and adv vars - $:GPU_LOOP(parallelism='[seq]') - do q = 1, num_fluids - q_cons_vf(q)%sf(j, k, l) = alpha_rho_IP(q) - q_cons_vf(advxb + q - 1)%sf(j, k, l) = alpha_IP(q) - end do + ! Set momentum + $:GPU_LOOP(parallelism='[seq]') + do q = momxb, momxe + q_cons_vf(q)%sf(j, k, l) = rho*vel_g(q - momxb + 1) + dyn_pres = dyn_pres + q_cons_vf(q)%sf(j, k, l)* & + vel_g(q - momxb + 1)/2._wp + end do - ! Set color function - if (surface_tension) then - q_cons_vf(c_idx)%sf(j, k, l) = c_IP - end if + ! Set continuity and adv vars + $:GPU_LOOP(parallelism='[seq]') + do q = 1, num_fluids + q_cons_vf(q)%sf(j, k, l) = alpha_rho_IP(q) + q_cons_vf(advxb + q - 1)%sf(j, k, l) = alpha_IP(q) + end do - ! Set Energy - if (bubbles_euler) then - q_cons_vf(E_idx)%sf(j, k, l) = (1 - alpha_IP(1))*(gamma*pres_IP + pi_inf + dyn_pres) - else - q_cons_vf(E_idx)%sf(j, k, l) = gamma*pres_IP + pi_inf + dyn_pres - end if + ! Set color function + if (surface_tension) then + q_cons_vf(c_idx)%sf(j, k, l) = c_IP + end if - ! Set bubble vars - if (bubbles_euler .and. .not. qbmm) then - call s_comp_n_from_prim(alpha_IP(1), r_IP, nbub, weight) - do q = 1, nb - q_cons_vf(bubxb + (q - 1)*2)%sf(j, k, l) = nbub*r_IP(q) - q_cons_vf(bubxb + (q - 1)*2 + 1)%sf(j, k, l) = nbub*v_IP(q) - if (.not. polytropic) then - q_cons_vf(bubxb + (q - 1)*4)%sf(j, k, l) = nbub*r_IP(q) - q_cons_vf(bubxb + (q - 1)*4 + 1)%sf(j, k, l) = nbub*v_IP(q) - q_cons_vf(bubxb + (q - 1)*4 + 2)%sf(j, k, l) = nbub*pb_IP(q) - q_cons_vf(bubxb + (q - 1)*4 + 3)%sf(j, k, l) = nbub*mv_IP(q) - end if - end do - end if + ! Set Energy + if (bubbles_euler) then + q_cons_vf(E_idx)%sf(j, k, l) = (1 - alpha_IP(1))*(gamma*pres_IP + pi_inf + dyn_pres) + else + q_cons_vf(E_idx)%sf(j, k, l) = gamma*pres_IP + pi_inf + dyn_pres + end if - if (qbmm) then + ! Set bubble vars + if (bubbles_euler .and. .not. qbmm) then + call s_comp_n_from_prim(alpha_IP(1), r_IP, nbub, weight) + do q = 1, nb + q_cons_vf(bubxb + (q - 1)*2)%sf(j, k, l) = nbub*r_IP(q) + q_cons_vf(bubxb + (q - 1)*2 + 1)%sf(j, k, l) = nbub*v_IP(q) + if (.not. polytropic) then + q_cons_vf(bubxb + (q - 1)*4)%sf(j, k, l) = nbub*r_IP(q) + q_cons_vf(bubxb + (q - 1)*4 + 1)%sf(j, k, l) = nbub*v_IP(q) + q_cons_vf(bubxb + (q - 1)*4 + 2)%sf(j, k, l) = nbub*pb_IP(q) + q_cons_vf(bubxb + (q - 1)*4 + 3)%sf(j, k, l) = nbub*mv_IP(q) + end if + end do + end if - nbub = nmom_IP(1) - do q = 1, nb*nmom - q_cons_vf(bubxb + q - 1)%sf(j, k, l) = nbub*nmom_IP(q) - end do - do q = 1, nb - q_cons_vf(bubxb + (q - 1)*nmom)%sf(j, k, l) = nbub - end do + if (qbmm) then - if (.not. polytropic) then + nbub = nmom_IP(1) + do q = 1, nb*nmom + q_cons_vf(bubxb + q - 1)%sf(j, k, l) = nbub*nmom_IP(q) + end do do q = 1, nb - do r = 1, nnode - pb_in(j, k, l, r, q) = presb_IP((q - 1)*nnode + r) - mv_in(j, k, l, r, q) = massv_IP((q - 1)*nnode + r) - end do + q_cons_vf(bubxb + (q - 1)*nmom)%sf(j, k, l) = nbub end do + + if (.not. polytropic) then + do q = 1, nb + do r = 1, nnode + pb_in(j, k, l, r, q) = presb_IP((q - 1)*nnode + r) + mv_in(j, k, l, r, q) = massv_IP((q - 1)*nnode + r) + end do + end do + end if end if - end if - if (model_eqns == 3) then - $:GPU_LOOP(parallelism='[seq]') - do q = intxb, intxe - q_cons_vf(q)%sf(j, k, l) = alpha_IP(q - intxb + 1)*(gammas(q - intxb + 1)*pres_IP & - + pi_infs(q - intxb + 1)) - end do - end if - end do + if (model_eqns == 3) then + $:GPU_LOOP(parallelism='[seq]') + do q = intxb, intxe + q_cons_vf(q)%sf(j, k, l) = alpha_IP(q - intxb + 1)*(gammas(q - intxb + 1)*pres_IP & + + pi_infs(q - intxb + 1)) + end do + end if + end do #:endcall GPU_PARALLEL_LOOP !Correct the state of the inner points in IBs #:call GPU_PARALLEL_LOOP(private='[physical_loc,dyn_pres,alpha_rho_IP, alpha_IP,vel_g,rho,gamma,pi_inf,Re_K,innerp,j,k,l,q]') - do i = 1, num_inner_gps + do i = 1, num_inner_gps - innerp = inner_points(i) - j = innerp%loc(1) - k = innerp%loc(2) - l = innerp%loc(3) + innerp = inner_points(i) + j = innerp%loc(1) + k = innerp%loc(2) + l = innerp%loc(3) - $:GPU_LOOP(parallelism='[seq]') - do q = momxb, momxe - q_cons_vf(q)%sf(j, k, l) = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do q = momxb, momxe + q_cons_vf(q)%sf(j, k, l) = 0._wp + end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_ibm_correct_state diff --git a/src/simulation/m_mhd.fpp b/src/simulation/m_mhd.fpp index 43d8aeef18..1680efdb6f 100644 --- a/src/simulation/m_mhd.fpp +++ b/src/simulation/m_mhd.fpp @@ -77,58 +77,58 @@ contains real(wp) :: divB, vdotB #:call GPU_PARALLEL_LOOP(collapse=3, private='[v, B]') - do q = 0, p - do l = 0, n - do k = 0, m - - divB = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do r = -fd_number, fd_number - divB = divB + q_prim_vf(B_idx%beg)%sf(k + r, l, q)*fd_coeff_x_h(r, k) - end do - $:GPU_LOOP(parallelism='[seq]') - do r = -fd_number, fd_number - divB = divB + q_prim_vf(B_idx%beg + 1)%sf(k, l + r, q)*fd_coeff_y_h(r, l) - end do - if (p > 0) then + do q = 0, p + do l = 0, n + do k = 0, m + + divB = 0._wp $:GPU_LOOP(parallelism='[seq]') do r = -fd_number, fd_number - divB = divB + q_prim_vf(B_idx%beg + 2)%sf(k, l, q + r)*fd_coeff_z_h(r, q) + divB = divB + q_prim_vf(B_idx%beg)%sf(k + r, l, q)*fd_coeff_x_h(r, k) end do - end if - - v(1) = q_prim_vf(momxb)%sf(k, l, q) - v(2) = q_prim_vf(momxb + 1)%sf(k, l, q) - v(3) = q_prim_vf(momxb + 2)%sf(k, l, q) - - B(1) = q_prim_vf(B_idx%beg)%sf(k, l, q) - B(2) = q_prim_vf(B_idx%beg + 1)%sf(k, l, q) - B(3) = q_prim_vf(B_idx%beg + 2)%sf(k, l, q) - - vdotB = sum(v*B) - - ! 1: rho -> unchanged - ! 2: vx -> - (divB) * Bx - ! 3: vy -> - (divB) * By - ! 4: vz -> - (divB) * Bz - ! 5: E -> - (divB) * (vdotB) - ! 6: Bx -> - (divB) * vx - ! 7: By -> - (divB) * vy - ! 8: Bz -> - (divB) * vz - - rhs_vf(momxb)%sf(k, l, q) = rhs_vf(momxb)%sf(k, l, q) - divB*B(1) - rhs_vf(momxb + 1)%sf(k, l, q) = rhs_vf(momxb + 1)%sf(k, l, q) - divB*B(2) - rhs_vf(momxb + 2)%sf(k, l, q) = rhs_vf(momxb + 2)%sf(k, l, q) - divB*B(3) - - rhs_vf(E_idx)%sf(k, l, q) = rhs_vf(E_idx)%sf(k, l, q) - divB*vdotB - - rhs_vf(B_idx%beg)%sf(k, l, q) = rhs_vf(B_idx%beg)%sf(k, l, q) - divB*v(1) - rhs_vf(B_idx%beg + 1)%sf(k, l, q) = rhs_vf(B_idx%beg + 1)%sf(k, l, q) - divB*v(2) - rhs_vf(B_idx%beg + 2)%sf(k, l, q) = rhs_vf(B_idx%beg + 2)%sf(k, l, q) - divB*v(3) + $:GPU_LOOP(parallelism='[seq]') + do r = -fd_number, fd_number + divB = divB + q_prim_vf(B_idx%beg + 1)%sf(k, l + r, q)*fd_coeff_y_h(r, l) + end do + if (p > 0) then + $:GPU_LOOP(parallelism='[seq]') + do r = -fd_number, fd_number + divB = divB + q_prim_vf(B_idx%beg + 2)%sf(k, l, q + r)*fd_coeff_z_h(r, q) + end do + end if + + v(1) = q_prim_vf(momxb)%sf(k, l, q) + v(2) = q_prim_vf(momxb + 1)%sf(k, l, q) + v(3) = q_prim_vf(momxb + 2)%sf(k, l, q) + + B(1) = q_prim_vf(B_idx%beg)%sf(k, l, q) + B(2) = q_prim_vf(B_idx%beg + 1)%sf(k, l, q) + B(3) = q_prim_vf(B_idx%beg + 2)%sf(k, l, q) + + vdotB = sum(v*B) + + ! 1: rho -> unchanged + ! 2: vx -> - (divB) * Bx + ! 3: vy -> - (divB) * By + ! 4: vz -> - (divB) * Bz + ! 5: E -> - (divB) * (vdotB) + ! 6: Bx -> - (divB) * vx + ! 7: By -> - (divB) * vy + ! 8: Bz -> - (divB) * vz + + rhs_vf(momxb)%sf(k, l, q) = rhs_vf(momxb)%sf(k, l, q) - divB*B(1) + rhs_vf(momxb + 1)%sf(k, l, q) = rhs_vf(momxb + 1)%sf(k, l, q) - divB*B(2) + rhs_vf(momxb + 2)%sf(k, l, q) = rhs_vf(momxb + 2)%sf(k, l, q) - divB*B(3) + + rhs_vf(E_idx)%sf(k, l, q) = rhs_vf(E_idx)%sf(k, l, q) - divB*vdotB + + rhs_vf(B_idx%beg)%sf(k, l, q) = rhs_vf(B_idx%beg)%sf(k, l, q) - divB*v(1) + rhs_vf(B_idx%beg + 1)%sf(k, l, q) = rhs_vf(B_idx%beg + 1)%sf(k, l, q) - divB*v(2) + rhs_vf(B_idx%beg + 2)%sf(k, l, q) = rhs_vf(B_idx%beg + 2)%sf(k, l, q) - divB*v(3) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_mhd_powell_rhs diff --git a/src/simulation/m_mpi_proxy.fpp b/src/simulation/m_mpi_proxy.fpp index 915146fdfe..2a012cdc75 100644 --- a/src/simulation/m_mpi_proxy.fpp +++ b/src/simulation/m_mpi_proxy.fpp @@ -300,38 +300,38 @@ contains if (mpi_dir == ${mpi_dir}$) then #:if mpi_dir == 1 #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') - do l = 0, p - do k = 0, n - do j = 0, gp_layers - 1 - r = (j + gp_layers*(k + (n + 1)*l)) - ib_buff_send(r) = ib_markers%sf(j + pack_offset, k, l) + do l = 0, p + do k = 0, n + do j = 0, gp_layers - 1 + r = (j + gp_layers*(k + (n + 1)*l)) + ib_buff_send(r) = ib_markers%sf(j + pack_offset, k, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:elif mpi_dir == 2 #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') - do l = 0, p - do k = 0, gp_layers - 1 - do j = -gp_layers, m + gp_layers - r = ((j + gp_layers) + (m + 2*gp_layers + 1)* & - (k + gp_layers*l)) - ib_buff_send(r) = ib_markers%sf(j, k + pack_offset, l) + do l = 0, p + do k = 0, gp_layers - 1 + do j = -gp_layers, m + gp_layers + r = ((j + gp_layers) + (m + 2*gp_layers + 1)* & + (k + gp_layers*l)) + ib_buff_send(r) = ib_markers%sf(j, k + pack_offset, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:else #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') - do l = 0, gp_layers - 1 - do k = -gp_layers, n + gp_layers - do j = -gp_layers, m + gp_layers - r = ((j + gp_layers) + (m + 2*gp_layers + 1)* & - ((k + gp_layers) + (n + 2*gp_layers + 1)*l)) - ib_buff_send(r) = ib_markers%sf(j, k, l + pack_offset) + do l = 0, gp_layers - 1 + do k = -gp_layers, n + gp_layers + do j = -gp_layers, m + gp_layers + r = ((j + gp_layers) + (m + 2*gp_layers + 1)* & + ((k + gp_layers) + (n + 2*gp_layers + 1)*l)) + ib_buff_send(r) = ib_markers%sf(j, k, l + pack_offset) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:endif end if @@ -351,40 +351,40 @@ contains if (mpi_dir == ${mpi_dir}$) then #:if mpi_dir == 1 #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') - do l = 0, p - do k = 0, n - do j = -gp_layers, -1 - r = (j + gp_layers*((k + 1) + (n + 1)*l)) - ib_markers%sf(j + unpack_offset, k, l) = ib_buff_recv(r) + do l = 0, p + do k = 0, n + do j = -gp_layers, -1 + r = (j + gp_layers*((k + 1) + (n + 1)*l)) + ib_markers%sf(j + unpack_offset, k, l) = ib_buff_recv(r) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:elif mpi_dir == 2 #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') - do l = 0, p - do k = -gp_layers, -1 - do j = -gp_layers, m + gp_layers - r = ((j + gp_layers) + (m + 2*gp_layers + 1)* & - ((k + gp_layers) + gp_layers*l)) - ib_markers%sf(j, k + unpack_offset, l) = ib_buff_recv(r) + do l = 0, p + do k = -gp_layers, -1 + do j = -gp_layers, m + gp_layers + r = ((j + gp_layers) + (m + 2*gp_layers + 1)* & + ((k + gp_layers) + gp_layers*l)) + ib_markers%sf(j, k + unpack_offset, l) = ib_buff_recv(r) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:else ! Unpacking buffer from bc_z%beg #:call GPU_PARALLEL_LOOP(collapse=3,private='[r]') - do l = -gp_layers, -1 - do k = -gp_layers, n + gp_layers - do j = -gp_layers, m + gp_layers - r = ((j + gp_layers) + (m + 2*gp_layers + 1)* & - ((k + gp_layers) + (n + 2*gp_layers + 1)* & - (l + gp_layers))) - ib_markers%sf(j, k, l + unpack_offset) = ib_buff_recv(r) + do l = -gp_layers, -1 + do k = -gp_layers, n + gp_layers + do j = -gp_layers, m + gp_layers + r = ((j + gp_layers) + (m + 2*gp_layers + 1)* & + ((k + gp_layers) + (n + 2*gp_layers + 1)* & + (l + gp_layers))) + ib_markers%sf(j, k, l + unpack_offset) = ib_buff_recv(r) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:endif end if diff --git a/src/simulation/m_pressure_relaxation.fpp b/src/simulation/m_pressure_relaxation.fpp index 5449e84058..52340ccbb2 100644 --- a/src/simulation/m_pressure_relaxation.fpp +++ b/src/simulation/m_pressure_relaxation.fpp @@ -71,13 +71,13 @@ contains integer :: j, k, l #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - call s_relax_cell_pressure(q_cons_vf, j, k, l) + do l = 0, p + do k = 0, n + do j = 0, m + call s_relax_cell_pressure(q_cons_vf, j, k, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_pressure_relaxation_procedure diff --git a/src/simulation/m_qbmm.fpp b/src/simulation/m_qbmm.fpp index c5fbd486b4..6ce6005e87 100644 --- a/src/simulation/m_qbmm.fpp +++ b/src/simulation/m_qbmm.fpp @@ -434,130 +434,130 @@ contains if (.not. polytropic) then #:call GPU_PARALLEL_LOOP(collapse=5,private='[nb_q,nR,nR2,R,R2,nb_dot,nR_dot,nR2_dot,var,AX]') - do i = 1, nb - do q = 1, nnode - do l = 0, p - do k = 0, n - do j = 0, m - nb_q = q_cons_vf(bubxb + (i - 1)*nmom)%sf(j, k, l) - nR = q_cons_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l) - nR2 = q_cons_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l) - R = q_prim_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l) - R2 = q_prim_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l) - var = max(R2 - R**2._wp, verysmall) - if (q <= 2) then - AX = R - sqrt(var) - else - AX = R + sqrt(var) - end if - select case (idir) - case (1) - nb_dot = flux_n_vf(bubxb + (i - 1)*nmom)%sf(j - 1, k, l) - flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l) - nR_dot = flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j - 1, k, l) - flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l) - nR2_dot = flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j - 1, k, l) - flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dx(j)*AX*nb_q**2)* & - (nR_dot*nb_q - nR*nb_dot)*(pb(j, k, l, q, i)) - case (2) - nb_dot = flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k - 1, l) - flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l) - nR_dot = flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k - 1, l) - flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l) - nR2_dot = flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k - 1, l) - flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dy(k)*AX*nb_q**2)* & - (nR_dot*nb_q - nR*nb_dot)*(pb(j, k, l, q, i)) - case (3) - if (is_axisym) then - nb_dot = q_prim_vf(contxe + idir)%sf(j, k, l)*(flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l)) - nR_dot = q_prim_vf(contxe + idir)%sf(j, k, l)*(flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l)) - nR2_dot = q_prim_vf(contxe + idir)%sf(j, k, l)*(flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l)) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*y_cc(k)*AX*nb_q**2)* & - (nR_dot*nb_q - nR*nb_dot)*(pb(j, k, l, q, i)) + do i = 1, nb + do q = 1, nnode + do l = 0, p + do k = 0, n + do j = 0, m + nb_q = q_cons_vf(bubxb + (i - 1)*nmom)%sf(j, k, l) + nR = q_cons_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l) + nR2 = q_cons_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l) + R = q_prim_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l) + R2 = q_prim_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l) + var = max(R2 - R**2._wp, verysmall) + if (q <= 2) then + AX = R - sqrt(var) else - nb_dot = flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l) - nR_dot = flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l) - nR2_dot = flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*AX*nb_q**2)* & - (nR_dot*nb_q - nR*nb_dot)*(pb(j, k, l, q, i)) + AX = R + sqrt(var) end if - end select - if (q <= 2) then select case (idir) case (1) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dx(j)*AX*nb_q**2*sqrt(var)*2._wp)* & - (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dx(j)*AX*nb_q**2*sqrt(var)*2._wp)* & - (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) + nb_dot = flux_n_vf(bubxb + (i - 1)*nmom)%sf(j - 1, k, l) - flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l) + nR_dot = flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j - 1, k, l) - flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l) + nR2_dot = flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j - 1, k, l) - flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dx(j)*AX*nb_q**2)* & + (nR_dot*nb_q - nR*nb_dot)*(pb(j, k, l, q, i)) case (2) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dy(k)*AX*nb_q**2*sqrt(var)*2._wp)* & - (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dy(k)*AX*nb_q**2*sqrt(var)*2._wp)* & - (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) + nb_dot = flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k - 1, l) - flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l) + nR_dot = flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k - 1, l) - flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l) + nR2_dot = flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k - 1, l) - flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dy(k)*AX*nb_q**2)* & + (nR_dot*nb_q - nR*nb_dot)*(pb(j, k, l, q, i)) case (3) if (is_axisym) then - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dz(l)*y_cc(k)*AX*nb_q**2*sqrt(var)*2._wp)* & + nb_dot = q_prim_vf(contxe + idir)%sf(j, k, l)*(flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l)) + nR_dot = q_prim_vf(contxe + idir)%sf(j, k, l)*(flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l)) + nR2_dot = q_prim_vf(contxe + idir)%sf(j, k, l)*(flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l)) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*y_cc(k)*AX*nb_q**2)* & + (nR_dot*nb_q - nR*nb_dot)*(pb(j, k, l, q, i)) + else + nb_dot = flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + (i - 1)*nmom)%sf(j, k, l) + nR_dot = flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + 1 + (i - 1)*nmom)%sf(j, k, l) + nR2_dot = flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l - 1) - flux_n_vf(bubxb + 3 + (i - 1)*nmom)%sf(j, k, l) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*AX*nb_q**2)* & + (nR_dot*nb_q - nR*nb_dot)*(pb(j, k, l, q, i)) + end if + end select + if (q <= 2) then + select case (idir) + case (1) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dx(j)*AX*nb_q**2*sqrt(var)*2._wp)* & (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dz(l)*y_cc(k)*AX*nb_q**2*sqrt(var)*2._wp)* & + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dx(j)*AX*nb_q**2*sqrt(var)*2._wp)* & (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) - else - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dz(l)*AX*nb_q**2*sqrt(var)*2._wp)* & + case (2) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dy(k)*AX*nb_q**2*sqrt(var)*2._wp)* & (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dz(l)*AX*nb_q**2*sqrt(var)*2._wp)* & + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dy(k)*AX*nb_q**2*sqrt(var)*2._wp)* & (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) - end if - end select - else - select case (idir) - case (1) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dx(j)*AX*nb_q**2*sqrt(var)*2._wp)* & - (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dx(j)*AX*nb_q**2*sqrt(var)*2._wp)* & - (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) - case (2) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dy(k)*AX*nb_q**2*sqrt(var)*2._wp)* & - (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dy(k)*AX*nb_q**2*sqrt(var)*2._wp)* & - (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) - case (3) - if (is_axisym) then - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*y_cc(k)*AX*nb_q**2*sqrt(var)*2._wp)* & + case (3) + if (is_axisym) then + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dz(l)*y_cc(k)*AX*nb_q**2*sqrt(var)*2._wp)* & + (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dz(l)*y_cc(k)*AX*nb_q**2*sqrt(var)*2._wp)* & + (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) + else + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dz(l)*AX*nb_q**2*sqrt(var)*2._wp)* & + (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) + 3._wp*gam/(dz(l)*AX*nb_q**2*sqrt(var)*2._wp)* & + (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) + end if + end select + else + select case (idir) + case (1) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dx(j)*AX*nb_q**2*sqrt(var)*2._wp)* & (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*y_cc(k)*AX*nb_q**2*sqrt(var)*2._wp)* & + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dx(j)*AX*nb_q**2*sqrt(var)*2._wp)* & (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) - else - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*AX*nb_q**2*sqrt(var)*2._wp)* & + case (2) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dy(k)*AX*nb_q**2*sqrt(var)*2._wp)* & (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) - rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*AX*nb_q**2*sqrt(var)*2._wp)* & + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dy(k)*AX*nb_q**2*sqrt(var)*2._wp)* & (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) - end if - end select - end if + case (3) + if (is_axisym) then + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*y_cc(k)*AX*nb_q**2*sqrt(var)*2._wp)* & + (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*y_cc(k)*AX*nb_q**2*sqrt(var)*2._wp)* & + (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) + else + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*AX*nb_q**2*sqrt(var)*2._wp)* & + (nR2_dot*nb_q - nR2*nb_dot)*(pb(j, k, l, q, i)) + rhs_pb(j, k, l, q, i) = rhs_pb(j, k, l, q, i) - 3._wp*gam/(dz(l)*AX*nb_q**2*sqrt(var)*2._wp)* & + (-2._wp*(nR/nb_q)*(nR_dot*nb_q - nR*nb_dot))*(pb(j, k, l, q, i)) + end if + end select + end if + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if ! The following block is not repeated and is left as is if (idir == 1) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do q = 0, n - do i = 0, m - rhs_vf(alf_idx)%sf(i, q, l) = rhs_vf(alf_idx)%sf(i, q, l) + mom_sp(2)%sf(i, q, l) - j = bubxb - $:GPU_LOOP(parallelism='[seq]') - do k = 1, nb - rhs_vf(j)%sf(i, q, l) = rhs_vf(j)%sf(i, q, l) + mom_3d(0, 0, k)%sf(i, q, l) - rhs_vf(j + 1)%sf(i, q, l) = rhs_vf(j + 1)%sf(i, q, l) + mom_3d(1, 0, k)%sf(i, q, l) - rhs_vf(j + 2)%sf(i, q, l) = rhs_vf(j + 2)%sf(i, q, l) + mom_3d(0, 1, k)%sf(i, q, l) - rhs_vf(j + 3)%sf(i, q, l) = rhs_vf(j + 3)%sf(i, q, l) + mom_3d(2, 0, k)%sf(i, q, l) - rhs_vf(j + 4)%sf(i, q, l) = rhs_vf(j + 4)%sf(i, q, l) + mom_3d(1, 1, k)%sf(i, q, l) - rhs_vf(j + 5)%sf(i, q, l) = rhs_vf(j + 5)%sf(i, q, l) + mom_3d(0, 2, k)%sf(i, q, l) - j = j + 6 + do l = 0, p + do q = 0, n + do i = 0, m + rhs_vf(alf_idx)%sf(i, q, l) = rhs_vf(alf_idx)%sf(i, q, l) + mom_sp(2)%sf(i, q, l) + j = bubxb + $:GPU_LOOP(parallelism='[seq]') + do k = 1, nb + rhs_vf(j)%sf(i, q, l) = rhs_vf(j)%sf(i, q, l) + mom_3d(0, 0, k)%sf(i, q, l) + rhs_vf(j + 1)%sf(i, q, l) = rhs_vf(j + 1)%sf(i, q, l) + mom_3d(1, 0, k)%sf(i, q, l) + rhs_vf(j + 2)%sf(i, q, l) = rhs_vf(j + 2)%sf(i, q, l) + mom_3d(0, 1, k)%sf(i, q, l) + rhs_vf(j + 3)%sf(i, q, l) = rhs_vf(j + 3)%sf(i, q, l) + mom_3d(2, 0, k)%sf(i, q, l) + rhs_vf(j + 4)%sf(i, q, l) = rhs_vf(j + 4)%sf(i, q, l) + mom_3d(1, 1, k)%sf(i, q, l) + rhs_vf(j + 5)%sf(i, q, l) = rhs_vf(j + 5)%sf(i, q, l) + mom_3d(0, 2, k)%sf(i, q, l) + j = j + 6 + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -715,142 +715,142 @@ contains $:GPU_UPDATE(device='[is1_qbmm,is2_qbmm,is3_qbmm]') #:call GPU_PARALLEL_LOOP(collapse=3, private='[moms, msum, wght, abscX, abscY, wght_pb, wght_mv, wght_ht, coeff, ht, r, q, n_tait, B_tait, pres, rho, nbub, c, alf, momsum, drdt, drdt2, chi_vw, x_vw, rho_mw, k_mw, T_bar, grad_T]') - do id3 = is3_qbmm%beg, is3_qbmm%end - do id2 = is2_qbmm%beg, is2_qbmm%end - do id1 = is1_qbmm%beg, is1_qbmm%end - - alf = q_prim_vf(alf_idx)%sf(id1, id2, id3) - pres = q_prim_vf(E_idx)%sf(id1, id2, id3) - rho = q_prim_vf(contxb)%sf(id1, id2, id3) - - if (bubble_model == 2) then - n_tait = 1._wp/gammas(1) + 1._wp - B_tait = pi_infs(1)*(n_tait - 1)/n_tait - c = n_tait*(pres + B_tait)*(1._wp - alf)/(rho) - c = merge(sqrt(c), sgm_eps, c > 0._wp) - end if + do id3 = is3_qbmm%beg, is3_qbmm%end + do id2 = is2_qbmm%beg, is2_qbmm%end + do id1 = is1_qbmm%beg, is1_qbmm%end + + alf = q_prim_vf(alf_idx)%sf(id1, id2, id3) + pres = q_prim_vf(E_idx)%sf(id1, id2, id3) + rho = q_prim_vf(contxb)%sf(id1, id2, id3) + + if (bubble_model == 2) then + n_tait = 1._wp/gammas(1) + 1._wp + B_tait = pi_infs(1)*(n_tait - 1)/n_tait + c = n_tait*(pres + B_tait)*(1._wp - alf)/(rho) + c = merge(sqrt(c), sgm_eps, c > 0._wp) + end if - call s_coeff_selector(pres, rho, c, coeff, polytropic) + call s_coeff_selector(pres, rho, c, coeff, polytropic) - if (alf > small_alf) then - nbub = q_cons_vf(bubxb)%sf(id1, id2, id3) - $:GPU_LOOP(parallelism='[seq]') - do q = 1, nb - ! Gather moments for this bubble bin + if (alf > small_alf) then + nbub = q_cons_vf(bubxb)%sf(id1, id2, id3) $:GPU_LOOP(parallelism='[seq]') - do r = 2, nmom - moms(r) = q_prim_vf(bubmoms(q, r))%sf(id1, id2, id3) - end do - moms(1) = 1._wp - call s_chyqmom(moms, wght(:, q), abscX(:, q), abscY(:, q)) - - if (polytropic) then - $:GPU_LOOP(parallelism='[seq]') - do j = 1, nnode - wght_pb(j, q) = wght(j, q)*(pb0(q) - pv) - end do - else + do q = 1, nb + ! Gather moments for this bubble bin $:GPU_LOOP(parallelism='[seq]') - do j = 1, nnode - chi_vw = 1._wp/(1._wp + R_v/R_n*(pb(id1, id2, id3, j, q)/pv - 1._wp)) - x_vw = M_n*chi_vw/(M_v + (M_n - M_v)*chi_vw) - k_mw = x_vw*k_v(q)/(x_vw + (1._wp - x_vw)*phi_vn) + (1._wp - x_vw)*k_n(q)/(x_vw*phi_nv + 1._wp - x_vw) - rho_mw = pv/(chi_vw*R_v*Tw) - rhs_mv(id1, id2, id3, j, q) = -Re_trans_c(q)*((mv(id1, id2, id3, j, q)/(mv(id1, id2, id3, j, q) + mass_n0(q))) - chi_vw) - rhs_mv(id1, id2, id3, j, q) = rho_mw*rhs_mv(id1, id2, id3, j, q)/Pe_c/(1._wp - chi_vw)/abscX(j, q) - T_bar = Tw*(pb(id1, id2, id3, j, q)/pb0(q))*(abscX(j, q)/R0(q))**3*(mass_n0(q) + mass_v0(q))/(mass_n0(q) + mv(id1, id2, id3, j, q)) - grad_T = -Re_trans_T(q)*(T_bar - Tw) - ht(j, q) = pb0(q)*k_mw*grad_T/Pe_T(q)/abscX(j, q) - wght_pb(j, q) = wght(j, q)*(pb(id1, id2, id3, j, q)) - wght_mv(j, q) = wght(j, q)*(rhs_mv(id1, id2, id3, j, q)) - wght_ht(j, q) = wght(j, q)*ht(j, q) + do r = 2, nmom + moms(r) = q_prim_vf(bubmoms(q, r))%sf(id1, id2, id3) end do - end if + moms(1) = 1._wp + call s_chyqmom(moms, wght(:, q), abscX(:, q), abscY(:, q)) + + if (polytropic) then + $:GPU_LOOP(parallelism='[seq]') + do j = 1, nnode + wght_pb(j, q) = wght(j, q)*(pb0(q) - pv) + end do + else + $:GPU_LOOP(parallelism='[seq]') + do j = 1, nnode + chi_vw = 1._wp/(1._wp + R_v/R_n*(pb(id1, id2, id3, j, q)/pv - 1._wp)) + x_vw = M_n*chi_vw/(M_v + (M_n - M_v)*chi_vw) + k_mw = x_vw*k_v(q)/(x_vw + (1._wp - x_vw)*phi_vn) + (1._wp - x_vw)*k_n(q)/(x_vw*phi_nv + 1._wp - x_vw) + rho_mw = pv/(chi_vw*R_v*Tw) + rhs_mv(id1, id2, id3, j, q) = -Re_trans_c(q)*((mv(id1, id2, id3, j, q)/(mv(id1, id2, id3, j, q) + mass_n0(q))) - chi_vw) + rhs_mv(id1, id2, id3, j, q) = rho_mw*rhs_mv(id1, id2, id3, j, q)/Pe_c/(1._wp - chi_vw)/abscX(j, q) + T_bar = Tw*(pb(id1, id2, id3, j, q)/pb0(q))*(abscX(j, q)/R0(q))**3*(mass_n0(q) + mass_v0(q))/(mass_n0(q) + mv(id1, id2, id3, j, q)) + grad_T = -Re_trans_T(q)*(T_bar - Tw) + ht(j, q) = pb0(q)*k_mw*grad_T/Pe_T(q)/abscX(j, q) + wght_pb(j, q) = wght(j, q)*(pb(id1, id2, id3, j, q)) + wght_mv(j, q) = wght(j, q)*(rhs_mv(id1, id2, id3, j, q)) + wght_ht(j, q) = wght(j, q)*ht(j, q) + end do + end if - ! Compute change in moments due to bubble dynamics - r = 1 - $:GPU_LOOP(parallelism='[seq]') - do i2 = 0, 2 + ! Compute change in moments due to bubble dynamics + r = 1 $:GPU_LOOP(parallelism='[seq]') - do i1 = 0, 2 - if ((i1 + i2) <= 2) then - momsum = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do j = 1, nterms - select case (bubble_model) - case (3) - if (j == 3) then - momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght_pb(:, q), momrhs(:, i1, i2, j, q)) - else - momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght(:, q), momrhs(:, i1, i2, j, q)) - end if - case (2) - if ((j >= 7 .and. j <= 9) .or. (j >= 22 .and. j <= 23) .or. (j >= 10 .and. j <= 11) .or. (j == 26)) then - momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght_pb(:, q), momrhs(:, i1, i2, j, q)) - else if ((j >= 27 .and. j <= 29) .and. (.not. polytropic)) then - momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght_mv(:, q), momrhs(:, i1, i2, j, q)) - else if ((j >= 30 .and. j <= 32) .and. (.not. polytropic)) then - momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght_ht(:, q), momrhs(:, i1, i2, j, q)) - else - momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght(:, q), momrhs(:, i1, i2, j, q)) - end if - end select - end do - moms3d(i1, i2, q)%sf(id1, id2, id3) = nbub*momsum - msum(r) = momsum - r = r + 1 - end if + do i2 = 0, 2 + $:GPU_LOOP(parallelism='[seq]') + do i1 = 0, 2 + if ((i1 + i2) <= 2) then + momsum = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do j = 1, nterms + select case (bubble_model) + case (3) + if (j == 3) then + momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght_pb(:, q), momrhs(:, i1, i2, j, q)) + else + momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght(:, q), momrhs(:, i1, i2, j, q)) + end if + case (2) + if ((j >= 7 .and. j <= 9) .or. (j >= 22 .and. j <= 23) .or. (j >= 10 .and. j <= 11) .or. (j == 26)) then + momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght_pb(:, q), momrhs(:, i1, i2, j, q)) + else if ((j >= 27 .and. j <= 29) .and. (.not. polytropic)) then + momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght_mv(:, q), momrhs(:, i1, i2, j, q)) + else if ((j >= 30 .and. j <= 32) .and. (.not. polytropic)) then + momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght_ht(:, q), momrhs(:, i1, i2, j, q)) + else + momsum = momsum + coeff(j, i1, i2)*(R0(q)**momrhs(3, i1, i2, j, q))*f_quad2D(abscX(:, q), abscY(:, q), wght(:, q), momrhs(:, i1, i2, j, q)) + end if + end select + end do + moms3d(i1, i2, q)%sf(id1, id2, id3) = nbub*momsum + msum(r) = momsum + r = r + 1 + end if + end do end do - end do - ! Compute change in pb and mv for non-polytropic model - if (.not. polytropic) then - $:GPU_LOOP(parallelism='[seq]') - do j = 1, nnode - drdt = msum(2) - drdt2 = merge(-1._wp, 1._wp, j == 1 .or. j == 2)/(2._wp*sqrt(merge(moms(4) - moms(2)**2._wp, verysmall, moms(4) - moms(2)**2._wp > 0._wp))) - drdt2 = drdt2*(msum(3) - 2._wp*moms(2)*msum(2)) - drdt = drdt + drdt2 - rhs_pb(id1, id2, id3, j, q) = (-3._wp*gam*drdt/abscX(j, q))*(pb(id1, id2, id3, j, q)) - rhs_pb(id1, id2, id3, j, q) = rhs_pb(id1, id2, id3, j, q) + (3._wp*gam/abscX(j, q))*rhs_mv(id1, id2, id3, j, q)*R_v*Tw - rhs_pb(id1, id2, id3, j, q) = rhs_pb(id1, id2, id3, j, q) + (3._wp*gam/abscX(j, q))*ht(j, q) - rhs_mv(id1, id2, id3, j, q) = rhs_mv(id1, id2, id3, j, q)*(4._wp*pi*abscX(j, q)**2._wp) - end do - end if - end do + ! Compute change in pb and mv for non-polytropic model + if (.not. polytropic) then + $:GPU_LOOP(parallelism='[seq]') + do j = 1, nnode + drdt = msum(2) + drdt2 = merge(-1._wp, 1._wp, j == 1 .or. j == 2)/(2._wp*sqrt(merge(moms(4) - moms(2)**2._wp, verysmall, moms(4) - moms(2)**2._wp > 0._wp))) + drdt2 = drdt2*(msum(3) - 2._wp*moms(2)*msum(2)) + drdt = drdt + drdt2 + rhs_pb(id1, id2, id3, j, q) = (-3._wp*gam*drdt/abscX(j, q))*(pb(id1, id2, id3, j, q)) + rhs_pb(id1, id2, id3, j, q) = rhs_pb(id1, id2, id3, j, q) + (3._wp*gam/abscX(j, q))*rhs_mv(id1, id2, id3, j, q)*R_v*Tw + rhs_pb(id1, id2, id3, j, q) = rhs_pb(id1, id2, id3, j, q) + (3._wp*gam/abscX(j, q))*ht(j, q) + rhs_mv(id1, id2, id3, j, q) = rhs_mv(id1, id2, id3, j, q)*(4._wp*pi*abscX(j, q)**2._wp) + end do + end if + end do - ! Compute special high-order moments - momsp(1)%sf(id1, id2, id3) = f_quad(abscX, abscY, wght, 3._wp, 0._wp, 0._wp) - momsp(2)%sf(id1, id2, id3) = 4._wp*pi*nbub*f_quad(abscX, abscY, wght, 2._wp, 1._wp, 0._wp) - momsp(3)%sf(id1, id2, id3) = f_quad(abscX, abscY, wght, 3._wp, 2._wp, 0._wp) - if (abs(gam - 1._wp) <= 1.e-4_wp) then - momsp(4)%sf(id1, id2, id3) = 1._wp - else - if (polytropic) then - momsp(4)%sf(id1, id2, id3) = f_quad(abscX, abscY, wght_pb, 3._wp*(1._wp - gam), 0._wp, 3._wp*gam) + pv*f_quad(abscX, abscY, wght, 3._wp, 0._wp, 0._wp) - 4._wp*Re_inv*f_quad(abscX, abscY, wght, 2._wp, 1._wp, 0._wp) - (2._wp/Web)*f_quad(abscX, abscY, wght, 2._wp, 0._wp, 0._wp) + ! Compute special high-order moments + momsp(1)%sf(id1, id2, id3) = f_quad(abscX, abscY, wght, 3._wp, 0._wp, 0._wp) + momsp(2)%sf(id1, id2, id3) = 4._wp*pi*nbub*f_quad(abscX, abscY, wght, 2._wp, 1._wp, 0._wp) + momsp(3)%sf(id1, id2, id3) = f_quad(abscX, abscY, wght, 3._wp, 2._wp, 0._wp) + if (abs(gam - 1._wp) <= 1.e-4_wp) then + momsp(4)%sf(id1, id2, id3) = 1._wp else - momsp(4)%sf(id1, id2, id3) = f_quad(abscX, abscY, wght_pb, 3._wp, 0._wp, 0._wp) - 4._wp*Re_inv*f_quad(abscX, abscY, wght, 2._wp, 1._wp, 0._wp) - (2._wp/Web)*f_quad(abscX, abscY, wght, 2._wp, 0._wp, 0._wp) + if (polytropic) then + momsp(4)%sf(id1, id2, id3) = f_quad(abscX, abscY, wght_pb, 3._wp*(1._wp - gam), 0._wp, 3._wp*gam) + pv*f_quad(abscX, abscY, wght, 3._wp, 0._wp, 0._wp) - 4._wp*Re_inv*f_quad(abscX, abscY, wght, 2._wp, 1._wp, 0._wp) - (2._wp/Web)*f_quad(abscX, abscY, wght, 2._wp, 0._wp, 0._wp) + else + momsp(4)%sf(id1, id2, id3) = f_quad(abscX, abscY, wght_pb, 3._wp, 0._wp, 0._wp) - 4._wp*Re_inv*f_quad(abscX, abscY, wght, 2._wp, 1._wp, 0._wp) - (2._wp/Web)*f_quad(abscX, abscY, wght, 2._wp, 0._wp, 0._wp) + end if end if - end if - else - $:GPU_LOOP(parallelism='[seq]') - do q = 1, nb + else $:GPU_LOOP(parallelism='[seq]') - do i1 = 0, 2 + do q = 1, nb $:GPU_LOOP(parallelism='[seq]') - do i2 = 0, 2 - moms3d(i1, i2, q)%sf(id1, id2, id3) = 0._wp + do i1 = 0, 2 + $:GPU_LOOP(parallelism='[seq]') + do i2 = 0, 2 + moms3d(i1, i2, q)%sf(id1, id2, id3) = 0._wp + end do end do end do - end do - momsp(1)%sf(id1, id2, id3) = 0._wp - momsp(2)%sf(id1, id2, id3) = 0._wp - momsp(3)%sf(id1, id2, id3) = 0._wp - momsp(4)%sf(id1, id2, id3) = 0._wp - end if + momsp(1)%sf(id1, id2, id3) = 0._wp + momsp(2)%sf(id1, id2, id3) = 0._wp + momsp(3)%sf(id1, id2, id3) = 0._wp + momsp(4)%sf(id1, id2, id3) = 0._wp + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP contains diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index 526751323f..9761f469ef 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -911,17 +911,17 @@ contains if (ib) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - if (ib_markers%sf(j, k, l) /= 0) then - do i = 1, sys_size - rhs_vf(i)%sf(j, k, l) = 0._wp - end do - end if + do l = 0, p + do k = 0, n + do j = 0, m + if (ib_markers%sf(j, k, l) /= 0) then + do i = 1, sys_size + rhs_vf(i)%sf(j, k, l) = 0._wp + end do + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1020,28 +1020,28 @@ contains if (alt_soundspeed) then #:call GPU_PARALLEL_LOOP(collapse=3) - do q_loop = 0, p - do l_loop = 0, n - do k_loop = 0, m - blkmod1(k_loop, l_loop, q_loop) = ((gammas(1) + 1._wp)*q_prim_vf%vf(E_idx)%sf(k_loop, l_loop, q_loop) + & - pi_infs(1))/gammas(1) - blkmod2(k_loop, l_loop, q_loop) = ((gammas(2) + 1._wp)*q_prim_vf%vf(E_idx)%sf(k_loop, l_loop, q_loop) + & - pi_infs(2))/gammas(2) - alpha1(k_loop, l_loop, q_loop) = q_cons_vf%vf(advxb)%sf(k_loop, l_loop, q_loop) - - if (bubbles_euler) then - alpha2(k_loop, l_loop, q_loop) = q_cons_vf%vf(alf_idx - 1)%sf(k_loop, l_loop, q_loop) - else - alpha2(k_loop, l_loop, q_loop) = q_cons_vf%vf(advxe)%sf(k_loop, l_loop, q_loop) - end if - - Kterm(k_loop, l_loop, q_loop) = alpha1(k_loop, l_loop, q_loop)*alpha2(k_loop, l_loop, q_loop)* & - (blkmod2(k_loop, l_loop, q_loop) - blkmod1(k_loop, l_loop, q_loop))/ & - (alpha1(k_loop, l_loop, q_loop)*blkmod2(k_loop, l_loop, q_loop) + & - alpha2(k_loop, l_loop, q_loop)*blkmod1(k_loop, l_loop, q_loop)) + do q_loop = 0, p + do l_loop = 0, n + do k_loop = 0, m + blkmod1(k_loop, l_loop, q_loop) = ((gammas(1) + 1._wp)*q_prim_vf%vf(E_idx)%sf(k_loop, l_loop, q_loop) + & + pi_infs(1))/gammas(1) + blkmod2(k_loop, l_loop, q_loop) = ((gammas(2) + 1._wp)*q_prim_vf%vf(E_idx)%sf(k_loop, l_loop, q_loop) + & + pi_infs(2))/gammas(2) + alpha1(k_loop, l_loop, q_loop) = q_cons_vf%vf(advxb)%sf(k_loop, l_loop, q_loop) + + if (bubbles_euler) then + alpha2(k_loop, l_loop, q_loop) = q_cons_vf%vf(alf_idx - 1)%sf(k_loop, l_loop, q_loop) + else + alpha2(k_loop, l_loop, q_loop) = q_cons_vf%vf(advxe)%sf(k_loop, l_loop, q_loop) + end if + + Kterm(k_loop, l_loop, q_loop) = alpha1(k_loop, l_loop, q_loop)*alpha2(k_loop, l_loop, q_loop)* & + (blkmod2(k_loop, l_loop, q_loop) - blkmod1(k_loop, l_loop, q_loop))/ & + (alpha1(k_loop, l_loop, q_loop)*blkmod2(k_loop, l_loop, q_loop) + & + alpha2(k_loop, l_loop, q_loop)*blkmod1(k_loop, l_loop, q_loop)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1055,38 +1055,38 @@ contains end if #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,flux_face1,flux_face2]') - do j = 1, sys_size - do q_loop = 0, p - do l_loop = 0, n - do k_loop = 0, m - inv_ds = 1._wp/dx(k_loop) - flux_face1 = flux_n(1)%vf(j)%sf(k_loop - 1, l_loop, q_loop) - flux_face2 = flux_n(1)%vf(j)%sf(k_loop, l_loop, q_loop) - rhs_vf(j)%sf(k_loop, l_loop, q_loop) = inv_ds*(flux_face1 - flux_face2) + do j = 1, sys_size + do q_loop = 0, p + do l_loop = 0, n + do k_loop = 0, m + inv_ds = 1._wp/dx(k_loop) + flux_face1 = flux_n(1)%vf(j)%sf(k_loop - 1, l_loop, q_loop) + flux_face2 = flux_n(1)%vf(j)%sf(k_loop, l_loop, q_loop) + rhs_vf(j)%sf(k_loop, l_loop, q_loop) = inv_ds*(flux_face1 - flux_face2) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (model_eqns == 3) then #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, pressure_val,flux_face1,flux_face2]') - do q_loop = 0, p - do l_loop = 0, n - do k_loop = 0, m - do i_fluid_loop = 1, num_fluids - inv_ds = 1._wp/dx(k_loop) - advected_qty_val = q_cons_vf%vf(i_fluid_loop + advxb - 1)%sf(k_loop, l_loop, q_loop) - pressure_val = q_prim_vf%vf(E_idx)%sf(k_loop, l_loop, q_loop) - flux_face1 = flux_src_n_vf%vf(advxb)%sf(k_loop, l_loop, q_loop) - flux_face2 = flux_src_n_vf%vf(advxb)%sf(k_loop - 1, l_loop, q_loop) - rhs_vf(i_fluid_loop + intxb - 1)%sf(k_loop, l_loop, q_loop) = & - rhs_vf(i_fluid_loop + intxb - 1)%sf(k_loop, l_loop, q_loop) - & - inv_ds*advected_qty_val*pressure_val*(flux_face1 - flux_face2) + do q_loop = 0, p + do l_loop = 0, n + do k_loop = 0, m + do i_fluid_loop = 1, num_fluids + inv_ds = 1._wp/dx(k_loop) + advected_qty_val = q_cons_vf%vf(i_fluid_loop + advxb - 1)%sf(k_loop, l_loop, q_loop) + pressure_val = q_prim_vf%vf(E_idx)%sf(k_loop, l_loop, q_loop) + flux_face1 = flux_src_n_vf%vf(advxb)%sf(k_loop, l_loop, q_loop) + flux_face2 = flux_src_n_vf%vf(advxb)%sf(k_loop - 1, l_loop, q_loop) + rhs_vf(i_fluid_loop + intxb - 1)%sf(k_loop, l_loop, q_loop) = & + rhs_vf(i_fluid_loop + intxb - 1)%sf(k_loop, l_loop, q_loop) - & + inv_ds*advected_qty_val*pressure_val*(flux_face1 - flux_face2) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1101,60 +1101,60 @@ contains end if #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,flux_face1,flux_face2]') - do j = 1, sys_size - do l = 0, p - do k = 0, n - do q = 0, m - inv_ds = 1._wp/dy(k) - flux_face1 = flux_n(2)%vf(j)%sf(q, k - 1, l) - flux_face2 = flux_n(2)%vf(j)%sf(q, k, l) - rhs_vf(j)%sf(q, k, l) = rhs_vf(j)%sf(q, k, l) + inv_ds*(flux_face1 - flux_face2) + do j = 1, sys_size + do l = 0, p + do k = 0, n + do q = 0, m + inv_ds = 1._wp/dy(k) + flux_face1 = flux_n(2)%vf(j)%sf(q, k - 1, l) + flux_face2 = flux_n(2)%vf(j)%sf(q, k, l) + rhs_vf(j)%sf(q, k, l) = rhs_vf(j)%sf(q, k, l) + inv_ds*(flux_face1 - flux_face2) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (model_eqns == 3) then #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, pressure_val,flux_face1,flux_face2]') - do l = 0, p - do k = 0, n - do q = 0, m - do i_fluid_loop = 1, num_fluids - inv_ds = 1._wp/dy(k) - advected_qty_val = q_cons_vf%vf(i_fluid_loop + advxb - 1)%sf(q, k, l) - pressure_val = q_prim_vf%vf(E_idx)%sf(q, k, l) - flux_face1 = flux_src_n_vf%vf(advxb)%sf(q, k, l) - flux_face2 = flux_src_n_vf%vf(advxb)%sf(q, k - 1, l) - rhs_vf(i_fluid_loop + intxb - 1)%sf(q, k, l) = & - rhs_vf(i_fluid_loop + intxb - 1)%sf(q, k, l) - & - inv_ds*advected_qty_val*pressure_val*(flux_face1 - flux_face2) - if (cyl_coord) then + do l = 0, p + do k = 0, n + do q = 0, m + do i_fluid_loop = 1, num_fluids + inv_ds = 1._wp/dy(k) + advected_qty_val = q_cons_vf%vf(i_fluid_loop + advxb - 1)%sf(q, k, l) + pressure_val = q_prim_vf%vf(E_idx)%sf(q, k, l) + flux_face1 = flux_src_n_vf%vf(advxb)%sf(q, k, l) + flux_face2 = flux_src_n_vf%vf(advxb)%sf(q, k - 1, l) rhs_vf(i_fluid_loop + intxb - 1)%sf(q, k, l) = & rhs_vf(i_fluid_loop + intxb - 1)%sf(q, k, l) - & - 5.e-1_wp/y_cc(k)*advected_qty_val*pressure_val*(flux_face1 + flux_face2) - end if + inv_ds*advected_qty_val*pressure_val*(flux_face1 - flux_face2) + if (cyl_coord) then + rhs_vf(i_fluid_loop + intxb - 1)%sf(q, k, l) = & + rhs_vf(i_fluid_loop + intxb - 1)%sf(q, k, l) - & + 5.e-1_wp/y_cc(k)*advected_qty_val*pressure_val*(flux_face1 + flux_face2) + end if + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (cyl_coord) then #:call GPU_PARALLEL_LOOP(collapse=4,private='[flux_face1,flux_face2]') - do j = 1, sys_size - do l = 0, p - do k = 0, n - do q = 0, m - flux_face1 = flux_gsrc_n(2)%vf(j)%sf(q, k - 1, l) - flux_face2 = flux_gsrc_n(2)%vf(j)%sf(q, k, l) - rhs_vf(j)%sf(q, k, l) = rhs_vf(j)%sf(q, k, l) - & - 5.e-1_wp/y_cc(k)*(flux_face1 + flux_face2) + do j = 1, sys_size + do l = 0, p + do k = 0, n + do q = 0, m + flux_face1 = flux_gsrc_n(2)%vf(j)%sf(q, k - 1, l) + flux_face2 = flux_gsrc_n(2)%vf(j)%sf(q, k, l) + rhs_vf(j)%sf(q, k, l) = rhs_vf(j)%sf(q, k, l) - & + 5.e-1_wp/y_cc(k)*(flux_face1 + flux_face2) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1170,70 +1170,70 @@ contains if (grid_geometry == 3) then ! Cylindrical Coordinates #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,velocity_val,flux_face1,flux_face2]') - do j = 1, sys_size - do k = 0, p - do q = 0, n - do l = 0, m - inv_ds = 1._wp/(dz(k)*y_cc(q)) - velocity_val = q_prim_vf%vf(contxe + idir)%sf(l, q, k) - flux_face1 = flux_n(3)%vf(j)%sf(l, q, k - 1) - flux_face2 = flux_n(3)%vf(j)%sf(l, q, k) - rhs_vf(j)%sf(l, q, k) = rhs_vf(j)%sf(l, q, k) + & - inv_ds*velocity_val*(flux_face1 - flux_face2) + do j = 1, sys_size + do k = 0, p + do q = 0, n + do l = 0, m + inv_ds = 1._wp/(dz(k)*y_cc(q)) + velocity_val = q_prim_vf%vf(contxe + idir)%sf(l, q, k) + flux_face1 = flux_n(3)%vf(j)%sf(l, q, k - 1) + flux_face2 = flux_n(3)%vf(j)%sf(l, q, k) + rhs_vf(j)%sf(l, q, k) = rhs_vf(j)%sf(l, q, k) + & + inv_ds*velocity_val*(flux_face1 - flux_face2) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=4,private='[flux_face1,flux_face2]') - do j = 1, sys_size - do k = 0, p - do q = 0, n - do l = 0, m - flux_face1 = flux_gsrc_n(3)%vf(j)%sf(l, q, k - 1) - flux_face2 = flux_gsrc_n(3)%vf(j)%sf(l, q, k) - rhs_vf(j)%sf(l, q, k) = rhs_vf(j)%sf(l, q, k) - & - 5.e-1_wp/y_cc(q)*(flux_face1 + flux_face2) + do j = 1, sys_size + do k = 0, p + do q = 0, n + do l = 0, m + flux_face1 = flux_gsrc_n(3)%vf(j)%sf(l, q, k - 1) + flux_face2 = flux_gsrc_n(3)%vf(j)%sf(l, q, k) + rhs_vf(j)%sf(l, q, k) = rhs_vf(j)%sf(l, q, k) - & + 5.e-1_wp/y_cc(q)*(flux_face1 + flux_face2) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else ! Cartesian Coordinates #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,flux_face1,flux_face2]') - do j = 1, sys_size - do k = 0, p - do q = 0, n - do l = 0, m - inv_ds = 1._wp/dz(k) - flux_face1 = flux_n(3)%vf(j)%sf(l, q, k - 1) - flux_face2 = flux_n(3)%vf(j)%sf(l, q, k) - rhs_vf(j)%sf(l, q, k) = rhs_vf(j)%sf(l, q, k) + inv_ds*(flux_face1 - flux_face2) + do j = 1, sys_size + do k = 0, p + do q = 0, n + do l = 0, m + inv_ds = 1._wp/dz(k) + flux_face1 = flux_n(3)%vf(j)%sf(l, q, k - 1) + flux_face2 = flux_n(3)%vf(j)%sf(l, q, k) + rhs_vf(j)%sf(l, q, k) = rhs_vf(j)%sf(l, q, k) + inv_ds*(flux_face1 - flux_face2) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (model_eqns == 3) then #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, pressure_val,flux_face1,flux_face2]') - do k = 0, p - do q = 0, n - do l = 0, m - do i_fluid_loop = 1, num_fluids - inv_ds = 1._wp/dz(k) - advected_qty_val = q_cons_vf%vf(i_fluid_loop + advxb - 1)%sf(l, q, k) - pressure_val = q_prim_vf%vf(E_idx)%sf(l, q, k) - flux_face1 = flux_src_n_vf%vf(advxb)%sf(l, q, k) - flux_face2 = flux_src_n_vf%vf(advxb)%sf(l, q, k - 1) - rhs_vf(i_fluid_loop + intxb - 1)%sf(l, q, k) = & - rhs_vf(i_fluid_loop + intxb - 1)%sf(l, q, k) - & - inv_ds*advected_qty_val*pressure_val*(flux_face1 - flux_face2) + do k = 0, p + do q = 0, n + do l = 0, m + do i_fluid_loop = 1, num_fluids + inv_ds = 1._wp/dz(k) + advected_qty_val = q_cons_vf%vf(i_fluid_loop + advxb - 1)%sf(l, q, k) + pressure_val = q_prim_vf%vf(E_idx)%sf(l, q, k) + flux_face1 = flux_src_n_vf%vf(advxb)%sf(l, q, k) + flux_face2 = flux_src_n_vf%vf(advxb)%sf(l, q, k - 1) + rhs_vf(i_fluid_loop + intxb - 1)%sf(l, q, k) = & + rhs_vf(i_fluid_loop + intxb - 1)%sf(l, q, k) - & + inv_ds*advected_qty_val*pressure_val*(flux_face1 - flux_face2) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1263,210 +1263,210 @@ contains use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) if (use_standard_riemann) then #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') - do j_adv = advxb, advxe - do q_idx = 0, p ! z_extent - do l_idx = 0, n ! y_extent - do k_idx = 0, m ! x_extent - local_inv_ds = 1._wp/dx(k_idx) - local_term_coeff = q_prim_vf_arg%vf(contxe + current_idir)%sf(k_idx, l_idx, q_idx) - local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(k_idx - 1, l_idx, q_idx) - local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(k_idx, l_idx, q_idx) - rhs_vf_arg(j_adv)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(j_adv)%sf(k_idx, l_idx, q_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - else ! Other Riemann solvers - if (alt_soundspeed) then - if (bubbles_euler .neqv. .true.) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') - do q_idx = 0, p; do l_idx = 0, n; do k_idx = 0, m - local_inv_ds = 1._wp/dx(k_idx) - local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(k_idx, l_idx, q_idx) - local_k_term_val = Kterm_arg(k_idx, l_idx, q_idx) ! Access is safe due to outer alt_soundspeed check - local_term_coeff = local_q_cons_val - local_k_term_val - local_flux1 = flux_src_n_vf_arg%vf(advxe)%sf(k_idx, l_idx, q_idx) - local_flux2 = flux_src_n_vf_arg%vf(advxe)%sf(k_idx - 1, l_idx, q_idx) - rhs_vf_arg(advxe)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(advxe)%sf(k_idx, l_idx, q_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - - #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds,local_q_cons_val, local_k_term_val,local_term_coeff, local_flux1, local_flux2]') - do q_idx = 0, p; do l_idx = 0, n; do k_idx = 0, m - local_inv_ds = 1._wp/dx(k_idx) - local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(k_idx, l_idx, q_idx) - local_k_term_val = Kterm_arg(k_idx, l_idx, q_idx) ! Access is safe - local_term_coeff = local_q_cons_val + local_k_term_val - local_flux1 = flux_src_n_vf_arg%vf(advxb)%sf(k_idx, l_idx, q_idx) - local_flux2 = flux_src_n_vf_arg%vf(advxb)%sf(k_idx - 1, l_idx, q_idx) - rhs_vf_arg(advxb)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(advxb)%sf(k_idx, l_idx, q_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - end if - else ! NOT alt_soundspeed - #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') do j_adv = advxb, advxe - do q_idx = 0, p; do l_idx = 0, n; do k_idx = 0, m + do q_idx = 0, p ! z_extent + do l_idx = 0, n ! y_extent + do k_idx = 0, m ! x_extent local_inv_ds = 1._wp/dx(k_idx) - local_term_coeff = q_cons_vf_arg%vf(j_adv)%sf(k_idx, l_idx, q_idx) - local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(k_idx, l_idx, q_idx) - local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(k_idx - 1, l_idx, q_idx) + local_term_coeff = q_prim_vf_arg%vf(contxe + current_idir)%sf(k_idx, l_idx, q_idx) + local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(k_idx - 1, l_idx, q_idx) + local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(k_idx, l_idx, q_idx) rhs_vf_arg(j_adv)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(j_adv)%sf(k_idx, l_idx, q_idx) + & local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - end do - end if - end if - - case (2) ! y-direction: loops q_idx (x), k_idx (y), l_idx (z); sf(q_idx, k_idx, l_idx); dy(k_idx); Kterm(q_idx,k_idx,l_idx) - use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) - if (use_standard_riemann) then - #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') - do j_adv = advxb, advxe - do l_idx = 0, p ! z_extent - do k_idx = 0, n ! y_extent - do q_idx = 0, m ! x_extent - local_inv_ds = 1._wp/dy(k_idx) - local_term_coeff = q_prim_vf_arg%vf(contxe + current_idir)%sf(q_idx, k_idx, l_idx) - local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx - 1, l_idx) - local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) - rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else ! Other Riemann solvers if (alt_soundspeed) then if (bubbles_euler .neqv. .true.) then #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') - do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m - local_inv_ds = 1._wp/dy(k_idx) - local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(q_idx, k_idx, l_idx) - local_k_term_val = Kterm_arg(q_idx, k_idx, l_idx) ! Access is safe - local_term_coeff = local_q_cons_val - local_k_term_val - local_flux1 = flux_src_n_vf_arg%vf(advxe)%sf(q_idx, k_idx, l_idx) - local_flux2 = flux_src_n_vf_arg%vf(advxe)%sf(q_idx, k_idx - 1, l_idx) - rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - if (cyl_coord) then - rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) - & - (local_k_term_val/(2._wp*y_cc(k_idx)))*(local_flux1 + local_flux2) - end if - end do; end do; end do + do q_idx = 0, p; do l_idx = 0, n; do k_idx = 0, m + local_inv_ds = 1._wp/dx(k_idx) + local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(k_idx, l_idx, q_idx) + local_k_term_val = Kterm_arg(k_idx, l_idx, q_idx) ! Access is safe due to outer alt_soundspeed check + local_term_coeff = local_q_cons_val - local_k_term_val + local_flux1 = flux_src_n_vf_arg%vf(advxe)%sf(k_idx, l_idx, q_idx) + local_flux2 = flux_src_n_vf_arg%vf(advxe)%sf(k_idx - 1, l_idx, q_idx) + rhs_vf_arg(advxe)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(advxe)%sf(k_idx, l_idx, q_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do #:endcall GPU_PARALLEL_LOOP - #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val,local_term_coeff, local_flux1, local_flux2]') - do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m - local_inv_ds = 1._wp/dy(k_idx) - local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(q_idx, k_idx, l_idx) - local_k_term_val = Kterm_arg(q_idx, k_idx, l_idx) ! Access is safe - local_term_coeff = local_q_cons_val + local_k_term_val - local_flux1 = flux_src_n_vf_arg%vf(advxb)%sf(q_idx, k_idx, l_idx) - local_flux2 = flux_src_n_vf_arg%vf(advxb)%sf(q_idx, k_idx - 1, l_idx) - rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - if (cyl_coord) then - rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) + & - (local_k_term_val/(2._wp*y_cc(k_idx)))*(local_flux1 + local_flux2) - end if - end do; end do; end do + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds,local_q_cons_val, local_k_term_val,local_term_coeff, local_flux1, local_flux2]') + do q_idx = 0, p; do l_idx = 0, n; do k_idx = 0, m + local_inv_ds = 1._wp/dx(k_idx) + local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(k_idx, l_idx, q_idx) + local_k_term_val = Kterm_arg(k_idx, l_idx, q_idx) ! Access is safe + local_term_coeff = local_q_cons_val + local_k_term_val + local_flux1 = flux_src_n_vf_arg%vf(advxb)%sf(k_idx, l_idx, q_idx) + local_flux2 = flux_src_n_vf_arg%vf(advxb)%sf(k_idx - 1, l_idx, q_idx) + rhs_vf_arg(advxb)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(advxb)%sf(k_idx, l_idx, q_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do #:endcall GPU_PARALLEL_LOOP end if else ! NOT alt_soundspeed #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') - do j_adv = advxb, advxe - do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m - local_inv_ds = 1._wp/dy(k_idx) - local_term_coeff = q_cons_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) - local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) - local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx - 1, l_idx) - rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - end do - end if - end if - - case (3) ! z-direction: loops l_idx (x), q_idx (y), k_idx (z); sf(l_idx, q_idx, k_idx); dz(k_idx); Kterm(l_idx,q_idx,k_idx) - if (grid_geometry == 3) then - use_standard_riemann = (riemann_solver == 1) - else - use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) - end if - - if (use_standard_riemann) then - #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') - do j_adv = advxb, advxe - do k_idx = 0, p ! z_extent - do q_idx = 0, n ! y_extent - do l_idx = 0, m ! x_extent - local_inv_ds = 1._wp/dz(k_idx) - local_term_coeff = q_prim_vf_arg%vf(contxe + current_idir)%sf(l_idx, q_idx, k_idx) - local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx - 1) - local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) - rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - else ! Other Riemann solvers - if (alt_soundspeed) then - if (bubbles_euler .neqv. .true.) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds,local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') - do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m - local_inv_ds = 1._wp/dz(k_idx) - local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx) - local_k_term_val = Kterm_arg(l_idx, q_idx, k_idx) ! Access is safe - local_term_coeff = local_q_cons_val - local_k_term_val - local_flux1 = flux_src_n_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx) - local_flux2 = flux_src_n_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx - 1) - rhs_vf_arg(advxe)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(advxe)%sf(l_idx, q_idx, k_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do + do j_adv = advxb, advxe + do q_idx = 0, p; do l_idx = 0, n; do k_idx = 0, m + local_inv_ds = 1._wp/dx(k_idx) + local_term_coeff = q_cons_vf_arg%vf(j_adv)%sf(k_idx, l_idx, q_idx) + local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(k_idx, l_idx, q_idx) + local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(k_idx - 1, l_idx, q_idx) + rhs_vf_arg(j_adv)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(j_adv)%sf(k_idx, l_idx, q_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do #:endcall GPU_PARALLEL_LOOP + end do + end if + end if - #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') - do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m - local_inv_ds = 1._wp/dz(k_idx) - local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx) - local_k_term_val = Kterm_arg(l_idx, q_idx, k_idx) ! Access is safe - local_term_coeff = local_q_cons_val + local_k_term_val - local_flux1 = flux_src_n_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx) - local_flux2 = flux_src_n_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx - 1) - rhs_vf_arg(advxb)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(advxb)%sf(l_idx, q_idx, k_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do + case (2) ! y-direction: loops q_idx (x), k_idx (y), l_idx (z); sf(q_idx, k_idx, l_idx); dy(k_idx); Kterm(q_idx,k_idx,l_idx) + use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) + if (use_standard_riemann) then + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') + do j_adv = advxb, advxe + do l_idx = 0, p ! z_extent + do k_idx = 0, n ! y_extent + do q_idx = 0, m ! x_extent + local_inv_ds = 1._wp/dy(k_idx) + local_term_coeff = q_prim_vf_arg%vf(contxe + current_idir)%sf(q_idx, k_idx, l_idx) + local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx - 1, l_idx) + local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) + rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do + end do + end do + end do #:endcall GPU_PARALLEL_LOOP - end if - else ! NOT alt_soundspeed - #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') - do j_adv = advxb, advxe - do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m - local_inv_ds = 1._wp/dz(k_idx) - local_term_coeff = q_cons_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) - local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) - local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx - 1) - rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - end do - end if - end if - end select - end subroutine s_add_directional_advection_source_terms + else ! Other Riemann solvers + if (alt_soundspeed) then + if (bubbles_euler .neqv. .true.) then + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') + do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m + local_inv_ds = 1._wp/dy(k_idx) + local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(q_idx, k_idx, l_idx) + local_k_term_val = Kterm_arg(q_idx, k_idx, l_idx) ! Access is safe + local_term_coeff = local_q_cons_val - local_k_term_val + local_flux1 = flux_src_n_vf_arg%vf(advxe)%sf(q_idx, k_idx, l_idx) + local_flux2 = flux_src_n_vf_arg%vf(advxe)%sf(q_idx, k_idx - 1, l_idx) + rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + if (cyl_coord) then + rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) - & + (local_k_term_val/(2._wp*y_cc(k_idx)))*(local_flux1 + local_flux2) + end if + end do; end do; end do + #:endcall GPU_PARALLEL_LOOP + + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val,local_term_coeff, local_flux1, local_flux2]') + do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m + local_inv_ds = 1._wp/dy(k_idx) + local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(q_idx, k_idx, l_idx) + local_k_term_val = Kterm_arg(q_idx, k_idx, l_idx) ! Access is safe + local_term_coeff = local_q_cons_val + local_k_term_val + local_flux1 = flux_src_n_vf_arg%vf(advxb)%sf(q_idx, k_idx, l_idx) + local_flux2 = flux_src_n_vf_arg%vf(advxb)%sf(q_idx, k_idx - 1, l_idx) + rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + if (cyl_coord) then + rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) + & + (local_k_term_val/(2._wp*y_cc(k_idx)))*(local_flux1 + local_flux2) + end if + end do; end do; end do + #:endcall GPU_PARALLEL_LOOP + end if + else ! NOT alt_soundspeed + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') + do j_adv = advxb, advxe + do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m + local_inv_ds = 1._wp/dy(k_idx) + local_term_coeff = q_cons_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) + local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) + local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx - 1, l_idx) + rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do + #:endcall GPU_PARALLEL_LOOP + end do + end if + end if - end subroutine s_compute_advection_source_term + case (3) ! z-direction: loops l_idx (x), q_idx (y), k_idx (z); sf(l_idx, q_idx, k_idx); dz(k_idx); Kterm(l_idx,q_idx,k_idx) + if (grid_geometry == 3) then + use_standard_riemann = (riemann_solver == 1) + else + use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) + end if + + if (use_standard_riemann) then + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') + do j_adv = advxb, advxe + do k_idx = 0, p ! z_extent + do q_idx = 0, n ! y_extent + do l_idx = 0, m ! x_extent + local_inv_ds = 1._wp/dz(k_idx) + local_term_coeff = q_prim_vf_arg%vf(contxe + current_idir)%sf(l_idx, q_idx, k_idx) + local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx - 1) + local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) + rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + else ! Other Riemann solvers + if (alt_soundspeed) then + if (bubbles_euler .neqv. .true.) then + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds,local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') + do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m + local_inv_ds = 1._wp/dz(k_idx) + local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx) + local_k_term_val = Kterm_arg(l_idx, q_idx, k_idx) ! Access is safe + local_term_coeff = local_q_cons_val - local_k_term_val + local_flux1 = flux_src_n_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx) + local_flux2 = flux_src_n_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx - 1) + rhs_vf_arg(advxe)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(advxe)%sf(l_idx, q_idx, k_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do + #:endcall GPU_PARALLEL_LOOP + + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') + do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m + local_inv_ds = 1._wp/dz(k_idx) + local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx) + local_k_term_val = Kterm_arg(l_idx, q_idx, k_idx) ! Access is safe + local_term_coeff = local_q_cons_val + local_k_term_val + local_flux1 = flux_src_n_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx) + local_flux2 = flux_src_n_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx - 1) + rhs_vf_arg(advxb)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(advxb)%sf(l_idx, q_idx, k_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do + #:endcall GPU_PARALLEL_LOOP + end if + else ! NOT alt_soundspeed + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') + do j_adv = advxb, advxe + do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m + local_inv_ds = 1._wp/dz(k_idx) + local_term_coeff = q_cons_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) + local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) + local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx - 1) + rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do + #:endcall GPU_PARALLEL_LOOP + end do + end if + end if + end select + end subroutine s_add_directional_advection_source_terms + + end subroutine s_compute_advection_source_term subroutine s_compute_additional_physics_rhs(idir, q_prim_vf, rhs_vf, flux_src_n_in, & dq_prim_dx_vf, dq_prim_dy_vf, dq_prim_dz_vf) @@ -1477,9 +1477,9 @@ contains type(scalar_field), dimension(sys_size), intent(in) :: flux_src_n_in type(scalar_field), dimension(sys_size), intent(in) :: dq_prim_dx_vf, dq_prim_dy_vf, dq_prim_dz_vf - integer :: i, j, k, l + integer :: i, j, k, l - if (idir == 1) then ! x-direction + if (idir == 1) then ! x-direction if (surface_tension) then #:call GPU_PARALLEL_LOOP(collapse=3) @@ -1513,7 +1513,7 @@ contains end do #:endcall GPU_PARALLEL_LOOP - elseif (idir == 2) then ! y-direction + elseif (idir == 2) then ! y-direction if (surface_tension) then #:call GPU_PARALLEL_LOOP(collapse=3) @@ -1549,21 +1549,21 @@ contains idwbuff(1), idwbuff(2), idwbuff(3)) end if - #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - rhs_vf(i)%sf(j, 0, l) = & - rhs_vf(i)%sf(j, 0, l) + 1._wp/(y_cc(1) - y_cc(-1))* & - (tau_Re_vf(i)%sf(j, -1, l) & - - tau_Re_vf(i)%sf(j, 1, l)) - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP + #:call GPU_PARALLEL_LOOP(collapse=2) + do l = 0, p + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + rhs_vf(i)%sf(j, 0, l) = & + rhs_vf(i)%sf(j, 0, l) + 1._wp/(y_cc(1) - y_cc(-1))* & + (tau_Re_vf(i)%sf(j, -1, l) & + - tau_Re_vf(i)%sf(j, 1, l)) + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP - end if + end if #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p @@ -1620,21 +1620,21 @@ contains end do #:endcall GPU_PARALLEL_LOOP - if (viscous) then - #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - rhs_vf(i)%sf(j, 0, l) = & - rhs_vf(i)%sf(j, 0, l) - 1._wp/y_cc(0)* & - tau_Re_vf(i)%sf(j, 0, l) - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if - else + if (viscous) then + #:call GPU_PARALLEL_LOOP(collapse=2) + do l = 0, p + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + rhs_vf(i)%sf(j, 0, l) = & + rhs_vf(i)%sf(j, 0, l) - 1._wp/y_cc(0)* & + tau_Re_vf(i)%sf(j, 0, l) + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if + else #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p @@ -1654,7 +1654,7 @@ contains end if end if - elseif (idir == 3) then ! z-direction + elseif (idir == 3) then ! z-direction if (surface_tension) then #:call GPU_PARALLEL_LOOP(collapse=3) @@ -1709,16 +1709,16 @@ contains end if end if - end subroutine s_compute_additional_physics_rhs + end subroutine s_compute_additional_physics_rhs - !> The purpose of this procedure is to infinitely relax + !> The purpose of this procedure is to infinitely relax !! the pressures from the internal-energy equations to a !! unique pressure, from which the corresponding volume !! fraction of each phase are recomputed. For conservation !! purpose, this pressure is finally corrected using the !! mixture-total-energy equation. - !> The purpose of this subroutine is to WENO-reconstruct the + !> The purpose of this subroutine is to WENO-reconstruct the !! left and the right cell-boundary values, including values !! at the Gaussian quadrature points, from the cell-averaged !! variables. @@ -1728,34 +1728,34 @@ contains !! @param vR_qp Right WENO-reconstructed, cell-boundary values including !! the values at the quadrature points, of the cell-average variables !! @param norm_dir Splitting coordinate direction - subroutine s_reconstruct_cell_boundary_values(v_vf, vL_x, vL_y, vL_z, vR_x, vR_y, vR_z, & - norm_dir) + subroutine s_reconstruct_cell_boundary_values(v_vf, vL_x, vL_y, vL_z, vR_x, vR_y, vR_z, & + norm_dir) - type(scalar_field), dimension(iv%beg:iv%end), intent(in) :: v_vf - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vL_x, vL_y, vL_z - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vR_x, vR_y, vR_z - integer, intent(in) :: norm_dir + type(scalar_field), dimension(iv%beg:iv%end), intent(in) :: v_vf + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vL_x, vL_y, vL_z + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vR_x, vR_y, vR_z + integer, intent(in) :: norm_dir - integer :: weno_dir !< Coordinate direction of the WENO reconstruction + integer :: weno_dir !< Coordinate direction of the WENO reconstruction - ! Reconstruction in s1-direction + ! Reconstruction in s1-direction - if (norm_dir == 1) then - is1 = idwbuff(1); is2 = idwbuff(2); is3 = idwbuff(3) - weno_dir = 1; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn + if (norm_dir == 1) then + is1 = idwbuff(1); is2 = idwbuff(2); is3 = idwbuff(3) + weno_dir = 1; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn - elseif (norm_dir == 2) then - is1 = idwbuff(2); is2 = idwbuff(1); is3 = idwbuff(3) - weno_dir = 2; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn + elseif (norm_dir == 2) then + is1 = idwbuff(2); is2 = idwbuff(1); is3 = idwbuff(3) + weno_dir = 2; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn - else - is1 = idwbuff(3); is2 = idwbuff(2); is3 = idwbuff(1) - weno_dir = 3; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn + else + is1 = idwbuff(3); is2 = idwbuff(2); is3 = idwbuff(1) + weno_dir = 3; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn - end if + end if if (n > 0) then if (p > 0) then @@ -1776,89 +1776,89 @@ contains is1, is2, is3) end if - end subroutine s_reconstruct_cell_boundary_values - - subroutine s_reconstruct_cell_boundary_values_first_order(v_vf, vL_x, vL_y, vL_z, vR_x, vR_y, vR_z, & - norm_dir) + end subroutine s_reconstruct_cell_boundary_values - type(scalar_field), dimension(iv%beg:iv%end), intent(in) :: v_vf - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vL_x, vL_y, vL_z - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vR_x, vR_y, vR_z - integer, intent(in) :: norm_dir + subroutine s_reconstruct_cell_boundary_values_first_order(v_vf, vL_x, vL_y, vL_z, vR_x, vR_y, vR_z, & + norm_dir) - integer :: recon_dir !< Coordinate direction of the WENO reconstruction + type(scalar_field), dimension(iv%beg:iv%end), intent(in) :: v_vf + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vL_x, vL_y, vL_z + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vR_x, vR_y, vR_z + integer, intent(in) :: norm_dir - integer :: i, j, k, l - ! Reconstruction in s1-direction + integer :: recon_dir !< Coordinate direction of the WENO reconstruction - if (norm_dir == 1) then - is1 = idwbuff(1); is2 = idwbuff(2); is3 = idwbuff(3) - recon_dir = 1; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn + integer :: i, j, k, l + ! Reconstruction in s1-direction - elseif (norm_dir == 2) then - is1 = idwbuff(2); is2 = idwbuff(1); is3 = idwbuff(3) - recon_dir = 2; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn + if (norm_dir == 1) then + is1 = idwbuff(1); is2 = idwbuff(2); is3 = idwbuff(3) + recon_dir = 1; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn - else - is1 = idwbuff(3); is2 = idwbuff(2); is3 = idwbuff(1) - recon_dir = 3; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn + elseif (norm_dir == 2) then + is1 = idwbuff(2); is2 = idwbuff(1); is3 = idwbuff(3) + recon_dir = 2; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn - end if + else + is1 = idwbuff(3); is2 = idwbuff(2); is3 = idwbuff(1) + recon_dir = 3; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn - $:GPU_UPDATE(device='[is1,is2,is3,iv]') + end if - if (recon_dir == 1) then - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - vL_x(j, k, l, i) = v_vf(i)%sf(j, k, l) - vR_x(j, k, l, i) = v_vf(i)%sf(j, k, l) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - else if (recon_dir == 2) then - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - vL_y(j, k, l, i) = v_vf(i)%sf(k, j, l) - vR_y(j, k, l, i) = v_vf(i)%sf(k, j, l) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - else if (recon_dir == 3) then - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - vL_z(j, k, l, i) = v_vf(i)%sf(l, k, j) - vR_z(j, k, l, i) = v_vf(i)%sf(l, k, j) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if + $:GPU_UPDATE(device='[is1,is2,is3,iv]') + + if (recon_dir == 1) then + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = iv%beg, iv%end + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + vL_x(j, k, l, i) = v_vf(i)%sf(j, k, l) + vR_x(j, k, l, i) = v_vf(i)%sf(j, k, l) + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + else if (recon_dir == 2) then + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = iv%beg, iv%end + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + vL_y(j, k, l, i) = v_vf(i)%sf(k, j, l) + vR_y(j, k, l, i) = v_vf(i)%sf(k, j, l) + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + else if (recon_dir == 3) then + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = iv%beg, iv%end + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + vL_z(j, k, l, i) = v_vf(i)%sf(l, k, j) + vR_z(j, k, l, i) = v_vf(i)%sf(l, k, j) + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - end subroutine s_reconstruct_cell_boundary_values_first_order + end subroutine s_reconstruct_cell_boundary_values_first_order - !> Module deallocation and/or disassociation procedures - impure subroutine s_finalize_rhs_module + !> Module deallocation and/or disassociation procedures + impure subroutine s_finalize_rhs_module - integer :: i, j, l + integer :: i, j, l - call s_finalize_pressure_relaxation_module + call s_finalize_pressure_relaxation_module if (.not. igr) then do j = cont_idx%beg, cont_idx%end @@ -1975,8 +1975,8 @@ contains deallocate (alf_sum%sf) end if - @:DEALLOCATE(dqL_prim_dx_n, dqL_prim_dy_n, dqL_prim_dz_n) - @:DEALLOCATE(dqR_prim_dx_n, dqR_prim_dy_n, dqR_prim_dz_n) + @:DEALLOCATE(dqL_prim_dx_n, dqL_prim_dy_n, dqL_prim_dz_n) + @:DEALLOCATE(dqR_prim_dx_n, dqR_prim_dy_n, dqR_prim_dz_n) if (.not. igr) then do i = num_dims, 1, -1 @@ -2017,7 +2017,7 @@ contains @:DEALLOCATE(flux_n, flux_src_n, flux_gsrc_n) end if - end subroutine s_finalize_rhs_module + end subroutine s_finalize_rhs_module -end module m_rhs + end module m_rhs diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index 9214cc4893..4a82254c3d 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -204,16 +204,16 @@ contains !! 1) s_compute_cartesian_viscous_source_flux !! 2) s_compute_cylindrical_viscous_source_flux subroutine s_compute_viscous_source_flux(velL_vf, & - dvelL_dx_vf, & - dvelL_dy_vf, & - dvelL_dz_vf, & - velR_vf, & - dvelR_dx_vf, & - dvelR_dy_vf, & - dvelR_dz_vf, & - flux_src_vf, & - norm_dir, & - ix, iy, iz) + dvelL_dx_vf, & + dvelL_dy_vf, & + dvelL_dz_vf, & + velR_vf, & + dvelR_dx_vf, & + dvelR_dy_vf, & + dvelR_dz_vf, & + flux_src_vf, & + norm_dir, & + ix, iy, iz) type(scalar_field), & dimension(num_vels), & @@ -358,643 +358,643 @@ contains if (norm_dir == ${NORM_DIR}$) then #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - alpha_rho_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, i) - alpha_rho_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) - end do + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + alpha_rho_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, i) + alpha_rho_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + end do - vel_L_rms = 0._wp; vel_R_rms = 0._wp + vel_L_rms = 0._wp; vel_R_rms = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_vels - vel_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + i) - vel_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + i) - vel_L_rms = vel_L_rms + vel_L(i)**2._wp - vel_R_rms = vel_R_rms + vel_R(i)**2._wp - end do + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_vels + vel_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + i) + vel_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + i) + vel_L_rms = vel_L_rms + vel_L(i)**2._wp + vel_R_rms = vel_R_rms + vel_R(i)**2._wp + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) - alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) - end do + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) + alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) + end do + + pres_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) + pres_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) - pres_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) - pres_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) - - if (mhd) then - if (n == 0) then ! 1D: constant Bx; By, Bz as variables - B%L(1) = Bx0 - B%R(1) = Bx0 - B%L(2) = qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg) - B%R(2) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg) - B%L(3) = qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + 1) - B%R(3) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + 1) - else ! 2D/3D: Bx, By, Bz as variables - B%L(1) = qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg) - B%R(1) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg) - B%L(2) = qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + 1) - B%R(2) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + 1) - B%L(3) = qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + 2) - B%R(3) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + 2) + if (mhd) then + if (n == 0) then ! 1D: constant Bx; By, Bz as variables + B%L(1) = Bx0 + B%R(1) = Bx0 + B%L(2) = qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg) + B%R(2) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg) + B%L(3) = qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + 1) + B%R(3) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + 1) + else ! 2D/3D: Bx, By, Bz as variables + B%L(1) = qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg) + B%R(1) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg) + B%L(2) = qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + 1) + B%R(2) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + 1) + B%L(3) = qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + 2) + B%R(3) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + 2) + end if end if - end if - rho_L = 0._wp - gamma_L = 0._wp - pi_inf_L = 0._wp - qv_L = 0._wp + rho_L = 0._wp + gamma_L = 0._wp + pi_inf_L = 0._wp + qv_L = 0._wp + + rho_R = 0._wp + gamma_R = 0._wp + pi_inf_R = 0._wp + qv_R = 0._wp + + alpha_L_sum = 0._wp + alpha_R_sum = 0._wp - rho_R = 0._wp - gamma_R = 0._wp - pi_inf_R = 0._wp - qv_R = 0._wp + pres_mag%L = 0._wp + pres_mag%R = 0._wp - alpha_L_sum = 0._wp - alpha_R_sum = 0._wp + if (mpp_lim) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_L(i) = max(0._wp, alpha_rho_L(i)) + alpha_L(i) = min(max(0._wp, alpha_L(i)), 1._wp) + alpha_L_sum = alpha_L_sum + alpha_L(i) + alpha_rho_R(i) = max(0._wp, alpha_rho_R(i)) + alpha_R(i) = min(max(0._wp, alpha_R(i)), 1._wp) + alpha_R_sum = alpha_R_sum + alpha_R(i) + end do - pres_mag%L = 0._wp - pres_mag%R = 0._wp + alpha_L = alpha_L/max(alpha_L_sum, sgm_eps) + alpha_R = alpha_R/max(alpha_R_sum, sgm_eps) + end if - if (mpp_lim) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - alpha_rho_L(i) = max(0._wp, alpha_rho_L(i)) - alpha_L(i) = min(max(0._wp, alpha_L(i)), 1._wp) - alpha_L_sum = alpha_L_sum + alpha_L(i) - alpha_rho_R(i) = max(0._wp, alpha_rho_R(i)) - alpha_R(i) = min(max(0._wp, alpha_R(i)), 1._wp) - alpha_R_sum = alpha_R_sum + alpha_R(i) + rho_L = rho_L + alpha_rho_L(i) + gamma_L = gamma_L + alpha_L(i)*gammas(i) + pi_inf_L = pi_inf_L + alpha_L(i)*pi_infs(i) + qv_L = qv_L + alpha_rho_L(i)*qvs(i) + + rho_R = rho_R + alpha_rho_R(i) + gamma_R = gamma_R + alpha_R(i)*gammas(i) + pi_inf_R = pi_inf_R + alpha_R(i)*pi_infs(i) + qv_R = qv_R + alpha_rho_R(i)*qvs(i) end do - alpha_L = alpha_L/max(alpha_L_sum, sgm_eps) - alpha_R = alpha_R/max(alpha_R_sum, sgm_eps) - end if + if (viscous) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_L(i) = dflt_real + Re_R(i) = dflt_real - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_L = rho_L + alpha_rho_L(i) - gamma_L = gamma_L + alpha_L(i)*gammas(i) - pi_inf_L = pi_inf_L + alpha_L(i)*pi_infs(i) - qv_L = qv_L + alpha_rho_L(i)*qvs(i) - - rho_R = rho_R + alpha_rho_R(i) - gamma_R = gamma_R + alpha_R(i)*gammas(i) - pi_inf_R = pi_inf_R + alpha_R(i)*pi_infs(i) - qv_R = qv_R + alpha_rho_R(i)*qvs(i) - end do + if (Re_size(i) > 0) Re_L(i) = 0._wp + if (Re_size(i) > 0) Re_R(i) = 0._wp - if (viscous) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_L(i) = dflt_real - Re_R(i) = dflt_real + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_L(i) = alpha_L(Re_idx(i, q))/Res(i, q) & + + Re_L(i) + Re_R(i) = alpha_R(Re_idx(i, q))/Res(i, q) & + + Re_R(i) + end do - if (Re_size(i) > 0) Re_L(i) = 0._wp - if (Re_size(i) > 0) Re_R(i) = 0._wp + Re_L(i) = 1._wp/max(Re_L(i), sgm_eps) + Re_R(i) = 1._wp/max(Re_R(i), sgm_eps) + end do + end if + if (chemistry) then $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_L(i) = alpha_L(Re_idx(i, q))/Res(i, q) & - + Re_L(i) - Re_R(i) = alpha_R(Re_idx(i, q))/Res(i, q) & - + Re_R(i) + do i = chemxb, chemxe + Ys_L(i - chemxb + 1) = qL_prim_rs${XYZ}$_vf(j, k, l, i) + Ys_R(i - chemxb + 1) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) end do - Re_L(i) = 1._wp/max(Re_L(i), sgm_eps) - Re_R(i) = 1._wp/max(Re_R(i), sgm_eps) - end do - end if - - if (chemistry) then - $:GPU_LOOP(parallelism='[seq]') - do i = chemxb, chemxe - Ys_L(i - chemxb + 1) = qL_prim_rs${XYZ}$_vf(j, k, l, i) - Ys_R(i - chemxb + 1) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) - end do + call get_mixture_molecular_weight(Ys_L, MW_L) + call get_mixture_molecular_weight(Ys_R, MW_R) - call get_mixture_molecular_weight(Ys_L, MW_L) - call get_mixture_molecular_weight(Ys_R, MW_R) - - Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) - Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) - - R_gas_L = gas_constant/MW_L - R_gas_R = gas_constant/MW_R - T_L = pres_L/rho_L/R_gas_L - T_R = pres_R/rho_R/R_gas_R - - call get_species_specific_heats_r(T_L, Cp_iL) - call get_species_specific_heats_r(T_R, Cp_iR) - - if (chem_params%gamma_method == 1) then - ! gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. - Gamma_iL = Cp_iL/(Cp_iL - 1.0_wp) - Gamma_iR = Cp_iR/(Cp_iR - 1.0_wp) - - gamma_L = sum(Xs_L(:)/(Gamma_iL(:) - 1.0_wp)) - gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) - else if (chem_params%gamma_method == 2) then - ! gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. - call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) - call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) - call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) - call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) - - Gamm_L = Cp_L/Cv_L - gamma_L = 1.0_wp/(Gamm_L - 1.0_wp) - Gamm_R = Cp_R/Cv_R - gamma_R = 1.0_wp/(Gamm_R - 1.0_wp) - end if + Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) + Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) - call get_mixture_energy_mass(T_L, Ys_L, E_L) - call get_mixture_energy_mass(T_R, Ys_R, E_R) - - E_L = rho_L*E_L + 5.e-1*rho_L*vel_L_rms - E_R = rho_R*E_R + 5.e-1*rho_R*vel_R_rms - H_L = (E_L + pres_L)/rho_L - H_R = (E_R + pres_R)/rho_R - elseif (mhd .and. relativity) then - Ga%L = 1._wp/sqrt(1._wp - vel_L_rms) - Ga%R = 1._wp/sqrt(1._wp - vel_R_rms) - vdotB%L = vel_L(1)*B%L(1) + vel_L(2)*B%L(2) + vel_L(3)*B%L(3) - vdotB%R = vel_R(1)*B%R(1) + vel_R(2)*B%R(2) + vel_R(3)*B%R(3) - - b4%L(1:3) = B%L(1:3)/Ga%L + Ga%L*vel_L(1:3)*vdotB%L - b4%R(1:3) = B%R(1:3)/Ga%R + Ga%R*vel_R(1:3)*vdotB%R - B2%L = B%L(1)**2._wp + B%L(2)**2._wp + B%L(3)**2._wp - B2%R = B%R(1)**2._wp + B%R(2)**2._wp + B%R(3)**2._wp - - pres_mag%L = 0.5_wp*(B2%L/Ga%L**2._wp + vdotB%L**2._wp) - pres_mag%R = 0.5_wp*(B2%R/Ga%R**2._wp + vdotB%R**2._wp) - - ! Hard-coded EOS - H_L = 1._wp + (gamma_L + 1)*pres_L/rho_L - H_R = 1._wp + (gamma_R + 1)*pres_R/rho_R - - cm%L(1:3) = (rho_L*H_L*Ga%L**2 + B2%L)*vel_L(1:3) - vdotB%L*B%L(1:3) - cm%R(1:3) = (rho_R*H_R*Ga%R**2 + B2%R)*vel_R(1:3) - vdotB%R*B%R(1:3) - - E_L = rho_L*H_L*Ga%L**2 - pres_L + 0.5_wp*(B2%L + vel_L_rms*B2%L - vdotB%L**2._wp) - rho_L*Ga%L - E_R = rho_R*H_R*Ga%R**2 - pres_R + 0.5_wp*(B2%R + vel_R_rms*B2%R - vdotB%R**2._wp) - rho_R*Ga%R - elseif (mhd .and. .not. relativity) then - pres_mag%L = 0.5_wp*(B%L(1)**2._wp + B%L(2)**2._wp + B%L(3)**2._wp) - pres_mag%R = 0.5_wp*(B%R(1)**2._wp + B%R(2)**2._wp + B%R(3)**2._wp) - E_L = gamma_L*pres_L + pi_inf_L + 0.5_wp*rho_L*vel_L_rms + qv_L + pres_mag%L - E_R = gamma_R*pres_R + pi_inf_R + 0.5_wp*rho_R*vel_R_rms + qv_R + pres_mag%R ! includes magnetic energy - H_L = (E_L + pres_L - pres_mag%L)/rho_L - H_R = (E_R + pres_R - pres_mag%R)/rho_R ! stagnation enthalpy here excludes magnetic energy (only used to find speed of sound) - else - E_L = gamma_L*pres_L + pi_inf_L + 5.e-1*rho_L*vel_L_rms + qv_L - E_R = gamma_R*pres_R + pi_inf_R + 5.e-1*rho_R*vel_R_rms + qv_R - H_L = (E_L + pres_L)/rho_L - H_R = (E_R + pres_R)/rho_R - end if + R_gas_L = gas_constant/MW_L + R_gas_R = gas_constant/MW_R + T_L = pres_L/rho_L/R_gas_L + T_R = pres_R/rho_R/R_gas_R - ! elastic energy update - if (hypoelasticity) then - G_L = 0._wp; G_R = 0._wp + call get_species_specific_heats_r(T_L, Cp_iL) + call get_species_specific_heats_r(T_R, Cp_iR) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - G_L = G_L + alpha_L(i)*Gs(i) - G_R = G_R + alpha_R(i)*Gs(i) - end do + if (chem_params%gamma_method == 1) then + ! gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. + Gamma_iL = Cp_iL/(Cp_iL - 1.0_wp) + Gamma_iR = Cp_iR/(Cp_iR - 1.0_wp) - if (cont_damage) then - G_L = G_L*max((1._wp - qL_prim_rs${XYZ}$_vf(j, k, l, damage_idx)), 0._wp) - G_R = G_R*max((1._wp - qR_prim_rs${XYZ}$_vf(j, k, l, damage_idx)), 0._wp) - end if + gamma_L = sum(Xs_L(:)/(Gamma_iL(:) - 1.0_wp)) + gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) + else if (chem_params%gamma_method == 2) then + ! gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. + call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) + call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) + call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) + call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) - do i = 1, strxe - strxb + 1 - tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) - tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) - ! Elastic contribution to energy if G large enough - !TODO take out if statement if stable without - if ((G_L > 1000) .and. (G_R > 1000)) then - E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) - E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) - ! Double for shear stresses - if (any(strxb - 1 + i == shear_indices)) then - E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) - E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) - end if + Gamm_L = Cp_L/Cv_L + gamma_L = 1.0_wp/(Gamm_L - 1.0_wp) + Gamm_R = Cp_R/Cv_R + gamma_R = 1.0_wp/(Gamm_R - 1.0_wp) end if - end do - end if - - ! elastic energy update - !if ( hyperelasticity ) then - ! G_L = 0._wp - ! G_R = 0._wp - ! - ! $:GPU_LOOP(parallelism='[seq]') - ! do i = 1, num_fluids - ! G_L = G_L + alpha_L(i)*Gs(i) - ! G_R = G_R + alpha_R(i)*Gs(i) - ! end do - ! ! Elastic contribution to energy if G large enough - ! if ((G_L > 1.e-3_wp) .and. (G_R > 1.e-3_wp)) then - ! E_L = E_L + G_L*qL_prim_rs${XYZ}$_vf(j, k, l, xiend + 1) - ! E_R = E_R + G_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, xiend + 1) - ! $:GPU_LOOP(parallelism='[seq]') - ! do i = 1, b_size-1 - ! tau_e_L(i) = G_L*qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) - ! tau_e_R(i) = G_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) - ! end do - ! $:GPU_LOOP(parallelism='[seq]') - ! do i = 1, b_size-1 - ! tau_e_L(i) = 0._wp - ! tau_e_R(i) = 0._wp - ! end do - ! $:GPU_LOOP(parallelism='[seq]') - ! do i = 1, num_dims - ! xi_field_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) - ! xi_field_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, xibeg - 1 + i) - ! end do - ! end if - !end if - - @:compute_average_state() - - call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & - vel_L_rms, 0._wp, c_L) - - call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & - vel_R_rms, 0._wp, c_R) - - !> The computation of c_avg does not require all the variables, and therefore the non '_avg' - ! variables are placeholders to call the subroutine. - - call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & - vel_avg_rms, c_sum_Yi_Phi, c_avg) - - if (mhd) then - call s_compute_fast_magnetosonic_speed(rho_L, c_L, B%L, norm_dir, c_fast%L, H_L) - call s_compute_fast_magnetosonic_speed(rho_R, c_R, B%R, norm_dir, c_fast%R, H_R) - end if - if (viscous) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_avg_rs${XYZ}$_vf(j, k, l, i) = 2._wp/(1._wp/Re_L(i) + 1._wp/Re_R(i)) - end do - end if + call get_mixture_energy_mass(T_L, Ys_L, E_L) + call get_mixture_energy_mass(T_R, Ys_R, E_R) - if (wave_speeds == 1) then - if (mhd) then - s_L = min(vel_L(dir_idx(1)) - c_fast%L, vel_R(dir_idx(1)) - c_fast%R) - s_R = max(vel_R(dir_idx(1)) + c_fast%R, vel_L(dir_idx(1)) + c_fast%L) - elseif (hypoelasticity) then - s_L = min(vel_L(dir_idx(1)) - sqrt(c_L*c_L + & - (((4._wp*G_L)/3._wp) + & - tau_e_L(dir_idx_tau(1)))/rho_L) & - , vel_R(dir_idx(1)) - sqrt(c_R*c_R + & - (((4._wp*G_R)/3._wp) + & - tau_e_R(dir_idx_tau(1)))/rho_R)) - s_R = max(vel_R(dir_idx(1)) + sqrt(c_R*c_R + & - (((4._wp*G_R)/3._wp) + & - tau_e_R(dir_idx_tau(1)))/rho_R) & - , vel_L(dir_idx(1)) + sqrt(c_L*c_L + & - (((4._wp*G_L)/3._wp) + & - tau_e_L(dir_idx_tau(1)))/rho_L)) - else if (hyperelasticity) then - s_L = min(vel_L(dir_idx(1)) - sqrt(c_L*c_L + (4._wp*G_L/3._wp)/rho_L) & - , vel_R(dir_idx(1)) - sqrt(c_R*c_R + (4._wp*G_R/3._wp)/rho_R)) - s_R = max(vel_R(dir_idx(1)) + sqrt(c_R*c_R + (4._wp*G_R/3._wp)/rho_R) & - , vel_L(dir_idx(1)) + sqrt(c_L*c_L + (4._wp*G_L/3._wp)/rho_L)) + E_L = rho_L*E_L + 5.e-1*rho_L*vel_L_rms + E_R = rho_R*E_R + 5.e-1*rho_R*vel_R_rms + H_L = (E_L + pres_L)/rho_L + H_R = (E_R + pres_R)/rho_R + elseif (mhd .and. relativity) then + Ga%L = 1._wp/sqrt(1._wp - vel_L_rms) + Ga%R = 1._wp/sqrt(1._wp - vel_R_rms) + vdotB%L = vel_L(1)*B%L(1) + vel_L(2)*B%L(2) + vel_L(3)*B%L(3) + vdotB%R = vel_R(1)*B%R(1) + vel_R(2)*B%R(2) + vel_R(3)*B%R(3) + + b4%L(1:3) = B%L(1:3)/Ga%L + Ga%L*vel_L(1:3)*vdotB%L + b4%R(1:3) = B%R(1:3)/Ga%R + Ga%R*vel_R(1:3)*vdotB%R + B2%L = B%L(1)**2._wp + B%L(2)**2._wp + B%L(3)**2._wp + B2%R = B%R(1)**2._wp + B%R(2)**2._wp + B%R(3)**2._wp + + pres_mag%L = 0.5_wp*(B2%L/Ga%L**2._wp + vdotB%L**2._wp) + pres_mag%R = 0.5_wp*(B2%R/Ga%R**2._wp + vdotB%R**2._wp) + + ! Hard-coded EOS + H_L = 1._wp + (gamma_L + 1)*pres_L/rho_L + H_R = 1._wp + (gamma_R + 1)*pres_R/rho_R + + cm%L(1:3) = (rho_L*H_L*Ga%L**2 + B2%L)*vel_L(1:3) - vdotB%L*B%L(1:3) + cm%R(1:3) = (rho_R*H_R*Ga%R**2 + B2%R)*vel_R(1:3) - vdotB%R*B%R(1:3) + + E_L = rho_L*H_L*Ga%L**2 - pres_L + 0.5_wp*(B2%L + vel_L_rms*B2%L - vdotB%L**2._wp) - rho_L*Ga%L + E_R = rho_R*H_R*Ga%R**2 - pres_R + 0.5_wp*(B2%R + vel_R_rms*B2%R - vdotB%R**2._wp) - rho_R*Ga%R + elseif (mhd .and. .not. relativity) then + pres_mag%L = 0.5_wp*(B%L(1)**2._wp + B%L(2)**2._wp + B%L(3)**2._wp) + pres_mag%R = 0.5_wp*(B%R(1)**2._wp + B%R(2)**2._wp + B%R(3)**2._wp) + E_L = gamma_L*pres_L + pi_inf_L + 0.5_wp*rho_L*vel_L_rms + qv_L + pres_mag%L + E_R = gamma_R*pres_R + pi_inf_R + 0.5_wp*rho_R*vel_R_rms + qv_R + pres_mag%R ! includes magnetic energy + H_L = (E_L + pres_L - pres_mag%L)/rho_L + H_R = (E_R + pres_R - pres_mag%R)/rho_R ! stagnation enthalpy here excludes magnetic energy (only used to find speed of sound) else - s_L = min(vel_L(dir_idx(1)) - c_L, vel_R(dir_idx(1)) - c_R) - s_R = max(vel_R(dir_idx(1)) + c_R, vel_L(dir_idx(1)) + c_L) + E_L = gamma_L*pres_L + pi_inf_L + 5.e-1*rho_L*vel_L_rms + qv_L + E_R = gamma_R*pres_R + pi_inf_R + 5.e-1*rho_R*vel_R_rms + qv_R + H_L = (E_L + pres_L)/rho_L + H_R = (E_R + pres_R)/rho_R end if - s_S = (pres_R - pres_L + rho_L*vel_L(dir_idx(1))* & - (s_L - vel_L(dir_idx(1))) - & - rho_R*vel_R(dir_idx(1))* & - (s_R - vel_R(dir_idx(1)))) & - /(rho_L*(s_L - vel_L(dir_idx(1))) - & - rho_R*(s_R - vel_R(dir_idx(1)))) - elseif (wave_speeds == 2) then - pres_SL = 5.e-1_wp*(pres_L + pres_R + rho_avg*c_avg* & - (vel_L(dir_idx(1)) - & - vel_R(dir_idx(1)))) - - pres_SR = pres_SL - - Ms_L = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_L)/(1._wp + gamma_L))* & - (pres_SL/pres_L - 1._wp)*pres_L/ & - ((pres_L + pi_inf_L/(1._wp + gamma_L))))) - Ms_R = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_R)/(1._wp + gamma_R))* & - (pres_SR/pres_R - 1._wp)*pres_R/ & - ((pres_R + pi_inf_R/(1._wp + gamma_R))))) - - s_L = vel_L(dir_idx(1)) - c_L*Ms_L - s_R = vel_R(dir_idx(1)) + c_R*Ms_R - - s_S = 5.e-1_wp*((vel_L(dir_idx(1)) + vel_R(dir_idx(1))) + & - (pres_L - pres_R)/ & - (rho_avg*c_avg)) - end if + ! elastic energy update + if (hypoelasticity) then + G_L = 0._wp; G_R = 0._wp - s_M = min(0._wp, s_L); s_P = max(0._wp, s_R) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + G_L = G_L + alpha_L(i)*Gs(i) + G_R = G_R + alpha_R(i)*Gs(i) + end do - xi_M = (5.e-1_wp + sign(5.e-1_wp, s_L)) & - + (5.e-1_wp - sign(5.e-1_wp, s_L)) & - *(5.e-1_wp + sign(5.e-1_wp, s_R)) - xi_P = (5.e-1_wp - sign(5.e-1_wp, s_R)) & - + (5.e-1_wp - sign(5.e-1_wp, s_L)) & - *(5.e-1_wp + sign(5.e-1_wp, s_R)) + if (cont_damage) then + G_L = G_L*max((1._wp - qL_prim_rs${XYZ}$_vf(j, k, l, damage_idx)), 0._wp) + G_R = G_R*max((1._wp - qR_prim_rs${XYZ}$_vf(j, k, l, damage_idx)), 0._wp) + end if - ! Low Mach correction - if (low_Mach == 1) then - @:compute_low_Mach_correction() - else - pcorr = 0._wp - end if + do i = 1, strxe - strxb + 1 + tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) + tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) + ! Elastic contribution to energy if G large enough + !TODO take out if statement if stable without + if ((G_L > 1000) .and. (G_R > 1000)) then + E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) + E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) + ! Double for shear stresses + if (any(strxb - 1 + i == shear_indices)) then + E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) + E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) + end if + end if + end do + end if - ! Mass - if (.not. relativity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - (s_M*alpha_rho_R(i)*vel_R(norm_dir) & - - s_P*alpha_rho_L(i)*vel_L(norm_dir) & - + s_M*s_P*(alpha_rho_L(i) & - - alpha_rho_R(i))) & - /(s_M - s_P) - end do - elseif (relativity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - (s_M*Ga%R*alpha_rho_R(i)*vel_R(norm_dir) & - - s_P*Ga%L*alpha_rho_L(i)*vel_L(norm_dir) & - + s_M*s_P*(Ga%L*alpha_rho_L(i) & - - Ga%R*alpha_rho_R(i))) & - /(s_M - s_P) - end do - end if + ! elastic energy update + !if ( hyperelasticity ) then + ! G_L = 0._wp + ! G_R = 0._wp + ! + ! $:GPU_LOOP(parallelism='[seq]') + ! do i = 1, num_fluids + ! G_L = G_L + alpha_L(i)*Gs(i) + ! G_R = G_R + alpha_R(i)*Gs(i) + ! end do + ! ! Elastic contribution to energy if G large enough + ! if ((G_L > 1.e-3_wp) .and. (G_R > 1.e-3_wp)) then + ! E_L = E_L + G_L*qL_prim_rs${XYZ}$_vf(j, k, l, xiend + 1) + ! E_R = E_R + G_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, xiend + 1) + ! $:GPU_LOOP(parallelism='[seq]') + ! do i = 1, b_size-1 + ! tau_e_L(i) = G_L*qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) + ! tau_e_R(i) = G_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) + ! end do + ! $:GPU_LOOP(parallelism='[seq]') + ! do i = 1, b_size-1 + ! tau_e_L(i) = 0._wp + ! tau_e_R(i) = 0._wp + ! end do + ! $:GPU_LOOP(parallelism='[seq]') + ! do i = 1, num_dims + ! xi_field_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) + ! xi_field_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, xibeg - 1 + i) + ! end do + ! end if + !end if - ! Momentum - if (mhd .and. (.not. relativity)) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 3 - ! Flux of rho*v_i in the ${XYZ}$ direction - ! = rho * v_i * v_${XYZ}$ - B_i * B_${XYZ}$ + delta_(${XYZ}$,i) * p_tot - flux_rs${XYZ}$_vf(j, k, l, contxe + i) = & - (s_M*(rho_R*vel_R(i)*vel_R(norm_dir) & - - B%R(i)*B%R(norm_dir) & - + dir_flg(i)*(pres_R + pres_mag%R)) & - - s_P*(rho_L*vel_L(i)*vel_L(norm_dir) & - - B%L(i)*B%L(norm_dir) & - + dir_flg(i)*(pres_L + pres_mag%L)) & - + s_M*s_P*(rho_L*vel_L(i) - rho_R*vel_R(i))) & - /(s_M - s_P) - end do - elseif (mhd .and. relativity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 3 - ! Flux of m_i in the ${XYZ}$ direction - ! = m_i * v_${XYZ}$ - b_i/Gamma * B_${XYZ}$ + delta_(${XYZ}$,i) * p_tot - flux_rs${XYZ}$_vf(j, k, l, contxe + i) = & - (s_M*(cm%R(i)*vel_R(norm_dir) & - - b4%R(i)/Ga%R*B%R(norm_dir) & - + dir_flg(i)*(pres_R + pres_mag%R)) & - - s_P*(cm%L(i)*vel_L(norm_dir) & - - b4%L(i)/Ga%L*B%L(norm_dir) & - + dir_flg(i)*(pres_L + pres_mag%L)) & - + s_M*s_P*(cm%L(i) - cm%R(i))) & - /(s_M - s_P) - end do - elseif (bubbles_euler) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_vels - flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & - (s_M*(rho_R*vel_R(dir_idx(1)) & - *vel_R(dir_idx(i)) & - + dir_flg(dir_idx(i))*(pres_R - ptilde_R)) & - - s_P*(rho_L*vel_L(dir_idx(1)) & - *vel_L(dir_idx(i)) & - + dir_flg(dir_idx(i))*(pres_L - ptilde_L)) & - + s_M*s_P*(rho_L*vel_L(dir_idx(i)) & - - rho_R*vel_R(dir_idx(i)))) & - /(s_M - s_P) & - + (s_M/s_L)*(s_P/s_R)*pcorr*(vel_R(dir_idx(i)) - vel_L(dir_idx(i))) - end do - else if (hypoelasticity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_vels - flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & - (s_M*(rho_R*vel_R(dir_idx(1)) & - *vel_R(dir_idx(i)) & - + dir_flg(dir_idx(i))*pres_R & - - tau_e_R(dir_idx_tau(i))) & - - s_P*(rho_L*vel_L(dir_idx(1)) & - *vel_L(dir_idx(i)) & - + dir_flg(dir_idx(i))*pres_L & - - tau_e_L(dir_idx_tau(i))) & - + s_M*s_P*(rho_L*vel_L(dir_idx(i)) & - - rho_R*vel_R(dir_idx(i)))) & - /(s_M - s_P) - end do - else - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_vels - flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & - (s_M*(rho_R*vel_R(dir_idx(1)) & - *vel_R(dir_idx(i)) & - + dir_flg(dir_idx(i))*pres_R) & - - s_P*(rho_L*vel_L(dir_idx(1)) & - *vel_L(dir_idx(i)) & - + dir_flg(dir_idx(i))*pres_L) & - + s_M*s_P*(rho_L*vel_L(dir_idx(i)) & - - rho_R*vel_R(dir_idx(i)))) & - /(s_M - s_P) & - + (s_M/s_L)*(s_P/s_R)*pcorr*(vel_R(dir_idx(i)) - vel_L(dir_idx(i))) - end do - end if + @:compute_average_state() - ! Energy - if (mhd .and. (.not. relativity)) then - ! energy flux = (E + p + p_mag) * v_${XYZ}$ - B_${XYZ}$ * (v_x*B_x + v_y*B_y + v_z*B_z) - flux_rs${XYZ}$_vf(j, k, l, E_idx) = & - (s_M*(vel_R(norm_dir)*(E_R + pres_R + pres_mag%R) - B%R(norm_dir)*(vel_R(1)*B%R(1) + vel_R(2)*B%R(2) + vel_R(3)*B%R(3))) & - - s_P*(vel_L(norm_dir)*(E_L + pres_L + pres_mag%L) - B%L(norm_dir)*(vel_L(1)*B%L(1) + vel_L(2)*B%L(2) + vel_L(3)*B%L(3))) & - + s_M*s_P*(E_L - E_R)) & - /(s_M - s_P) - elseif (mhd .and. relativity) then - ! energy flux = m_${XYZ}$ - mass flux - ! Hard-coded for single-component for now - flux_rs${XYZ}$_vf(j, k, l, E_idx) = & - (s_M*(cm%R(norm_dir) - Ga%R*alpha_rho_R(1)*vel_R(norm_dir)) & - - s_P*(cm%L(norm_dir) - Ga%L*alpha_rho_L(1)*vel_L(norm_dir)) & - + s_M*s_P*(E_L - E_R)) & - /(s_M - s_P) - else if (bubbles_euler) then - flux_rs${XYZ}$_vf(j, k, l, E_idx) = & - (s_M*vel_R(dir_idx(1))*(E_R + pres_R - ptilde_R) & - - s_P*vel_L(dir_idx(1))*(E_L + pres_L - ptilde_L) & - + s_M*s_P*(E_L - E_R)) & - /(s_M - s_P) & - + (s_M/s_L)*(s_P/s_R)*pcorr*(vel_R_rms - vel_L_rms)/2._wp - else if (hypoelasticity) then - flux_tau_L = 0._wp; flux_tau_R = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - flux_tau_L = flux_tau_L + tau_e_L(dir_idx_tau(i))*vel_L(dir_idx(i)) - flux_tau_R = flux_tau_R + tau_e_R(dir_idx_tau(i))*vel_R(dir_idx(i)) - end do - flux_rs${XYZ}$_vf(j, k, l, E_idx) = & - (s_M*(vel_R(dir_idx(1))*(E_R + pres_R) - flux_tau_R) & - - s_P*(vel_L(dir_idx(1))*(E_L + pres_L) - flux_tau_L) & - + s_M*s_P*(E_L - E_R))/(s_M - s_P) - else - flux_rs${XYZ}$_vf(j, k, l, E_idx) = & - (s_M*vel_R(dir_idx(1))*(E_R + pres_R) & - - s_P*vel_L(dir_idx(1))*(E_L + pres_L) & - + s_M*s_P*(E_L - E_R)) & - /(s_M - s_P) & - + (s_M/s_L)*(s_P/s_R)*pcorr*(vel_R_rms - vel_L_rms)/2._wp - end if + call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & + vel_L_rms, 0._wp, c_L) - ! Elastic Stresses - if (hypoelasticity) then - do i = 1, strxe - strxb + 1 !TODO: this indexing may be slow - flux_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) = & - (s_M*(rho_R*vel_R(dir_idx(1)) & - *tau_e_R(i)) & - - s_P*(rho_L*vel_L(dir_idx(1)) & - *tau_e_L(i)) & - + s_M*s_P*(rho_L*tau_e_L(i) & - - rho_R*tau_e_R(i))) & - /(s_M - s_P) - end do - end if + call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & + vel_R_rms, 0._wp, c_R) - ! Advection - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - (qL_prim_rs${XYZ}$_vf(j, k, l, i) & - - qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)) & - *s_M*s_P/(s_M - s_P) - flux_src_rs${XYZ}$_vf(j, k, l, i) = & - (s_M*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & - - s_P*qL_prim_rs${XYZ}$_vf(j, k, l, i)) & - /(s_M - s_P) - end do + !> The computation of c_avg does not require all the variables, and therefore the non '_avg' + ! variables are placeholders to call the subroutine. - ! Xi field - !if ( hyperelasticity ) then - ! do i = 1, num_dims - ! flux_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) = & - ! (s_M*rho_R*vel_R(dir_idx(1))*xi_field_R(i) & - ! - s_P*rho_L*vel_L(dir_idx(1))*xi_field_L(i) & - ! + s_M*s_P*(rho_L*xi_field_L(i) & - ! - rho_R*xi_field_R(i))) & - ! /(s_M - s_P) - ! end do - !end if - - ! Div(U)? - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_vels - vel_src_rs${XYZ}$_vf(j, k, l, dir_idx(i)) = & - (xi_M*(rho_L*vel_L(dir_idx(i))* & - (s_L - vel_L(dir_idx(1))) - & - pres_L*dir_flg(dir_idx(i))) - & - xi_P*(rho_R*vel_R(dir_idx(i))* & - (s_R - vel_R(dir_idx(1))) - & - pres_R*dir_flg(dir_idx(i)))) & - /(xi_M*rho_L*(s_L - vel_L(dir_idx(1))) - & - xi_P*rho_R*(s_R - vel_R(dir_idx(1)))) - end do + call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & + vel_avg_rms, c_sum_Yi_Phi, c_avg) - if (bubbles_euler) then - ! From HLLC: Kills mass transport @ bubble gas density - if (num_fluids > 1) then - flux_rs${XYZ}$_vf(j, k, l, contxe) = 0._wp + if (mhd) then + call s_compute_fast_magnetosonic_speed(rho_L, c_L, B%L, norm_dir, c_fast%L, H_L) + call s_compute_fast_magnetosonic_speed(rho_R, c_R, B%R, norm_dir, c_fast%R, H_R) end if - end if - - if (chemistry) then - $:GPU_LOOP(parallelism='[seq]') - do i = chemxb, chemxe - Y_L = qL_prim_rs${XYZ}$_vf(j, k, l, i) - Y_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) - - flux_rs${XYZ}$_vf(j, k, l, i) = (s_M*Y_R*rho_R*vel_R(dir_idx(1)) & - - s_P*Y_L*rho_L*vel_L(dir_idx(1)) & - + s_M*s_P*(Y_L*rho_L - Y_R*rho_R)) & - /(s_M - s_P) - flux_src_rs${XYZ}$_vf(j, k, l, i) = 0._wp - end do - end if - if (mhd) then - if (n == 0) then ! 1D: d/dx flux only & Bx = Bx0 = const. - ! B_y flux = v_x * B_y - v_y * Bx0 - ! B_z flux = v_x * B_z - v_z * Bx0 - $:GPU_LOOP(parallelism='[seq]') - do i = 0, 1 - flux_rsx_vf(j, k, l, B_idx%beg + i) = (s_M*(vel_R(1)*B%R(2 + i) - vel_R(2 + i)*Bx0) & - - s_P*(vel_L(1)*B%L(2 + i) - vel_L(2 + i)*Bx0) & - + s_M*s_P*(B%L(2 + i) - B%R(2 + i)))/(s_M - s_P) - end do - else ! 2D/3D: Bx, By, Bz /= const. but zero flux component in the same direction - ! B_x d/d${XYZ}$ flux = (1 - delta(x,${XYZ}$)) * (v_${XYZ}$ * B_x - v_x * B_${XYZ}$) - ! B_y d/d${XYZ}$ flux = (1 - delta(y,${XYZ}$)) * (v_${XYZ}$ * B_y - v_y * B_${XYZ}$) - ! B_z d/d${XYZ}$ flux = (1 - delta(z,${XYZ}$)) * (v_${XYZ}$ * B_z - v_z * B_${XYZ}$) + if (viscous) then $:GPU_LOOP(parallelism='[seq]') - do i = 0, 2 - flux_rs${XYZ}$_vf(j, k, l, B_idx%beg + i) = (1 - dir_flg(i + 1))*( & - s_M*(vel_R(dir_idx(1))*B%R(i + 1) - vel_R(i + 1)*B%R(norm_dir)) - & - s_P*(vel_L(dir_idx(1))*B%L(i + 1) - vel_L(i + 1)*B%L(norm_dir)) + & - s_M*s_P*(B%L(i + 1) - B%R(i + 1)))/(s_M - s_P) + do i = 1, 2 + Re_avg_rs${XYZ}$_vf(j, k, l, i) = 2._wp/(1._wp/Re_L(i) + 1._wp/Re_R(i)) end do end if - flux_src_rs${XYZ}$_vf(j, k, l, advxb) = 0._wp - end if - #:if (NORM_DIR == 2) - if (cyl_coord) then - !Substituting the advective flux into the inviscid geometrical source flux - $:GPU_LOOP(parallelism='[seq]') - do i = 1, E_idx - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) - end do - ! Recalculating the radial momentum geometric source flux - flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + 2) = & - flux_rs${XYZ}$_vf(j, k, l, contxe + 2) & - - (s_M*pres_R - s_P*pres_L)/(s_M - s_P) - ! Geometrical source of the void fraction(s) is zero - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) - end do - end if + if (wave_speeds == 1) then + if (mhd) then + s_L = min(vel_L(dir_idx(1)) - c_fast%L, vel_R(dir_idx(1)) - c_fast%R) + s_R = max(vel_R(dir_idx(1)) + c_fast%R, vel_L(dir_idx(1)) + c_fast%L) + elseif (hypoelasticity) then + s_L = min(vel_L(dir_idx(1)) - sqrt(c_L*c_L + & + (((4._wp*G_L)/3._wp) + & + tau_e_L(dir_idx_tau(1)))/rho_L) & + , vel_R(dir_idx(1)) - sqrt(c_R*c_R + & + (((4._wp*G_R)/3._wp) + & + tau_e_R(dir_idx_tau(1)))/rho_R)) + s_R = max(vel_R(dir_idx(1)) + sqrt(c_R*c_R + & + (((4._wp*G_R)/3._wp) + & + tau_e_R(dir_idx_tau(1)))/rho_R) & + , vel_L(dir_idx(1)) + sqrt(c_L*c_L + & + (((4._wp*G_L)/3._wp) + & + tau_e_L(dir_idx_tau(1)))/rho_L)) + else if (hyperelasticity) then + s_L = min(vel_L(dir_idx(1)) - sqrt(c_L*c_L + (4._wp*G_L/3._wp)/rho_L) & + , vel_R(dir_idx(1)) - sqrt(c_R*c_R + (4._wp*G_R/3._wp)/rho_R)) + s_R = max(vel_R(dir_idx(1)) + sqrt(c_R*c_R + (4._wp*G_R/3._wp)/rho_R) & + , vel_L(dir_idx(1)) + sqrt(c_L*c_L + (4._wp*G_L/3._wp)/rho_L)) + else + s_L = min(vel_L(dir_idx(1)) - c_L, vel_R(dir_idx(1)) - c_R) + s_R = max(vel_R(dir_idx(1)) + c_R, vel_L(dir_idx(1)) + c_L) + end if - if (cyl_coord .and. hypoelasticity) then - ! += tau_sigmasigma using HLL - flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + 2) = & - flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + 2) + & - (s_M*tau_e_R(4) - s_P*tau_e_L(4)) & - /(s_M - s_P) + s_S = (pres_R - pres_L + rho_L*vel_L(dir_idx(1))* & + (s_L - vel_L(dir_idx(1))) - & + rho_R*vel_R(dir_idx(1))* & + (s_R - vel_R(dir_idx(1)))) & + /(rho_L*(s_L - vel_L(dir_idx(1))) - & + rho_R*(s_R - vel_R(dir_idx(1)))) + elseif (wave_speeds == 2) then + pres_SL = 5.e-1_wp*(pres_L + pres_R + rho_avg*c_avg* & + (vel_L(dir_idx(1)) - & + vel_R(dir_idx(1)))) - $:GPU_LOOP(parallelism='[seq]') - do i = strxb, strxe - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) + pres_SR = pres_SL + + Ms_L = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_L)/(1._wp + gamma_L))* & + (pres_SL/pres_L - 1._wp)*pres_L/ & + ((pres_L + pi_inf_L/(1._wp + gamma_L))))) + Ms_R = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_R)/(1._wp + gamma_R))* & + (pres_SR/pres_R - 1._wp)*pres_R/ & + ((pres_R + pi_inf_R/(1._wp + gamma_R))))) + + s_L = vel_L(dir_idx(1)) - c_L*Ms_L + s_R = vel_R(dir_idx(1)) + c_R*Ms_R + + s_S = 5.e-1_wp*((vel_L(dir_idx(1)) + vel_R(dir_idx(1))) + & + (pres_L - pres_R)/ & + (rho_avg*c_avg)) + end if + + s_M = min(0._wp, s_L); s_P = max(0._wp, s_R) + + xi_M = (5.e-1_wp + sign(5.e-1_wp, s_L)) & + + (5.e-1_wp - sign(5.e-1_wp, s_L)) & + *(5.e-1_wp + sign(5.e-1_wp, s_R)) + xi_P = (5.e-1_wp - sign(5.e-1_wp, s_R)) & + + (5.e-1_wp - sign(5.e-1_wp, s_L)) & + *(5.e-1_wp + sign(5.e-1_wp, s_R)) + + ! Low Mach correction + if (low_Mach == 1) then + @:compute_low_Mach_correction() + else + pcorr = 0._wp + end if + + ! Mass + if (.not. relativity) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + (s_M*alpha_rho_R(i)*vel_R(norm_dir) & + - s_P*alpha_rho_L(i)*vel_L(norm_dir) & + + s_M*s_P*(alpha_rho_L(i) & + - alpha_rho_R(i))) & + /(s_M - s_P) + end do + elseif (relativity) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + (s_M*Ga%R*alpha_rho_R(i)*vel_R(norm_dir) & + - s_P*Ga%L*alpha_rho_L(i)*vel_L(norm_dir) & + + s_M*s_P*(Ga%L*alpha_rho_L(i) & + - Ga%R*alpha_rho_R(i))) & + /(s_M - s_P) + end do + end if + + ! Momentum + if (mhd .and. (.not. relativity)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 3 + ! Flux of rho*v_i in the ${XYZ}$ direction + ! = rho * v_i * v_${XYZ}$ - B_i * B_${XYZ}$ + delta_(${XYZ}$,i) * p_tot + flux_rs${XYZ}$_vf(j, k, l, contxe + i) = & + (s_M*(rho_R*vel_R(i)*vel_R(norm_dir) & + - B%R(i)*B%R(norm_dir) & + + dir_flg(i)*(pres_R + pres_mag%R)) & + - s_P*(rho_L*vel_L(i)*vel_L(norm_dir) & + - B%L(i)*B%L(norm_dir) & + + dir_flg(i)*(pres_L + pres_mag%L)) & + + s_M*s_P*(rho_L*vel_L(i) - rho_R*vel_R(i))) & + /(s_M - s_P) + end do + elseif (mhd .and. relativity) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 3 + ! Flux of m_i in the ${XYZ}$ direction + ! = m_i * v_${XYZ}$ - b_i/Gamma * B_${XYZ}$ + delta_(${XYZ}$,i) * p_tot + flux_rs${XYZ}$_vf(j, k, l, contxe + i) = & + (s_M*(cm%R(i)*vel_R(norm_dir) & + - b4%R(i)/Ga%R*B%R(norm_dir) & + + dir_flg(i)*(pres_R + pres_mag%R)) & + - s_P*(cm%L(i)*vel_L(norm_dir) & + - b4%L(i)/Ga%L*B%L(norm_dir) & + + dir_flg(i)*(pres_L + pres_mag%L)) & + + s_M*s_P*(cm%L(i) - cm%R(i))) & + /(s_M - s_P) + end do + elseif (bubbles_euler) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_vels + flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & + (s_M*(rho_R*vel_R(dir_idx(1)) & + *vel_R(dir_idx(i)) & + + dir_flg(dir_idx(i))*(pres_R - ptilde_R)) & + - s_P*(rho_L*vel_L(dir_idx(1)) & + *vel_L(dir_idx(i)) & + + dir_flg(dir_idx(i))*(pres_L - ptilde_L)) & + + s_M*s_P*(rho_L*vel_L(dir_idx(i)) & + - rho_R*vel_R(dir_idx(i)))) & + /(s_M - s_P) & + + (s_M/s_L)*(s_P/s_R)*pcorr*(vel_R(dir_idx(i)) - vel_L(dir_idx(i))) + end do + else if (hypoelasticity) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_vels + flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & + (s_M*(rho_R*vel_R(dir_idx(1)) & + *vel_R(dir_idx(i)) & + + dir_flg(dir_idx(i))*pres_R & + - tau_e_R(dir_idx_tau(i))) & + - s_P*(rho_L*vel_L(dir_idx(1)) & + *vel_L(dir_idx(i)) & + + dir_flg(dir_idx(i))*pres_L & + - tau_e_L(dir_idx_tau(i))) & + + s_M*s_P*(rho_L*vel_L(dir_idx(i)) & + - rho_R*vel_R(dir_idx(i)))) & + /(s_M - s_P) + end do + else + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_vels + flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & + (s_M*(rho_R*vel_R(dir_idx(1)) & + *vel_R(dir_idx(i)) & + + dir_flg(dir_idx(i))*pres_R) & + - s_P*(rho_L*vel_L(dir_idx(1)) & + *vel_L(dir_idx(i)) & + + dir_flg(dir_idx(i))*pres_L) & + + s_M*s_P*(rho_L*vel_L(dir_idx(i)) & + - rho_R*vel_R(dir_idx(i)))) & + /(s_M - s_P) & + + (s_M/s_L)*(s_P/s_R)*pcorr*(vel_R(dir_idx(i)) - vel_L(dir_idx(i))) end do end if - #:endif + ! Energy + if (mhd .and. (.not. relativity)) then + ! energy flux = (E + p + p_mag) * v_${XYZ}$ - B_${XYZ}$ * (v_x*B_x + v_y*B_y + v_z*B_z) + flux_rs${XYZ}$_vf(j, k, l, E_idx) = & + (s_M*(vel_R(norm_dir)*(E_R + pres_R + pres_mag%R) - B%R(norm_dir)*(vel_R(1)*B%R(1) + vel_R(2)*B%R(2) + vel_R(3)*B%R(3))) & + - s_P*(vel_L(norm_dir)*(E_L + pres_L + pres_mag%L) - B%L(norm_dir)*(vel_L(1)*B%L(1) + vel_L(2)*B%L(2) + vel_L(3)*B%L(3))) & + + s_M*s_P*(E_L - E_R)) & + /(s_M - s_P) + elseif (mhd .and. relativity) then + ! energy flux = m_${XYZ}$ - mass flux + ! Hard-coded for single-component for now + flux_rs${XYZ}$_vf(j, k, l, E_idx) = & + (s_M*(cm%R(norm_dir) - Ga%R*alpha_rho_R(1)*vel_R(norm_dir)) & + - s_P*(cm%L(norm_dir) - Ga%L*alpha_rho_L(1)*vel_L(norm_dir)) & + + s_M*s_P*(E_L - E_R)) & + /(s_M - s_P) + else if (bubbles_euler) then + flux_rs${XYZ}$_vf(j, k, l, E_idx) = & + (s_M*vel_R(dir_idx(1))*(E_R + pres_R - ptilde_R) & + - s_P*vel_L(dir_idx(1))*(E_L + pres_L - ptilde_L) & + + s_M*s_P*(E_L - E_R)) & + /(s_M - s_P) & + + (s_M/s_L)*(s_P/s_R)*pcorr*(vel_R_rms - vel_L_rms)/2._wp + else if (hypoelasticity) then + flux_tau_L = 0._wp; flux_tau_R = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + flux_tau_L = flux_tau_L + tau_e_L(dir_idx_tau(i))*vel_L(dir_idx(i)) + flux_tau_R = flux_tau_R + tau_e_R(dir_idx_tau(i))*vel_R(dir_idx(i)) + end do + flux_rs${XYZ}$_vf(j, k, l, E_idx) = & + (s_M*(vel_R(dir_idx(1))*(E_R + pres_R) - flux_tau_R) & + - s_P*(vel_L(dir_idx(1))*(E_L + pres_L) - flux_tau_L) & + + s_M*s_P*(E_L - E_R))/(s_M - s_P) + else + flux_rs${XYZ}$_vf(j, k, l, E_idx) = & + (s_M*vel_R(dir_idx(1))*(E_R + pres_R) & + - s_P*vel_L(dir_idx(1))*(E_L + pres_L) & + + s_M*s_P*(E_L - E_R)) & + /(s_M - s_P) & + + (s_M/s_L)*(s_P/s_R)*pcorr*(vel_R_rms - vel_L_rms)/2._wp + end if + + ! Elastic Stresses + if (hypoelasticity) then + do i = 1, strxe - strxb + 1 !TODO: this indexing may be slow + flux_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) = & + (s_M*(rho_R*vel_R(dir_idx(1)) & + *tau_e_R(i)) & + - s_P*(rho_L*vel_L(dir_idx(1)) & + *tau_e_L(i)) & + + s_M*s_P*(rho_L*tau_e_L(i) & + - rho_R*tau_e_R(i))) & + /(s_M - s_P) + end do + end if + + ! Advection + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + (qL_prim_rs${XYZ}$_vf(j, k, l, i) & + - qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)) & + *s_M*s_P/(s_M - s_P) + flux_src_rs${XYZ}$_vf(j, k, l, i) = & + (s_M*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & + - s_P*qL_prim_rs${XYZ}$_vf(j, k, l, i)) & + /(s_M - s_P) + end do + + ! Xi field + !if ( hyperelasticity ) then + ! do i = 1, num_dims + ! flux_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) = & + ! (s_M*rho_R*vel_R(dir_idx(1))*xi_field_R(i) & + ! - s_P*rho_L*vel_L(dir_idx(1))*xi_field_L(i) & + ! + s_M*s_P*(rho_L*xi_field_L(i) & + ! - rho_R*xi_field_R(i))) & + ! /(s_M - s_P) + ! end do + !end if + + ! Div(U)? + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_vels + vel_src_rs${XYZ}$_vf(j, k, l, dir_idx(i)) = & + (xi_M*(rho_L*vel_L(dir_idx(i))* & + (s_L - vel_L(dir_idx(1))) - & + pres_L*dir_flg(dir_idx(i))) - & + xi_P*(rho_R*vel_R(dir_idx(i))* & + (s_R - vel_R(dir_idx(1))) - & + pres_R*dir_flg(dir_idx(i)))) & + /(xi_M*rho_L*(s_L - vel_L(dir_idx(1))) - & + xi_P*rho_R*(s_R - vel_R(dir_idx(1)))) + end do + + if (bubbles_euler) then + ! From HLLC: Kills mass transport @ bubble gas density + if (num_fluids > 1) then + flux_rs${XYZ}$_vf(j, k, l, contxe) = 0._wp + end if + end if + + if (chemistry) then + $:GPU_LOOP(parallelism='[seq]') + do i = chemxb, chemxe + Y_L = qL_prim_rs${XYZ}$_vf(j, k, l, i) + Y_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + + flux_rs${XYZ}$_vf(j, k, l, i) = (s_M*Y_R*rho_R*vel_R(dir_idx(1)) & + - s_P*Y_L*rho_L*vel_L(dir_idx(1)) & + + s_M*s_P*(Y_L*rho_L - Y_R*rho_R)) & + /(s_M - s_P) + flux_src_rs${XYZ}$_vf(j, k, l, i) = 0._wp + end do + end if + + if (mhd) then + if (n == 0) then ! 1D: d/dx flux only & Bx = Bx0 = const. + ! B_y flux = v_x * B_y - v_y * Bx0 + ! B_z flux = v_x * B_z - v_z * Bx0 + $:GPU_LOOP(parallelism='[seq]') + do i = 0, 1 + flux_rsx_vf(j, k, l, B_idx%beg + i) = (s_M*(vel_R(1)*B%R(2 + i) - vel_R(2 + i)*Bx0) & + - s_P*(vel_L(1)*B%L(2 + i) - vel_L(2 + i)*Bx0) & + + s_M*s_P*(B%L(2 + i) - B%R(2 + i)))/(s_M - s_P) + end do + else ! 2D/3D: Bx, By, Bz /= const. but zero flux component in the same direction + ! B_x d/d${XYZ}$ flux = (1 - delta(x,${XYZ}$)) * (v_${XYZ}$ * B_x - v_x * B_${XYZ}$) + ! B_y d/d${XYZ}$ flux = (1 - delta(y,${XYZ}$)) * (v_${XYZ}$ * B_y - v_y * B_${XYZ}$) + ! B_z d/d${XYZ}$ flux = (1 - delta(z,${XYZ}$)) * (v_${XYZ}$ * B_z - v_z * B_${XYZ}$) + $:GPU_LOOP(parallelism='[seq]') + do i = 0, 2 + flux_rs${XYZ}$_vf(j, k, l, B_idx%beg + i) = (1 - dir_flg(i + 1))*( & + s_M*(vel_R(dir_idx(1))*B%R(i + 1) - vel_R(i + 1)*B%R(norm_dir)) - & + s_P*(vel_L(dir_idx(1))*B%L(i + 1) - vel_L(i + 1)*B%L(norm_dir)) + & + s_M*s_P*(B%L(i + 1) - B%R(i + 1)))/(s_M - s_P) + end do + end if + flux_src_rs${XYZ}$_vf(j, k, l, advxb) = 0._wp + end if + + #:if (NORM_DIR == 2) + if (cyl_coord) then + !Substituting the advective flux into the inviscid geometrical source flux + $:GPU_LOOP(parallelism='[seq]') + do i = 1, E_idx + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) + end do + ! Recalculating the radial momentum geometric source flux + flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + 2) = & + flux_rs${XYZ}$_vf(j, k, l, contxe + 2) & + - (s_M*pres_R - s_P*pres_L)/(s_M - s_P) + ! Geometrical source of the void fraction(s) is zero + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) + end do + end if + + if (cyl_coord .and. hypoelasticity) then + ! += tau_sigmasigma using HLL + flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + 2) = & + flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + 2) + & + (s_M*tau_e_R(4) - s_P*tau_e_L(4)) & + /(s_M - s_P) + + $:GPU_LOOP(parallelism='[seq]') + do i = strxb, strxe + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) + end do + end if + #:endif + + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1183,1652 +1183,1652 @@ contains if (model_eqns == 3) then !ME3 #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel_L, vel_R, vel_K_Star, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, vel_avg_rms, alpha_L, alpha_R, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, tau_e_L, tau_e_R, G_L, G_R, flux_ene_e, xi_field_L, xi_field_R, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - - idx1 = dir_idx(1) - - vel_L_rms = 0._wp; vel_R_rms = 0._wp - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + i) - vel_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + i) - vel_L_rms = vel_L_rms + vel_L(i)**2._wp - vel_R_rms = vel_R_rms + vel_R(i)**2._wp - end do - - pres_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) - pres_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) - - rho_L = 0._wp - gamma_L = 0._wp - pi_inf_L = 0._wp - qv_L = 0._wp - - rho_R = 0._wp - gamma_R = 0._wp - pi_inf_R = 0._wp - qv_R = 0._wp - - alpha_L_sum = 0._wp - alpha_R_sum = 0._wp + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end - if (mpp_lim) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - qL_prim_rs${XYZ}$_vf(j, k, l, i) = max(0._wp, qL_prim_rs${XYZ}$_vf(j, k, l, i)) - qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) = min(max(0._wp, qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)), 1._wp) - alpha_L_sum = alpha_L_sum + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) - end do + idx1 = dir_idx(1) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)/max(alpha_L_sum, sgm_eps) - end do + vel_L_rms = 0._wp; vel_R_rms = 0._wp $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) = max(0._wp, qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)) - qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) = min(max(0._wp, qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)), 1._wp) - alpha_R_sum = alpha_R_sum + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) + do i = 1, num_dims + vel_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + i) + vel_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + i) + vel_L_rms = vel_L_rms + vel_L(i)**2._wp + vel_R_rms = vel_R_rms + vel_R(i)**2._wp end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)/max(alpha_R_sum, sgm_eps) - end do - end if + pres_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) + pres_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_L = rho_L + qL_prim_rs${XYZ}$_vf(j, k, l, i) - gamma_L = gamma_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*gammas(i) - pi_inf_L = pi_inf_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*pi_infs(i) - qv_L = qv_L + qL_prim_rs${XYZ}$_vf(j, k, l, i)*qvs(i) - - rho_R = rho_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) - gamma_R = gamma_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*gammas(i) - pi_inf_R = pi_inf_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*pi_infs(i) - qv_R = qv_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*qvs(i) - - alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, advxb + i - 1) - alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, advxb + i - 1) - end do + rho_L = 0._wp + gamma_L = 0._wp + pi_inf_L = 0._wp + qv_L = 0._wp - if (viscous) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_L(i) = dflt_real + rho_R = 0._wp + gamma_R = 0._wp + pi_inf_R = 0._wp + qv_R = 0._wp - if (Re_size(i) > 0) Re_L(i) = 0._wp + alpha_L_sum = 0._wp + alpha_R_sum = 0._wp + if (mpp_lim) then $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q))/Res(i, q) & - + Re_L(i) + do i = 1, num_fluids + qL_prim_rs${XYZ}$_vf(j, k, l, i) = max(0._wp, qL_prim_rs${XYZ}$_vf(j, k, l, i)) + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) = min(max(0._wp, qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)), 1._wp) + alpha_L_sum = alpha_L_sum + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) end do - Re_L(i) = 1._wp/max(Re_L(i), sgm_eps) - - end do - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_R(i) = dflt_real - - if (Re_size(i) > 0) Re_R(i) = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q))/Res(i, q) & - + Re_R(i) + do i = 1, num_fluids + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)/max(alpha_L_sum, sgm_eps) end do - Re_R(i) = 1._wp/max(Re_R(i), sgm_eps) - end do - end if - - E_L = gamma_L*pres_L + pi_inf_L + 5.e-1_wp*rho_L*vel_L_rms + qv_L - - E_R = gamma_R*pres_R + pi_inf_R + 5.e-1_wp*rho_R*vel_R_rms + qv_R - - ! ENERGY ADJUSTMENTS FOR HYPOELASTIC ENERGY - if (hypoelasticity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, strxe - strxb + 1 - tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) - tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) - end do - G_L = 0._wp; G_R = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - G_L = G_L + alpha_L(i)*Gs(i) - G_R = G_R + alpha_R(i)*Gs(i) - end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, strxe - strxb + 1 - ! Elastic contribution to energy if G large enough - if ((G_L > verysmall) .and. (G_R > verysmall)) then - E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) - E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) - ! Additional terms in 2D and 3D - if ((i == 2) .or. (i == 4) .or. (i == 5)) then - E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) - E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) - end if - end if - end do - end if - - ! ENERGY ADJUSTMENTS FOR HYPERELASTIC ENERGY - if (hyperelasticity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - xi_field_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) - xi_field_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, xibeg - 1 + i) - end do - G_L = 0._wp; G_R = 0._wp; - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - ! Mixture left and right shear modulus - G_L = G_L + alpha_L(i)*Gs(i) - G_R = G_R + alpha_R(i)*Gs(i) - end do - ! Elastic contribution to energy if G large enough - if (G_L > verysmall .and. G_R > verysmall) then - E_L = E_L + G_L*qL_prim_rs${XYZ}$_vf(j, k, l, xiend + 1) - E_R = E_R + G_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, xiend + 1) - end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, b_size - 1 - tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) - tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) - end do - end if - - H_L = (E_L + pres_L)/rho_L - H_R = (E_R + pres_R)/rho_R - - @:compute_average_state() - - call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & - vel_L_rms, 0._wp, c_L) - - call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & - vel_R_rms, 0._wp, c_R) - - !> The computation of c_avg does not require all the variables, and therefore the non '_avg' - ! variables are placeholders to call the subroutine. - call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & - vel_avg_rms, 0._wp, c_avg) - - if (viscous) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_avg_rs${XYZ}$_vf(j, k, l, i) = 2._wp/(1._wp/Re_L(i) + 1._wp/Re_R(i)) - end do - end if - - ! Low Mach correction - if (low_Mach == 2) then - @:compute_low_Mach_correction() - end if - - ! COMPUTING THE DIRECT WAVE SPEEDS - if (wave_speeds == 1) then - if (elasticity) then - s_L = min(vel_L(dir_idx(1)) - sqrt(c_L*c_L + & - (((4._wp*G_L)/3._wp) + tau_e_L(dir_idx_tau(1)))/rho_L), vel_R(dir_idx(1)) - sqrt(c_R*c_R + & - (((4._wp*G_R)/3._wp) + tau_e_R(dir_idx_tau(1)))/rho_R)) - s_R = max(vel_R(dir_idx(1)) + sqrt(c_R*c_R + & - (((4._wp*G_R)/3._wp) + tau_e_R(dir_idx_tau(1)))/rho_R), vel_L(dir_idx(1)) + sqrt(c_L*c_L + & - (((4._wp*G_L)/3._wp) + tau_e_L(dir_idx_tau(1)))/rho_L)) - s_S = (pres_R - tau_e_R(dir_idx_tau(1)) - pres_L + & - tau_e_L(dir_idx_tau(1)) + rho_L*vel_L(idx1)*(s_L - vel_L(idx1)) - & - rho_R*vel_R(idx1)*(s_R - vel_R(idx1)))/(rho_L*(s_L - vel_L(idx1)) - & - rho_R*(s_R - vel_R(idx1))) - else - s_L = min(vel_L(dir_idx(1)) - c_L, vel_R(dir_idx(1)) - c_R) - s_R = max(vel_R(dir_idx(1)) + c_R, vel_L(dir_idx(1)) + c_L) - s_S = (pres_R - pres_L + rho_L*vel_L(dir_idx(1))* & - (s_L - vel_L(dir_idx(1))) - rho_R*vel_R(dir_idx(1))*(s_R - vel_R(dir_idx(1)))) & - /(rho_L*(s_L - vel_L(dir_idx(1))) - rho_R*(s_R - vel_R(dir_idx(1)))) - - end if - elseif (wave_speeds == 2) then - pres_SL = 5.e-1_wp*(pres_L + pres_R + rho_avg*c_avg* & - (vel_L(dir_idx(1)) - & - vel_R(dir_idx(1)))) - - pres_SR = pres_SL - - Ms_L = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_L)/(1._wp + gamma_L))* & - (pres_SL/pres_L - 1._wp)*pres_L/ & - ((pres_L + pi_inf_L/(1._wp + gamma_L))))) - Ms_R = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_R)/(1._wp + gamma_R))* & - (pres_SR/pres_R - 1._wp)*pres_R/ & - ((pres_R + pi_inf_R/(1._wp + gamma_R))))) - - s_L = vel_L(dir_idx(1)) - c_L*Ms_L - s_R = vel_R(dir_idx(1)) + c_R*Ms_R - - s_S = 5.e-1_wp*((vel_L(dir_idx(1)) + vel_R(dir_idx(1))) + & - (pres_L - pres_R)/ & - (rho_avg*c_avg)) - end if - - ! follows Einfeldt et al. - ! s_M/P = min/max(0.,s_L/R) - s_M = min(0._wp, s_L); s_P = max(0._wp, s_R) - - ! goes with q_star_L/R = xi_L/R * (variable) - ! xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) ) - xi_L = (s_L - vel_L(idx1))/(s_L - s_S) - xi_R = (s_R - vel_R(idx1))/(s_R - s_S) - - ! goes with numerical star velocity in x/y/z directions - ! xi_P/M = 0.5 +/m sgn(0.5,s_star) - xi_M = (5.e-1_wp + sign(0.5_wp, s_S)) - xi_P = (5.e-1_wp - sign(0.5_wp, s_S)) - - ! goes with the numerical velocity in x/y/z directions - ! xi_P/M (pressure) = min/max(0. sgn(1,sL/sR)) - xi_MP = -min(0._wp, sign(1._wp, s_L)) - xi_PP = max(0._wp, sign(1._wp, s_R)) - - E_star = xi_M*(E_L + xi_MP*(xi_L*(E_L + (s_S - vel_L(dir_idx(1)))* & - (rho_L*s_S + pres_L/(s_L - vel_L(dir_idx(1))))) - E_L)) + & - xi_P*(E_R + xi_PP*(xi_R*(E_R + (s_S - vel_R(dir_idx(1)))* & - (rho_R*s_S + pres_R/(s_R - vel_R(dir_idx(1))))) - E_R)) - p_Star = xi_M*(pres_L + xi_MP*(rho_L*(s_L - vel_L(dir_idx(1)))*(s_S - vel_L(dir_idx(1))))) + & - xi_P*(pres_R + xi_PP*(rho_R*(s_R - vel_R(dir_idx(1)))*(s_S - vel_R(dir_idx(1))))) - - rho_Star = xi_M*(rho_L*(xi_MP*xi_L + 1._wp - xi_MP)) + & - xi_P*(rho_R*(xi_PP*xi_R + 1._wp - xi_PP)) - - vel_K_Star = vel_L(idx1)*(1._wp - xi_MP) + xi_MP*vel_R(idx1) + & - xi_MP*xi_PP*(s_S - vel_R(idx1)) - - ! Low Mach correction - if (low_Mach == 1) then - @:compute_low_Mach_correction() - else - pcorr = 0._wp - end if - - ! COMPUTING FLUXES - ! MASS FLUX. - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i)*(vel_L(idx1) + s_M*(xi_L - 1._wp)) + & - xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*(vel_R(idx1) + s_P*(xi_R - 1._wp)) - end do - - ! MOMENTUM FLUX. - ! f = \rho u u - \sigma, q = \rho u, q_star = \xi * \rho*(s_star, v, w) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - idxi = dir_idx(i) - flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) = rho_Star*vel_K_Star* & - (dir_flg(idxi)*vel_K_Star + (1._wp - dir_flg(idxi))*(xi_M*vel_L(idxi) + xi_P*vel_R(idxi))) + dir_flg(idxi)*p_Star & - + (s_M/s_L)*(s_P/s_R)*dir_flg(idxi)*pcorr - end do - - ! ENERGY FLUX. - ! f = u*(E-\sigma), q = E, q_star = \xi*E+(s-u)(\rho s_star - \sigma/(s-u)) - flux_rs${XYZ}$_vf(j, k, l, E_idx) = (E_star + p_Star)*vel_K_Star & - + (s_M/s_L)*(s_P/s_R)*pcorr*s_S - - ! ELASTICITY. Elastic shear stress additions for the momentum and energy flux - if (elasticity) then - flux_ene_e = 0._wp; - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - idxi = dir_idx(i) - ! MOMENTUM ELASTIC FLUX. - flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) = & - flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) & - - xi_M*tau_e_L(dir_idx_tau(i)) - xi_P*tau_e_R(dir_idx_tau(i)) - ! ENERGY ELASTIC FLUX. - flux_ene_e = flux_ene_e - & - xi_M*(vel_L(idxi)*tau_e_L(dir_idx_tau(i)) + & - s_M*(xi_L*((s_S - vel_L(i))*(tau_e_L(dir_idx_tau(i))/(s_L - vel_L(i)))))) - & - xi_P*(vel_R(idxi)*tau_e_R(dir_idx_tau(i)) + & - s_P*(xi_R*((s_S - vel_R(i))*(tau_e_R(dir_idx_tau(i))/(s_R - vel_R(i)))))) - end do - flux_rs${XYZ}$_vf(j, k, l, E_idx) = flux_rs${XYZ}$_vf(j, k, l, E_idx) + flux_ene_e - end if - - ! VOLUME FRACTION FLUX. - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i)*s_S + & - xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*s_S - end do - - ! SOURCE TERM FOR VOLUME FRACTION ADVECTION FLUX. - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - idxi = dir_idx(i) - vel_src_rs${XYZ}$_vf(j, k, l, idxi) = & - xi_M*(vel_L(idxi) + dir_flg(idxi)*(s_S*(xi_MP*(xi_L - 1) + 1) - vel_L(idxi))) + & - xi_P*(vel_R(idxi) + dir_flg(idxi)*(s_S*(xi_PP*(xi_R - 1) + 1) - vel_R(idxi))) - end do - - ! INTERNAL ENERGIES ADVECTION FLUX. - ! K-th pressure and velocity in preparation for the internal energy flux - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - p_K_Star = xi_M*(xi_MP*((pres_L + pi_infs(i)/(1._wp + gammas(i)))* & - xi_L**(1._wp/gammas(i) + 1._wp) - pi_infs(i)/(1._wp + gammas(i)) - pres_L) + pres_L) + & - xi_P*(xi_PP*((pres_R + pi_infs(i)/(1._wp + gammas(i)))* & - xi_R**(1._wp/gammas(i) + 1._wp) - pi_infs(i)/(1._wp + gammas(i)) - pres_R) + pres_R) - - flux_rs${XYZ}$_vf(j, k, l, i + intxb - 1) = & - ((xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i + advxb - 1) + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i + advxb - 1))* & - (gammas(i)*p_K_Star + pi_infs(i)) + & - (xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i + contxb - 1) + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i + contxb - 1))* & - qvs(i))*vel_K_Star & - + (s_M/s_L)*(s_P/s_R)*pcorr*s_S*(xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i + advxb - 1) + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i + advxb - 1)) - end do - - flux_src_rs${XYZ}$_vf(j, k, l, advxb) = vel_src_rs${XYZ}$_vf(j, k, l, idx1) - - ! HYPOELASTIC STRESS EVOLUTION FLUX. - if (hypoelasticity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, strxe - strxb + 1 - flux_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) = & - xi_M*(s_S/(s_L - s_S))*(s_L*rho_L*tau_e_L(i) - rho_L*vel_L(idx1)*tau_e_L(i)) + & - xi_P*(s_S/(s_R - s_S))*(s_R*rho_R*tau_e_R(i) - rho_R*vel_R(idx1)*tau_e_R(i)) - end do - end if - - ! REFERENCE MAP FLUX. - if (hyperelasticity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - flux_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) = & - xi_M*(s_S/(s_L - s_S))*(s_L*rho_L*xi_field_L(i) & - - rho_L*vel_L(idx1)*xi_field_L(i)) + & - xi_P*(s_S/(s_R - s_S))*(s_R*rho_R*xi_field_R(i) & - - rho_R*vel_R(idx1)*xi_field_R(i)) - end do - end if - - ! COLOR FUNCTION FLUX - if (surface_tension) then - flux_rs${XYZ}$_vf(j, k, l, c_idx) = & - (xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, c_idx) + & - xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, c_idx))*s_S - end if - - ! Geometrical source flux for cylindrical coordinates - #:if (NORM_DIR == 2) - if (cyl_coord) then - !Substituting the advective flux into the inviscid geometrical source flux - $:GPU_LOOP(parallelism='[seq]') - do i = 1, E_idx - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) - end do - $:GPU_LOOP(parallelism='[seq]') - do i = intxb, intxe - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) - end do - ! Recalculating the radial momentum geometric source flux - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb - 1 + dir_idx(1)) = & - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb - 1 + dir_idx(1)) - p_Star - ! Geometrical source of the void fraction(s) is zero $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + do i = 1, num_fluids + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) = max(0._wp, qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)) + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) = min(max(0._wp, qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)), 1._wp) + alpha_R_sum = alpha_R_sum + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) end do - end if - #:endif - #:if (NORM_DIR == 3) - if (grid_geometry == 3) then + $:GPU_LOOP(parallelism='[seq]') - do i = 1, sys_size - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + do i = 1, num_fluids + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)/max(alpha_R_sum, sgm_eps) end do - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb - 1 + dir_idx(1)) = & - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb - 1 + dir_idx(1)) - p_Star - - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxe) = flux_rs${XYZ}$_vf(j, k, l, momxb + 1) end if - #:endif - - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - elseif (model_eqns == 4) then - !ME4 - #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, vel_avg_rms, nbub_L, nbub_R, ptilde_L, ptilde_R]') - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + rho_L = rho_L + qL_prim_rs${XYZ}$_vf(j, k, l, i) + gamma_L = gamma_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*gammas(i) + pi_inf_L = pi_inf_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*pi_infs(i) + qv_L = qv_L + qL_prim_rs${XYZ}$_vf(j, k, l, i)*qvs(i) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - alpha_rho_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, i) - alpha_rho_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) - end do + rho_R = rho_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + gamma_R = gamma_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*gammas(i) + pi_inf_R = pi_inf_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*pi_infs(i) + qv_R = qv_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*qvs(i) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + i) - vel_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + i) - end do + alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, advxb + i - 1) + alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, advxb + i - 1) + end do - vel_L_rms = 0._wp; vel_R_rms = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_L_rms = vel_L_rms + vel_L(i)**2._wp - vel_R_rms = vel_R_rms + vel_R(i)**2._wp - end do + if (viscous) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_L(i) = dflt_real - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) - alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) - end do + if (Re_size(i) > 0) Re_L(i) = 0._wp - pres_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) - pres_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q))/Res(i, q) & + + Re_L(i) + end do - rho_L = 0._wp - gamma_L = 0._wp - pi_inf_L = 0._wp - qv_L = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_L = rho_L + alpha_rho_L(i) - gamma_L = gamma_L + alpha_L(i)*gammas(i) - pi_inf_L = pi_inf_L + alpha_L(i)*pi_infs(i) - qv_L = qv_L + alpha_rho_L(i)*qvs(i) - end do + Re_L(i) = 1._wp/max(Re_L(i), sgm_eps) - rho_R = 0._wp - gamma_R = 0._wp - pi_inf_R = 0._wp - qv_R = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_R = rho_R + alpha_rho_R(i) - gamma_R = gamma_R + alpha_R(i)*gammas(i) - pi_inf_R = pi_inf_R + alpha_R(i)*pi_infs(i) - qv_R = qv_R + alpha_rho_R(i)*qvs(i) - end do + end do - E_L = gamma_L*pres_L + pi_inf_L + 5.e-1_wp*rho_L*vel_L_rms + qv_L + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_R(i) = dflt_real - E_R = gamma_R*pres_R + pi_inf_R + 5.e-1_wp*rho_R*vel_R_rms + qv_R + if (Re_size(i) > 0) Re_R(i) = 0._wp - H_L = (E_L + pres_L)/rho_L - H_R = (E_R + pres_R)/rho_R + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q))/Res(i, q) & + + Re_R(i) + end do - @:compute_average_state() + Re_R(i) = 1._wp/max(Re_R(i), sgm_eps) + end do + end if - call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & - vel_L_rms, 0._wp, c_L) + E_L = gamma_L*pres_L + pi_inf_L + 5.e-1_wp*rho_L*vel_L_rms + qv_L - call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & - vel_R_rms, 0._wp, c_R) + E_R = gamma_R*pres_R + pi_inf_R + 5.e-1_wp*rho_R*vel_R_rms + qv_R - !> The computation of c_avg does not require all the variables, and therefore the non '_avg' - ! variables are placeholders to call the subroutine. + ! ENERGY ADJUSTMENTS FOR HYPOELASTIC ENERGY + if (hypoelasticity) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, strxe - strxb + 1 + tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) + tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) + end do + G_L = 0._wp; G_R = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + G_L = G_L + alpha_L(i)*Gs(i) + G_R = G_R + alpha_R(i)*Gs(i) + end do + $:GPU_LOOP(parallelism='[seq]') + do i = 1, strxe - strxb + 1 + ! Elastic contribution to energy if G large enough + if ((G_L > verysmall) .and. (G_R > verysmall)) then + E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) + E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) + ! Additional terms in 2D and 3D + if ((i == 2) .or. (i == 4) .or. (i == 5)) then + E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) + E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) + end if + end if + end do + end if - call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & - vel_avg_rms, 0._wp, c_avg) + ! ENERGY ADJUSTMENTS FOR HYPERELASTIC ENERGY + if (hyperelasticity) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + xi_field_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) + xi_field_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, xibeg - 1 + i) + end do + G_L = 0._wp; G_R = 0._wp; + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + ! Mixture left and right shear modulus + G_L = G_L + alpha_L(i)*Gs(i) + G_R = G_R + alpha_R(i)*Gs(i) + end do + ! Elastic contribution to energy if G large enough + if (G_L > verysmall .and. G_R > verysmall) then + E_L = E_L + G_L*qL_prim_rs${XYZ}$_vf(j, k, l, xiend + 1) + E_R = E_R + G_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, xiend + 1) + end if + $:GPU_LOOP(parallelism='[seq]') + do i = 1, b_size - 1 + tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) + tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) + end do + end if - if (wave_speeds == 1) then - s_L = min(vel_L(dir_idx(1)) - c_L, vel_R(dir_idx(1)) - c_R) - s_R = max(vel_R(dir_idx(1)) + c_R, vel_L(dir_idx(1)) + c_L) + H_L = (E_L + pres_L)/rho_L + H_R = (E_R + pres_R)/rho_R - s_S = (pres_R - pres_L + rho_L*vel_L(dir_idx(1))* & - (s_L - vel_L(dir_idx(1))) - & - rho_R*vel_R(dir_idx(1))* & - (s_R - vel_R(dir_idx(1)))) & - /(rho_L*(s_L - vel_L(dir_idx(1))) - & - rho_R*(s_R - vel_R(dir_idx(1)))) - elseif (wave_speeds == 2) then - pres_SL = 5.e-1_wp*(pres_L + pres_R + rho_avg*c_avg* & - (vel_L(dir_idx(1)) - & - vel_R(dir_idx(1)))) + @:compute_average_state() - pres_SR = pres_SL + call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & + vel_L_rms, 0._wp, c_L) - Ms_L = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_L)/(1._wp + gamma_L))* & - (pres_SL/pres_L - 1._wp)*pres_L/ & - ((pres_L + pi_inf_L/(1._wp + gamma_L))))) - Ms_R = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_R)/(1._wp + gamma_R))* & - (pres_SR/pres_R - 1._wp)*pres_R/ & - ((pres_R + pi_inf_R/(1._wp + gamma_R))))) + call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & + vel_R_rms, 0._wp, c_R) - s_L = vel_L(dir_idx(1)) - c_L*Ms_L - s_R = vel_R(dir_idx(1)) + c_R*Ms_R + !> The computation of c_avg does not require all the variables, and therefore the non '_avg' + ! variables are placeholders to call the subroutine. + call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & + vel_avg_rms, 0._wp, c_avg) - s_S = 5.e-1_wp*((vel_L(dir_idx(1)) + vel_R(dir_idx(1))) + & - (pres_L - pres_R)/ & - (rho_avg*c_avg)) - end if + if (viscous) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_avg_rs${XYZ}$_vf(j, k, l, i) = 2._wp/(1._wp/Re_L(i) + 1._wp/Re_R(i)) + end do + end if - ! follows Einfeldt et al. - ! s_M/P = min/max(0.,s_L/R) - s_M = min(0._wp, s_L); s_P = max(0._wp, s_R) + ! Low Mach correction + if (low_Mach == 2) then + @:compute_low_Mach_correction() + end if - ! goes with q_star_L/R = xi_L/R * (variable) - ! xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) ) - xi_L = (s_L - vel_L(dir_idx(1)))/(s_L - s_S) - xi_R = (s_R - vel_R(dir_idx(1)))/(s_R - s_S) + ! COMPUTING THE DIRECT WAVE SPEEDS + if (wave_speeds == 1) then + if (elasticity) then + s_L = min(vel_L(dir_idx(1)) - sqrt(c_L*c_L + & + (((4._wp*G_L)/3._wp) + tau_e_L(dir_idx_tau(1)))/rho_L), vel_R(dir_idx(1)) - sqrt(c_R*c_R + & + (((4._wp*G_R)/3._wp) + tau_e_R(dir_idx_tau(1)))/rho_R)) + s_R = max(vel_R(dir_idx(1)) + sqrt(c_R*c_R + & + (((4._wp*G_R)/3._wp) + tau_e_R(dir_idx_tau(1)))/rho_R), vel_L(dir_idx(1)) + sqrt(c_L*c_L + & + (((4._wp*G_L)/3._wp) + tau_e_L(dir_idx_tau(1)))/rho_L)) + s_S = (pres_R - tau_e_R(dir_idx_tau(1)) - pres_L + & + tau_e_L(dir_idx_tau(1)) + rho_L*vel_L(idx1)*(s_L - vel_L(idx1)) - & + rho_R*vel_R(idx1)*(s_R - vel_R(idx1)))/(rho_L*(s_L - vel_L(idx1)) - & + rho_R*(s_R - vel_R(idx1))) + else + s_L = min(vel_L(dir_idx(1)) - c_L, vel_R(dir_idx(1)) - c_R) + s_R = max(vel_R(dir_idx(1)) + c_R, vel_L(dir_idx(1)) + c_L) + s_S = (pres_R - pres_L + rho_L*vel_L(dir_idx(1))* & + (s_L - vel_L(dir_idx(1))) - rho_R*vel_R(dir_idx(1))*(s_R - vel_R(dir_idx(1)))) & + /(rho_L*(s_L - vel_L(dir_idx(1))) - rho_R*(s_R - vel_R(dir_idx(1)))) - ! goes with numerical velocity in x/y/z directions - ! xi_P/M = 0.5 +/m sgn(0.5,s_star) - xi_M = (5.e-1_wp + sign(5.e-1_wp, s_S)) - xi_P = (5.e-1_wp - sign(5.e-1_wp, s_S)) + end if + elseif (wave_speeds == 2) then + pres_SL = 5.e-1_wp*(pres_L + pres_R + rho_avg*c_avg* & + (vel_L(dir_idx(1)) - & + vel_R(dir_idx(1)))) + + pres_SR = pres_SL + + Ms_L = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_L)/(1._wp + gamma_L))* & + (pres_SL/pres_L - 1._wp)*pres_L/ & + ((pres_L + pi_inf_L/(1._wp + gamma_L))))) + Ms_R = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_R)/(1._wp + gamma_R))* & + (pres_SR/pres_R - 1._wp)*pres_R/ & + ((pres_R + pi_inf_R/(1._wp + gamma_R))))) + + s_L = vel_L(dir_idx(1)) - c_L*Ms_L + s_R = vel_R(dir_idx(1)) + c_R*Ms_R + + s_S = 5.e-1_wp*((vel_L(dir_idx(1)) + vel_R(dir_idx(1))) + & + (pres_L - pres_R)/ & + (rho_avg*c_avg)) + end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - xi_M*alpha_rho_L(i) & - *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & - + xi_P*alpha_rho_R(i) & - *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) - end do + ! follows Einfeldt et al. + ! s_M/P = min/max(0.,s_L/R) + s_M = min(0._wp, s_L); s_P = max(0._wp, s_R) + + ! goes with q_star_L/R = xi_L/R * (variable) + ! xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) ) + xi_L = (s_L - vel_L(idx1))/(s_L - s_S) + xi_R = (s_R - vel_R(idx1))/(s_R - s_S) + + ! goes with numerical star velocity in x/y/z directions + ! xi_P/M = 0.5 +/m sgn(0.5,s_star) + xi_M = (5.e-1_wp + sign(0.5_wp, s_S)) + xi_P = (5.e-1_wp - sign(0.5_wp, s_S)) + + ! goes with the numerical velocity in x/y/z directions + ! xi_P/M (pressure) = min/max(0. sgn(1,sL/sR)) + xi_MP = -min(0._wp, sign(1._wp, s_L)) + xi_PP = max(0._wp, sign(1._wp, s_R)) + + E_star = xi_M*(E_L + xi_MP*(xi_L*(E_L + (s_S - vel_L(dir_idx(1)))* & + (rho_L*s_S + pres_L/(s_L - vel_L(dir_idx(1))))) - E_L)) + & + xi_P*(E_R + xi_PP*(xi_R*(E_R + (s_S - vel_R(dir_idx(1)))* & + (rho_R*s_S + pres_R/(s_R - vel_R(dir_idx(1))))) - E_R)) + p_Star = xi_M*(pres_L + xi_MP*(rho_L*(s_L - vel_L(dir_idx(1)))*(s_S - vel_L(dir_idx(1))))) + & + xi_P*(pres_R + xi_PP*(rho_R*(s_R - vel_R(dir_idx(1)))*(s_S - vel_R(dir_idx(1))))) + + rho_Star = xi_M*(rho_L*(xi_MP*xi_L + 1._wp - xi_MP)) + & + xi_P*(rho_R*(xi_PP*xi_R + 1._wp - xi_PP)) + + vel_K_Star = vel_L(idx1)*(1._wp - xi_MP) + xi_MP*vel_R(idx1) + & + xi_MP*xi_PP*(s_S - vel_R(idx1)) + + ! Low Mach correction + if (low_Mach == 1) then + @:compute_low_Mach_correction() + else + pcorr = 0._wp + end if - ! Momentum flux. - ! f = \rho u u + p I, q = \rho u, q_star = \xi * \rho*(s_star, v, w) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & - xi_M*(rho_L*(vel_L(dir_idx(1))* & - vel_L(dir_idx(i)) + & - s_M*(xi_L*(dir_flg(dir_idx(i))*s_S + & - (1._wp - dir_flg(dir_idx(i)))* & - vel_L(dir_idx(i))) - vel_L(dir_idx(i)))) + & - dir_flg(dir_idx(i))*pres_L) & - + xi_P*(rho_R*(vel_R(dir_idx(1))* & - vel_R(dir_idx(i)) + & - s_P*(xi_R*(dir_flg(dir_idx(i))*s_S + & - (1._wp - dir_flg(dir_idx(i)))* & - vel_R(dir_idx(i))) - vel_R(dir_idx(i)))) + & - dir_flg(dir_idx(i))*pres_R) - end do + ! COMPUTING FLUXES + ! MASS FLUX. + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i)*(vel_L(idx1) + s_M*(xi_L - 1._wp)) + & + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*(vel_R(idx1) + s_P*(xi_R - 1._wp)) + end do - if (bubbles_euler) then - ! Put p_tilde in + ! MOMENTUM FLUX. + ! f = \rho u u - \sigma, q = \rho u, q_star = \xi * \rho*(s_star, v, w) $:GPU_LOOP(parallelism='[seq]') do i = 1, num_dims - flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & - flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) + & - xi_M*(dir_flg(dir_idx(i))*(-1._wp*ptilde_L)) & - + xi_P*(dir_flg(dir_idx(i))*(-1._wp*ptilde_R)) + idxi = dir_idx(i) + flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) = rho_Star*vel_K_Star* & + (dir_flg(idxi)*vel_K_Star + (1._wp - dir_flg(idxi))*(xi_M*vel_L(idxi) + xi_P*vel_R(idxi))) + dir_flg(idxi)*p_Star & + + (s_M/s_L)*(s_P/s_R)*dir_flg(idxi)*pcorr end do - end if - - flux_rs${XYZ}$_vf(j, k, l, E_idx) = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = alf_idx, alf_idx !only advect the void fraction - flux_rs${XYZ}$_vf(j, k, l, i) = & - xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i) & - *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & - + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & - *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) - end do + ! ENERGY FLUX. + ! f = u*(E-\sigma), q = E, q_star = \xi*E+(s-u)(\rho s_star - \sigma/(s-u)) + flux_rs${XYZ}$_vf(j, k, l, E_idx) = (E_star + p_Star)*vel_K_Star & + + (s_M/s_L)*(s_P/s_R)*pcorr*s_S - ! Source for volume fraction advection equation - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims + ! ELASTICITY. Elastic shear stress additions for the momentum and energy flux + if (elasticity) then + flux_ene_e = 0._wp; + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + idxi = dir_idx(i) + ! MOMENTUM ELASTIC FLUX. + flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) = & + flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) & + - xi_M*tau_e_L(dir_idx_tau(i)) - xi_P*tau_e_R(dir_idx_tau(i)) + ! ENERGY ELASTIC FLUX. + flux_ene_e = flux_ene_e - & + xi_M*(vel_L(idxi)*tau_e_L(dir_idx_tau(i)) + & + s_M*(xi_L*((s_S - vel_L(i))*(tau_e_L(dir_idx_tau(i))/(s_L - vel_L(i)))))) - & + xi_P*(vel_R(idxi)*tau_e_R(dir_idx_tau(i)) + & + s_P*(xi_R*((s_S - vel_R(i))*(tau_e_R(dir_idx_tau(i))/(s_R - vel_R(i)))))) + end do + flux_rs${XYZ}$_vf(j, k, l, E_idx) = flux_rs${XYZ}$_vf(j, k, l, E_idx) + flux_ene_e + end if - vel_src_rs${XYZ}$_vf(j, k, l, dir_idx(i)) = 0._wp - !IF ( (model_eqns == 4) .or. (num_fluids==1) ) vel_src_rs_vf(dir_idx(i))%sf(j,k,l) = 0._wp - end do + ! VOLUME FRACTION FLUX. + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i)*s_S + & + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*s_S + end do - flux_src_rs${XYZ}$_vf(j, k, l, advxb) = vel_src_rs${XYZ}$_vf(j, k, l, dir_idx(1)) + ! SOURCE TERM FOR VOLUME FRACTION ADVECTION FLUX. + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + idxi = dir_idx(i) + vel_src_rs${XYZ}$_vf(j, k, l, idxi) = & + xi_M*(vel_L(idxi) + dir_flg(idxi)*(s_S*(xi_MP*(xi_L - 1) + 1) - vel_L(idxi))) + & + xi_P*(vel_R(idxi) + dir_flg(idxi)*(s_S*(xi_PP*(xi_R - 1) + 1) - vel_R(idxi))) + end do - ! Add advection flux for bubble variables - if (bubbles_euler) then + ! INTERNAL ENERGIES ADVECTION FLUX. + ! K-th pressure and velocity in preparation for the internal energy flux $:GPU_LOOP(parallelism='[seq]') - do i = bubxb, bubxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - xi_M*nbub_L*qL_prim_rs${XYZ}$_vf(j, k, l, i) & - *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & - + xi_P*nbub_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & - *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) + do i = 1, num_fluids + p_K_Star = xi_M*(xi_MP*((pres_L + pi_infs(i)/(1._wp + gammas(i)))* & + xi_L**(1._wp/gammas(i) + 1._wp) - pi_infs(i)/(1._wp + gammas(i)) - pres_L) + pres_L) + & + xi_P*(xi_PP*((pres_R + pi_infs(i)/(1._wp + gammas(i)))* & + xi_R**(1._wp/gammas(i) + 1._wp) - pi_infs(i)/(1._wp + gammas(i)) - pres_R) + pres_R) + + flux_rs${XYZ}$_vf(j, k, l, i + intxb - 1) = & + ((xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i + advxb - 1) + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i + advxb - 1))* & + (gammas(i)*p_K_Star + pi_infs(i)) + & + (xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i + contxb - 1) + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i + contxb - 1))* & + qvs(i))*vel_K_Star & + + (s_M/s_L)*(s_P/s_R)*pcorr*s_S*(xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i + advxb - 1) + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i + advxb - 1)) end do - end if - ! Geometrical source flux for cylindrical coordinates + flux_src_rs${XYZ}$_vf(j, k, l, advxb) = vel_src_rs${XYZ}$_vf(j, k, l, idx1) - #:if (NORM_DIR == 2) - if (cyl_coord) then - ! Substituting the advective flux into the inviscid geometrical source flux - $:GPU_LOOP(parallelism='[seq]') - do i = 1, E_idx - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) - end do - ! Recalculating the radial momentum geometric source flux - flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(1)) = & - xi_M*(rho_L*(vel_L(dir_idx(1))* & - vel_L(dir_idx(1)) + & - s_M*(xi_L*(dir_flg(dir_idx(1))*s_S + & - (1._wp - dir_flg(dir_idx(1)))* & - vel_L(dir_idx(1))) - vel_L(dir_idx(1))))) & - + xi_P*(rho_R*(vel_R(dir_idx(1))* & - vel_R(dir_idx(1)) + & - s_P*(xi_R*(dir_flg(dir_idx(1))*s_S + & - (1._wp - dir_flg(dir_idx(1)))* & - vel_R(dir_idx(1))) - vel_R(dir_idx(1))))) - ! Geometrical source of the void fraction(s) is zero + ! HYPOELASTIC STRESS EVOLUTION FLUX. + if (hypoelasticity) then $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + do i = 1, strxe - strxb + 1 + flux_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) = & + xi_M*(s_S/(s_L - s_S))*(s_L*rho_L*tau_e_L(i) - rho_L*vel_L(idx1)*tau_e_L(i)) + & + xi_P*(s_S/(s_R - s_S))*(s_R*rho_R*tau_e_R(i) - rho_R*vel_R(idx1)*tau_e_R(i)) end do end if - #:endif - #:if (NORM_DIR == 3) - if (grid_geometry == 3) then + + ! REFERENCE MAP FLUX. + if (hyperelasticity) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, sys_size - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + do i = 1, num_dims + flux_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) = & + xi_M*(s_S/(s_L - s_S))*(s_L*rho_L*xi_field_L(i) & + - rho_L*vel_L(idx1)*xi_field_L(i)) + & + xi_P*(s_S/(s_R - s_S))*(s_R*rho_R*xi_field_R(i) & + - rho_R*vel_R(idx1)*xi_field_R(i)) end do - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb + 1) = & - -xi_M*(rho_L*(vel_L(dir_idx(1))* & - vel_L(dir_idx(1)) + & - s_M*(xi_L*(dir_flg(dir_idx(1))*s_S + & - (1._wp - dir_flg(dir_idx(1)))* & - vel_L(dir_idx(1))) - vel_L(dir_idx(1))))) & - - xi_P*(rho_R*(vel_R(dir_idx(1))* & - vel_R(dir_idx(1)) + & - s_P*(xi_R*(dir_flg(dir_idx(1))*s_S + & - (1._wp - dir_flg(dir_idx(1)))* & - vel_R(dir_idx(1))) - vel_R(dir_idx(1))))) - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxe) = flux_rs${XYZ}$_vf(j, k, l, momxb + 1) end if - #:endif - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - elseif (model_eqns == 2 .and. bubbles_euler) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[R0_L, R0_R, V0_L, V0_R, P0_L, P0_R, pbw_L, pbw_R, vel_L, vel_R, rho_avg, alpha_L, alpha_R, h_avg, gamma_avg, s_L, s_R, s_S, nbub_L, nbub_R, ptilde_L, ptilde_R, vel_avg_rms, Re_L, Re_R, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end + ! COLOR FUNCTION FLUX + if (surface_tension) then + flux_rs${XYZ}$_vf(j, k, l, c_idx) = & + (xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, c_idx) + & + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, c_idx))*s_S + end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) - alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) - end do + ! Geometrical source flux for cylindrical coordinates + #:if (NORM_DIR == 2) + if (cyl_coord) then + !Substituting the advective flux into the inviscid geometrical source flux + $:GPU_LOOP(parallelism='[seq]') + do i = 1, E_idx + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) + end do + $:GPU_LOOP(parallelism='[seq]') + do i = intxb, intxe + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) + end do + ! Recalculating the radial momentum geometric source flux + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb - 1 + dir_idx(1)) = & + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb - 1 + dir_idx(1)) - p_Star + ! Geometrical source of the void fraction(s) is zero + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + end do + end if + #:endif + #:if (NORM_DIR == 3) + if (grid_geometry == 3) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, sys_size + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + end do + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb - 1 + dir_idx(1)) = & + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb - 1 + dir_idx(1)) - p_Star - vel_L_rms = 0._wp; vel_R_rms = 0._wp + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxe) = flux_rs${XYZ}$_vf(j, k, l, momxb + 1) + end if + #:endif - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + i) - vel_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + i) - vel_L_rms = vel_L_rms + vel_L(i)**2._wp - vel_R_rms = vel_R_rms + vel_R(i)**2._wp end do + end do + end do + #:endcall GPU_PARALLEL_LOOP - pres_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) - pres_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) + elseif (model_eqns == 4) then + !ME4 + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, vel_avg_rms, nbub_L, nbub_R, ptilde_L, ptilde_R]') + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end - rho_L = 0._wp - gamma_L = 0._wp - pi_inf_L = 0._wp - qv_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + alpha_rho_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, i) + alpha_rho_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + end do - ! Retain this in the refactor - if (mpp_lim .and. (num_fluids > 2)) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_L = rho_L + qL_prim_rs${XYZ}$_vf(j, k, l, i) - gamma_L = gamma_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*gammas(i) - pi_inf_L = pi_inf_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*pi_infs(i) - qv_L = qv_L + qL_prim_rs${XYZ}$_vf(j, k, l, i)*qvs(i) + do i = 1, num_dims + vel_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + i) + vel_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + i) end do - else if (num_fluids > 2) then + + vel_L_rms = 0._wp; vel_R_rms = 0._wp $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - rho_L = rho_L + qL_prim_rs${XYZ}$_vf(j, k, l, i) - gamma_L = gamma_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*gammas(i) - pi_inf_L = pi_inf_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*pi_infs(i) - qv_L = qv_L + qL_prim_rs${XYZ}$_vf(j, k, l, i)*qvs(i) + do i = 1, num_dims + vel_L_rms = vel_L_rms + vel_L(i)**2._wp + vel_R_rms = vel_R_rms + vel_R(i)**2._wp end do - else - rho_L = qL_prim_rs${XYZ}$_vf(j, k, l, 1) - gamma_L = gammas(1) - pi_inf_L = pi_infs(1) - qv_L = qvs(1) - end if - rho_R = 0._wp - gamma_R = 0._wp - pi_inf_R = 0._wp - qv_R = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) + alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) + end do - if (mpp_lim .and. (num_fluids > 2)) then + pres_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) + pres_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) + + rho_L = 0._wp + gamma_L = 0._wp + pi_inf_L = 0._wp + qv_L = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - rho_R = rho_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) - gamma_R = gamma_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*gammas(i) - pi_inf_R = pi_inf_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*pi_infs(i) - qv_R = qv_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*qvs(i) + rho_L = rho_L + alpha_rho_L(i) + gamma_L = gamma_L + alpha_L(i)*gammas(i) + pi_inf_L = pi_inf_L + alpha_L(i)*pi_infs(i) + qv_L = qv_L + alpha_rho_L(i)*qvs(i) end do - else if (num_fluids > 2) then + + rho_R = 0._wp + gamma_R = 0._wp + pi_inf_R = 0._wp + qv_R = 0._wp $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - rho_R = rho_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) - gamma_R = gamma_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*gammas(i) - pi_inf_R = pi_inf_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*pi_infs(i) - qv_R = qv_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*qvs(i) + do i = 1, num_fluids + rho_R = rho_R + alpha_rho_R(i) + gamma_R = gamma_R + alpha_R(i)*gammas(i) + pi_inf_R = pi_inf_R + alpha_R(i)*pi_infs(i) + qv_R = qv_R + alpha_rho_R(i)*qvs(i) end do - else - rho_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, 1) - gamma_R = gammas(1) - pi_inf_R = pi_infs(1) - qv_R = qvs(1) - end if - if (viscous) then - if (num_fluids == 1) then ! Need to consider case with num_fluids >= 2 - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_L(i) = dflt_real + E_L = gamma_L*pres_L + pi_inf_L + 5.e-1_wp*rho_L*vel_L_rms + qv_L - if (Re_size(i) > 0) Re_L(i) = 0._wp + E_R = gamma_R*pres_R + pi_inf_R + 5.e-1_wp*rho_R*vel_R_rms + qv_R - $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_L(i) = (1._wp - qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q)))/Res(i, q) & - + Re_L(i) - end do + H_L = (E_L + pres_L)/rho_L + H_R = (E_R + pres_R)/rho_R - Re_L(i) = 1._wp/max(Re_L(i), sgm_eps) + @:compute_average_state() - end do + call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & + vel_L_rms, 0._wp, c_L) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_R(i) = dflt_real + call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & + vel_R_rms, 0._wp, c_R) - if (Re_size(i) > 0) Re_R(i) = 0._wp + !> The computation of c_avg does not require all the variables, and therefore the non '_avg' + ! variables are placeholders to call the subroutine. - $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_R(i) = (1._wp - qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q)))/Res(i, q) & - + Re_R(i) - end do + call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & + vel_avg_rms, 0._wp, c_avg) - Re_R(i) = 1._wp/max(Re_R(i), sgm_eps) - end do + if (wave_speeds == 1) then + s_L = min(vel_L(dir_idx(1)) - c_L, vel_R(dir_idx(1)) - c_R) + s_R = max(vel_R(dir_idx(1)) + c_R, vel_L(dir_idx(1)) + c_L) + + s_S = (pres_R - pres_L + rho_L*vel_L(dir_idx(1))* & + (s_L - vel_L(dir_idx(1))) - & + rho_R*vel_R(dir_idx(1))* & + (s_R - vel_R(dir_idx(1)))) & + /(rho_L*(s_L - vel_L(dir_idx(1))) - & + rho_R*(s_R - vel_R(dir_idx(1)))) + elseif (wave_speeds == 2) then + pres_SL = 5.e-1_wp*(pres_L + pres_R + rho_avg*c_avg* & + (vel_L(dir_idx(1)) - & + vel_R(dir_idx(1)))) + + pres_SR = pres_SL + + Ms_L = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_L)/(1._wp + gamma_L))* & + (pres_SL/pres_L - 1._wp)*pres_L/ & + ((pres_L + pi_inf_L/(1._wp + gamma_L))))) + Ms_R = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_R)/(1._wp + gamma_R))* & + (pres_SR/pres_R - 1._wp)*pres_R/ & + ((pres_R + pi_inf_R/(1._wp + gamma_R))))) + + s_L = vel_L(dir_idx(1)) - c_L*Ms_L + s_R = vel_R(dir_idx(1)) + c_R*Ms_R + + s_S = 5.e-1_wp*((vel_L(dir_idx(1)) + vel_R(dir_idx(1))) + & + (pres_L - pres_R)/ & + (rho_avg*c_avg)) end if - end if - E_L = gamma_L*pres_L + pi_inf_L + 5.e-1_wp*rho_L*vel_L_rms + ! follows Einfeldt et al. + ! s_M/P = min/max(0.,s_L/R) + s_M = min(0._wp, s_L); s_P = max(0._wp, s_R) - E_R = gamma_R*pres_R + pi_inf_R + 5.e-1_wp*rho_R*vel_R_rms + ! goes with q_star_L/R = xi_L/R * (variable) + ! xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) ) + xi_L = (s_L - vel_L(dir_idx(1)))/(s_L - s_S) + xi_R = (s_R - vel_R(dir_idx(1)))/(s_R - s_S) - H_L = (E_L + pres_L)/rho_L - H_R = (E_R + pres_R)/rho_R + ! goes with numerical velocity in x/y/z directions + ! xi_P/M = 0.5 +/m sgn(0.5,s_star) + xi_M = (5.e-1_wp + sign(5.e-1_wp, s_S)) + xi_P = (5.e-1_wp - sign(5.e-1_wp, s_S)) - if (avg_state == 2) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, nb - R0_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, rs(i)) - R0_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, rs(i)) - - V0_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, vs(i)) - V0_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, vs(i)) - if (.not. polytropic .and. .not. qbmm) then - P0_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, ps(i)) - P0_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, ps(i)) - end if + do i = 1, contxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + xi_M*alpha_rho_L(i) & + *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & + + xi_P*alpha_rho_R(i) & + *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) end do - if (.not. qbmm) then - if (adv_n) then - nbub_L = qL_prim_rs${XYZ}$_vf(j, k, l, n_idx) - nbub_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, n_idx) - else - nbub_L_denom = 0._wp - nbub_R_denom = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, nb - nbub_L_denom = nbub_L_denom + (R0_L(i)**3._wp)*weight(i) - nbub_R_denom = nbub_R_denom + (R0_R(i)**3._wp)*weight(i) - end do - nbub_L = (3._wp/(4._wp*pi))*qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + num_fluids)/nbub_L_denom - nbub_R = (3._wp/(4._wp*pi))*qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + num_fluids)/nbub_R_denom - end if - else - !nb stored in 0th moment of first R0 bin in variable conversion module - nbub_L = qL_prim_rs${XYZ}$_vf(j, k, l, bubxb) - nbub_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, bubxb) - end if - + ! Momentum flux. + ! f = \rho u u + p I, q = \rho u, q_star = \xi * \rho*(s_star, v, w) $:GPU_LOOP(parallelism='[seq]') - do i = 1, nb - if (.not. qbmm) then - if (polytropic) then - pbw_L(i) = f_cpbw_KM(R0(i), R0_L(i), V0_L(i), 0._wp) - pbw_R(i) = f_cpbw_KM(R0(i), R0_R(i), V0_R(i), 0._wp) - else - pbw_L(i) = f_cpbw_KM(R0(i), R0_L(i), V0_L(i), P0_L(i)) - pbw_R(i) = f_cpbw_KM(R0(i), R0_R(i), V0_R(i), P0_R(i)) - end if - end if + do i = 1, num_dims + flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & + xi_M*(rho_L*(vel_L(dir_idx(1))* & + vel_L(dir_idx(i)) + & + s_M*(xi_L*(dir_flg(dir_idx(i))*s_S + & + (1._wp - dir_flg(dir_idx(i)))* & + vel_L(dir_idx(i))) - vel_L(dir_idx(i)))) + & + dir_flg(dir_idx(i))*pres_L) & + + xi_P*(rho_R*(vel_R(dir_idx(1))* & + vel_R(dir_idx(i)) + & + s_P*(xi_R*(dir_flg(dir_idx(i))*s_S + & + (1._wp - dir_flg(dir_idx(i)))* & + vel_R(dir_idx(i))) - vel_R(dir_idx(i)))) + & + dir_flg(dir_idx(i))*pres_R) end do - if (qbmm) then - PbwR3Lbar = mom_sp_rs${XYZ}$_vf(j, k, l, 4) - PbwR3Rbar = mom_sp_rs${XYZ}$_vf(j + 1, k, l, 4) + if (bubbles_euler) then + ! Put p_tilde in + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & + flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) + & + xi_M*(dir_flg(dir_idx(i))*(-1._wp*ptilde_L)) & + + xi_P*(dir_flg(dir_idx(i))*(-1._wp*ptilde_R)) + end do + end if - R3Lbar = mom_sp_rs${XYZ}$_vf(j, k, l, 1) - R3Rbar = mom_sp_rs${XYZ}$_vf(j + 1, k, l, 1) + flux_rs${XYZ}$_vf(j, k, l, E_idx) = 0._wp - R3V2Lbar = mom_sp_rs${XYZ}$_vf(j, k, l, 3) - R3V2Rbar = mom_sp_rs${XYZ}$_vf(j + 1, k, l, 3) - else + $:GPU_LOOP(parallelism='[seq]') + do i = alf_idx, alf_idx !only advect the void fraction + flux_rs${XYZ}$_vf(j, k, l, i) = & + xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i) & + *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & + + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & + *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) + end do - PbwR3Lbar = 0._wp - PbwR3Rbar = 0._wp + ! Source for volume fraction advection equation + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims - R3Lbar = 0._wp - R3Rbar = 0._wp + vel_src_rs${XYZ}$_vf(j, k, l, dir_idx(i)) = 0._wp + !IF ( (model_eqns == 4) .or. (num_fluids==1) ) vel_src_rs_vf(dir_idx(i))%sf(j,k,l) = 0._wp + end do - R3V2Lbar = 0._wp - R3V2Rbar = 0._wp + flux_src_rs${XYZ}$_vf(j, k, l, advxb) = vel_src_rs${XYZ}$_vf(j, k, l, dir_idx(1)) + ! Add advection flux for bubble variables + if (bubbles_euler) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, nb - PbwR3Lbar = PbwR3Lbar + pbw_L(i)*(R0_L(i)**3._wp)*weight(i) - PbwR3Rbar = PbwR3Rbar + pbw_R(i)*(R0_R(i)**3._wp)*weight(i) - - R3Lbar = R3Lbar + (R0_L(i)**3._wp)*weight(i) - R3Rbar = R3Rbar + (R0_R(i)**3._wp)*weight(i) - - R3V2Lbar = R3V2Lbar + (R0_L(i)**3._wp)*(V0_L(i)**2._wp)*weight(i) - R3V2Rbar = R3V2Rbar + (R0_R(i)**3._wp)*(V0_R(i)**2._wp)*weight(i) + do i = bubxb, bubxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + xi_M*nbub_L*qL_prim_rs${XYZ}$_vf(j, k, l, i) & + *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & + + xi_P*nbub_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & + *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) end do end if - if (qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + num_fluids) < small_alf .or. R3Lbar < small_alf) then - ptilde_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + num_fluids)*pres_L - else - ptilde_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + num_fluids)*(pres_L - PbwR3Lbar/R3Lbar - & - rho_L*R3V2Lbar/R3Lbar) - end if + ! Geometrical source flux for cylindrical coordinates - if (qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + num_fluids) < small_alf .or. R3Rbar < small_alf) then - ptilde_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + num_fluids)*pres_R - else - ptilde_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + num_fluids)*(pres_R - PbwR3Rbar/R3Rbar - & - rho_R*R3V2Rbar/R3Rbar) - end if + #:if (NORM_DIR == 2) + if (cyl_coord) then + ! Substituting the advective flux into the inviscid geometrical source flux + $:GPU_LOOP(parallelism='[seq]') + do i = 1, E_idx + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) + end do + ! Recalculating the radial momentum geometric source flux + flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(1)) = & + xi_M*(rho_L*(vel_L(dir_idx(1))* & + vel_L(dir_idx(1)) + & + s_M*(xi_L*(dir_flg(dir_idx(1))*s_S + & + (1._wp - dir_flg(dir_idx(1)))* & + vel_L(dir_idx(1))) - vel_L(dir_idx(1))))) & + + xi_P*(rho_R*(vel_R(dir_idx(1))* & + vel_R(dir_idx(1)) + & + s_P*(xi_R*(dir_flg(dir_idx(1))*s_S + & + (1._wp - dir_flg(dir_idx(1)))* & + vel_R(dir_idx(1))) - vel_R(dir_idx(1))))) + ! Geometrical source of the void fraction(s) is zero + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + end do + end if + #:endif + #:if (NORM_DIR == 3) + if (grid_geometry == 3) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, sys_size + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + end do + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb + 1) = & + -xi_M*(rho_L*(vel_L(dir_idx(1))* & + vel_L(dir_idx(1)) + & + s_M*(xi_L*(dir_flg(dir_idx(1))*s_S + & + (1._wp - dir_flg(dir_idx(1)))* & + vel_L(dir_idx(1))) - vel_L(dir_idx(1))))) & + - xi_P*(rho_R*(vel_R(dir_idx(1))* & + vel_R(dir_idx(1)) + & + s_P*(xi_R*(dir_flg(dir_idx(1))*s_S + & + (1._wp - dir_flg(dir_idx(1)))* & + vel_R(dir_idx(1))) - vel_R(dir_idx(1))))) + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxe) = flux_rs${XYZ}$_vf(j, k, l, momxb + 1) + end if + #:endif + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP - if ((.not. f_approx_equal(ptilde_L, ptilde_L)) .or. (.not. f_approx_equal(ptilde_R, ptilde_R))) then - end if + elseif (model_eqns == 2 .and. bubbles_euler) then + #:call GPU_PARALLEL_LOOP(collapse=3, private='[R0_L, R0_R, V0_L, V0_R, P0_L, P0_R, pbw_L, pbw_R, vel_L, vel_R, rho_avg, alpha_L, alpha_R, h_avg, gamma_avg, s_L, s_R, s_S, nbub_L, nbub_R, ptilde_L, ptilde_R, vel_avg_rms, Re_L, Re_R, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end - rho_avg = 5.e-1_wp*(rho_L + rho_R) - H_avg = 5.e-1_wp*(H_L + H_R) - gamma_avg = 5.e-1_wp*(gamma_L + gamma_R) - vel_avg_rms = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) + alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) + end do + + vel_L_rms = 0._wp; vel_R_rms = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_dims - vel_avg_rms = vel_avg_rms + (5.e-1_wp*(vel_L(i) + vel_R(i)))**2._wp + vel_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + i) + vel_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + i) + vel_L_rms = vel_L_rms + vel_L(i)**2._wp + vel_R_rms = vel_R_rms + vel_R(i)**2._wp end do - end if + pres_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) + pres_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) - call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & - vel_L_rms, 0._wp, c_L) + rho_L = 0._wp + gamma_L = 0._wp + pi_inf_L = 0._wp + qv_L = 0._wp - call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & - vel_R_rms, 0._wp, c_R) + ! Retain this in the refactor + if (mpp_lim .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + rho_L = rho_L + qL_prim_rs${XYZ}$_vf(j, k, l, i) + gamma_L = gamma_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*gammas(i) + pi_inf_L = pi_inf_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*pi_infs(i) + qv_L = qv_L + qL_prim_rs${XYZ}$_vf(j, k, l, i)*qvs(i) + end do + else if (num_fluids > 2) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + rho_L = rho_L + qL_prim_rs${XYZ}$_vf(j, k, l, i) + gamma_L = gamma_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*gammas(i) + pi_inf_L = pi_inf_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*pi_infs(i) + qv_L = qv_L + qL_prim_rs${XYZ}$_vf(j, k, l, i)*qvs(i) + end do + else + rho_L = qL_prim_rs${XYZ}$_vf(j, k, l, 1) + gamma_L = gammas(1) + pi_inf_L = pi_infs(1) + qv_L = qvs(1) + end if - !> The computation of c_avg does not require all the variables, and therefore the non '_avg' - ! variables are placeholders to call the subroutine. - call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & - vel_avg_rms, 0._wp, c_avg) + rho_R = 0._wp + gamma_R = 0._wp + pi_inf_R = 0._wp + qv_R = 0._wp - if (viscous) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_avg_rs${XYZ}$_vf(j, k, l, i) = 2._wp/(1._wp/Re_L(i) + 1._wp/Re_R(i)) - end do - end if + if (mpp_lim .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + rho_R = rho_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + gamma_R = gamma_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*gammas(i) + pi_inf_R = pi_inf_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*pi_infs(i) + qv_R = qv_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*qvs(i) + end do + else if (num_fluids > 2) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + rho_R = rho_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + gamma_R = gamma_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*gammas(i) + pi_inf_R = pi_inf_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*pi_infs(i) + qv_R = qv_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*qvs(i) + end do + else + rho_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, 1) + gamma_R = gammas(1) + pi_inf_R = pi_infs(1) + qv_R = qvs(1) + end if - ! Low Mach correction - if (low_Mach == 2) then - @:compute_low_Mach_correction() - end if + if (viscous) then + if (num_fluids == 1) then ! Need to consider case with num_fluids >= 2 + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_L(i) = dflt_real - if (wave_speeds == 1) then - s_L = min(vel_L(dir_idx(1)) - c_L, vel_R(dir_idx(1)) - c_R) - s_R = max(vel_R(dir_idx(1)) + c_R, vel_L(dir_idx(1)) + c_L) + if (Re_size(i) > 0) Re_L(i) = 0._wp - s_S = (pres_R - pres_L + rho_L*vel_L(dir_idx(1))* & - (s_L - vel_L(dir_idx(1))) - & - rho_R*vel_R(dir_idx(1))* & - (s_R - vel_R(dir_idx(1)))) & - /(rho_L*(s_L - vel_L(dir_idx(1))) - & - rho_R*(s_R - vel_R(dir_idx(1)))) - elseif (wave_speeds == 2) then - pres_SL = 5.e-1_wp*(pres_L + pres_R + rho_avg*c_avg* & - (vel_L(dir_idx(1)) - & - vel_R(dir_idx(1)))) + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_L(i) = (1._wp - qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q)))/Res(i, q) & + + Re_L(i) + end do - pres_SR = pres_SL + Re_L(i) = 1._wp/max(Re_L(i), sgm_eps) - Ms_L = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_L)/(1._wp + gamma_L))* & - (pres_SL/pres_L - 1._wp)*pres_L/ & - ((pres_L + pi_inf_L/(1._wp + gamma_L))))) - Ms_R = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_R)/(1._wp + gamma_R))* & - (pres_SR/pres_R - 1._wp)*pres_R/ & - ((pres_R + pi_inf_R/(1._wp + gamma_R))))) + end do - s_L = vel_L(dir_idx(1)) - c_L*Ms_L - s_R = vel_R(dir_idx(1)) + c_R*Ms_R + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_R(i) = dflt_real - s_S = 5.e-1_wp*((vel_L(dir_idx(1)) + vel_R(dir_idx(1))) + & - (pres_L - pres_R)/ & - (rho_avg*c_avg)) - end if + if (Re_size(i) > 0) Re_R(i) = 0._wp - ! follows Einfeldt et al. - ! s_M/P = min/max(0.,s_L/R) - s_M = min(0._wp, s_L); s_P = max(0._wp, s_R) + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_R(i) = (1._wp - qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q)))/Res(i, q) & + + Re_R(i) + end do - ! goes with q_star_L/R = xi_L/R * (variable) - ! xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) ) - xi_L = (s_L - vel_L(dir_idx(1)))/(s_L - s_S) - xi_R = (s_R - vel_R(dir_idx(1)))/(s_R - s_S) + Re_R(i) = 1._wp/max(Re_R(i), sgm_eps) + end do + end if + end if - ! goes with numerical velocity in x/y/z directions - ! xi_P/M = 0.5 +/m sgn(0.5,s_star) - xi_M = (5.e-1_wp + sign(5.e-1_wp, s_S)) - xi_P = (5.e-1_wp - sign(5.e-1_wp, s_S)) + E_L = gamma_L*pres_L + pi_inf_L + 5.e-1_wp*rho_L*vel_L_rms - ! Low Mach correction - if (low_Mach == 1) then - @:compute_low_Mach_correction() - else - pcorr = 0._wp - end if + E_R = gamma_R*pres_R + pi_inf_R + 5.e-1_wp*rho_R*vel_R_rms - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i) & - *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & - + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & - *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) - end do + H_L = (E_L + pres_L)/rho_L + H_R = (E_R + pres_R)/rho_R - if (bubbles_euler .and. (num_fluids > 1)) then - ! Kill mass transport @ gas density - flux_rs${XYZ}$_vf(j, k, l, contxe) = 0._wp - end if + if (avg_state == 2) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, nb + R0_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, rs(i)) + R0_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, rs(i)) + + V0_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, vs(i)) + V0_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, vs(i)) + if (.not. polytropic .and. .not. qbmm) then + P0_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, ps(i)) + P0_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, ps(i)) + end if + end do - ! Momentum flux. - ! f = \rho u u + p I, q = \rho u, q_star = \xi * \rho*(s_star, v, w) + if (.not. qbmm) then + if (adv_n) then + nbub_L = qL_prim_rs${XYZ}$_vf(j, k, l, n_idx) + nbub_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, n_idx) + else + nbub_L_denom = 0._wp + nbub_R_denom = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, nb + nbub_L_denom = nbub_L_denom + (R0_L(i)**3._wp)*weight(i) + nbub_R_denom = nbub_R_denom + (R0_R(i)**3._wp)*weight(i) + end do + nbub_L = (3._wp/(4._wp*pi))*qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + num_fluids)/nbub_L_denom + nbub_R = (3._wp/(4._wp*pi))*qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + num_fluids)/nbub_R_denom + end if + else + !nb stored in 0th moment of first R0 bin in variable conversion module + nbub_L = qL_prim_rs${XYZ}$_vf(j, k, l, bubxb) + nbub_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, bubxb) + end if - ! Include p_tilde + $:GPU_LOOP(parallelism='[seq]') + do i = 1, nb + if (.not. qbmm) then + if (polytropic) then + pbw_L(i) = f_cpbw_KM(R0(i), R0_L(i), V0_L(i), 0._wp) + pbw_R(i) = f_cpbw_KM(R0(i), R0_R(i), V0_R(i), 0._wp) + else + pbw_L(i) = f_cpbw_KM(R0(i), R0_L(i), V0_L(i), P0_L(i)) + pbw_R(i) = f_cpbw_KM(R0(i), R0_R(i), V0_R(i), P0_R(i)) + end if + end if + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & - xi_M*(rho_L*(vel_L(dir_idx(1))* & - vel_L(dir_idx(i)) + & - s_M*(xi_L*(dir_flg(dir_idx(i))*s_S + & - (1._wp - dir_flg(dir_idx(i)))* & - vel_L(dir_idx(i))) - vel_L(dir_idx(i)))) + & - dir_flg(dir_idx(i))*(pres_L - ptilde_L)) & - + xi_P*(rho_R*(vel_R(dir_idx(1))* & - vel_R(dir_idx(i)) + & - s_P*(xi_R*(dir_flg(dir_idx(i))*s_S + & - (1._wp - dir_flg(dir_idx(i)))* & - vel_R(dir_idx(i))) - vel_R(dir_idx(i)))) + & - dir_flg(dir_idx(i))*(pres_R - ptilde_R)) & - + (s_M/s_L)*(s_P/s_R)*dir_flg(dir_idx(i))*pcorr - end do + if (qbmm) then + PbwR3Lbar = mom_sp_rs${XYZ}$_vf(j, k, l, 4) + PbwR3Rbar = mom_sp_rs${XYZ}$_vf(j + 1, k, l, 4) - ! Energy flux. - ! f = u*(E+p), q = E, q_star = \xi*E+(s-u)(\rho s_star + p/(s-u)) - flux_rs${XYZ}$_vf(j, k, l, E_idx) = & - xi_M*(vel_L(dir_idx(1))*(E_L + pres_L - ptilde_L) + & - s_M*(xi_L*(E_L + (s_S - vel_L(dir_idx(1)))* & - (rho_L*s_S + (pres_L - ptilde_L)/ & - (s_L - vel_L(dir_idx(1))))) - E_L)) & - + xi_P*(vel_R(dir_idx(1))*(E_R + pres_R - ptilde_R) + & - s_P*(xi_R*(E_R + (s_S - vel_R(dir_idx(1)))* & - (rho_R*s_S + (pres_R - ptilde_R)/ & - (s_R - vel_R(dir_idx(1))))) - E_R)) & - + (s_M/s_L)*(s_P/s_R)*pcorr*s_S - - ! Volume fraction flux - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i) & - *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & - + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & - *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) - end do + R3Lbar = mom_sp_rs${XYZ}$_vf(j, k, l, 1) + R3Rbar = mom_sp_rs${XYZ}$_vf(j + 1, k, l, 1) - ! Source for volume fraction advection equation - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_src_rs${XYZ}$_vf(j, k, l, dir_idx(i)) = & - xi_M*(vel_L(dir_idx(i)) + & - dir_flg(dir_idx(i))* & - s_M*(xi_L - 1._wp)) & - + xi_P*(vel_R(dir_idx(i)) + & - dir_flg(dir_idx(i))* & - s_P*(xi_R - 1._wp)) - - !IF ( (model_eqns == 4) .or. (num_fluids==1) ) vel_src_rs_vf(idxi)%sf(j,k,l) = 0._wp - end do + R3V2Lbar = mom_sp_rs${XYZ}$_vf(j, k, l, 3) + R3V2Rbar = mom_sp_rs${XYZ}$_vf(j + 1, k, l, 3) + else - flux_src_rs${XYZ}$_vf(j, k, l, advxb) = vel_src_rs${XYZ}$_vf(j, k, l, dir_idx(1)) + PbwR3Lbar = 0._wp + PbwR3Rbar = 0._wp - ! Add advection flux for bubble variables - $:GPU_LOOP(parallelism='[seq]') - do i = bubxb, bubxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - xi_M*nbub_L*qL_prim_rs${XYZ}$_vf(j, k, l, i) & - *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & - + xi_P*nbub_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & - *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) - end do + R3Lbar = 0._wp + R3Rbar = 0._wp - if (qbmm) then - flux_rs${XYZ}$_vf(j, k, l, bubxb) = & - xi_M*nbub_L & - *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & - + xi_P*nbub_R & - *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) - end if + R3V2Lbar = 0._wp + R3V2Rbar = 0._wp - if (adv_n) then - flux_rs${XYZ}$_vf(j, k, l, n_idx) = & - xi_M*nbub_L & - *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & - + xi_P*nbub_R & - *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) - end if + $:GPU_LOOP(parallelism='[seq]') + do i = 1, nb + PbwR3Lbar = PbwR3Lbar + pbw_L(i)*(R0_L(i)**3._wp)*weight(i) + PbwR3Rbar = PbwR3Rbar + pbw_R(i)*(R0_R(i)**3._wp)*weight(i) + + R3Lbar = R3Lbar + (R0_L(i)**3._wp)*weight(i) + R3Rbar = R3Rbar + (R0_R(i)**3._wp)*weight(i) + + R3V2Lbar = R3V2Lbar + (R0_L(i)**3._wp)*(V0_L(i)**2._wp)*weight(i) + R3V2Rbar = R3V2Rbar + (R0_R(i)**3._wp)*(V0_R(i)**2._wp)*weight(i) + end do + end if + + if (qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + num_fluids) < small_alf .or. R3Lbar < small_alf) then + ptilde_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + num_fluids)*pres_L + else + ptilde_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + num_fluids)*(pres_L - PbwR3Lbar/R3Lbar - & + rho_L*R3V2Lbar/R3Lbar) + end if + + if (qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + num_fluids) < small_alf .or. R3Rbar < small_alf) then + ptilde_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + num_fluids)*pres_R + else + ptilde_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + num_fluids)*(pres_R - PbwR3Rbar/R3Rbar - & + rho_R*R3V2Rbar/R3Rbar) + end if + + if ((.not. f_approx_equal(ptilde_L, ptilde_L)) .or. (.not. f_approx_equal(ptilde_R, ptilde_R))) then + end if + + rho_avg = 5.e-1_wp*(rho_L + rho_R) + H_avg = 5.e-1_wp*(H_L + H_R) + gamma_avg = 5.e-1_wp*(gamma_L + gamma_R) + vel_avg_rms = 0._wp - ! Geometrical source flux for cylindrical coordinates - #:if (NORM_DIR == 2) - if (cyl_coord) then - ! Substituting the advective flux into the inviscid geometrical source flux - $:GPU_LOOP(parallelism='[seq]') - do i = 1, E_idx - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) - end do - ! Recalculating the radial momentum geometric source flux - flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(1)) = & - xi_M*(rho_L*(vel_L(dir_idx(1))* & - vel_L(dir_idx(1)) + & - s_M*(xi_L*(dir_flg(dir_idx(1))*s_S + & - (1._wp - dir_flg(dir_idx(1)))* & - vel_L(dir_idx(1))) - vel_L(dir_idx(1))))) & - + xi_P*(rho_R*(vel_R(dir_idx(1))* & - vel_R(dir_idx(1)) + & - s_P*(xi_R*(dir_flg(dir_idx(1))*s_S + & - (1._wp - dir_flg(dir_idx(1)))* & - vel_R(dir_idx(1))) - vel_R(dir_idx(1))))) - ! Geometrical source of the void fraction(s) is zero $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + do i = 1, num_dims + vel_avg_rms = vel_avg_rms + (5.e-1_wp*(vel_L(i) + vel_R(i)))**2._wp end do + end if - #:endif - #:if (NORM_DIR == 3) - if (grid_geometry == 3) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, sys_size - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp - end do - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb + 1) = & - -xi_M*(rho_L*(vel_L(dir_idx(1))* & - vel_L(dir_idx(1)) + & - s_M*(xi_L*(dir_flg(dir_idx(1))*s_S + & - (1._wp - dir_flg(dir_idx(1)))* & - vel_L(dir_idx(1))) - vel_L(dir_idx(1))))) & - - xi_P*(rho_R*(vel_R(dir_idx(1))* & - vel_R(dir_idx(1)) + & - s_P*(xi_R*(dir_flg(dir_idx(1))*s_S + & - (1._wp - dir_flg(dir_idx(1)))* & - vel_R(dir_idx(1))) - vel_R(dir_idx(1))))) - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxe) = flux_rs${XYZ}$_vf(j, k, l, momxb + 1) + call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & + vel_L_rms, 0._wp, c_L) + + call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & + vel_R_rms, 0._wp, c_R) + !> The computation of c_avg does not require all the variables, and therefore the non '_avg' + ! variables are placeholders to call the subroutine. + call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & + vel_avg_rms, 0._wp, c_avg) + + if (viscous) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_avg_rs${XYZ}$_vf(j, k, l, i) = 2._wp/(1._wp/Re_L(i) + 1._wp/Re_R(i)) + end do end if - #:endif - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - else - ! 5-EQUATION MODEL WITH HLLC - #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel_L, vel_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, alpha_L, alpha_R, s_L, s_R, s_S, vel_avg_rms, pcorr, zcoef, vel_L_tmp, vel_R_tmp, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, tau_e_L, tau_e_R, xi_field_L, xi_field_R, Yi_avg,Phi_avg, h_iL, h_iR, h_avg_2]', copyin='[is1, is2, is3]') - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - !idx1 = 1; if (dir_idx(1) == 2) idx1 = 2; if (dir_idx(1) == 3) idx1 = 3 + ! Low Mach correction + if (low_Mach == 2) then + @:compute_low_Mach_correction() + end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) - alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) - end do + if (wave_speeds == 1) then + s_L = min(vel_L(dir_idx(1)) - c_L, vel_R(dir_idx(1)) - c_R) + s_R = max(vel_R(dir_idx(1)) + c_R, vel_L(dir_idx(1)) + c_L) - vel_L_rms = 0._wp; vel_R_rms = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + i) - vel_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + i) - vel_L_rms = vel_L_rms + vel_L(i)**2._wp - vel_R_rms = vel_R_rms + vel_R(i)**2._wp - end do + s_S = (pres_R - pres_L + rho_L*vel_L(dir_idx(1))* & + (s_L - vel_L(dir_idx(1))) - & + rho_R*vel_R(dir_idx(1))* & + (s_R - vel_R(dir_idx(1)))) & + /(rho_L*(s_L - vel_L(dir_idx(1))) - & + rho_R*(s_R - vel_R(dir_idx(1)))) + elseif (wave_speeds == 2) then + pres_SL = 5.e-1_wp*(pres_L + pres_R + rho_avg*c_avg* & + (vel_L(dir_idx(1)) - & + vel_R(dir_idx(1)))) + + pres_SR = pres_SL + + Ms_L = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_L)/(1._wp + gamma_L))* & + (pres_SL/pres_L - 1._wp)*pres_L/ & + ((pres_L + pi_inf_L/(1._wp + gamma_L))))) + Ms_R = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_R)/(1._wp + gamma_R))* & + (pres_SR/pres_R - 1._wp)*pres_R/ & + ((pres_R + pi_inf_R/(1._wp + gamma_R))))) + + s_L = vel_L(dir_idx(1)) - c_L*Ms_L + s_R = vel_R(dir_idx(1)) + c_R*Ms_R + + s_S = 5.e-1_wp*((vel_L(dir_idx(1)) + vel_R(dir_idx(1))) + & + (pres_L - pres_R)/ & + (rho_avg*c_avg)) + end if - pres_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) - pres_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) + ! follows Einfeldt et al. + ! s_M/P = min/max(0.,s_L/R) + s_M = min(0._wp, s_L); s_P = max(0._wp, s_R) - rho_L = 0._wp - gamma_L = 0._wp - pi_inf_L = 0._wp - qv_L = 0._wp + ! goes with q_star_L/R = xi_L/R * (variable) + ! xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) ) + xi_L = (s_L - vel_L(dir_idx(1)))/(s_L - s_S) + xi_R = (s_R - vel_R(dir_idx(1)))/(s_R - s_S) - rho_R = 0._wp - gamma_R = 0._wp - pi_inf_R = 0._wp - qv_R = 0._wp + ! goes with numerical velocity in x/y/z directions + ! xi_P/M = 0.5 +/m sgn(0.5,s_star) + xi_M = (5.e-1_wp + sign(5.e-1_wp, s_S)) + xi_P = (5.e-1_wp - sign(5.e-1_wp, s_S)) - alpha_L_sum = 0._wp - alpha_R_sum = 0._wp + ! Low Mach correction + if (low_Mach == 1) then + @:compute_low_Mach_correction() + else + pcorr = 0._wp + end if - ! Change this by splitting it into the cases - ! present in the bubbles_euler - if (mpp_lim) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - qL_prim_rs${XYZ}$_vf(j, k, l, i) = max(0._wp, qL_prim_rs${XYZ}$_vf(j, k, l, i)) - qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) = min(max(0._wp, qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)), 1._wp) - alpha_L_sum = alpha_L_sum + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) + do i = 1, contxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i) & + *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & + + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & + *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) end do + if (bubbles_euler .and. (num_fluids > 1)) then + ! Kill mass transport @ gas density + flux_rs${XYZ}$_vf(j, k, l, contxe) = 0._wp + end if + + ! Momentum flux. + ! f = \rho u u + p I, q = \rho u, q_star = \xi * \rho*(s_star, v, w) + + ! Include p_tilde + $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)/max(alpha_L_sum, sgm_eps) + do i = 1, num_dims + flux_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) = & + xi_M*(rho_L*(vel_L(dir_idx(1))* & + vel_L(dir_idx(i)) + & + s_M*(xi_L*(dir_flg(dir_idx(i))*s_S + & + (1._wp - dir_flg(dir_idx(i)))* & + vel_L(dir_idx(i))) - vel_L(dir_idx(i)))) + & + dir_flg(dir_idx(i))*(pres_L - ptilde_L)) & + + xi_P*(rho_R*(vel_R(dir_idx(1))* & + vel_R(dir_idx(i)) + & + s_P*(xi_R*(dir_flg(dir_idx(i))*s_S + & + (1._wp - dir_flg(dir_idx(i)))* & + vel_R(dir_idx(i))) - vel_R(dir_idx(i)))) + & + dir_flg(dir_idx(i))*(pres_R - ptilde_R)) & + + (s_M/s_L)*(s_P/s_R)*dir_flg(dir_idx(i))*pcorr end do + ! Energy flux. + ! f = u*(E+p), q = E, q_star = \xi*E+(s-u)(\rho s_star + p/(s-u)) + flux_rs${XYZ}$_vf(j, k, l, E_idx) = & + xi_M*(vel_L(dir_idx(1))*(E_L + pres_L - ptilde_L) + & + s_M*(xi_L*(E_L + (s_S - vel_L(dir_idx(1)))* & + (rho_L*s_S + (pres_L - ptilde_L)/ & + (s_L - vel_L(dir_idx(1))))) - E_L)) & + + xi_P*(vel_R(dir_idx(1))*(E_R + pres_R - ptilde_R) + & + s_P*(xi_R*(E_R + (s_S - vel_R(dir_idx(1)))* & + (rho_R*s_S + (pres_R - ptilde_R)/ & + (s_R - vel_R(dir_idx(1))))) - E_R)) & + + (s_M/s_L)*(s_P/s_R)*pcorr*s_S + + ! Volume fraction flux $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) = max(0._wp, qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)) - qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) = min(max(0._wp, qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)), 1._wp) - alpha_R_sum = alpha_R_sum + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) + do i = advxb, advxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i) & + *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & + + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & + *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) end do + ! Source for volume fraction advection equation $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)/max(alpha_R_sum, sgm_eps) + do i = 1, num_dims + vel_src_rs${XYZ}$_vf(j, k, l, dir_idx(i)) = & + xi_M*(vel_L(dir_idx(i)) + & + dir_flg(dir_idx(i))* & + s_M*(xi_L - 1._wp)) & + + xi_P*(vel_R(dir_idx(i)) + & + dir_flg(dir_idx(i))* & + s_P*(xi_R - 1._wp)) + + !IF ( (model_eqns == 4) .or. (num_fluids==1) ) vel_src_rs_vf(idxi)%sf(j,k,l) = 0._wp end do - end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_L = rho_L + qL_prim_rs${XYZ}$_vf(j, k, l, i) - gamma_L = gamma_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*gammas(i) - pi_inf_L = pi_inf_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*pi_infs(i) - qv_L = qv_L + qL_prim_rs${XYZ}$_vf(j, k, l, i)*qvs(i) - - rho_R = rho_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) - gamma_R = gamma_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*gammas(i) - pi_inf_R = pi_inf_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*pi_infs(i) - qv_R = qv_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*qvs(i) - end do + flux_src_rs${XYZ}$_vf(j, k, l, advxb) = vel_src_rs${XYZ}$_vf(j, k, l, dir_idx(1)) - if (viscous) then + ! Add advection flux for bubble variables $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_L(i) = dflt_real + do i = bubxb, bubxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + xi_M*nbub_L*qL_prim_rs${XYZ}$_vf(j, k, l, i) & + *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & + + xi_P*nbub_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & + *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) + end do - if (Re_size(i) > 0) Re_L(i) = 0._wp + if (qbmm) then + flux_rs${XYZ}$_vf(j, k, l, bubxb) = & + xi_M*nbub_L & + *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & + + xi_P*nbub_R & + *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) + end if - $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q))/Res(i, q) & - + Re_L(i) - end do + if (adv_n) then + flux_rs${XYZ}$_vf(j, k, l, n_idx) = & + xi_M*nbub_L & + *(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) & + + xi_P*nbub_R & + *(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp)) + end if - Re_L(i) = 1._wp/max(Re_L(i), sgm_eps) + ! Geometrical source flux for cylindrical coordinates + #:if (NORM_DIR == 2) + if (cyl_coord) then + ! Substituting the advective flux into the inviscid geometrical source flux + $:GPU_LOOP(parallelism='[seq]') + do i = 1, E_idx + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) + end do + ! Recalculating the radial momentum geometric source flux + flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(1)) = & + xi_M*(rho_L*(vel_L(dir_idx(1))* & + vel_L(dir_idx(1)) + & + s_M*(xi_L*(dir_flg(dir_idx(1))*s_S + & + (1._wp - dir_flg(dir_idx(1)))* & + vel_L(dir_idx(1))) - vel_L(dir_idx(1))))) & + + xi_P*(rho_R*(vel_R(dir_idx(1))* & + vel_R(dir_idx(1)) + & + s_P*(xi_R*(dir_flg(dir_idx(1))*s_S + & + (1._wp - dir_flg(dir_idx(1)))* & + vel_R(dir_idx(1))) - vel_R(dir_idx(1))))) + ! Geometrical source of the void fraction(s) is zero + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + end do + end if + #:endif + #:if (NORM_DIR == 3) + if (grid_geometry == 3) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, sys_size + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + end do + + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb + 1) = & + -xi_M*(rho_L*(vel_L(dir_idx(1))* & + vel_L(dir_idx(1)) + & + s_M*(xi_L*(dir_flg(dir_idx(1))*s_S + & + (1._wp - dir_flg(dir_idx(1)))* & + vel_L(dir_idx(1))) - vel_L(dir_idx(1))))) & + - xi_P*(rho_R*(vel_R(dir_idx(1))* & + vel_R(dir_idx(1)) + & + s_P*(xi_R*(dir_flg(dir_idx(1))*s_S + & + (1._wp - dir_flg(dir_idx(1)))* & + vel_R(dir_idx(1))) - vel_R(dir_idx(1))))) + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxe) = flux_rs${XYZ}$_vf(j, k, l, momxb + 1) + + end if + #:endif + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + else + ! 5-EQUATION MODEL WITH HLLC + #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel_L, vel_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, alpha_L, alpha_R, s_L, s_R, s_S, vel_avg_rms, pcorr, zcoef, vel_L_tmp, vel_R_tmp, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, tau_e_L, tau_e_R, xi_field_L, xi_field_R, Yi_avg,Phi_avg, h_iL, h_iR, h_avg_2]', copyin='[is1, is2, is3]') + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + + !idx1 = 1; if (dir_idx(1) == 2) idx1 = 2; if (dir_idx(1) == 3) idx1 = 3 + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) + alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) end do + vel_L_rms = 0._wp; vel_R_rms = 0._wp $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_R(i) = dflt_real + do i = 1, num_dims + vel_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + i) + vel_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + i) + vel_L_rms = vel_L_rms + vel_L(i)**2._wp + vel_R_rms = vel_R_rms + vel_R(i)**2._wp + end do - if (Re_size(i) > 0) Re_R(i) = 0._wp + pres_L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) + pres_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) + + rho_L = 0._wp + gamma_L = 0._wp + pi_inf_L = 0._wp + qv_L = 0._wp + + rho_R = 0._wp + gamma_R = 0._wp + pi_inf_R = 0._wp + qv_R = 0._wp + + alpha_L_sum = 0._wp + alpha_R_sum = 0._wp + ! Change this by splitting it into the cases + ! present in the bubbles_euler + if (mpp_lim) then $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q))/Res(i, q) & - + Re_R(i) + do i = 1, num_fluids + qL_prim_rs${XYZ}$_vf(j, k, l, i) = max(0._wp, qL_prim_rs${XYZ}$_vf(j, k, l, i)) + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) = min(max(0._wp, qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)), 1._wp) + alpha_L_sum = alpha_L_sum + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) end do - Re_R(i) = 1._wp/max(Re_R(i), sgm_eps) - end do - end if + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)/max(alpha_L_sum, sgm_eps) + end do + + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) = max(0._wp, qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)) + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) = min(max(0._wp, qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)), 1._wp) + alpha_R_sum = alpha_R_sum + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) + end do + + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)/max(alpha_R_sum, sgm_eps) + end do + end if - if (chemistry) then - c_sum_Yi_Phi = 0.0_wp $:GPU_LOOP(parallelism='[seq]') - do i = chemxb, chemxe - Ys_L(i - chemxb + 1) = qL_prim_rs${XYZ}$_vf(j, k, l, i) - Ys_R(i - chemxb + 1) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + do i = 1, num_fluids + rho_L = rho_L + qL_prim_rs${XYZ}$_vf(j, k, l, i) + gamma_L = gamma_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*gammas(i) + pi_inf_L = pi_inf_L + qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i)*pi_infs(i) + qv_L = qv_L + qL_prim_rs${XYZ}$_vf(j, k, l, i)*qvs(i) + + rho_R = rho_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + gamma_R = gamma_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*gammas(i) + pi_inf_R = pi_inf_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i)*pi_infs(i) + qv_R = qv_R + qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)*qvs(i) end do - call get_mixture_molecular_weight(Ys_L, MW_L) - call get_mixture_molecular_weight(Ys_R, MW_R) + if (viscous) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_L(i) = dflt_real - Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) - Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) + if (Re_size(i) > 0) Re_L(i) = 0._wp - R_gas_L = gas_constant/MW_L - R_gas_R = gas_constant/MW_R + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q))/Res(i, q) & + + Re_L(i) + end do - T_L = pres_L/rho_L/R_gas_L - T_R = pres_R/rho_R/R_gas_R + Re_L(i) = 1._wp/max(Re_L(i), sgm_eps) - call get_species_specific_heats_r(T_L, Cp_iL) - call get_species_specific_heats_r(T_R, Cp_iR) + end do - if (chem_params%gamma_method == 1) then - !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. - Gamma_iL = Cp_iL/(Cp_iL - 1.0_wp) - Gamma_iR = Cp_iR/(Cp_iR - 1.0_wp) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_R(i) = dflt_real - gamma_L = sum(Xs_L(:)/(Gamma_iL(:) - 1.0_wp)) - gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) - else if (chem_params%gamma_method == 2) then - !> gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. - call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) - call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) - call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) - call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) + if (Re_size(i) > 0) Re_R(i) = 0._wp - Gamm_L = Cp_L/Cv_L - gamma_L = 1.0_wp/(Gamm_L - 1.0_wp) - Gamm_R = Cp_R/Cv_R - gamma_R = 1.0_wp/(Gamm_R - 1.0_wp) + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q))/Res(i, q) & + + Re_R(i) + end do + + Re_R(i) = 1._wp/max(Re_R(i), sgm_eps) + end do end if - call get_mixture_energy_mass(T_L, Ys_L, E_L) - call get_mixture_energy_mass(T_R, Ys_R, E_R) + if (chemistry) then + c_sum_Yi_Phi = 0.0_wp + $:GPU_LOOP(parallelism='[seq]') + do i = chemxb, chemxe + Ys_L(i - chemxb + 1) = qL_prim_rs${XYZ}$_vf(j, k, l, i) + Ys_R(i - chemxb + 1) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + end do - E_L = rho_L*E_L + 5.e-1*rho_L*vel_L_rms - E_R = rho_R*E_R + 5.e-1*rho_R*vel_R_rms - H_L = (E_L + pres_L)/rho_L - H_R = (E_R + pres_R)/rho_R - else - E_L = gamma_L*pres_L + pi_inf_L + 5.e-1*rho_L*vel_L_rms + qv_L + call get_mixture_molecular_weight(Ys_L, MW_L) + call get_mixture_molecular_weight(Ys_R, MW_R) - E_R = gamma_R*pres_R + pi_inf_R + 5.e-1*rho_R*vel_R_rms + qv_R + Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) + Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) - H_L = (E_L + pres_L)/rho_L - H_R = (E_R + pres_R)/rho_R - end if + R_gas_L = gas_constant/MW_L + R_gas_R = gas_constant/MW_R - ! ENERGY ADJUSTMENTS FOR HYPOELASTIC ENERGY - if (hypoelasticity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, strxe - strxb + 1 - tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) - tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) - end do - G_L = 0._wp - G_R = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - G_L = G_L + alpha_L(i)*Gs(i) - G_R = G_R + alpha_R(i)*Gs(i) - end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, strxe - strxb + 1 - ! Elastic contribution to energy if G large enough - if ((G_L > verysmall) .and. (G_R > verysmall)) then - E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) - E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) - ! Additional terms in 2D and 3D - if ((i == 2) .or. (i == 4) .or. (i == 5)) then - E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) - E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) - end if + T_L = pres_L/rho_L/R_gas_L + T_R = pres_R/rho_R/R_gas_R + + call get_species_specific_heats_r(T_L, Cp_iL) + call get_species_specific_heats_r(T_R, Cp_iR) + + if (chem_params%gamma_method == 1) then + !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. + Gamma_iL = Cp_iL/(Cp_iL - 1.0_wp) + Gamma_iR = Cp_iR/(Cp_iR - 1.0_wp) + + gamma_L = sum(Xs_L(:)/(Gamma_iL(:) - 1.0_wp)) + gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) + else if (chem_params%gamma_method == 2) then + !> gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. + call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) + call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) + call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) + call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) + + Gamm_L = Cp_L/Cv_L + gamma_L = 1.0_wp/(Gamm_L - 1.0_wp) + Gamm_R = Cp_R/Cv_R + gamma_R = 1.0_wp/(Gamm_R - 1.0_wp) end if - end do - end if - ! ENERGY ADJUSTMENTS FOR HYPERELASTIC ENERGY - if (hyperelasticity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - xi_field_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) - xi_field_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, xibeg - 1 + i) - end do - G_L = 0._wp - G_R = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - ! Mixture left and right shear modulus - G_L = G_L + alpha_L(i)*Gs(i) - G_R = G_R + alpha_R(i)*Gs(i) - end do - ! Elastic contribution to energy if G large enough - if (G_L > verysmall .and. G_R > verysmall) then - E_L = E_L + G_L*qL_prim_rs${XYZ}$_vf(j, k, l, xiend + 1) - E_R = E_R + G_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, xiend + 1) - end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, b_size - 1 - tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) - tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) - end do - end if + call get_mixture_energy_mass(T_L, Ys_L, E_L) + call get_mixture_energy_mass(T_R, Ys_R, E_R) - H_L = (E_L + pres_L)/rho_L - H_R = (E_R + pres_R)/rho_R + E_L = rho_L*E_L + 5.e-1*rho_L*vel_L_rms + E_R = rho_R*E_R + 5.e-1*rho_R*vel_R_rms + H_L = (E_L + pres_L)/rho_L + H_R = (E_R + pres_R)/rho_R + else + E_L = gamma_L*pres_L + pi_inf_L + 5.e-1*rho_L*vel_L_rms + qv_L - @:compute_average_state() + E_R = gamma_R*pres_R + pi_inf_R + 5.e-1*rho_R*vel_R_rms + qv_R - call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & - vel_L_rms, 0._wp, c_L) + H_L = (E_L + pres_L)/rho_L + H_R = (E_R + pres_R)/rho_R + end if - call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & - vel_R_rms, 0._wp, c_R) + ! ENERGY ADJUSTMENTS FOR HYPOELASTIC ENERGY + if (hypoelasticity) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, strxe - strxb + 1 + tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) + tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) + end do + G_L = 0._wp + G_R = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + G_L = G_L + alpha_L(i)*Gs(i) + G_R = G_R + alpha_R(i)*Gs(i) + end do + $:GPU_LOOP(parallelism='[seq]') + do i = 1, strxe - strxb + 1 + ! Elastic contribution to energy if G large enough + if ((G_L > verysmall) .and. (G_R > verysmall)) then + E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) + E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) + ! Additional terms in 2D and 3D + if ((i == 2) .or. (i == 4) .or. (i == 5)) then + E_L = E_L + (tau_e_L(i)*tau_e_L(i))/(4._wp*G_L) + E_R = E_R + (tau_e_R(i)*tau_e_R(i))/(4._wp*G_R) + end if + end if + end do + end if - !> The computation of c_avg does not require all the variables, and therefore the non '_avg' - ! variables are placeholders to call the subroutine. - call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & - vel_avg_rms, c_sum_Yi_Phi, c_avg) + ! ENERGY ADJUSTMENTS FOR HYPERELASTIC ENERGY + if (hyperelasticity) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + xi_field_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) + xi_field_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, xibeg - 1 + i) + end do + G_L = 0._wp + G_R = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + ! Mixture left and right shear modulus + G_L = G_L + alpha_L(i)*Gs(i) + G_R = G_R + alpha_R(i)*Gs(i) + end do + ! Elastic contribution to energy if G large enough + if (G_L > verysmall .and. G_R > verysmall) then + E_L = E_L + G_L*qL_prim_rs${XYZ}$_vf(j, k, l, xiend + 1) + E_R = E_R + G_R*qR_prim_rs${XYZ}$_vf(j + 1, k, l, xiend + 1) + end if + $:GPU_LOOP(parallelism='[seq]') + do i = 1, b_size - 1 + tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) + tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) + end do + end if - if (viscous) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_avg_rs${XYZ}$_vf(j, k, l, i) = 2._wp/(1._wp/Re_L(i) + 1._wp/Re_R(i)) - end do - end if + H_L = (E_L + pres_L)/rho_L + H_R = (E_R + pres_R)/rho_R - ! Low Mach correction - if (low_Mach == 2) then - @:compute_low_Mach_correction() - end if + @:compute_average_state() - if (wave_speeds == 1) then - if (elasticity) then - s_L = min(vel_L(dir_idx(1)) - sqrt(c_L*c_L + & - (((4._wp*G_L)/3._wp) + tau_e_L(dir_idx_tau(1)))/rho_L), vel_R(dir_idx(1)) - sqrt(c_R*c_R + & - (((4._wp*G_R)/3._wp) + tau_e_R(dir_idx_tau(1)))/rho_R)) - s_R = max(vel_R(dir_idx(1)) + sqrt(c_R*c_R + & - (((4._wp*G_R)/3._wp) + tau_e_R(dir_idx_tau(1)))/rho_R), vel_L(dir_idx(1)) + sqrt(c_L*c_L + & - (((4._wp*G_L)/3._wp) + tau_e_L(dir_idx_tau(1)))/rho_L)) - s_S = (pres_R - tau_e_R(dir_idx_tau(1)) - pres_L + & - tau_e_L(dir_idx_tau(1)) + rho_L*vel_L(idx1)*(s_L - vel_L(idx1)) - & - rho_R*vel_R(idx1)*(s_R - vel_R(idx1)))/(rho_L*(s_L - vel_L(idx1)) - & - rho_R*(s_R - vel_R(idx1))) - else - s_L = min(vel_L(dir_idx(1)) - c_L, vel_R(dir_idx(1)) - c_R) - s_R = max(vel_R(dir_idx(1)) + c_R, vel_L(dir_idx(1)) + c_L) - s_S = (pres_R - pres_L + rho_L*vel_L(dir_idx(1))* & - (s_L - vel_L(dir_idx(1))) - rho_R*vel_R(dir_idx(1))*(s_R - vel_R(dir_idx(1)))) & - /(rho_L*(s_L - vel_L(dir_idx(1))) - rho_R*(s_R - vel_R(dir_idx(1)))) + call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & + vel_L_rms, 0._wp, c_L) - end if - elseif (wave_speeds == 2) then - pres_SL = 5.e-1_wp*(pres_L + pres_R + rho_avg*c_avg* & - (vel_L(idx1) - & - vel_R(idx1))) + call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & + vel_R_rms, 0._wp, c_R) - pres_SR = pres_SL + !> The computation of c_avg does not require all the variables, and therefore the non '_avg' + ! variables are placeholders to call the subroutine. + call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & + vel_avg_rms, c_sum_Yi_Phi, c_avg) - Ms_L = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_L)/(1._wp + gamma_L))* & - (pres_SL/pres_L - 1._wp)*pres_L/ & - ((pres_L + pi_inf_L/(1._wp + gamma_L))))) - Ms_R = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_R)/(1._wp + gamma_R))* & - (pres_SR/pres_R - 1._wp)*pres_R/ & - ((pres_R + pi_inf_R/(1._wp + gamma_R))))) + if (viscous) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_avg_rs${XYZ}$_vf(j, k, l, i) = 2._wp/(1._wp/Re_L(i) + 1._wp/Re_R(i)) + end do + end if - s_L = vel_L(idx1) - c_L*Ms_L - s_R = vel_R(idx1) + c_R*Ms_R + ! Low Mach correction + if (low_Mach == 2) then + @:compute_low_Mach_correction() + end if - s_S = 5.e-1_wp*((vel_L(idx1) + vel_R(idx1)) + & - (pres_L - pres_R)/ & - (rho_avg*c_avg)) - end if + if (wave_speeds == 1) then + if (elasticity) then + s_L = min(vel_L(dir_idx(1)) - sqrt(c_L*c_L + & + (((4._wp*G_L)/3._wp) + tau_e_L(dir_idx_tau(1)))/rho_L), vel_R(dir_idx(1)) - sqrt(c_R*c_R + & + (((4._wp*G_R)/3._wp) + tau_e_R(dir_idx_tau(1)))/rho_R)) + s_R = max(vel_R(dir_idx(1)) + sqrt(c_R*c_R + & + (((4._wp*G_R)/3._wp) + tau_e_R(dir_idx_tau(1)))/rho_R), vel_L(dir_idx(1)) + sqrt(c_L*c_L + & + (((4._wp*G_L)/3._wp) + tau_e_L(dir_idx_tau(1)))/rho_L)) + s_S = (pres_R - tau_e_R(dir_idx_tau(1)) - pres_L + & + tau_e_L(dir_idx_tau(1)) + rho_L*vel_L(idx1)*(s_L - vel_L(idx1)) - & + rho_R*vel_R(idx1)*(s_R - vel_R(idx1)))/(rho_L*(s_L - vel_L(idx1)) - & + rho_R*(s_R - vel_R(idx1))) + else + s_L = min(vel_L(dir_idx(1)) - c_L, vel_R(dir_idx(1)) - c_R) + s_R = max(vel_R(dir_idx(1)) + c_R, vel_L(dir_idx(1)) + c_L) + s_S = (pres_R - pres_L + rho_L*vel_L(dir_idx(1))* & + (s_L - vel_L(dir_idx(1))) - rho_R*vel_R(dir_idx(1))*(s_R - vel_R(dir_idx(1)))) & + /(rho_L*(s_L - vel_L(dir_idx(1))) - rho_R*(s_R - vel_R(dir_idx(1)))) - ! follows Einfeldt et al. - ! s_M/P = min/max(0.,s_L/R) - s_M = min(0._wp, s_L); s_P = max(0._wp, s_R) + end if + elseif (wave_speeds == 2) then + pres_SL = 5.e-1_wp*(pres_L + pres_R + rho_avg*c_avg* & + (vel_L(idx1) - & + vel_R(idx1))) + + pres_SR = pres_SL + + Ms_L = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_L)/(1._wp + gamma_L))* & + (pres_SL/pres_L - 1._wp)*pres_L/ & + ((pres_L + pi_inf_L/(1._wp + gamma_L))))) + Ms_R = max(1._wp, sqrt(1._wp + ((5.e-1_wp + gamma_R)/(1._wp + gamma_R))* & + (pres_SR/pres_R - 1._wp)*pres_R/ & + ((pres_R + pi_inf_R/(1._wp + gamma_R))))) + + s_L = vel_L(idx1) - c_L*Ms_L + s_R = vel_R(idx1) + c_R*Ms_R + + s_S = 5.e-1_wp*((vel_L(idx1) + vel_R(idx1)) + & + (pres_L - pres_R)/ & + (rho_avg*c_avg)) + end if - ! goes with q_star_L/R = xi_L/R * (variable) - ! xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) ) - xi_L = (s_L - vel_L(idx1))/(s_L - s_S) - xi_R = (s_R - vel_R(idx1))/(s_R - s_S) + ! follows Einfeldt et al. + ! s_M/P = min/max(0.,s_L/R) + s_M = min(0._wp, s_L); s_P = max(0._wp, s_R) - ! goes with numerical velocity in x/y/z directions - ! xi_P/M = 0.5 +/m sgn(0.5,s_star) - xi_M = (5.e-1_wp + sign(5.e-1_wp, s_S)) - xi_P = (5.e-1_wp - sign(5.e-1_wp, s_S)) + ! goes with q_star_L/R = xi_L/R * (variable) + ! xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) ) + xi_L = (s_L - vel_L(idx1))/(s_L - s_S) + xi_R = (s_R - vel_R(idx1))/(s_R - s_S) - ! Low Mach correction - if (low_Mach == 1) then - @:compute_low_Mach_correction() - else - pcorr = 0._wp - end if + ! goes with numerical velocity in x/y/z directions + ! xi_P/M = 0.5 +/m sgn(0.5,s_star) + xi_M = (5.e-1_wp + sign(5.e-1_wp, s_S)) + xi_P = (5.e-1_wp - sign(5.e-1_wp, s_S)) - ! COMPUTING THE HLLC FLUXES - ! MASS FLUX. - $:GPU_LOOP(parallelism='[seq]') - do i = 1, contxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i) & - *(vel_L(idx1) + s_M*(xi_L - 1._wp)) & - + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & - *(vel_R(idx1) + s_P*(xi_R - 1._wp)) - end do + ! Low Mach correction + if (low_Mach == 1) then + @:compute_low_Mach_correction() + else + pcorr = 0._wp + end if - ! MOMENTUM FLUX. - ! f = \rho u u - \sigma, q = \rho u, q_star = \xi * \rho*(s_star, v, w) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - idxi = dir_idx(i) - flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) = & - xi_M*(rho_L*(vel_L(idx1)* & - vel_L(idxi) + & - s_M*(xi_L*(dir_flg(idxi)*s_S + & - (1._wp - dir_flg(idxi))* & - vel_L(idxi)) - vel_L(idxi))) + & - dir_flg(idxi)*(pres_L)) & - + xi_P*(rho_R*(vel_R(idx1)* & - vel_R(idxi) + & - s_P*(xi_R*(dir_flg(idxi)*s_S + & - (1._wp - dir_flg(idxi))* & - vel_R(idxi)) - vel_R(idxi))) + & - dir_flg(idxi)*(pres_R)) & - + (s_M/s_L)*(s_P/s_R)*dir_flg(idxi)*pcorr - end do + ! COMPUTING THE HLLC FLUXES + ! MASS FLUX. + $:GPU_LOOP(parallelism='[seq]') + do i = 1, contxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i) & + *(vel_L(idx1) + s_M*(xi_L - 1._wp)) & + + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & + *(vel_R(idx1) + s_P*(xi_R - 1._wp)) + end do - ! ENERGY FLUX. - ! f = u*(E-\sigma), q = E, q_star = \xi*E+(s-u)(\rho s_star - \sigma/(s-u)) - flux_rs${XYZ}$_vf(j, k, l, E_idx) = & - xi_M*(vel_L(idx1)*(E_L + pres_L) + & - s_M*(xi_L*(E_L + (s_S - vel_L(idx1))* & - (rho_L*s_S + pres_L/ & - (s_L - vel_L(idx1)))) - E_L)) & - + xi_P*(vel_R(idx1)*(E_R + pres_R) + & - s_P*(xi_R*(E_R + (s_S - vel_R(idx1))* & - (rho_R*s_S + pres_R/ & - (s_R - vel_R(idx1)))) - E_R)) & - + (s_M/s_L)*(s_P/s_R)*pcorr*s_S - - ! ELASTICITY. Elastic shear stress additions for the momentum and energy flux - if (elasticity) then - flux_ene_e = 0._wp + ! MOMENTUM FLUX. + ! f = \rho u u - \sigma, q = \rho u, q_star = \xi * \rho*(s_star, v, w) $:GPU_LOOP(parallelism='[seq]') do i = 1, num_dims idxi = dir_idx(i) - ! MOMENTUM ELASTIC FLUX. flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) = & - flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) & - - xi_M*tau_e_L(dir_idx_tau(i)) - xi_P*tau_e_R(dir_idx_tau(i)) - ! ENERGY ELASTIC FLUX. - flux_ene_e = flux_ene_e - & - xi_M*(vel_L(idxi)*tau_e_L(dir_idx_tau(i)) + & - s_M*(xi_L*((s_S - vel_L(i))*(tau_e_L(dir_idx_tau(i))/(s_L - vel_L(i)))))) - & - xi_P*(vel_R(idxi)*tau_e_R(dir_idx_tau(i)) + & - s_P*(xi_R*((s_S - vel_R(i))*(tau_e_R(dir_idx_tau(i))/(s_R - vel_R(i)))))) - end do - flux_rs${XYZ}$_vf(j, k, l, E_idx) = flux_rs${XYZ}$_vf(j, k, l, E_idx) + flux_ene_e - end if - - ! HYPOELASTIC STRESS EVOLUTION FLUX. - if (hypoelasticity) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, strxe - strxb + 1 - flux_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) = & - xi_M*(s_S/(s_L - s_S))*(s_L*rho_L*tau_e_L(i) - rho_L*vel_L(idx1)*tau_e_L(i)) + & - xi_P*(s_S/(s_R - s_S))*(s_R*rho_R*tau_e_R(i) - rho_R*vel_R(idx1)*tau_e_R(i)) + xi_M*(rho_L*(vel_L(idx1)* & + vel_L(idxi) + & + s_M*(xi_L*(dir_flg(idxi)*s_S + & + (1._wp - dir_flg(idxi))* & + vel_L(idxi)) - vel_L(idxi))) + & + dir_flg(idxi)*(pres_L)) & + + xi_P*(rho_R*(vel_R(idx1)* & + vel_R(idxi) + & + s_P*(xi_R*(dir_flg(idxi)*s_S + & + (1._wp - dir_flg(idxi))* & + vel_R(idxi)) - vel_R(idxi))) + & + dir_flg(idxi)*(pres_R)) & + + (s_M/s_L)*(s_P/s_R)*dir_flg(idxi)*pcorr end do - end if - - ! VOLUME FRACTION FLUX. - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_rs${XYZ}$_vf(j, k, l, i) = & - xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i) & - *(vel_L(idx1) + s_M*(xi_L - 1._wp)) & - + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & - *(vel_R(idx1) + s_P*(xi_R - 1._wp)) - end do - ! VOLUME FRACTION SOURCE FLUX. - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - idxi = dir_idx(i) - vel_src_rs${XYZ}$_vf(j, k, l, idxi) = & - xi_M*(vel_L(idxi) + & - dir_flg(idxi)* & - s_M*(xi_L - 1._wp)) & - + xi_P*(vel_R(idxi) + & - dir_flg(idxi)* & - s_P*(xi_R - 1._wp)) - end do + ! ENERGY FLUX. + ! f = u*(E-\sigma), q = E, q_star = \xi*E+(s-u)(\rho s_star - \sigma/(s-u)) + flux_rs${XYZ}$_vf(j, k, l, E_idx) = & + xi_M*(vel_L(idx1)*(E_L + pres_L) + & + s_M*(xi_L*(E_L + (s_S - vel_L(idx1))* & + (rho_L*s_S + pres_L/ & + (s_L - vel_L(idx1)))) - E_L)) & + + xi_P*(vel_R(idx1)*(E_R + pres_R) + & + s_P*(xi_R*(E_R + (s_S - vel_R(idx1))* & + (rho_R*s_S + pres_R/ & + (s_R - vel_R(idx1)))) - E_R)) & + + (s_M/s_L)*(s_P/s_R)*pcorr*s_S + + ! ELASTICITY. Elastic shear stress additions for the momentum and energy flux + if (elasticity) then + flux_ene_e = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + idxi = dir_idx(i) + ! MOMENTUM ELASTIC FLUX. + flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) = & + flux_rs${XYZ}$_vf(j, k, l, contxe + idxi) & + - xi_M*tau_e_L(dir_idx_tau(i)) - xi_P*tau_e_R(dir_idx_tau(i)) + ! ENERGY ELASTIC FLUX. + flux_ene_e = flux_ene_e - & + xi_M*(vel_L(idxi)*tau_e_L(dir_idx_tau(i)) + & + s_M*(xi_L*((s_S - vel_L(i))*(tau_e_L(dir_idx_tau(i))/(s_L - vel_L(i)))))) - & + xi_P*(vel_R(idxi)*tau_e_R(dir_idx_tau(i)) + & + s_P*(xi_R*((s_S - vel_R(i))*(tau_e_R(dir_idx_tau(i))/(s_R - vel_R(i)))))) + end do + flux_rs${XYZ}$_vf(j, k, l, E_idx) = flux_rs${XYZ}$_vf(j, k, l, E_idx) + flux_ene_e + end if - ! COLOR FUNCTION FLUX - if (surface_tension) then - flux_rs${XYZ}$_vf(j, k, l, c_idx) = & - xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, c_idx) & - *(vel_L(idx1) + s_M*(xi_L - 1._wp)) & - + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, c_idx) & - *(vel_R(idx1) + s_P*(xi_R - 1._wp)) - end if + ! HYPOELASTIC STRESS EVOLUTION FLUX. + if (hypoelasticity) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, strxe - strxb + 1 + flux_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) = & + xi_M*(s_S/(s_L - s_S))*(s_L*rho_L*tau_e_L(i) - rho_L*vel_L(idx1)*tau_e_L(i)) + & + xi_P*(s_S/(s_R - s_S))*(s_R*rho_R*tau_e_R(i) - rho_R*vel_R(idx1)*tau_e_R(i)) + end do + end if - ! REFERENCE MAP FLUX. - if (hyperelasticity) then + ! VOLUME FRACTION FLUX. $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - flux_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) = & - xi_M*(s_S/(s_L - s_S))*(s_L*rho_L*xi_field_L(i) & - - rho_L*vel_L(idx1)*xi_field_L(i)) + & - xi_P*(s_S/(s_R - s_S))*(s_R*rho_R*xi_field_R(i) & - - rho_R*vel_R(idx1)*xi_field_R(i)) + do i = advxb, advxe + flux_rs${XYZ}$_vf(j, k, l, i) = & + xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, i) & + *(vel_L(idx1) + s_M*(xi_L - 1._wp)) & + + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) & + *(vel_R(idx1) + s_P*(xi_R - 1._wp)) end do - end if - - flux_src_rs${XYZ}$_vf(j, k, l, advxb) = vel_src_rs${XYZ}$_vf(j, k, l, idx1) - if (chemistry) then + ! VOLUME FRACTION SOURCE FLUX. $:GPU_LOOP(parallelism='[seq]') - do i = chemxb, chemxe - Y_L = qL_prim_rs${XYZ}$_vf(j, k, l, i) - Y_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) - - flux_rs${XYZ}$_vf(j, k, l, i) = xi_M*rho_L*Y_L*(vel_L(idx1) + s_M*(xi_L - 1._wp)) & - + xi_P*rho_R*Y_R*(vel_R(idx1) + s_P*(xi_R - 1._wp)) - flux_src_rs${XYZ}$_vf(j, k, l, i) = 0.0_wp + do i = 1, num_dims + idxi = dir_idx(i) + vel_src_rs${XYZ}$_vf(j, k, l, idxi) = & + xi_M*(vel_L(idxi) + & + dir_flg(idxi)* & + s_M*(xi_L - 1._wp)) & + + xi_P*(vel_R(idxi) + & + dir_flg(idxi)* & + s_P*(xi_R - 1._wp)) end do - end if - ! Geometrical source flux for cylindrical coordinates - #:if (NORM_DIR == 2) - if (cyl_coord) then - !Substituting the advective flux into the inviscid geometrical source flux - $:GPU_LOOP(parallelism='[seq]') - do i = 1, E_idx - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) - end do - ! Recalculating the radial momentum geometric source flux - flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + idx1) = & - xi_M*(rho_L*(vel_L(idx1)* & - vel_L(idx1) + & - s_M*(xi_L*(dir_flg(idx1)*s_S + & - (1._wp - dir_flg(idx1))* & - vel_L(idx1)) - vel_L(idx1)))) & - + xi_P*(rho_R*(vel_R(idx1)* & - vel_R(idx1) + & - s_P*(xi_R*(dir_flg(idx1)*s_S + & - (1._wp - dir_flg(idx1))* & - vel_R(idx1)) - vel_R(idx1)))) - ! Geometrical source of the void fraction(s) is zero + ! COLOR FUNCTION FLUX + if (surface_tension) then + flux_rs${XYZ}$_vf(j, k, l, c_idx) = & + xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, c_idx) & + *(vel_L(idx1) + s_M*(xi_L - 1._wp)) & + + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, c_idx) & + *(vel_R(idx1) + s_P*(xi_R - 1._wp)) + end if + + ! REFERENCE MAP FLUX. + if (hyperelasticity) then $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + do i = 1, num_dims + flux_rs${XYZ}$_vf(j, k, l, xibeg - 1 + i) = & + xi_M*(s_S/(s_L - s_S))*(s_L*rho_L*xi_field_L(i) & + - rho_L*vel_L(idx1)*xi_field_L(i)) + & + xi_P*(s_S/(s_R - s_S))*(s_R*rho_R*xi_field_R(i) & + - rho_R*vel_R(idx1)*xi_field_R(i)) end do end if - #:endif - #:if (NORM_DIR == 3) - if (grid_geometry == 3) then + + flux_src_rs${XYZ}$_vf(j, k, l, advxb) = vel_src_rs${XYZ}$_vf(j, k, l, idx1) + + if (chemistry) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, sys_size - flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + do i = chemxb, chemxe + Y_L = qL_prim_rs${XYZ}$_vf(j, k, l, i) + Y_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + + flux_rs${XYZ}$_vf(j, k, l, i) = xi_M*rho_L*Y_L*(vel_L(idx1) + s_M*(xi_L - 1._wp)) & + + xi_P*rho_R*Y_R*(vel_R(idx1) + s_P*(xi_R - 1._wp)) + flux_src_rs${XYZ}$_vf(j, k, l, i) = 0.0_wp end do + end if + + ! Geometrical source flux for cylindrical coordinates + #:if (NORM_DIR == 2) + if (cyl_coord) then + !Substituting the advective flux into the inviscid geometrical source flux + $:GPU_LOOP(parallelism='[seq]') + do i = 1, E_idx + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = flux_rs${XYZ}$_vf(j, k, l, i) + end do + ! Recalculating the radial momentum geometric source flux + flux_gsrc_rs${XYZ}$_vf(j, k, l, contxe + idx1) = & + xi_M*(rho_L*(vel_L(idx1)* & + vel_L(idx1) + & + s_M*(xi_L*(dir_flg(idx1)*s_S + & + (1._wp - dir_flg(idx1))* & + vel_L(idx1)) - vel_L(idx1)))) & + + xi_P*(rho_R*(vel_R(idx1)* & + vel_R(idx1) + & + s_P*(xi_R*(dir_flg(idx1)*s_S + & + (1._wp - dir_flg(idx1))* & + vel_R(idx1)) - vel_R(idx1)))) + ! Geometrical source of the void fraction(s) is zero + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + end do + end if + #:endif + #:if (NORM_DIR == 3) + if (grid_geometry == 3) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, sys_size + flux_gsrc_rs${XYZ}$_vf(j, k, l, i) = 0._wp + end do - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb + 1) = & - -xi_M*(rho_L*(vel_L(idx1)* & - vel_L(idx1) + & - s_M*(xi_L*(dir_flg(idx1)*s_S + & - (1._wp - dir_flg(idx1))* & - vel_L(idx1)) - vel_L(idx1)))) & - - xi_P*(rho_R*(vel_R(idx1)* & - vel_R(idx1) + & - s_P*(xi_R*(dir_flg(idx1)*s_S + & - (1._wp - dir_flg(idx1))* & - vel_R(idx1)) - vel_R(idx1)))) - flux_gsrc_rs${XYZ}$_vf(j, k, l, momxe) = flux_rs${XYZ}$_vf(j, k, l, momxb + 1) + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxb + 1) = & + -xi_M*(rho_L*(vel_L(idx1)* & + vel_L(idx1) + & + s_M*(xi_L*(dir_flg(idx1)*s_S + & + (1._wp - dir_flg(idx1))* & + vel_L(idx1)) - vel_L(idx1)))) & + - xi_P*(rho_R*(vel_R(idx1)* & + vel_R(idx1) + & + s_P*(xi_R*(dir_flg(idx1)*s_S + & + (1._wp - dir_flg(idx1))* & + vel_R(idx1)) - vel_R(idx1)))) + flux_gsrc_rs${XYZ}$_vf(j, k, l, momxe) = flux_rs${XYZ}$_vf(j, k, l, momxb + 1) - end if - #:endif + end if + #:endif + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if @@ -2943,177 +2943,177 @@ contains #:for NORM_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (norm_dir == ${NORM_DIR}$) then #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel, alpha_L, alpha_R, rho, pres,E, H_no_mag, gamma, pi_inf, qv, vel_rms, B, c, c_fast, pres_mag, U_L, U_R, U_starL, U_starR, U_doubleL, U_doubleR, F_L, F_R, F_starL, F_starR, F_hlld]') - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end - ! (1) Extract the left/right primitive states - do i = 1, contxe - alpha_rho_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, i) - alpha_rho_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) - end do + ! (1) Extract the left/right primitive states + do i = 1, contxe + alpha_rho_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, i) + alpha_rho_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) + end do - ! NOTE: unlike HLL & HLLC, vel_L here is permutated by dir_idx for simpler logic - do i = 1, num_vels - vel%L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) - vel%R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + dir_idx(i)) - end do + ! NOTE: unlike HLL & HLLC, vel_L here is permutated by dir_idx for simpler logic + do i = 1, num_vels + vel%L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, contxe + dir_idx(i)) + vel%R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, contxe + dir_idx(i)) + end do - vel_rms%L = sum(vel%L**2._wp) - vel_rms%R = sum(vel%R**2._wp) + vel_rms%L = sum(vel%L**2._wp) + vel_rms%R = sum(vel%R**2._wp) - do i = 1, num_fluids - alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) - alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) - end do + do i = 1, num_fluids + alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + i) + alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + i) + end do + + pres%L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) + pres%R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) - pres%L = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx) - pres%R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx) - - ! NOTE: unlike HLL, Bx, By, Bz are permutated by dir_idx for simpler logic - if (mhd) then - if (n == 0) then ! 1D: constant Bx; By, Bz as variables; only in x so not permutated - B%L = [Bx0, qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg), qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + 1)] - B%R = [Bx0, qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg), qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + 1)] - else ! 2D/3D: Bx, By, Bz as variables - B%L = [qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + dir_idx(1) - 1), & - qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + dir_idx(2) - 1), & - qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + dir_idx(3) - 1)] - B%R = [qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + dir_idx(1) - 1), & - qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + dir_idx(2) - 1), & - qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + dir_idx(3) - 1)] + ! NOTE: unlike HLL, Bx, By, Bz are permutated by dir_idx for simpler logic + if (mhd) then + if (n == 0) then ! 1D: constant Bx; By, Bz as variables; only in x so not permutated + B%L = [Bx0, qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg), qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + 1)] + B%R = [Bx0, qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg), qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + 1)] + else ! 2D/3D: Bx, By, Bz as variables + B%L = [qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + dir_idx(1) - 1), & + qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + dir_idx(2) - 1), & + qL_prim_rs${XYZ}$_vf(j, k, l, B_idx%beg + dir_idx(3) - 1)] + B%R = [qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + dir_idx(1) - 1), & + qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + dir_idx(2) - 1), & + qR_prim_rs${XYZ}$_vf(j + 1, k, l, B_idx%beg + dir_idx(3) - 1)] + end if end if - end if - ! Sum properties of all fluid components - rho%L = 0._wp; gamma%L = 0._wp; pi_inf%L = 0._wp; qv%L = 0._wp - rho%R = 0._wp; gamma%R = 0._wp; pi_inf%R = 0._wp; qv%R = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho%L = rho%L + alpha_rho_L(i) - gamma%L = gamma%L + alpha_L(i)*gammas(i) - pi_inf%L = pi_inf%L + alpha_L(i)*pi_infs(i) - qv%L = qv%L + alpha_rho_L(i)*qvs(i) - - rho%R = rho%R + alpha_rho_R(i) - gamma%R = gamma%R + alpha_R(i)*gammas(i) - pi_inf%R = pi_inf%R + alpha_R(i)*pi_infs(i) - qv%R = qv%R + alpha_rho_R(i)*qvs(i) - end do + ! Sum properties of all fluid components + rho%L = 0._wp; gamma%L = 0._wp; pi_inf%L = 0._wp; qv%L = 0._wp + rho%R = 0._wp; gamma%R = 0._wp; pi_inf%R = 0._wp; qv%R = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + rho%L = rho%L + alpha_rho_L(i) + gamma%L = gamma%L + alpha_L(i)*gammas(i) + pi_inf%L = pi_inf%L + alpha_L(i)*pi_infs(i) + qv%L = qv%L + alpha_rho_L(i)*qvs(i) + + rho%R = rho%R + alpha_rho_R(i) + gamma%R = gamma%R + alpha_R(i)*gammas(i) + pi_inf%R = pi_inf%R + alpha_R(i)*pi_infs(i) + qv%R = qv%R + alpha_rho_R(i)*qvs(i) + end do - pres_mag%L = 0.5_wp*sum(B%L**2._wp) - pres_mag%R = 0.5_wp*sum(B%R**2._wp) - E%L = gamma%L*pres%L + pi_inf%L + 0.5_wp*rho%L*vel_rms%L + qv%L + pres_mag%L - E%R = gamma%R*pres%R + pi_inf%R + 0.5_wp*rho%R*vel_rms%R + qv%R + pres_mag%R ! includes magnetic energy - H_no_mag%L = (E%L + pres%L - pres_mag%L)/rho%L - H_no_mag%R = (E%R + pres%R - pres_mag%R)/rho%R ! stagnation enthalpy here excludes magnetic energy (only used to find speed of sound) - - ! (2) Compute fast wave speeds - call s_compute_speed_of_sound(pres%L, rho%L, gamma%L, pi_inf%L, H_no_mag%L, alpha_L, vel_rms%L, 0._wp, c%L) - call s_compute_speed_of_sound(pres%R, rho%R, gamma%R, pi_inf%R, H_no_mag%R, alpha_R, vel_rms%R, 0._wp, c%R) - call s_compute_fast_magnetosonic_speed(rho%L, c%L, B%L, norm_dir, c_fast%L, H_no_mag%L) - call s_compute_fast_magnetosonic_speed(rho%R, c%R, B%R, norm_dir, c_fast%R, H_no_mag%R) - - ! (3) Compute contact speed s_M [Miyoshi Equ. (38)] - s_L = min(vel%L(1) - c_fast%L, vel%R(1) - c_fast%R) - s_R = max(vel%R(1) + c_fast%R, vel%L(1) + c_fast%L) - - pTot_L = pres%L + pres_mag%L - pTot_R = pres%R + pres_mag%R - - s_M = (((s_R - vel%R(1))*rho%R*vel%R(1) - & - (s_L - vel%L(1))*rho%L*vel%L(1) - pTot_R + pTot_L)/ & - ((s_R - vel%R(1))*rho%R - (s_L - vel%L(1))*rho%L)) - - ! (4) Compute star state variables - rhoL_star = rho%L*(s_L - vel%L(1))/(s_L - s_M) - rhoR_star = rho%R*(s_R - vel%R(1))/(s_R - s_M) - p_star = pTot_L + rho%L*(s_L - vel%L(1))*(s_M - vel%L(1))/(s_L - s_M) - E_starL = ((s_L - vel%L(1))*E%L - pTot_L*vel%L(1) + p_star*s_M)/(s_L - s_M) - E_starR = ((s_R - vel%R(1))*E%R - pTot_R*vel%R(1) + p_star*s_M)/(s_R - s_M) - - ! (5) Compute left/right state vectors and fluxes - U_L = [rho%L, rho%L*vel%L(1:3), B%L(2:3), E%L] - U_starL = [rhoL_star, rhoL_star*s_M, rhoL_star*vel%L(2:3), B%L(2:3), E_starL] - U_R = [rho%R, rho%R*vel%R(1:3), B%R(2:3), E%R] - U_starR = [rhoR_star, rhoR_star*s_M, rhoR_star*vel%R(2:3), B%R(2:3), E_starR] - - ! Compute the left/right fluxes - F_L(1) = U_L(2) - F_L(2) = U_L(2)*vel%L(1) - B%L(1)*B%L(1) + pTot_L - F_L(3:4) = U_L(2)*vel%L(2:3) - B%L(1)*B%L(2:3) - F_L(5:6) = vel%L(1)*B%L(2:3) - vel%L(2:3)*B%L(1) - F_L(7) = (E%L + pTot_L)*vel%L(1) - B%L(1)*(vel%L(1)*B%L(1) + vel%L(2)*B%L(2) + vel%L(3)*B%L(3)) - - F_R(1) = U_R(2) - F_R(2) = U_R(2)*vel%R(1) - B%R(1)*B%R(1) + pTot_R - F_R(3:4) = U_R(2)*vel%R(2:3) - B%R(1)*B%R(2:3) - F_R(5:6) = vel%R(1)*B%R(2:3) - vel%R(2:3)*B%R(1) - F_R(7) = (E%R + pTot_R)*vel%R(1) - B%R(1)*(vel%R(1)*B%R(1) + vel%R(2)*B%R(2) + vel%R(3)*B%R(3)) - ! Compute the star flux using HLL relation - F_starL = F_L + s_L*(U_starL - U_L) - F_starR = F_R + s_R*(U_starR - U_R) - ! Compute the rotational (Alfvén) speeds - s_starL = s_M - abs(B%L(1))/sqrt(rhoL_star) - s_starR = s_M + abs(B%L(1))/sqrt(rhoR_star) - ! Compute the double–star states [Miyoshi Eqns. (59)-(62)] - sqrt_rhoL_star = sqrt(rhoL_star); sqrt_rhoR_star = sqrt(rhoR_star) - vL_star = vel%L(2); wL_star = vel%L(3) - vR_star = vel%R(2); wR_star = vel%R(3) - - ! (6) Compute the double–star states [Miyoshi Eqns. (59)-(62)] - denom_ds = sqrt_rhoL_star + sqrt_rhoR_star - sign_Bx = sign(1._wp, B%L(1)) - v_double = (sqrt_rhoL_star*vL_star + sqrt_rhoR_star*vR_star + (B%R(2) - B%L(2))*sign_Bx)/denom_ds - w_double = (sqrt_rhoL_star*wL_star + sqrt_rhoR_star*wR_star + (B%R(3) - B%L(3))*sign_Bx)/denom_ds - By_double = (sqrt_rhoL_star*B%R(2) + sqrt_rhoR_star*B%L(2) + sqrt_rhoL_star*sqrt_rhoR_star*(vR_star - vL_star)*sign_Bx)/denom_ds - Bz_double = (sqrt_rhoL_star*B%R(3) + sqrt_rhoR_star*B%L(3) + sqrt_rhoL_star*sqrt_rhoR_star*(wR_star - wL_star)*sign_Bx)/denom_ds - - E_doubleL = E_starL - sqrt_rhoL_star*((vL_star*B%L(2) + wL_star*B%L(3)) - (v_double*By_double + w_double*Bz_double))*sign_Bx - E_doubleR = E_starR + sqrt_rhoR_star*((vR_star*B%R(2) + wR_star*B%R(3)) - (v_double*By_double + w_double*Bz_double))*sign_Bx - E_double = 0.5_wp*(E_doubleL + E_doubleR) - - U_doubleL = [rhoL_star, rhoL_star*s_M, rhoL_star*v_double, rhoL_star*w_double, By_double, Bz_double, E_double] - U_doubleR = [rhoR_star, rhoR_star*s_M, rhoR_star*v_double, rhoR_star*w_double, By_double, Bz_double, E_double] - - ! (11) Choose HLLD flux based on wave-speed regions - if (0.0_wp <= s_L) then - F_hlld = F_L - else if (0.0_wp <= s_starL) then - F_hlld = F_L + s_L*(U_starL - U_L) - else if (0.0_wp <= s_M) then - F_hlld = F_starL + s_starL*(U_doubleL - U_starL) - else if (0.0_wp <= s_starR) then - F_hlld = F_starR + s_starR*(U_doubleR - U_starR) - else if (0.0_wp <= s_R) then - F_hlld = F_R + s_R*(U_starR - U_R) - else - F_hlld = F_R - end if + pres_mag%L = 0.5_wp*sum(B%L**2._wp) + pres_mag%R = 0.5_wp*sum(B%R**2._wp) + E%L = gamma%L*pres%L + pi_inf%L + 0.5_wp*rho%L*vel_rms%L + qv%L + pres_mag%L + E%R = gamma%R*pres%R + pi_inf%R + 0.5_wp*rho%R*vel_rms%R + qv%R + pres_mag%R ! includes magnetic energy + H_no_mag%L = (E%L + pres%L - pres_mag%L)/rho%L + H_no_mag%R = (E%R + pres%R - pres_mag%R)/rho%R ! stagnation enthalpy here excludes magnetic energy (only used to find speed of sound) + + ! (2) Compute fast wave speeds + call s_compute_speed_of_sound(pres%L, rho%L, gamma%L, pi_inf%L, H_no_mag%L, alpha_L, vel_rms%L, 0._wp, c%L) + call s_compute_speed_of_sound(pres%R, rho%R, gamma%R, pi_inf%R, H_no_mag%R, alpha_R, vel_rms%R, 0._wp, c%R) + call s_compute_fast_magnetosonic_speed(rho%L, c%L, B%L, norm_dir, c_fast%L, H_no_mag%L) + call s_compute_fast_magnetosonic_speed(rho%R, c%R, B%R, norm_dir, c_fast%R, H_no_mag%R) + + ! (3) Compute contact speed s_M [Miyoshi Equ. (38)] + s_L = min(vel%L(1) - c_fast%L, vel%R(1) - c_fast%R) + s_R = max(vel%R(1) + c_fast%R, vel%L(1) + c_fast%L) + + pTot_L = pres%L + pres_mag%L + pTot_R = pres%R + pres_mag%R + + s_M = (((s_R - vel%R(1))*rho%R*vel%R(1) - & + (s_L - vel%L(1))*rho%L*vel%L(1) - pTot_R + pTot_L)/ & + ((s_R - vel%R(1))*rho%R - (s_L - vel%L(1))*rho%L)) + + ! (4) Compute star state variables + rhoL_star = rho%L*(s_L - vel%L(1))/(s_L - s_M) + rhoR_star = rho%R*(s_R - vel%R(1))/(s_R - s_M) + p_star = pTot_L + rho%L*(s_L - vel%L(1))*(s_M - vel%L(1))/(s_L - s_M) + E_starL = ((s_L - vel%L(1))*E%L - pTot_L*vel%L(1) + p_star*s_M)/(s_L - s_M) + E_starR = ((s_R - vel%R(1))*E%R - pTot_R*vel%R(1) + p_star*s_M)/(s_R - s_M) + + ! (5) Compute left/right state vectors and fluxes + U_L = [rho%L, rho%L*vel%L(1:3), B%L(2:3), E%L] + U_starL = [rhoL_star, rhoL_star*s_M, rhoL_star*vel%L(2:3), B%L(2:3), E_starL] + U_R = [rho%R, rho%R*vel%R(1:3), B%R(2:3), E%R] + U_starR = [rhoR_star, rhoR_star*s_M, rhoR_star*vel%R(2:3), B%R(2:3), E_starR] + + ! Compute the left/right fluxes + F_L(1) = U_L(2) + F_L(2) = U_L(2)*vel%L(1) - B%L(1)*B%L(1) + pTot_L + F_L(3:4) = U_L(2)*vel%L(2:3) - B%L(1)*B%L(2:3) + F_L(5:6) = vel%L(1)*B%L(2:3) - vel%L(2:3)*B%L(1) + F_L(7) = (E%L + pTot_L)*vel%L(1) - B%L(1)*(vel%L(1)*B%L(1) + vel%L(2)*B%L(2) + vel%L(3)*B%L(3)) + + F_R(1) = U_R(2) + F_R(2) = U_R(2)*vel%R(1) - B%R(1)*B%R(1) + pTot_R + F_R(3:4) = U_R(2)*vel%R(2:3) - B%R(1)*B%R(2:3) + F_R(5:6) = vel%R(1)*B%R(2:3) - vel%R(2:3)*B%R(1) + F_R(7) = (E%R + pTot_R)*vel%R(1) - B%R(1)*(vel%R(1)*B%R(1) + vel%R(2)*B%R(2) + vel%R(3)*B%R(3)) + ! Compute the star flux using HLL relation + F_starL = F_L + s_L*(U_starL - U_L) + F_starR = F_R + s_R*(U_starR - U_R) + ! Compute the rotational (Alfvén) speeds + s_starL = s_M - abs(B%L(1))/sqrt(rhoL_star) + s_starR = s_M + abs(B%L(1))/sqrt(rhoR_star) + ! Compute the double–star states [Miyoshi Eqns. (59)-(62)] + sqrt_rhoL_star = sqrt(rhoL_star); sqrt_rhoR_star = sqrt(rhoR_star) + vL_star = vel%L(2); wL_star = vel%L(3) + vR_star = vel%R(2); wR_star = vel%R(3) + + ! (6) Compute the double–star states [Miyoshi Eqns. (59)-(62)] + denom_ds = sqrt_rhoL_star + sqrt_rhoR_star + sign_Bx = sign(1._wp, B%L(1)) + v_double = (sqrt_rhoL_star*vL_star + sqrt_rhoR_star*vR_star + (B%R(2) - B%L(2))*sign_Bx)/denom_ds + w_double = (sqrt_rhoL_star*wL_star + sqrt_rhoR_star*wR_star + (B%R(3) - B%L(3))*sign_Bx)/denom_ds + By_double = (sqrt_rhoL_star*B%R(2) + sqrt_rhoR_star*B%L(2) + sqrt_rhoL_star*sqrt_rhoR_star*(vR_star - vL_star)*sign_Bx)/denom_ds + Bz_double = (sqrt_rhoL_star*B%R(3) + sqrt_rhoR_star*B%L(3) + sqrt_rhoL_star*sqrt_rhoR_star*(wR_star - wL_star)*sign_Bx)/denom_ds + + E_doubleL = E_starL - sqrt_rhoL_star*((vL_star*B%L(2) + wL_star*B%L(3)) - (v_double*By_double + w_double*Bz_double))*sign_Bx + E_doubleR = E_starR + sqrt_rhoR_star*((vR_star*B%R(2) + wR_star*B%R(3)) - (v_double*By_double + w_double*Bz_double))*sign_Bx + E_double = 0.5_wp*(E_doubleL + E_doubleR) + + U_doubleL = [rhoL_star, rhoL_star*s_M, rhoL_star*v_double, rhoL_star*w_double, By_double, Bz_double, E_double] + U_doubleR = [rhoR_star, rhoR_star*s_M, rhoR_star*v_double, rhoR_star*w_double, By_double, Bz_double, E_double] + + ! (11) Choose HLLD flux based on wave-speed regions + if (0.0_wp <= s_L) then + F_hlld = F_L + else if (0.0_wp <= s_starL) then + F_hlld = F_L + s_L*(U_starL - U_L) + else if (0.0_wp <= s_M) then + F_hlld = F_starL + s_starL*(U_doubleL - U_starL) + else if (0.0_wp <= s_starR) then + F_hlld = F_starR + s_starR*(U_doubleR - U_starR) + else if (0.0_wp <= s_R) then + F_hlld = F_R + s_R*(U_starR - U_R) + else + F_hlld = F_R + end if - ! (12) Reorder and write temporary variables to the flux array - ! Mass - flux_rs${XYZ}$_vf(j, k, l, 1) = F_hlld(1) ! TODO multi-component - ! Momentum - flux_rs${XYZ}$_vf(j, k, l, [contxe + dir_idx(1), contxe + dir_idx(2), contxe + dir_idx(3)]) = F_hlld([2, 3, 4]) - ! Magnetic field - if (n == 0) then - flux_rs${XYZ}$_vf(j, k, l, [B_idx%beg, B_idx%beg + 1]) = F_hlld([5, 6]) - else - flux_rs${XYZ}$_vf(j, k, l, [B_idx%beg + dir_idx(2) - 1, B_idx%beg + dir_idx(3) - 1]) = F_hlld([5, 6]) - end if - ! Energy - flux_rs${XYZ}$_vf(j, k, l, E_idx) = F_hlld(7) - ! Partial fraction - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - flux_rs${XYZ}$_vf(j, k, l, i) = 0._wp ! TODO multi-component (zero for now) - end do + ! (12) Reorder and write temporary variables to the flux array + ! Mass + flux_rs${XYZ}$_vf(j, k, l, 1) = F_hlld(1) ! TODO multi-component + ! Momentum + flux_rs${XYZ}$_vf(j, k, l, [contxe + dir_idx(1), contxe + dir_idx(2), contxe + dir_idx(3)]) = F_hlld([2, 3, 4]) + ! Magnetic field + if (n == 0) then + flux_rs${XYZ}$_vf(j, k, l, [B_idx%beg, B_idx%beg + 1]) = F_hlld([5, 6]) + else + flux_rs${XYZ}$_vf(j, k, l, [B_idx%beg + dir_idx(2) - 1, B_idx%beg + dir_idx(3) - 1]) = F_hlld([5, 6]) + end if + ! Energy + flux_rs${XYZ}$_vf(j, k, l, E_idx) = F_hlld(7) + ! Partial fraction + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe + flux_rs${XYZ}$_vf(j, k, l, i) = 0._wp ! TODO multi-component (zero for now) + end do - flux_src_rs${XYZ}$_vf(j, k, l, advxb) = 0._wp + flux_src_rs${XYZ}$_vf(j, k, l, advxb) = 0._wp + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:endfor @@ -3318,53 +3318,53 @@ contains if (bc_x%beg == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at beginning #:call GPU_PARALLEL_LOOP(collapse=3) - do i = 1, sys_size - do l = is3%beg, is3%end - do k = is2%beg, is2%end - qL_prim_rsx_vf(-1, k, l, i) = & - qR_prim_rsx_vf(0, k, l, i) + do i = 1, sys_size + do l = is3%beg, is3%end + do k = is2%beg, is2%end + qL_prim_rsx_vf(-1, k, l, i) = & + qR_prim_rsx_vf(0, k, l, i) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (viscous) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do k = isy%beg, isy%end + do i = momxb, momxe + do l = isz%beg, isz%end + do k = isy%beg, isy%end - dqL_prim_dx_vf(i)%sf(-1, k, l) = & - dqR_prim_dx_vf(i)%sf(0, k, l) + dqL_prim_dx_vf(i)%sf(-1, k, l) = & + dqR_prim_dx_vf(i)%sf(0, k, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (n > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do k = isy%beg, isy%end + do i = momxb, momxe + do l = isz%beg, isz%end + do k = isy%beg, isy%end - dqL_prim_dy_vf(i)%sf(-1, k, l) = & - dqR_prim_dy_vf(i)%sf(0, k, l) + dqL_prim_dy_vf(i)%sf(-1, k, l) = & + dqR_prim_dy_vf(i)%sf(0, k, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (p > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do k = isy%beg, isy%end + do i = momxb, momxe + do l = isz%beg, isz%end + do k = isy%beg, isy%end - dqL_prim_dz_vf(i)%sf(-1, k, l) = & - dqR_prim_dz_vf(i)%sf(0, k, l) + dqL_prim_dz_vf(i)%sf(-1, k, l) = & + dqR_prim_dz_vf(i)%sf(0, k, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -3377,54 +3377,54 @@ contains if (bc_x%end == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at end #:call GPU_PARALLEL_LOOP(collapse=3) - do i = 1, sys_size - do l = is3%beg, is3%end - do k = is2%beg, is2%end - qR_prim_rsx_vf(m + 1, k, l, i) = & - qL_prim_rsx_vf(m, k, l, i) + do i = 1, sys_size + do l = is3%beg, is3%end + do k = is2%beg, is2%end + qR_prim_rsx_vf(m + 1, k, l, i) = & + qL_prim_rsx_vf(m, k, l, i) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (viscous) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do k = isy%beg, isy%end + do i = momxb, momxe + do l = isz%beg, isz%end + do k = isy%beg, isy%end - dqR_prim_dx_vf(i)%sf(m + 1, k, l) = & - dqL_prim_dx_vf(i)%sf(m, k, l) + dqR_prim_dx_vf(i)%sf(m + 1, k, l) = & + dqL_prim_dx_vf(i)%sf(m, k, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (n > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do k = isy%beg, isy%end + do i = momxb, momxe + do l = isz%beg, isz%end + do k = isy%beg, isy%end - dqR_prim_dy_vf(i)%sf(m + 1, k, l) = & - dqL_prim_dy_vf(i)%sf(m, k, l) + dqR_prim_dy_vf(i)%sf(m + 1, k, l) = & + dqL_prim_dy_vf(i)%sf(m, k, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (p > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do k = isy%beg, isy%end + do i = momxb, momxe + do l = isz%beg, isz%end + do k = isy%beg, isy%end - dqR_prim_dz_vf(i)%sf(m + 1, k, l) = & - dqL_prim_dz_vf(i)%sf(m, k, l) + dqR_prim_dz_vf(i)%sf(m + 1, k, l) = & + dqL_prim_dz_vf(i)%sf(m, k, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -3440,50 +3440,50 @@ contains if (bc_y%beg == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at beginning #:call GPU_PARALLEL_LOOP(collapse=3) - do i = 1, sys_size - do l = is3%beg, is3%end - do k = is2%beg, is2%end - qL_prim_rsy_vf(-1, k, l, i) = & - qR_prim_rsy_vf(0, k, l, i) + do i = 1, sys_size + do l = is3%beg, is3%end + do k = is2%beg, is2%end + qL_prim_rsy_vf(-1, k, l, i) = & + qR_prim_rsy_vf(0, k, l, i) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (viscous) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do j = isx%beg, isx%end - dqL_prim_dx_vf(i)%sf(j, -1, l) = & - dqR_prim_dx_vf(i)%sf(j, 0, l) + do i = momxb, momxe + do l = isz%beg, isz%end + do j = isx%beg, isx%end + dqL_prim_dx_vf(i)%sf(j, -1, l) = & + dqR_prim_dx_vf(i)%sf(j, 0, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do j = isx%beg, isx%end - dqL_prim_dy_vf(i)%sf(j, -1, l) = & - dqR_prim_dy_vf(i)%sf(j, 0, l) + do i = momxb, momxe + do l = isz%beg, isz%end + do j = isx%beg, isx%end + dqL_prim_dy_vf(i)%sf(j, -1, l) = & + dqR_prim_dy_vf(i)%sf(j, 0, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (p > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do j = isx%beg, isx%end - dqL_prim_dz_vf(i)%sf(j, -1, l) = & - dqR_prim_dz_vf(i)%sf(j, 0, l) + do i = momxb, momxe + do l = isz%beg, isz%end + do j = isx%beg, isx%end + dqL_prim_dz_vf(i)%sf(j, -1, l) = & + dqR_prim_dz_vf(i)%sf(j, 0, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -3494,50 +3494,50 @@ contains if (bc_y%end == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at end #:call GPU_PARALLEL_LOOP(collapse=3) - do i = 1, sys_size - do l = is3%beg, is3%end - do k = is2%beg, is2%end - qR_prim_rsy_vf(n + 1, k, l, i) = & - qL_prim_rsy_vf(n, k, l, i) + do i = 1, sys_size + do l = is3%beg, is3%end + do k = is2%beg, is2%end + qR_prim_rsy_vf(n + 1, k, l, i) = & + qL_prim_rsy_vf(n, k, l, i) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (viscous) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do j = isx%beg, isx%end - dqR_prim_dx_vf(i)%sf(j, n + 1, l) = & - dqL_prim_dx_vf(i)%sf(j, n, l) + do i = momxb, momxe + do l = isz%beg, isz%end + do j = isx%beg, isx%end + dqR_prim_dx_vf(i)%sf(j, n + 1, l) = & + dqL_prim_dx_vf(i)%sf(j, n, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do j = isx%beg, isx%end - dqR_prim_dy_vf(i)%sf(j, n + 1, l) = & - dqL_prim_dy_vf(i)%sf(j, n, l) + do i = momxb, momxe + do l = isz%beg, isz%end + do j = isx%beg, isx%end + dqR_prim_dy_vf(i)%sf(j, n + 1, l) = & + dqL_prim_dy_vf(i)%sf(j, n, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (p > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do l = isz%beg, isz%end - do j = isx%beg, isx%end - dqR_prim_dz_vf(i)%sf(j, n + 1, l) = & - dqL_prim_dz_vf(i)%sf(j, n, l) + do i = momxb, momxe + do l = isz%beg, isz%end + do j = isx%beg, isx%end + dqR_prim_dz_vf(i)%sf(j, n + 1, l) = & + dqL_prim_dz_vf(i)%sf(j, n, l) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -3551,46 +3551,46 @@ contains if (bc_z%beg == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at beginning #:call GPU_PARALLEL_LOOP(collapse=3) - do i = 1, sys_size - do l = is3%beg, is3%end - do k = is2%beg, is2%end - qL_prim_rsz_vf(-1, k, l, i) = & - qR_prim_rsz_vf(0, k, l, i) + do i = 1, sys_size + do l = is3%beg, is3%end + do k = is2%beg, is2%end + qL_prim_rsz_vf(-1, k, l, i) = & + qR_prim_rsz_vf(0, k, l, i) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (viscous) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do k = isy%beg, isy%end - do j = isx%beg, isx%end - dqL_prim_dx_vf(i)%sf(j, k, -1) = & - dqR_prim_dx_vf(i)%sf(j, k, 0) + do i = momxb, momxe + do k = isy%beg, isy%end + do j = isx%beg, isx%end + dqL_prim_dx_vf(i)%sf(j, k, -1) = & + dqR_prim_dx_vf(i)%sf(j, k, 0) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do k = isy%beg, isy%end - do j = isx%beg, isx%end - dqL_prim_dy_vf(i)%sf(j, k, -1) = & - dqR_prim_dy_vf(i)%sf(j, k, 0) + do i = momxb, momxe + do k = isy%beg, isy%end + do j = isx%beg, isx%end + dqL_prim_dy_vf(i)%sf(j, k, -1) = & + dqR_prim_dy_vf(i)%sf(j, k, 0) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do k = isy%beg, isy%end - do j = isx%beg, isx%end - dqL_prim_dz_vf(i)%sf(j, k, -1) = & - dqR_prim_dz_vf(i)%sf(j, k, 0) + do i = momxb, momxe + do k = isy%beg, isy%end + do j = isx%beg, isx%end + dqL_prim_dz_vf(i)%sf(j, k, -1) = & + dqR_prim_dz_vf(i)%sf(j, k, 0) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -3599,48 +3599,48 @@ contains if (bc_z%end == BC_RIEMANN_EXTRAP) then ! Riemann state extrap. BC at end #:call GPU_PARALLEL_LOOP(collapse=3) - do i = 1, sys_size - do l = is3%beg, is3%end - do k = is2%beg, is2%end - qR_prim_rsz_vf(p + 1, k, l, i) = & - qL_prim_rsz_vf(p, k, l, i) + do i = 1, sys_size + do l = is3%beg, is3%end + do k = is2%beg, is2%end + qR_prim_rsz_vf(p + 1, k, l, i) = & + qL_prim_rsz_vf(p, k, l, i) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (viscous) then #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do k = isy%beg, isy%end - do j = isx%beg, isx%end - dqR_prim_dx_vf(i)%sf(j, k, p + 1) = & - dqL_prim_dx_vf(i)%sf(j, k, p) + do i = momxb, momxe + do k = isy%beg, isy%end + do j = isx%beg, isx%end + dqR_prim_dx_vf(i)%sf(j, k, p + 1) = & + dqL_prim_dx_vf(i)%sf(j, k, p) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do k = isy%beg, isy%end - do j = isx%beg, isx%end - dqR_prim_dy_vf(i)%sf(j, k, p + 1) = & - dqL_prim_dy_vf(i)%sf(j, k, p) + do i = momxb, momxe + do k = isy%beg, isy%end + do j = isx%beg, isx%end + dqR_prim_dy_vf(i)%sf(j, k, p + 1) = & + dqL_prim_dy_vf(i)%sf(j, k, p) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do i = momxb, momxe - do k = isy%beg, isy%end - do j = isx%beg, isx%end - dqR_prim_dz_vf(i)%sf(j, k, p + 1) = & - dqL_prim_dz_vf(i)%sf(j, k, p) + do i = momxb, momxe + do k = isy%beg, isy%end + do j = isx%beg, isx%end + dqR_prim_dz_vf(i)%sf(j, k, p + 1) = & + dqL_prim_dz_vf(i)%sf(j, k, p) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -3686,30 +3686,30 @@ contains if (viscous .or. (surface_tension)) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = momxb, E_idx - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - flux_src_vf(i)%sf(j, k, l) = 0._wp + do i = momxb, E_idx + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + flux_src_vf(i)%sf(j, k, l) = 0._wp + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (qbmm) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, 4 - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end + 1 - mom_sp_rsx_vf(j, k, l, i) = mom_sp(i)%sf(j, k, l) + do i = 1, 4 + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + 1 + mom_sp_rsx_vf(j, k, l, i) = mom_sp(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -3718,29 +3718,29 @@ contains if (viscous .or. (surface_tension)) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = momxb, E_idx - do l = is3%beg, is3%end - do j = is1%beg, is1%end - do k = is2%beg, is2%end - flux_src_vf(i)%sf(k, j, l) = 0._wp + do i = momxb, E_idx + do l = is3%beg, is3%end + do j = is1%beg, is1%end + do k = is2%beg, is2%end + flux_src_vf(i)%sf(k, j, l) = 0._wp + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (qbmm) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, 4 - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end + 1 - mom_sp_rsy_vf(j, k, l, i) = mom_sp(i)%sf(k, j, l) + do i = 1, 4 + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + 1 + mom_sp_rsy_vf(j, k, l, i) = mom_sp(i)%sf(k, j, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -3749,29 +3749,29 @@ contains if (viscous .or. (surface_tension)) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = momxb, E_idx - do j = is1%beg, is1%end - do k = is2%beg, is2%end - do l = is3%beg, is3%end - flux_src_vf(i)%sf(l, k, j) = 0._wp + do i = momxb, E_idx + do j = is1%beg, is1%end + do k = is2%beg, is2%end + do l = is3%beg, is3%end + flux_src_vf(i)%sf(l, k, j) = 0._wp + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (qbmm) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, 4 - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end + 1 - mom_sp_rsz_vf(j, k, l, i) = mom_sp(i)%sf(l, k, j) + do i = 1, 4 + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + 1 + mom_sp_rsz_vf(j, k, l, i) = mom_sp(i)%sf(l, k, j) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -3797,10 +3797,10 @@ contains !! @param[in] iy Global Y-direction loop bounds (int_bounds_info). !! @param[in] iz Global Z-direction loop bounds (int_bounds_info). subroutine s_compute_cylindrical_viscous_source_flux(velL_vf, & - dvelL_dx_vf, dvelL_dy_vf, dvelL_dz_vf, & - velR_vf, & - dvelR_dx_vf, dvelR_dy_vf, dvelR_dz_vf, & - flux_src_vf, norm_dir, ix, iy, iz) + dvelL_dx_vf, dvelL_dy_vf, dvelL_dz_vf, & + velR_vf, & + dvelR_dx_vf, dvelR_dy_vf, dvelR_dz_vf, & + flux_src_vf, norm_dir, ix, iy, iz) type(scalar_field), dimension(num_dims), intent(in) :: velL_vf, velR_vf type(scalar_field), dimension(num_dims), intent(in) :: dvelL_dx_vf, dvelR_dx_vf @@ -3830,111 +3830,111 @@ contains integer :: idx_rp(3) !!< Indices $(j,k,l)$ of 'right' point for averaging. #:call GPU_PARALLEL_LOOP(collapse=3, private='[idx_rp, avg_v_int, avg_dvdx_int, avg_dvdy_int, avg_dvdz_int, Re_s, Re_b, vel_src_int, r_eff, divergence_cyl, stress_vector_shear, stress_normal_bulk, div_v_term_const]') - do l = iz%beg, iz%end - do k = iy%beg, iy%end - do j = ix%beg, ix%end - - ! Determine indices for the 'right' state for averaging across the interface - idx_rp = [j, k, l] - idx_rp(norm_dir) = idx_rp(norm_dir) + 1 - - ! Average velocities and their derivatives at the interface - ! For cylindrical: x-dir ~ axial (z_cyl), y-dir ~ radial (r_cyl), z-dir ~ azimuthal (theta_cyl) - $:GPU_LOOP(parallelism='[seq]') - do i_vel = 1, num_dims - avg_v_int(i_vel) = 0.5_wp*(velL_vf(i_vel)%sf(j, k, l) + velR_vf(i_vel)%sf(idx_rp(1), idx_rp(2), idx_rp(3))) - - avg_dvdx_int(i_vel) = 0.5_wp*(dvelL_dx_vf(i_vel)%sf(j, k, l) + & - dvelR_dx_vf(i_vel)%sf(idx_rp(1), idx_rp(2), idx_rp(3))) - if (num_dims > 1) then - avg_dvdy_int(i_vel) = 0.5_wp*(dvelL_dy_vf(i_vel)%sf(j, k, l) + & - dvelR_dy_vf(i_vel)%sf(idx_rp(1), idx_rp(2), idx_rp(3))) - else - avg_dvdy_int(i_vel) = 0.0_wp - end if - if (num_dims > 2) then - avg_dvdz_int(i_vel) = 0.5_wp*(dvelL_dz_vf(i_vel)%sf(j, k, l) + & - dvelR_dz_vf(i_vel)%sf(idx_rp(1), idx_rp(2), idx_rp(3))) - else - avg_dvdz_int(i_vel) = 0.0_wp - end if - end do - - ! Get Re numbers and interface velocity for viscous work - select case (norm_dir) - case (1) ! x-face (axial face in z_cyl direction) - Re_s = Re_avg_rsx_vf(j, k, l, 1) - Re_b = Re_avg_rsx_vf(j, k, l, 2) - vel_src_int = vel_src_rsx_vf(j, k, l, 1:num_dims) - r_eff = y_cc(k) - case (2) ! y-face (radial face in r_cyl direction) - Re_s = Re_avg_rsy_vf(k, j, l, 1) - Re_b = Re_avg_rsy_vf(k, j, l, 2) - vel_src_int = vel_src_rsy_vf(k, j, l, 1:num_dims) - r_eff = y_cb(k) - case (3) ! z-face (azimuthal face in theta_cyl direction) - Re_s = Re_avg_rsz_vf(l, k, j, 1) - Re_b = Re_avg_rsz_vf(l, k, j, 2) - vel_src_int = vel_src_rsz_vf(l, k, j, 1:num_dims) - r_eff = y_cc(k) - end select - - ! Divergence in cylindrical coordinates (vx=vz_cyl, vy=vr_cyl, vz=vtheta_cyl) - divergence_cyl = avg_dvdx_int(1) + avg_dvdy_int(2) + avg_v_int(2)/r_eff - if (num_dims > 2) then - divergence_cyl = divergence_cyl + avg_dvdz_int(3)/r_eff - end if + do l = iz%beg, iz%end + do k = iy%beg, iy%end + do j = ix%beg, ix%end - stress_vector_shear = 0.0_wp - stress_normal_bulk = 0.0_wp + ! Determine indices for the 'right' state for averaging across the interface + idx_rp = [j, k, l] + idx_rp(norm_dir) = idx_rp(norm_dir) + 1 - if (shear_stress) then - div_v_term_const = -(2.0_wp/3.0_wp)*divergence_cyl/Re_s + ! Average velocities and their derivatives at the interface + ! For cylindrical: x-dir ~ axial (z_cyl), y-dir ~ radial (r_cyl), z-dir ~ azimuthal (theta_cyl) + $:GPU_LOOP(parallelism='[seq]') + do i_vel = 1, num_dims + avg_v_int(i_vel) = 0.5_wp*(velL_vf(i_vel)%sf(j, k, l) + velR_vf(i_vel)%sf(idx_rp(1), idx_rp(2), idx_rp(3))) - select case (norm_dir) - case (1) ! X-face (axial normal, z_cyl) - stress_vector_shear(1) = (2.0_wp*avg_dvdx_int(1))/Re_s + div_v_term_const - if (num_dims > 1) then - stress_vector_shear(2) = (avg_dvdy_int(1) + avg_dvdx_int(2))/Re_s - end if - if (num_dims > 2) then - stress_vector_shear(3) = (avg_dvdz_int(1)/r_eff + avg_dvdx_int(3))/Re_s - end if - case (2) ! Y-face (radial normal, r_cyl) + avg_dvdx_int(i_vel) = 0.5_wp*(dvelL_dx_vf(i_vel)%sf(j, k, l) + & + dvelR_dx_vf(i_vel)%sf(idx_rp(1), idx_rp(2), idx_rp(3))) if (num_dims > 1) then - stress_vector_shear(1) = (avg_dvdy_int(1) + avg_dvdx_int(2))/Re_s - stress_vector_shear(2) = (2.0_wp*avg_dvdy_int(2))/Re_s + div_v_term_const - if (num_dims > 2) then - stress_vector_shear(3) = (avg_dvdz_int(2)/r_eff - avg_v_int(3)/r_eff + avg_dvdy_int(3))/Re_s - end if + avg_dvdy_int(i_vel) = 0.5_wp*(dvelL_dy_vf(i_vel)%sf(j, k, l) + & + dvelR_dy_vf(i_vel)%sf(idx_rp(1), idx_rp(2), idx_rp(3))) else - stress_vector_shear(1) = (2.0_wp*avg_dvdx_int(1))/Re_s + div_v_term_const + avg_dvdy_int(i_vel) = 0.0_wp end if - case (3) ! Z-face (azimuthal normal, theta_cyl) if (num_dims > 2) then - stress_vector_shear(1) = (avg_dvdz_int(1)/r_eff + avg_dvdx_int(3))/Re_s - stress_vector_shear(2) = (avg_dvdz_int(2)/r_eff - avg_v_int(3)/r_eff + avg_dvdy_int(3))/Re_s - stress_vector_shear(3) = (2.0_wp*(avg_dvdz_int(3)/r_eff + avg_v_int(2)/r_eff))/Re_s + div_v_term_const + avg_dvdz_int(i_vel) = 0.5_wp*(dvelL_dz_vf(i_vel)%sf(j, k, l) + & + dvelR_dz_vf(i_vel)%sf(idx_rp(1), idx_rp(2), idx_rp(3))) + else + avg_dvdz_int(i_vel) = 0.0_wp end if + end do + + ! Get Re numbers and interface velocity for viscous work + select case (norm_dir) + case (1) ! x-face (axial face in z_cyl direction) + Re_s = Re_avg_rsx_vf(j, k, l, 1) + Re_b = Re_avg_rsx_vf(j, k, l, 2) + vel_src_int = vel_src_rsx_vf(j, k, l, 1:num_dims) + r_eff = y_cc(k) + case (2) ! y-face (radial face in r_cyl direction) + Re_s = Re_avg_rsy_vf(k, j, l, 1) + Re_b = Re_avg_rsy_vf(k, j, l, 2) + vel_src_int = vel_src_rsy_vf(k, j, l, 1:num_dims) + r_eff = y_cb(k) + case (3) ! z-face (azimuthal face in theta_cyl direction) + Re_s = Re_avg_rsz_vf(l, k, j, 1) + Re_b = Re_avg_rsz_vf(l, k, j, 2) + vel_src_int = vel_src_rsz_vf(l, k, j, 1:num_dims) + r_eff = y_cc(k) end select - $:GPU_LOOP(parallelism='[seq]') - do i_vel = 1, num_dims - flux_src_vf(momxb + i_vel - 1)%sf(j, k, l) = flux_src_vf(momxb + i_vel - 1)%sf(j, k, l) - stress_vector_shear(i_vel) - flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) - vel_src_int(i_vel)*stress_vector_shear(i_vel) - end do - end if + ! Divergence in cylindrical coordinates (vx=vz_cyl, vy=vr_cyl, vz=vtheta_cyl) + divergence_cyl = avg_dvdx_int(1) + avg_dvdy_int(2) + avg_v_int(2)/r_eff + if (num_dims > 2) then + divergence_cyl = divergence_cyl + avg_dvdz_int(3)/r_eff + end if - if (bulk_stress) then - stress_normal_bulk = divergence_cyl/Re_b + stress_vector_shear = 0.0_wp + stress_normal_bulk = 0.0_wp - flux_src_vf(momxb + norm_dir - 1)%sf(j, k, l) = flux_src_vf(momxb + norm_dir - 1)%sf(j, k, l) - stress_normal_bulk - flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) - vel_src_int(norm_dir)*stress_normal_bulk - end if + if (shear_stress) then + div_v_term_const = -(2.0_wp/3.0_wp)*divergence_cyl/Re_s + + select case (norm_dir) + case (1) ! X-face (axial normal, z_cyl) + stress_vector_shear(1) = (2.0_wp*avg_dvdx_int(1))/Re_s + div_v_term_const + if (num_dims > 1) then + stress_vector_shear(2) = (avg_dvdy_int(1) + avg_dvdx_int(2))/Re_s + end if + if (num_dims > 2) then + stress_vector_shear(3) = (avg_dvdz_int(1)/r_eff + avg_dvdx_int(3))/Re_s + end if + case (2) ! Y-face (radial normal, r_cyl) + if (num_dims > 1) then + stress_vector_shear(1) = (avg_dvdy_int(1) + avg_dvdx_int(2))/Re_s + stress_vector_shear(2) = (2.0_wp*avg_dvdy_int(2))/Re_s + div_v_term_const + if (num_dims > 2) then + stress_vector_shear(3) = (avg_dvdz_int(2)/r_eff - avg_v_int(3)/r_eff + avg_dvdy_int(3))/Re_s + end if + else + stress_vector_shear(1) = (2.0_wp*avg_dvdx_int(1))/Re_s + div_v_term_const + end if + case (3) ! Z-face (azimuthal normal, theta_cyl) + if (num_dims > 2) then + stress_vector_shear(1) = (avg_dvdz_int(1)/r_eff + avg_dvdx_int(3))/Re_s + stress_vector_shear(2) = (avg_dvdz_int(2)/r_eff - avg_v_int(3)/r_eff + avg_dvdy_int(3))/Re_s + stress_vector_shear(3) = (2.0_wp*(avg_dvdz_int(3)/r_eff + avg_v_int(2)/r_eff))/Re_s + div_v_term_const + end if + end select + + $:GPU_LOOP(parallelism='[seq]') + do i_vel = 1, num_dims + flux_src_vf(momxb + i_vel - 1)%sf(j, k, l) = flux_src_vf(momxb + i_vel - 1)%sf(j, k, l) - stress_vector_shear(i_vel) + flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) - vel_src_int(i_vel)*stress_vector_shear(i_vel) + end do + end if + + if (bulk_stress) then + stress_normal_bulk = divergence_cyl/Re_b + + flux_src_vf(momxb + norm_dir - 1)%sf(j, k, l) = flux_src_vf(momxb + norm_dir - 1)%sf(j, k, l) - stress_normal_bulk + flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) - vel_src_int(norm_dir)*stress_normal_bulk + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_cylindrical_viscous_source_flux @@ -3956,13 +3956,13 @@ contains !! @param[in] iy Y-direction loop bounds (int_bounds_info). !! @param[in] iz Z-direction loop bounds (int_bounds_info). subroutine s_compute_cartesian_viscous_source_flux(dvelL_dx_vf, & - dvelL_dy_vf, & - dvelL_dz_vf, & - dvelR_dx_vf, & - dvelR_dy_vf, & - dvelR_dz_vf, & - flux_src_vf, & - norm_dir) + dvelL_dy_vf, & + dvelL_dz_vf, & + dvelR_dx_vf, & + dvelR_dy_vf, & + dvelR_dz_vf, & + flux_src_vf, & + norm_dir) ! Arguments type(scalar_field), dimension(num_dims), intent(in) :: dvelL_dx_vf, dvelR_dx_vf @@ -3990,86 +3990,86 @@ contains real(wp) :: divergence_v !< Velocity divergence at interface. #:call GPU_PARALLEL_LOOP(collapse=3, private='[idx_right_phys, vel_grad_avg, current_tau_shear, current_tau_bulk, vel_src_at_interface, Re_shear, Re_bulk, divergence_v, i_dim, vel_comp_idx]') - do l_loop = isz%beg, isz%end - do k_loop = isy%beg, isy%end - do j_loop = isx%beg, isx%end - - idx_right_phys(1) = j_loop - idx_right_phys(2) = k_loop - idx_right_phys(3) = l_loop - idx_right_phys(norm_dir) = idx_right_phys(norm_dir) + 1 - - vel_grad_avg = 0.0_wp - do vel_comp_idx = 1, num_dims - vel_grad_avg(vel_comp_idx, 1) = 0.5_wp*(dvelL_dx_vf(vel_comp_idx)%sf(j_loop, k_loop, l_loop) + & - dvelR_dx_vf(vel_comp_idx)%sf(idx_right_phys(1), idx_right_phys(2), idx_right_phys(3))) - if (num_dims > 1) then - vel_grad_avg(vel_comp_idx, 2) = 0.5_wp*(dvelL_dy_vf(vel_comp_idx)%sf(j_loop, k_loop, l_loop) + & - dvelR_dy_vf(vel_comp_idx)%sf(idx_right_phys(1), idx_right_phys(2), idx_right_phys(3))) - end if - if (num_dims > 2) then - vel_grad_avg(vel_comp_idx, 3) = 0.5_wp*(dvelL_dz_vf(vel_comp_idx)%sf(j_loop, k_loop, l_loop) + & - dvelR_dz_vf(vel_comp_idx)%sf(idx_right_phys(1), idx_right_phys(2), idx_right_phys(3))) - end if - end do - - divergence_v = 0.0_wp - do i_dim = 1, num_dims - divergence_v = divergence_v + vel_grad_avg(i_dim, i_dim) - end do - - vel_src_at_interface = 0.0_wp - if (norm_dir == 1) then - Re_shear = Re_avg_rsx_vf(j_loop, k_loop, l_loop, 1) - Re_bulk = Re_avg_rsx_vf(j_loop, k_loop, l_loop, 2) - do i_dim = 1, num_dims - vel_src_at_interface(i_dim) = vel_src_rsx_vf(j_loop, k_loop, l_loop, i_dim) - end do - else if (norm_dir == 2) then - Re_shear = Re_avg_rsy_vf(k_loop, j_loop, l_loop, 1) - Re_bulk = Re_avg_rsy_vf(k_loop, j_loop, l_loop, 2) - do i_dim = 1, num_dims - vel_src_at_interface(i_dim) = vel_src_rsy_vf(k_loop, j_loop, l_loop, i_dim) + do l_loop = isz%beg, isz%end + do k_loop = isy%beg, isy%end + do j_loop = isx%beg, isx%end + + idx_right_phys(1) = j_loop + idx_right_phys(2) = k_loop + idx_right_phys(3) = l_loop + idx_right_phys(norm_dir) = idx_right_phys(norm_dir) + 1 + + vel_grad_avg = 0.0_wp + do vel_comp_idx = 1, num_dims + vel_grad_avg(vel_comp_idx, 1) = 0.5_wp*(dvelL_dx_vf(vel_comp_idx)%sf(j_loop, k_loop, l_loop) + & + dvelR_dx_vf(vel_comp_idx)%sf(idx_right_phys(1), idx_right_phys(2), idx_right_phys(3))) + if (num_dims > 1) then + vel_grad_avg(vel_comp_idx, 2) = 0.5_wp*(dvelL_dy_vf(vel_comp_idx)%sf(j_loop, k_loop, l_loop) + & + dvelR_dy_vf(vel_comp_idx)%sf(idx_right_phys(1), idx_right_phys(2), idx_right_phys(3))) + end if + if (num_dims > 2) then + vel_grad_avg(vel_comp_idx, 3) = 0.5_wp*(dvelL_dz_vf(vel_comp_idx)%sf(j_loop, k_loop, l_loop) + & + dvelR_dz_vf(vel_comp_idx)%sf(idx_right_phys(1), idx_right_phys(2), idx_right_phys(3))) + end if end do - else - Re_shear = Re_avg_rsz_vf(l_loop, k_loop, j_loop, 1) - Re_bulk = Re_avg_rsz_vf(l_loop, k_loop, j_loop, 2) + + divergence_v = 0.0_wp do i_dim = 1, num_dims - vel_src_at_interface(i_dim) = vel_src_rsz_vf(l_loop, k_loop, j_loop, i_dim) + divergence_v = divergence_v + vel_grad_avg(i_dim, i_dim) end do - end if - if (shear_stress) then - ! current_tau_shear = 0.0_wp - call s_calculate_shear_stress_tensor(vel_grad_avg, Re_shear, divergence_v, current_tau_shear) + vel_src_at_interface = 0.0_wp + if (norm_dir == 1) then + Re_shear = Re_avg_rsx_vf(j_loop, k_loop, l_loop, 1) + Re_bulk = Re_avg_rsx_vf(j_loop, k_loop, l_loop, 2) + do i_dim = 1, num_dims + vel_src_at_interface(i_dim) = vel_src_rsx_vf(j_loop, k_loop, l_loop, i_dim) + end do + else if (norm_dir == 2) then + Re_shear = Re_avg_rsy_vf(k_loop, j_loop, l_loop, 1) + Re_bulk = Re_avg_rsy_vf(k_loop, j_loop, l_loop, 2) + do i_dim = 1, num_dims + vel_src_at_interface(i_dim) = vel_src_rsy_vf(k_loop, j_loop, l_loop, i_dim) + end do + else + Re_shear = Re_avg_rsz_vf(l_loop, k_loop, j_loop, 1) + Re_bulk = Re_avg_rsz_vf(l_loop, k_loop, j_loop, 2) + do i_dim = 1, num_dims + vel_src_at_interface(i_dim) = vel_src_rsz_vf(l_loop, k_loop, j_loop, i_dim) + end do + end if + + if (shear_stress) then + ! current_tau_shear = 0.0_wp + call s_calculate_shear_stress_tensor(vel_grad_avg, Re_shear, divergence_v, current_tau_shear) - do i_dim = 1, num_dims - flux_src_vf(momxb + i_dim - 1)%sf(j_loop, k_loop, l_loop) = & - flux_src_vf(momxb + i_dim - 1)%sf(j_loop, k_loop, l_loop) - current_tau_shear(norm_dir, i_dim) + do i_dim = 1, num_dims + flux_src_vf(momxb + i_dim - 1)%sf(j_loop, k_loop, l_loop) = & + flux_src_vf(momxb + i_dim - 1)%sf(j_loop, k_loop, l_loop) - current_tau_shear(norm_dir, i_dim) - flux_src_vf(E_idx)%sf(j_loop, k_loop, l_loop) = & - flux_src_vf(E_idx)%sf(j_loop, k_loop, l_loop) - & - vel_src_at_interface(i_dim)*current_tau_shear(norm_dir, i_dim) - end do - end if + flux_src_vf(E_idx)%sf(j_loop, k_loop, l_loop) = & + flux_src_vf(E_idx)%sf(j_loop, k_loop, l_loop) - & + vel_src_at_interface(i_dim)*current_tau_shear(norm_dir, i_dim) + end do + end if - if (bulk_stress) then - ! current_tau_bulk = 0.0_wp - call s_calculate_bulk_stress_tensor(Re_bulk, divergence_v, current_tau_bulk) + if (bulk_stress) then + ! current_tau_bulk = 0.0_wp + call s_calculate_bulk_stress_tensor(Re_bulk, divergence_v, current_tau_bulk) - do i_dim = 1, num_dims - flux_src_vf(momxb + i_dim - 1)%sf(j_loop, k_loop, l_loop) = & - flux_src_vf(momxb + i_dim - 1)%sf(j_loop, k_loop, l_loop) - current_tau_bulk(norm_dir, i_dim) + do i_dim = 1, num_dims + flux_src_vf(momxb + i_dim - 1)%sf(j_loop, k_loop, l_loop) = & + flux_src_vf(momxb + i_dim - 1)%sf(j_loop, k_loop, l_loop) - current_tau_bulk(norm_dir, i_dim) - flux_src_vf(E_idx)%sf(j_loop, k_loop, l_loop) = & - flux_src_vf(E_idx)%sf(j_loop, k_loop, l_loop) - & - vel_src_at_interface(i_dim)*current_tau_bulk(norm_dir, i_dim) - end do - end if + flux_src_vf(E_idx)%sf(j_loop, k_loop, l_loop) = & + flux_src_vf(E_idx)%sf(j_loop, k_loop, l_loop) - & + vel_src_at_interface(i_dim)*current_tau_bulk(norm_dir, i_dim) + end do + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_cartesian_viscous_source_flux @@ -4142,8 +4142,8 @@ contains !! @param flux_gsrc_vf Intercell geometric source fluxes !! @param norm_dir Dimensional splitting coordinate direction subroutine s_finalize_riemann_solver(flux_vf, flux_src_vf, & - flux_gsrc_vf, & - norm_dir) + flux_gsrc_vf, & + norm_dir) type(scalar_field), & dimension(sys_size), & @@ -4156,153 +4156,153 @@ contains ! Reshaping Outputted Data in y-direction if (norm_dir == 2) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = is3%beg, is3%end - do j = is1%beg, is1%end - do k = is2%beg, is2%end - flux_vf(i)%sf(k, j, l) = & - flux_rsy_vf(j, k, l, i) + do i = 1, sys_size + do l = is3%beg, is3%end + do j = is1%beg, is1%end + do k = is2%beg, is2%end + flux_vf(i)%sf(k, j, l) = & + flux_rsy_vf(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (cyl_coord) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = is3%beg, is3%end - do j = is1%beg, is1%end - do k = is2%beg, is2%end - flux_gsrc_vf(i)%sf(k, j, l) = & - flux_gsrc_rsy_vf(j, k, l, i) + do i = 1, sys_size + do l = is3%beg, is3%end + do j = is1%beg, is1%end + do k = is2%beg, is2%end + flux_gsrc_vf(i)%sf(k, j, l) = & + flux_gsrc_rsy_vf(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3%beg, is3%end - do j = is1%beg, is1%end - do k = is2%beg, is2%end - flux_src_vf(advxb)%sf(k, j, l) = & - flux_src_rsy_vf(j, k, l, advxb) + do l = is3%beg, is3%end + do j = is1%beg, is1%end + do k = is2%beg, is2%end + flux_src_vf(advxb)%sf(k, j, l) = & + flux_src_rsy_vf(j, k, l, advxb) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1 .or. riemann_solver == 4) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = advxb + 1, advxe - do l = is3%beg, is3%end - do j = is1%beg, is1%end - do k = is2%beg, is2%end - flux_src_vf(i)%sf(k, j, l) = & - flux_src_rsy_vf(j, k, l, i) + do i = advxb + 1, advxe + do l = is3%beg, is3%end + do j = is1%beg, is1%end + do k = is2%beg, is2%end + flux_src_vf(i)%sf(k, j, l) = & + flux_src_rsy_vf(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if ! Reshaping Outputted Data in z-direction elseif (norm_dir == 3) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do j = is1%beg, is1%end - do k = is2%beg, is2%end - do l = is3%beg, is3%end + do i = 1, sys_size + do j = is1%beg, is1%end + do k = is2%beg, is2%end + do l = is3%beg, is3%end - flux_vf(i)%sf(l, k, j) = & - flux_rsz_vf(j, k, l, i) + flux_vf(i)%sf(l, k, j) = & + flux_rsz_vf(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (grid_geometry == 3) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do j = is1%beg, is1%end - do k = is2%beg, is2%end - do l = is3%beg, is3%end + do i = 1, sys_size + do j = is1%beg, is1%end + do k = is2%beg, is2%end + do l = is3%beg, is3%end - flux_gsrc_vf(i)%sf(l, k, j) = & - flux_gsrc_rsz_vf(j, k, l, i) + flux_gsrc_vf(i)%sf(l, k, j) = & + flux_gsrc_rsz_vf(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:call GPU_PARALLEL_LOOP(collapse=3) - do j = is1%beg, is1%end - do k = is2%beg, is2%end - do l = is3%beg, is3%end - flux_src_vf(advxb)%sf(l, k, j) = & - flux_src_rsz_vf(j, k, l, advxb) + do j = is1%beg, is1%end + do k = is2%beg, is2%end + do l = is3%beg, is3%end + flux_src_vf(advxb)%sf(l, k, j) = & + flux_src_rsz_vf(j, k, l, advxb) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1 .or. riemann_solver == 4) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = advxb + 1, advxe - do j = is1%beg, is1%end - do k = is2%beg, is2%end - do l = is3%beg, is3%end - flux_src_vf(i)%sf(l, k, j) = & - flux_src_rsz_vf(j, k, l, i) + do i = advxb + 1, advxe + do j = is1%beg, is1%end + do k = is2%beg, is2%end + do l = is3%beg, is3%end + flux_src_vf(i)%sf(l, k, j) = & + flux_src_rsz_vf(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if elseif (norm_dir == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - flux_vf(i)%sf(j, k, l) = & - flux_rsx_vf(j, k, l, i) + do i = 1, sys_size + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + flux_vf(i)%sf(j, k, l) = & + flux_rsx_vf(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - flux_src_vf(advxb)%sf(j, k, l) = & - flux_src_rsx_vf(j, k, l, advxb) + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + flux_src_vf(advxb)%sf(j, k, l) = & + flux_src_rsx_vf(j, k, l, advxb) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (riemann_solver == 1 .or. riemann_solver == 4) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = advxb + 1, advxe - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - flux_src_vf(i)%sf(j, k, l) = & - flux_src_rsx_vf(j, k, l, i) + do i = advxb + 1, advxe + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + flux_src_vf(i)%sf(j, k, l) = & + flux_src_rsx_vf(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if diff --git a/src/simulation/m_surface_tension.fpp b/src/simulation/m_surface_tension.fpp index c817f7cce5..84c09ab6f5 100644 --- a/src/simulation/m_surface_tension.fpp +++ b/src/simulation/m_surface_tension.fpp @@ -86,139 +86,139 @@ contains if (id == 1) then #:call GPU_PARALLEL_LOOP(collapse=3, private='[Omega, w1L, w2L, w3L, w1R, w2R, w3R, w1, w2, w3, normWL, normWR, normW]') - do l = isz%beg, isz%end - do k = isy%beg, isy%end - do j = isx%beg, isx%end + do l = isz%beg, isz%end + do k = isy%beg, isy%end + do j = isx%beg, isx%end - w1L = gL_x(j, k, l, 1) - w2L = gL_x(j, k, l, 2) - w3L = 0._wp - if (p > 0) w3L = gL_x(j, k, l, 3) + w1L = gL_x(j, k, l, 1) + w2L = gL_x(j, k, l, 2) + w3L = 0._wp + if (p > 0) w3L = gL_x(j, k, l, 3) - w1R = gR_x(j + 1, k, l, 1) - w2R = gR_x(j + 1, k, l, 2) - w3R = 0._wp - if (p > 0) w3R = gR_x(j + 1, k, l, 3) + w1R = gR_x(j + 1, k, l, 1) + w2R = gR_x(j + 1, k, l, 2) + w3R = 0._wp + if (p > 0) w3R = gR_x(j + 1, k, l, 3) - normWL = gL_x(j, k, l, num_dims + 1) - normWR = gR_x(j + 1, k, l, num_dims + 1) + normWL = gL_x(j, k, l, num_dims + 1) + normWR = gR_x(j + 1, k, l, num_dims + 1) - w1 = (w1L + w1R)/2._wp - w2 = (w2L + w2R)/2._wp - w3 = (w3L + w3R)/2._wp - normW = (normWL + normWR)/2._wp + w1 = (w1L + w1R)/2._wp + w2 = (w2L + w2R)/2._wp + w3 = (w3L + w3R)/2._wp + normW = (normWL + normWR)/2._wp if (normW > capillary_cutoff) then @:compute_capillary_stress_tensor() - do i = 1, num_dims + do i = 1, num_dims - flux_src_vf(momxb + i - 1)%sf(j, k, l) = & - flux_src_vf(momxb + i - 1)%sf(j, k, l) + Omega(1, i) + flux_src_vf(momxb + i - 1)%sf(j, k, l) = & + flux_src_vf(momxb + i - 1)%sf(j, k, l) + Omega(1, i) - flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & - Omega(1, i)*vSrc_rsx_vf(j, k, l, i) + flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & + Omega(1, i)*vSrc_rsx_vf(j, k, l, i) - end do + end do - flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & - sigma*c_divs(num_dims + 1)%sf(j, k, l)*vSrc_rsx_vf(j, k, l, 1) - end if + flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & + sigma*c_divs(num_dims + 1)%sf(j, k, l)*vSrc_rsx_vf(j, k, l, 1) + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (id == 2) then #:call GPU_PARALLEL_LOOP(collapse=3, private='[Omega, w1L, w2L, w3L, w1R, w2R, w3R, w1, w2, w3, normWL, normWR, normW]') - do l = isz%beg, isz%end - do k = isy%beg, isy%end - do j = isx%beg, isx%end + do l = isz%beg, isz%end + do k = isy%beg, isy%end + do j = isx%beg, isx%end - w1L = gL_y(k, j, l, 1) - w2L = gL_y(k, j, l, 2) - w3L = 0._wp - if (p > 0) w3L = gL_y(k, j, l, 3) + w1L = gL_y(k, j, l, 1) + w2L = gL_y(k, j, l, 2) + w3L = 0._wp + if (p > 0) w3L = gL_y(k, j, l, 3) - w1R = gR_y(k + 1, j, l, 1) - w2R = gR_y(k + 1, j, l, 2) - w3R = 0._wp - if (p > 0) w3R = gR_y(k + 1, j, l, 3) + w1R = gR_y(k + 1, j, l, 1) + w2R = gR_y(k + 1, j, l, 2) + w3R = 0._wp + if (p > 0) w3R = gR_y(k + 1, j, l, 3) - normWL = gL_y(k, j, l, num_dims + 1) - normWR = gR_y(k + 1, j, l, num_dims + 1) + normWL = gL_y(k, j, l, num_dims + 1) + normWR = gR_y(k + 1, j, l, num_dims + 1) - w1 = (w1L + w1R)/2._wp - w2 = (w2L + w2R)/2._wp - w3 = (w3L + w3R)/2._wp - normW = (normWL + normWR)/2._wp + w1 = (w1L + w1R)/2._wp + w2 = (w2L + w2R)/2._wp + w3 = (w3L + w3R)/2._wp + normW = (normWL + normWR)/2._wp if (normW > capillary_cutoff) then @:compute_capillary_stress_tensor() - do i = 1, num_dims + do i = 1, num_dims - flux_src_vf(momxb + i - 1)%sf(j, k, l) = & - flux_src_vf(momxb + i - 1)%sf(j, k, l) + Omega(2, i) + flux_src_vf(momxb + i - 1)%sf(j, k, l) = & + flux_src_vf(momxb + i - 1)%sf(j, k, l) + Omega(2, i) - flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & - Omega(2, i)*vSrc_rsy_vf(k, j, l, i) + flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & + Omega(2, i)*vSrc_rsy_vf(k, j, l, i) - end do + end do - flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & - sigma*c_divs(num_dims + 1)%sf(j, k, l)*vSrc_rsy_vf(k, j, l, 2) - end if + flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & + sigma*c_divs(num_dims + 1)%sf(j, k, l)*vSrc_rsy_vf(k, j, l, 2) + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (id == 3) then #:call GPU_PARALLEL_LOOP(collapse=3, private='[Omega, w1L, w2L, w3L, w1R, w2R, w3R, w1, w2, w3, normWL, normWR, normW]') - do l = isz%beg, isz%end - do k = isy%beg, isy%end - do j = isx%beg, isx%end + do l = isz%beg, isz%end + do k = isy%beg, isy%end + do j = isx%beg, isx%end - w1L = gL_z(l, k, j, 1) - w2L = gL_z(l, k, j, 2) - w3L = 0._wp - if (p > 0) w3L = gL_z(l, k, j, 3) + w1L = gL_z(l, k, j, 1) + w2L = gL_z(l, k, j, 2) + w3L = 0._wp + if (p > 0) w3L = gL_z(l, k, j, 3) - w1R = gR_z(l + 1, k, j, 1) - w2R = gR_z(l + 1, k, j, 2) - w3R = 0._wp - if (p > 0) w3R = gR_z(l + 1, k, j, 3) + w1R = gR_z(l + 1, k, j, 1) + w2R = gR_z(l + 1, k, j, 2) + w3R = 0._wp + if (p > 0) w3R = gR_z(l + 1, k, j, 3) - normWL = gL_z(l, k, j, num_dims + 1) - normWR = gR_z(l + 1, k, j, num_dims + 1) + normWL = gL_z(l, k, j, num_dims + 1) + normWR = gR_z(l + 1, k, j, num_dims + 1) - w1 = (w1L + w1R)/2._wp - w2 = (w2L + w2R)/2._wp - w3 = (w3L + w3R)/2._wp - normW = (normWL + normWR)/2._wp + w1 = (w1L + w1R)/2._wp + w2 = (w2L + w2R)/2._wp + w3 = (w3L + w3R)/2._wp + normW = (normWL + normWR)/2._wp if (normW > capillary_cutoff) then @:compute_capillary_stress_tensor() - do i = 1, num_dims + do i = 1, num_dims - flux_src_vf(momxb + i - 1)%sf(j, k, l) = & - flux_src_vf(momxb + i - 1)%sf(j, k, l) + Omega(3, i) + flux_src_vf(momxb + i - 1)%sf(j, k, l) = & + flux_src_vf(momxb + i - 1)%sf(j, k, l) + Omega(3, i) - flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & - Omega(3, i)*vSrc_rsz_vf(l, k, j, i) + flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & + Omega(3, i)*vSrc_rsz_vf(l, k, j, i) - end do + end do - flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & - sigma*c_divs(num_dims + 1)%sf(j, k, l)*vSrc_rsz_vf(l, k, j, 3) - end if + flux_src_vf(E_idx)%sf(j, k, l) = flux_src_vf(E_idx)%sf(j, k, l) + & + sigma*c_divs(num_dims + 1)%sf(j, k, l)*vSrc_rsz_vf(l, k, j, 3) + end if + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -241,37 +241,37 @@ contains ! compute gradient components #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - c_divs(1)%sf(j, k, l) = 1._wp/(x_cc(j + 1) - x_cc(j - 1))* & - (q_prim_vf(c_idx)%sf(j + 1, k, l) - q_prim_vf(c_idx)%sf(j - 1, k, l)) + do l = 0, p + do k = 0, n + do j = 0, m + c_divs(1)%sf(j, k, l) = 1._wp/(x_cc(j + 1) - x_cc(j - 1))* & + (q_prim_vf(c_idx)%sf(j + 1, k, l) - q_prim_vf(c_idx)%sf(j - 1, k, l)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - c_divs(2)%sf(j, k, l) = 1._wp/(y_cc(k + 1) - y_cc(k - 1))* & - (q_prim_vf(c_idx)%sf(j, k + 1, l) - q_prim_vf(c_idx)%sf(j, k - 1, l)) + do l = 0, p + do k = 0, n + do j = 0, m + c_divs(2)%sf(j, k, l) = 1._wp/(y_cc(k + 1) - y_cc(k - 1))* & + (q_prim_vf(c_idx)%sf(j, k + 1, l) - q_prim_vf(c_idx)%sf(j, k - 1, l)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (p > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - c_divs(3)%sf(j, k, l) = 1._wp/(z_cc(l + 1) - z_cc(l - 1))* & - (q_prim_vf(c_idx)%sf(j, k, l + 1) - q_prim_vf(c_idx)%sf(j, k, l - 1)) + do l = 0, p + do k = 0, n + do j = 0, m + c_divs(3)%sf(j, k, l) = 1._wp/(z_cc(l + 1) - z_cc(l - 1))* & + (q_prim_vf(c_idx)%sf(j, k, l + 1) - q_prim_vf(c_idx)%sf(j, k, l - 1)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -340,42 +340,42 @@ contains if (recon_dir == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - vL_x(j, k, l, i) = v_vf(i)%sf(j, k, l) - vR_x(j, k, l, i) = v_vf(i)%sf(j, k, l) + do i = iv%beg, iv%end + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + vL_x(j, k, l, i) = v_vf(i)%sf(j, k, l) + vR_x(j, k, l, i) = v_vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else if (recon_dir == 2) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - vL_y(j, k, l, i) = v_vf(i)%sf(k, j, l) - vR_y(j, k, l, i) = v_vf(i)%sf(k, j, l) + do i = iv%beg, iv%end + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + vL_y(j, k, l, i) = v_vf(i)%sf(k, j, l) + vR_y(j, k, l, i) = v_vf(i)%sf(k, j, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else if (recon_dir == 3) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - vL_z(j, k, l, i) = v_vf(i)%sf(l, k, j) - vR_z(j, k, l, i) = v_vf(i)%sf(l, k, j) + do i = iv%beg, iv%end + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + vL_z(j, k, l, i) = v_vf(i)%sf(l, k, j) + vR_z(j, k, l, i) = v_vf(i)%sf(l, k, j) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index 84aa0b4107..66c85751ff 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -391,54 +391,53 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_ts(1)%vf(i)%sf(j, k, l) = & - q_cons_ts(1)%vf(i)%sf(j, k, l) & - + dt*rhs_vf(i)%sf(j, k, l) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(1)%vf(i)%sf(j, k, l) = & + q_cons_ts(1)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP - !Evolve pb and mv for non-polytropic qbmm if (qbmm .and. (.not. polytropic)) then #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - pb_ts(1)%sf(j, k, l, q, i) = & - pb_ts(1)%sf(j, k, l, q, i) & - + dt*rhs_pb(j, k, l, q, i) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + pb_ts(1)%sf(j, k, l, q, i) = & + pb_ts(1)%sf(j, k, l, q, i) & + + dt*rhs_pb(j, k, l, q, i) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (qbmm .and. (.not. polytropic)) then #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(1)%sf(j, k, l, q, i) = & - mv_ts(1)%sf(j, k, l, q, i) & - + dt*rhs_mv(j, k, l, q, i) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(1)%sf(j, k, l, q, i) = & + mv_ts(1)%sf(j, k, l, q, i) & + + dt*rhs_mv(j, k, l, q, i) + end do end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -501,176 +500,176 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_ts(2)%vf(i)%sf(j, k, l) = & - q_cons_ts(1)%vf(i)%sf(j, k, l) & - + dt*rhs_vf(i)%sf(j, k, l) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - - !Evolve pb and mv for non-polytropic qbmm - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb + do i = 1, sys_size do l = 0, p do k = 0, n do j = 0, m - do q = 1, nnode - pb_ts(2)%sf(j, k, l, q, i) = & - pb_ts(1)%sf(j, k, l, q, i) & - + dt*rhs_pb(j, k, l, q, i) - end do + q_cons_ts(2)%vf(i)%sf(j, k, l) = & + q_cons_ts(1)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l) end do end do end do end do - end if #:endcall GPU_PARALLEL_LOOP + !Evolve pb and mv for non-polytropic qbmm if (qbmm .and. (.not. polytropic)) then #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(2)%sf(j, k, l, q, i) = & - mv_ts(1)%sf(j, k, l, q, i) & - + dt*rhs_mv(j, k, l, q, i) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + pb_ts(2)%sf(j, k, l, q, i) = & + pb_ts(1)%sf(j, k, l, q, i) & + + dt*rhs_pb(j, k, l, q, i) + end do end do end do end do end do - end do - #:endcall GPU_PARALLEL_LOOP - end if + end if + #:endcall GPU_PARALLEL_LOOP + + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(2)%sf(j, k, l, q, i) = & + mv_ts(1)%sf(j, k, l, q, i) & + + dt*rhs_mv(j, k, l, q, i) + end do + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) - if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) - end if + if (model_eqns == 3 .and. (.not. relax)) then + call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) + end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) - if (ib) then - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) - else - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) - end if - end if - - ! Stage 2 of 2 + if (ib) then + if (qbmm .and. .not. polytropic) then + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) + else + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) + end if + end if - call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) + ! Stage 2 of 2 - if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) + call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_ts(1)%vf(i)%sf(j, k, l) = & - (q_cons_ts(1)%vf(i)%sf(j, k, l) & - + q_cons_ts(2)%vf(i)%sf(j, k, l) & - + dt*rhs_vf(i)%sf(j, k, l))/2._wp - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP + if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - pb_ts(1)%sf(j, k, l, q, i) = & - (pb_ts(1)%sf(j, k, l, q, i) & - + pb_ts(2)%sf(j, k, l, q, i) & - + dt*rhs_pb(j, k, l, q, i))/2._wp + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(1)%vf(i)%sf(j, k, l) = & + (q_cons_ts(1)%vf(i)%sf(j, k, l) & + + q_cons_ts(2)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l))/2._wp + end do end do end do end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if + #:endcall GPU_PARALLEL_LOOP + + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + pb_ts(1)%sf(j, k, l, q, i) = & + (pb_ts(1)%sf(j, k, l, q, i) & + + pb_ts(2)%sf(j, k, l, q, i) & + + dt*rhs_pb(j, k, l, q, i))/2._wp + end do + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(1)%sf(j, k, l, q, i) = & - (mv_ts(1)%sf(j, k, l, q, i) & - + mv_ts(2)%sf(j, k, l, q, i) & - + dt*rhs_mv(j, k, l, q, i))/2._wp + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(1)%sf(j, k, l, q, i) = & + (mv_ts(1)%sf(j, k, l, q, i) & + + mv_ts(2)%sf(j, k, l, q, i) & + + dt*rhs_mv(j, k, l, q, i))/2._wp + end do + end do + end do end do end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if + #:endcall GPU_PARALLEL_LOOP + end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(1)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(1)%vf) - if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(1)%vf) - end if + if (model_eqns == 3 .and. (.not. relax)) then + call s_pressure_relaxation_procedure(q_cons_ts(1)%vf) + end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(1)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(1)%vf) - if (ib) then - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) - else - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) - end if - end if + if (ib) then + if (qbmm .and. .not. polytropic) then + call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) + else + call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) + end if + end if - call nvtxEndRange + call nvtxEndRange - call cpu_time(finish) + call cpu_time(finish) - end subroutine s_2nd_order_tvd_rk + end subroutine s_2nd_order_tvd_rk - !> 3rd order TVD RK time-stepping algorithm + !> 3rd order TVD RK time-stepping algorithm !! @param t_step Current time-step - impure subroutine s_3rd_order_tvd_rk(t_step, time_avg) + impure subroutine s_3rd_order_tvd_rk(t_step, time_avg) - integer, intent(IN) :: t_step - real(wp), intent(INOUT) :: time_avg + integer, intent(IN) :: t_step + real(wp), intent(INOUT) :: time_avg - integer :: i, j, k, l, q !< Generic loop iterator + integer :: i, j, k, l, q !< Generic loop iterator - real(wp) :: start, finish + real(wp) :: start, finish - ! Stage 1 of 3 + ! Stage 1 of 3 - if (.not. adap_dt) then - call cpu_time(start) - call nvtxStartRange("TIMESTEP") - end if + if (.not. adap_dt) then + call cpu_time(start) + call nvtxStartRange("TIMESTEP") + end if - call s_compute_rhs(q_cons_ts(1)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(1)%sf, rhs_pb, mv_ts(1)%sf, rhs_mv, t_step, time_avg, 1) + call s_compute_rhs(q_cons_ts(1)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(1)%sf, rhs_pb, mv_ts(1)%sf, rhs_mv, t_step, time_avg, 1) if (run_time_info) then if (igr) then @@ -680,338 +679,338 @@ contains end if end if - if (probe_wrt) then - call s_time_step_cycling(t_step) - end if - - if (cfl_dt) then - if (mytime >= t_stop) return - else - if (t_step == t_step_stop) return - end if - - if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) + if (probe_wrt) then + call s_time_step_cycling(t_step) + end if - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_ts(2)%vf(i)%sf(j, k, l) = & - q_cons_ts(1)%vf(i)%sf(j, k, l) & - + dt*rhs_vf(i)%sf(j, k, l) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP + if (cfl_dt) then + if (mytime >= t_stop) return + else + if (t_step == t_step_stop) return + end if - !Evolve pb and mv for non-polytropic qbmm - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - pb_ts(2)%sf(j, k, l, q, i) = & - pb_ts(1)%sf(j, k, l, q, i) & - + dt*rhs_pb(j, k, l, q, i) + if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) + + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(2)%vf(i)%sf(j, k, l) = & + q_cons_ts(1)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l) + end do end do end do end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if - - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(2)%sf(j, k, l, q, i) = & - mv_ts(1)%sf(j, k, l, q, i) & - + dt*rhs_mv(j, k, l, q, i) + #:endcall GPU_PARALLEL_LOOP + + !Evolve pb and mv for non-polytropic qbmm + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + pb_ts(2)%sf(j, k, l, q, i) = & + pb_ts(1)%sf(j, k, l, q, i) & + + dt*rhs_pb(j, k, l, q, i) + end do + end do + end do end do end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if + #:endcall GPU_PARALLEL_LOOP + end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(2)%sf(j, k, l, q, i) = & + mv_ts(1)%sf(j, k, l, q, i) & + + dt*rhs_mv(j, k, l, q, i) + end do + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) - if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) - end if + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) + if (model_eqns == 3 .and. (.not. relax)) then + call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) + end if - if (ib) then - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) - else - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) - end if - end if + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) - ! Stage 2 of 3 + if (ib) then + if (qbmm .and. .not. polytropic) then + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) + else + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) + end if + end if - call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) + ! Stage 2 of 3 - if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) + call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_ts(2)%vf(i)%sf(j, k, l) = & - (3._wp*q_cons_ts(1)%vf(i)%sf(j, k, l) & - + q_cons_ts(2)%vf(i)%sf(j, k, l) & - + dt*rhs_vf(i)%sf(j, k, l))/4._wp - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP + if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - pb_ts(2)%sf(j, k, l, q, i) = & - (3._wp*pb_ts(1)%sf(j, k, l, q, i) & - + pb_ts(2)%sf(j, k, l, q, i) & - + dt*rhs_pb(j, k, l, q, i))/4._wp + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(2)%vf(i)%sf(j, k, l) = & + (3._wp*q_cons_ts(1)%vf(i)%sf(j, k, l) & + + q_cons_ts(2)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l))/4._wp + end do end do end do end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if - - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(2)%sf(j, k, l, q, i) = & - (3._wp*mv_ts(1)%sf(j, k, l, q, i) & - + mv_ts(2)%sf(j, k, l, q, i) & - + dt*rhs_mv(j, k, l, q, i))/4._wp + #:endcall GPU_PARALLEL_LOOP + + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + pb_ts(2)%sf(j, k, l, q, i) = & + (3._wp*pb_ts(1)%sf(j, k, l, q, i) & + + pb_ts(2)%sf(j, k, l, q, i) & + + dt*rhs_pb(j, k, l, q, i))/4._wp + end do + end do + end do end do end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if - - if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt/4._wp) - - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) + #:endcall GPU_PARALLEL_LOOP + end if - if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) - end if + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(2)%sf(j, k, l, q, i) = & + (3._wp*mv_ts(1)%sf(j, k, l, q, i) & + + mv_ts(2)%sf(j, k, l, q, i) & + + dt*rhs_mv(j, k, l, q, i))/4._wp + end do + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt/4._wp) - if (ib) then - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) - else - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) - end if - end if + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) - ! Stage 3 of 3 - call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 3) + if (model_eqns == 3 .and. (.not. relax)) then + call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) + end if - if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=3) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_ts(1)%vf(i)%sf(j, k, l) = & - (q_cons_ts(1)%vf(i)%sf(j, k, l) & - + 2._wp*q_cons_ts(2)%vf(i)%sf(j, k, l) & - + 2._wp*dt*rhs_vf(i)%sf(j, k, l))/3._wp - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP + if (ib) then + if (qbmm .and. .not. polytropic) then + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) + else + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) + end if + end if - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - pb_ts(1)%sf(j, k, l, q, i) = & - (pb_ts(1)%sf(j, k, l, q, i) & - + 2._wp*pb_ts(2)%sf(j, k, l, q, i) & - + 2._wp*dt*rhs_pb(j, k, l, q, i))/3._wp + ! Stage 3 of 3 + call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 3) + + if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=3) + + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(1)%vf(i)%sf(j, k, l) = & + (q_cons_ts(1)%vf(i)%sf(j, k, l) & + + 2._wp*q_cons_ts(2)%vf(i)%sf(j, k, l) & + + 2._wp*dt*rhs_vf(i)%sf(j, k, l))/3._wp + end do end do end do end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if + #:endcall GPU_PARALLEL_LOOP + + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + pb_ts(1)%sf(j, k, l, q, i) = & + (pb_ts(1)%sf(j, k, l, q, i) & + + 2._wp*pb_ts(2)%sf(j, k, l, q, i) & + + 2._wp*dt*rhs_pb(j, k, l, q, i))/3._wp + end do + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(1)%sf(j, k, l, q, i) = & - (mv_ts(1)%sf(j, k, l, q, i) & - + 2._wp*mv_ts(2)%sf(j, k, l, q, i) & - + 2._wp*dt*rhs_mv(j, k, l, q, i))/3._wp + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(1)%sf(j, k, l, q, i) = & + (mv_ts(1)%sf(j, k, l, q, i) & + + 2._wp*mv_ts(2)%sf(j, k, l, q, i) & + + 2._wp*dt*rhs_mv(j, k, l, q, i))/3._wp + end do + end do + end do end do end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if + #:endcall GPU_PARALLEL_LOOP + end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(1)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(1)%vf) - if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(1)%vf) - end if + if (model_eqns == 3 .and. (.not. relax)) then + call s_pressure_relaxation_procedure(q_cons_ts(1)%vf) + end if - call nvtxStartRange("RHS-ELASTIC") - if (hyperelasticity) call s_hyperelastic_rmt_stress_update(q_cons_ts(1)%vf, q_prim_vf) - call nvtxEndRange + call nvtxStartRange("RHS-ELASTIC") + if (hyperelasticity) call s_hyperelastic_rmt_stress_update(q_cons_ts(1)%vf, q_prim_vf) + call nvtxEndRange - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(1)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(1)%vf) - if (ib) then - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) - else - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) - end if - end if + if (ib) then + if (qbmm .and. .not. polytropic) then + call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) + else + call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) + end if + end if - if (.not. adap_dt) then - call nvtxEndRange - call cpu_time(finish) + if (.not. adap_dt) then + call nvtxEndRange + call cpu_time(finish) - time = time + (finish - start) - end if - end subroutine s_3rd_order_tvd_rk + time = time + (finish - start) + end if + end subroutine s_3rd_order_tvd_rk - !> Strang splitting scheme with 3rd order TVD RK time-stepping algorithm for + !> Strang splitting scheme with 3rd order TVD RK time-stepping algorithm for !! the flux term and adaptive time stepping algorithm for !! the source term !! @param t_step Current time-step - subroutine s_strang_splitting(t_step, time_avg) + subroutine s_strang_splitting(t_step, time_avg) - integer, intent(in) :: t_step - real(wp), intent(inout) :: time_avg + integer, intent(in) :: t_step + real(wp), intent(inout) :: time_avg - real(wp) :: start, finish + real(wp) :: start, finish - call cpu_time(start) + call cpu_time(start) - call nvtxStartRange("TIMESTEP") + call nvtxStartRange("TIMESTEP") - ! Stage 1 of 3 - call s_adaptive_dt_bubble(1) + ! Stage 1 of 3 + call s_adaptive_dt_bubble(1) - ! Stage 2 of 3 - call s_3rd_order_tvd_rk(t_step, time_avg) + ! Stage 2 of 3 + call s_3rd_order_tvd_rk(t_step, time_avg) - ! Stage 3 of 3 - call s_adaptive_dt_bubble(3) + ! Stage 3 of 3 + call s_adaptive_dt_bubble(3) - call nvtxEndRange + call nvtxEndRange - call cpu_time(finish) + call cpu_time(finish) - time = time + (finish - start) + time = time + (finish - start) - end subroutine s_strang_splitting + end subroutine s_strang_splitting - !> Bubble source part in Strang operator splitting scheme + !> Bubble source part in Strang operator splitting scheme !! @param t_step Current time-step - impure subroutine s_adaptive_dt_bubble(stage) + impure subroutine s_adaptive_dt_bubble(stage) - integer, intent(in) :: stage + integer, intent(in) :: stage - type(vector_field) :: gm_alpha_qp + type(vector_field) :: gm_alpha_qp - call s_convert_conservative_to_primitive_variables( & - q_cons_ts(1)%vf, & - q_T_sf, & - q_prim_vf, & - idwint) + call s_convert_conservative_to_primitive_variables( & + q_cons_ts(1)%vf, & + q_T_sf, & + q_prim_vf, & + idwint) - if (bubbles_euler) then + if (bubbles_euler) then call s_compute_bubble_EE_source(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, divu) call s_comp_alpha_from_n(q_cons_ts(1)%vf) - elseif (bubbles_lagrange) then - - call s_populate_variables_buffers(bc_type, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) - call s_compute_bubble_EL_dynamics(q_prim_vf, stage) - call s_transfer_data_to_tmp() - call s_smear_voidfraction() - if (stage == 3) then - if (lag_params%write_bubbles_stats) call s_calculate_lag_bubble_stats() - if (lag_params%write_bubbles) then - $:GPU_UPDATE(host='[gas_p,gas_mv,intfc_rad,intfc_vel]') - call s_write_lag_particles(mytime) - end if - call s_write_void_evol(mytime) - end if + elseif (bubbles_lagrange) then + + call s_populate_variables_buffers(bc_type, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) + call s_compute_bubble_EL_dynamics(q_prim_vf, stage) + call s_transfer_data_to_tmp() + call s_smear_voidfraction() + if (stage == 3) then + if (lag_params%write_bubbles_stats) call s_calculate_lag_bubble_stats() + if (lag_params%write_bubbles) then + $:GPU_UPDATE(host='[gas_p,gas_mv,intfc_rad,intfc_vel]') + call s_write_lag_particles(mytime) + end if + call s_write_void_evol(mytime) + end if - end if + end if - end subroutine s_adaptive_dt_bubble + end subroutine s_adaptive_dt_bubble - impure subroutine s_compute_dt() + impure subroutine s_compute_dt() - real(wp) :: rho !< Cell-avg. density - real(wp), dimension(num_vels) :: vel !< Cell-avg. velocity - real(wp) :: vel_sum !< Cell-avg. velocity sum - real(wp) :: pres !< Cell-avg. pressure - real(wp), dimension(num_fluids) :: alpha !< Cell-avg. volume fraction - real(wp) :: gamma !< Cell-avg. sp. heat ratio - real(wp) :: pi_inf !< Cell-avg. liquid stiffness function - real(wp) :: c !< Cell-avg. sound speed - real(wp) :: H !< Cell-avg. enthalpy - real(wp), dimension(2) :: Re !< Cell-avg. Reynolds numbers - type(vector_field) :: gm_alpha_qp + real(wp) :: rho !< Cell-avg. density + real(wp), dimension(num_vels) :: vel !< Cell-avg. velocity + real(wp) :: vel_sum !< Cell-avg. velocity sum + real(wp) :: pres !< Cell-avg. pressure + real(wp), dimension(num_fluids) :: alpha !< Cell-avg. volume fraction + real(wp) :: gamma !< Cell-avg. sp. heat ratio + real(wp) :: pi_inf !< Cell-avg. liquid stiffness function + real(wp) :: c !< Cell-avg. sound speed + real(wp) :: H !< Cell-avg. enthalpy + real(wp), dimension(2) :: Re !< Cell-avg. Reynolds numbers + type(vector_field) :: gm_alpha_qp - real(wp) :: dt_local - integer :: j, k, l !< Generic loop iterators + real(wp) :: dt_local + integer :: j, k, l !< Generic loop iterators if (.not. igr) then call s_convert_conservative_to_primitive_variables( & @@ -1031,30 +1030,30 @@ contains call s_compute_enthalpy(q_prim_vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) end if - ! Compute mixture sound speed - call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, alpha, vel_sum, 0._wp, c) + ! Compute mixture sound speed + call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, alpha, vel_sum, 0._wp, c) - call s_compute_dt_from_cfl(vel, c, max_dt, rho, Re, j, k, l) - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP + call s_compute_dt_from_cfl(vel, c, max_dt, rho, Re, j, k, l) + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL(copyout='[dt_local]', copyin='[max_dt]') dt_local = minval(max_dt) #:endcall GPU_PARALLEL - if (num_procs == 1) then - dt = dt_local - else - call s_mpi_allreduce_min(dt_local, dt) - end if + if (num_procs == 1) then + dt = dt_local + else + call s_mpi_allreduce_min(dt_local, dt) + end if - $:GPU_UPDATE(device='[dt]') + $:GPU_UPDATE(device='[dt]') - end subroutine s_compute_dt + end subroutine s_compute_dt - !> This subroutine applies the body forces source term at each + !> This subroutine applies the body forces source term at each !! Runge-Kutta stage subroutine s_apply_bodyforces(q_cons_vf, q_prim_vf_in, rhs_vf_in, ldt) @@ -1062,9 +1061,9 @@ contains type(scalar_field), dimension(1:sys_size), intent(in) :: q_prim_vf_in type(scalar_field), dimension(1:sys_size), intent(inout) :: rhs_vf_in - real(wp), intent(in) :: ldt !< local dt + real(wp), intent(in) :: ldt !< local dt - integer :: i, j, k, l + integer :: i, j, k, l call nvtxStartRange("RHS-BODYFORCES") call s_compute_body_forces_rhs(q_prim_vf_in, q_cons_vf, rhs_vf_in) @@ -1082,21 +1081,21 @@ contains end do #:endcall GPU_PARALLEL_LOOP - call nvtxEndRange + call nvtxEndRange - end subroutine s_apply_bodyforces + end subroutine s_apply_bodyforces - !> This subroutine saves the temporary q_prim_vf vector + !> This subroutine saves the temporary q_prim_vf vector !! into the q_prim_ts vector that is then used in p_main !! @param t_step current time-step - subroutine s_time_step_cycling(t_step) + subroutine s_time_step_cycling(t_step) - integer, intent(in) :: t_step + integer, intent(in) :: t_step integer :: i, j, k, l !< Generic loop iterator if (t_step == t_step_start) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -1106,8 +1105,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (t_step == t_step_start + 1) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -1117,8 +1117,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (t_step == t_step_start + 2) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -1128,8 +1129,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP elseif (t_step == t_step_start + 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -1139,8 +1141,9 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP else ! All other timesteps - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n @@ -1153,14 +1156,15 @@ contains end do end do end do + #:endcall GPU_PARALLEL_LOOP end if - end subroutine s_time_step_cycling + end subroutine s_time_step_cycling - !> Module deallocation and/or disassociation procedures - impure subroutine s_finalize_time_steppers_module + !> Module deallocation and/or disassociation procedures + impure subroutine s_finalize_time_steppers_module - integer :: i, j !< Generic loop iterators + integer :: i, j !< Generic loop iterators ! Deallocating the cell-average conservative variables do i = 1, num_ts @@ -1171,18 +1175,18 @@ contains @:DEALLOCATE(q_cons_ts(i)%vf) end do - @:DEALLOCATE(q_cons_ts) + @:DEALLOCATE(q_cons_ts) - ! Deallocating the cell-average primitive ts variables - if (probe_wrt) then - do i = 0, 3 - do j = 1, sys_size - @:DEALLOCATE(q_prim_ts(i)%vf(j)%sf) - end do - @:DEALLOCATE(q_prim_ts(i)%vf) - end do - @:DEALLOCATE(q_prim_ts) - end if + ! Deallocating the cell-average primitive ts variables + if (probe_wrt) then + do i = 0, 3 + do j = 1, sys_size + @:DEALLOCATE(q_prim_ts(i)%vf(j)%sf) + end do + @:DEALLOCATE(q_prim_ts(i)%vf) + end do + @:DEALLOCATE(q_prim_ts) + end if if (.not. igr) then ! Deallocating the cell-average primitive variables @@ -1225,20 +1229,20 @@ contains end if end if - @:DEALLOCATE(q_prim_vf) + @:DEALLOCATE(q_prim_vf) - ! Deallocating the cell-average RHS variables - do i = 1, sys_size - @:DEALLOCATE(rhs_vf(i)%sf) - end do + ! Deallocating the cell-average RHS variables + do i = 1, sys_size + @:DEALLOCATE(rhs_vf(i)%sf) + end do - @:DEALLOCATE(rhs_vf) + @:DEALLOCATE(rhs_vf) - ! Writing the footer of and closing the run-time information file - if (proc_rank == 0 .and. run_time_info) then - call s_close_run_time_information_file() - end if + ! Writing the footer of and closing the run-time information file + if (proc_rank == 0 .and. run_time_info) then + call s_close_run_time_information_file() + end if - end subroutine s_finalize_time_steppers_module + end subroutine s_finalize_time_steppers_module -end module m_time_steppers + end module m_time_steppers diff --git a/src/simulation/m_viscous.fpp b/src/simulation/m_viscous.fpp index d22fa9c5dd..b31285690f 100644 --- a/src/simulation/m_viscous.fpp +++ b/src/simulation/m_viscous.fpp @@ -78,226 +78,226 @@ contains $:GPU_UPDATE(device='[is1_viscous,is2_viscous,is3_viscous]') #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - tau_Re_vf(i)%sf(j, k, l) = 0._wp + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + tau_Re_vf(i)%sf(j, k, l) = 0._wp + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (shear_stress) then ! Shear stresses #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, alpha_rho_visc, Re_visc, tau_Re]') - do l = is3_viscous%beg, is3_viscous%end - do k = -1, 1 - do j = is1_viscous%beg, is1_viscous%end + do l = is3_viscous%beg, is3_viscous%end + do k = -1, 1 + do j = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_visc(i) = q_prim_vf(i)%sf(j, k, l) - if (bubbles_euler .and. num_fluids == 1) then - alpha_visc(i) = 1._wp - q_prim_vf(E_idx + i)%sf(j, k, l) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_visc(i) = q_prim_vf(i)%sf(j, k, l) + if (bubbles_euler .and. num_fluids == 1) then + alpha_visc(i) = 1._wp - q_prim_vf(E_idx + i)%sf(j, k, l) + else + alpha_visc(i) = q_prim_vf(E_idx + i)%sf(j, k, l) + end if + end do + + if (bubbles_euler) then + rho_visc = 0._wp + gamma_visc = 0._wp + pi_inf_visc = 0._wp + + if (mpp_lim .and. (model_eqns == 2) .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + rho_visc = rho_visc + alpha_rho_visc(i) + gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) + pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) + end do + else if ((model_eqns == 2) .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + rho_visc = rho_visc + alpha_rho_visc(i) + gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) + pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) + end do + else + rho_visc = alpha_rho_visc(1) + gamma_visc = gammas(1) + pi_inf_visc = pi_infs(1) + end if else - alpha_visc(i) = q_prim_vf(E_idx + i)%sf(j, k, l) - end if - end do + rho_visc = 0._wp + gamma_visc = 0._wp + pi_inf_visc = 0._wp - if (bubbles_euler) then - rho_visc = 0._wp - gamma_visc = 0._wp - pi_inf_visc = 0._wp + alpha_visc_sum = 0._wp + + if (mpp_lim) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_visc(i) = max(0._wp, alpha_rho_visc(i)) + alpha_visc(i) = min(max(0._wp, alpha_visc(i)), 1._wp) + alpha_visc_sum = alpha_visc_sum + alpha_visc(i) + end do + + alpha_visc = alpha_visc/max(alpha_visc_sum, sgm_eps) + + end if - if (mpp_lim .and. (model_eqns == 2) .and. (num_fluids > 2)) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids rho_visc = rho_visc + alpha_rho_visc(i) gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) end do - else if ((model_eqns == 2) .and. (num_fluids > 2)) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - rho_visc = rho_visc + alpha_rho_visc(i) - gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) - pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) - end do - else - rho_visc = alpha_rho_visc(1) - gamma_visc = gammas(1) - pi_inf_visc = pi_infs(1) - end if - else - rho_visc = 0._wp - gamma_visc = 0._wp - pi_inf_visc = 0._wp - alpha_visc_sum = 0._wp - - if (mpp_lim) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_visc(i) = max(0._wp, alpha_rho_visc(i)) - alpha_visc(i) = min(max(0._wp, alpha_visc(i)), 1._wp) - alpha_visc_sum = alpha_visc_sum + alpha_visc(i) - end do - - alpha_visc = alpha_visc/max(alpha_visc_sum, sgm_eps) - - end if + if (viscous) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_visc(i) = dflt_real - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_visc = rho_visc + alpha_rho_visc(i) - gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) - pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) - end do + if (Re_size(i) > 0) Re_visc(i) = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_visc(i) = alpha_visc(Re_idx(i, q))/Res_viscous(i, q) & + + Re_visc(i) + end do - if (viscous) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_visc(i) = dflt_real + Re_visc(i) = 1._wp/max(Re_visc(i), sgm_eps) - if (Re_size(i) > 0) Re_visc(i) = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_visc(i) = alpha_visc(Re_idx(i, q))/Res_viscous(i, q) & - + Re_visc(i) end do - - Re_visc(i) = 1._wp/max(Re_visc(i), sgm_eps) - - end do + end if end if - end if - - tau_Re(2, 1) = (grad_y_vf(1)%sf(j, k, l) + & - grad_x_vf(2)%sf(j, k, l))/ & - Re_visc(1) - tau_Re(2, 2) = (4._wp*grad_y_vf(2)%sf(j, k, l) & - - 2._wp*grad_x_vf(1)%sf(j, k, l) & - - 2._wp*q_prim_vf(momxb + 1)%sf(j, k, l)/y_cc(k))/ & - (3._wp*Re_visc(1)) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - tau_Re_vf(contxe + i)%sf(j, k, l) = & - tau_Re_vf(contxe + i)%sf(j, k, l) - & - tau_Re(2, i) + tau_Re(2, 1) = (grad_y_vf(1)%sf(j, k, l) + & + grad_x_vf(2)%sf(j, k, l))/ & + Re_visc(1) - tau_Re_vf(E_idx)%sf(j, k, l) = & - tau_Re_vf(E_idx)%sf(j, k, l) - & - q_prim_vf(contxe + i)%sf(j, k, l)*tau_Re(2, i) + tau_Re(2, 2) = (4._wp*grad_y_vf(2)%sf(j, k, l) & + - 2._wp*grad_x_vf(1)%sf(j, k, l) & + - 2._wp*q_prim_vf(momxb + 1)%sf(j, k, l)/y_cc(k))/ & + (3._wp*Re_visc(1)) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + tau_Re_vf(contxe + i)%sf(j, k, l) = & + tau_Re_vf(contxe + i)%sf(j, k, l) - & + tau_Re(2, i) + + tau_Re_vf(E_idx)%sf(j, k, l) = & + tau_Re_vf(E_idx)%sf(j, k, l) - & + q_prim_vf(contxe + i)%sf(j, k, l)*tau_Re(2, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (bulk_stress) then ! Bulk stresses #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, alpha_rho_visc, Re_visc, tau_Re]') - do l = is3_viscous%beg, is3_viscous%end - do k = -1, 1 - do j = is1_viscous%beg, is1_viscous%end + do l = is3_viscous%beg, is3_viscous%end + do k = -1, 1 + do j = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_visc(i) = q_prim_vf(i)%sf(j, k, l) - if (bubbles_euler .and. num_fluids == 1) then - alpha_visc(i) = 1._wp - q_prim_vf(E_idx + i)%sf(j, k, l) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_visc(i) = q_prim_vf(i)%sf(j, k, l) + if (bubbles_euler .and. num_fluids == 1) then + alpha_visc(i) = 1._wp - q_prim_vf(E_idx + i)%sf(j, k, l) + else + alpha_visc(i) = q_prim_vf(E_idx + i)%sf(j, k, l) + end if + end do + + if (bubbles_euler) then + rho_visc = 0._wp + gamma_visc = 0._wp + pi_inf_visc = 0._wp + + if (mpp_lim .and. (model_eqns == 2) .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + rho_visc = rho_visc + alpha_rho_visc(i) + gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) + pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) + end do + else if ((model_eqns == 2) .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + rho_visc = rho_visc + alpha_rho_visc(i) + gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) + pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) + end do + else + rho_visc = alpha_rho_visc(1) + gamma_visc = gammas(1) + pi_inf_visc = pi_infs(1) + end if else - alpha_visc(i) = q_prim_vf(E_idx + i)%sf(j, k, l) - end if - end do + rho_visc = 0._wp + gamma_visc = 0._wp + pi_inf_visc = 0._wp + + alpha_visc_sum = 0._wp + + if (mpp_lim) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_visc(i) = max(0._wp, alpha_rho_visc(i)) + alpha_visc(i) = min(max(0._wp, alpha_visc(i)), 1._wp) + alpha_visc_sum = alpha_visc_sum + alpha_visc(i) + end do - if (bubbles_euler) then - rho_visc = 0._wp - gamma_visc = 0._wp - pi_inf_visc = 0._wp + alpha_visc = alpha_visc/max(alpha_visc_sum, sgm_eps) + + end if - if (mpp_lim .and. (model_eqns == 2) .and. (num_fluids > 2)) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids rho_visc = rho_visc + alpha_rho_visc(i) gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) end do - else if ((model_eqns == 2) .and. (num_fluids > 2)) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - rho_visc = rho_visc + alpha_rho_visc(i) - gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) - pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) - end do - else - rho_visc = alpha_rho_visc(1) - gamma_visc = gammas(1) - pi_inf_visc = pi_infs(1) - end if - else - rho_visc = 0._wp - gamma_visc = 0._wp - pi_inf_visc = 0._wp - - alpha_visc_sum = 0._wp - - if (mpp_lim) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_visc(i) = max(0._wp, alpha_rho_visc(i)) - alpha_visc(i) = min(max(0._wp, alpha_visc(i)), 1._wp) - alpha_visc_sum = alpha_visc_sum + alpha_visc(i) - end do - alpha_visc = alpha_visc/max(alpha_visc_sum, sgm_eps) - - end if + if (viscous) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_visc(i) = dflt_real - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_visc = rho_visc + alpha_rho_visc(i) - gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) - pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) - end do + if (Re_size(i) > 0) Re_visc(i) = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_visc(i) = alpha_visc(Re_idx(i, q))/Res_viscous(i, q) & + + Re_visc(i) + end do - if (viscous) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_visc(i) = dflt_real + Re_visc(i) = 1._wp/max(Re_visc(i), sgm_eps) - if (Re_size(i) > 0) Re_visc(i) = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_visc(i) = alpha_visc(Re_idx(i, q))/Res_viscous(i, q) & - + Re_visc(i) end do - - Re_visc(i) = 1._wp/max(Re_visc(i), sgm_eps) - - end do + end if end if - end if - tau_Re(2, 2) = (grad_x_vf(1)%sf(j, k, l) + & - grad_y_vf(2)%sf(j, k, l) + & - q_prim_vf(momxb + 1)%sf(j, k, l)/y_cc(k))/ & - Re_visc(2) + tau_Re(2, 2) = (grad_x_vf(1)%sf(j, k, l) + & + grad_y_vf(2)%sf(j, k, l) + & + q_prim_vf(momxb + 1)%sf(j, k, l)/y_cc(k))/ & + Re_visc(2) - tau_Re_vf(momxb + 1)%sf(j, k, l) = & - tau_Re_vf(momxb + 1)%sf(j, k, l) - & - tau_Re(2, 2) + tau_Re_vf(momxb + 1)%sf(j, k, l) = & + tau_Re_vf(momxb + 1)%sf(j, k, l) - & + tau_Re(2, 2) - tau_Re_vf(E_idx)%sf(j, k, l) = & - tau_Re_vf(E_idx)%sf(j, k, l) - & - q_prim_vf(momxb + 1)%sf(j, k, l)*tau_Re(2, 2) + tau_Re_vf(E_idx)%sf(j, k, l) = & + tau_Re_vf(E_idx)%sf(j, k, l) - & + q_prim_vf(momxb + 1)%sf(j, k, l)*tau_Re(2, 2) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -305,211 +305,211 @@ contains if (shear_stress) then ! Shear stresses #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, alpha_rho_visc, Re_visc, tau_Re]') - do l = is3_viscous%beg, is3_viscous%end - do k = -1, 1 - do j = is1_viscous%beg, is1_viscous%end + do l = is3_viscous%beg, is3_viscous%end + do k = -1, 1 + do j = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_visc(i) = q_prim_vf(i)%sf(j, k, l) - if (bubbles_euler .and. num_fluids == 1) then - alpha_visc(i) = 1._wp - q_prim_vf(E_idx + i)%sf(j, k, l) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_visc(i) = q_prim_vf(i)%sf(j, k, l) + if (bubbles_euler .and. num_fluids == 1) then + alpha_visc(i) = 1._wp - q_prim_vf(E_idx + i)%sf(j, k, l) + else + alpha_visc(i) = q_prim_vf(E_idx + i)%sf(j, k, l) + end if + end do + + if (bubbles_euler) then + rho_visc = 0._wp + gamma_visc = 0._wp + pi_inf_visc = 0._wp + + if (mpp_lim .and. (model_eqns == 2) .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + rho_visc = rho_visc + alpha_rho_visc(i) + gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) + pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) + end do + else if ((model_eqns == 2) .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + rho_visc = rho_visc + alpha_rho_visc(i) + gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) + pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) + end do + else + rho_visc = alpha_rho_visc(1) + gamma_visc = gammas(1) + pi_inf_visc = pi_infs(1) + end if else - alpha_visc(i) = q_prim_vf(E_idx + i)%sf(j, k, l) - end if - end do + rho_visc = 0._wp + gamma_visc = 0._wp + pi_inf_visc = 0._wp + + alpha_visc_sum = 0._wp + + if (mpp_lim) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_visc(i) = max(0._wp, alpha_rho_visc(i)) + alpha_visc(i) = min(max(0._wp, alpha_visc(i)), 1._wp) + alpha_visc_sum = alpha_visc_sum + alpha_visc(i) + end do + + alpha_visc = alpha_visc/max(alpha_visc_sum, sgm_eps) - if (bubbles_euler) then - rho_visc = 0._wp - gamma_visc = 0._wp - pi_inf_visc = 0._wp + end if - if (mpp_lim .and. (model_eqns == 2) .and. (num_fluids > 2)) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids rho_visc = rho_visc + alpha_rho_visc(i) gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) end do - else if ((model_eqns == 2) .and. (num_fluids > 2)) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - rho_visc = rho_visc + alpha_rho_visc(i) - gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) - pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) - end do - else - rho_visc = alpha_rho_visc(1) - gamma_visc = gammas(1) - pi_inf_visc = pi_infs(1) - end if - else - rho_visc = 0._wp - gamma_visc = 0._wp - pi_inf_visc = 0._wp - - alpha_visc_sum = 0._wp - - if (mpp_lim) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_visc(i) = max(0._wp, alpha_rho_visc(i)) - alpha_visc(i) = min(max(0._wp, alpha_visc(i)), 1._wp) - alpha_visc_sum = alpha_visc_sum + alpha_visc(i) - end do - alpha_visc = alpha_visc/max(alpha_visc_sum, sgm_eps) + if (viscous) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_visc(i) = dflt_real - end if + if (Re_size(i) > 0) Re_visc(i) = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_visc(i) = alpha_visc(Re_idx(i, q))/Res_viscous(i, q) & + + Re_visc(i) + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_visc = rho_visc + alpha_rho_visc(i) - gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) - pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) - end do + Re_visc(i) = 1._wp/max(Re_visc(i), sgm_eps) - if (viscous) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_visc(i) = dflt_real - - if (Re_size(i) > 0) Re_visc(i) = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_visc(i) = alpha_visc(Re_idx(i, q))/Res_viscous(i, q) & - + Re_visc(i) end do - - Re_visc(i) = 1._wp/max(Re_visc(i), sgm_eps) - - end do + end if end if - end if - tau_Re(2, 2) = -(2._wp/3._wp)*grad_z_vf(3)%sf(j, k, l)/y_cc(k)/ & - Re_visc(1) + tau_Re(2, 2) = -(2._wp/3._wp)*grad_z_vf(3)%sf(j, k, l)/y_cc(k)/ & + Re_visc(1) - tau_Re(2, 3) = ((grad_z_vf(2)%sf(j, k, l) - & - q_prim_vf(momxe)%sf(j, k, l))/ & - y_cc(k) + grad_y_vf(3)%sf(j, k, l))/ & - Re_visc(1) + tau_Re(2, 3) = ((grad_z_vf(2)%sf(j, k, l) - & + q_prim_vf(momxe)%sf(j, k, l))/ & + y_cc(k) + grad_y_vf(3)%sf(j, k, l))/ & + Re_visc(1) - $:GPU_LOOP(parallelism='[seq]') - do i = 2, 3 - tau_Re_vf(contxe + i)%sf(j, k, l) = & - tau_Re_vf(contxe + i)%sf(j, k, l) - & - tau_Re(2, i) + $:GPU_LOOP(parallelism='[seq]') + do i = 2, 3 + tau_Re_vf(contxe + i)%sf(j, k, l) = & + tau_Re_vf(contxe + i)%sf(j, k, l) - & + tau_Re(2, i) + + tau_Re_vf(E_idx)%sf(j, k, l) = & + tau_Re_vf(E_idx)%sf(j, k, l) - & + q_prim_vf(contxe + i)%sf(j, k, l)*tau_Re(2, i) + end do - tau_Re_vf(E_idx)%sf(j, k, l) = & - tau_Re_vf(E_idx)%sf(j, k, l) - & - q_prim_vf(contxe + i)%sf(j, k, l)*tau_Re(2, i) end do - end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (bulk_stress) then ! Bulk stresses #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_visc, alpha_rho_visc, Re_visc, tau_Re]') - do l = is3_viscous%beg, is3_viscous%end - do k = -1, 1 - do j = is1_viscous%beg, is1_viscous%end + do l = is3_viscous%beg, is3_viscous%end + do k = -1, 1 + do j = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_visc(i) = q_prim_vf(i)%sf(j, k, l) - if (bubbles_euler .and. num_fluids == 1) then - alpha_visc(i) = 1._wp - q_prim_vf(E_idx + i)%sf(j, k, l) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_visc(i) = q_prim_vf(i)%sf(j, k, l) + if (bubbles_euler .and. num_fluids == 1) then + alpha_visc(i) = 1._wp - q_prim_vf(E_idx + i)%sf(j, k, l) + else + alpha_visc(i) = q_prim_vf(E_idx + i)%sf(j, k, l) + end if + end do + + if (bubbles_euler) then + rho_visc = 0._wp + gamma_visc = 0._wp + pi_inf_visc = 0._wp + + if (mpp_lim .and. (model_eqns == 2) .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + rho_visc = rho_visc + alpha_rho_visc(i) + gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) + pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) + end do + else if ((model_eqns == 2) .and. (num_fluids > 2)) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + rho_visc = rho_visc + alpha_rho_visc(i) + gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) + pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) + end do + else + rho_visc = alpha_rho_visc(1) + gamma_visc = gammas(1) + pi_inf_visc = pi_infs(1) + end if else - alpha_visc(i) = q_prim_vf(E_idx + i)%sf(j, k, l) - end if - end do + rho_visc = 0._wp + gamma_visc = 0._wp + pi_inf_visc = 0._wp - if (bubbles_euler) then - rho_visc = 0._wp - gamma_visc = 0._wp - pi_inf_visc = 0._wp + alpha_visc_sum = 0._wp + + if (mpp_lim) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_visc(i) = max(0._wp, alpha_rho_visc(i)) + alpha_visc(i) = min(max(0._wp, alpha_visc(i)), 1._wp) + alpha_visc_sum = alpha_visc_sum + alpha_visc(i) + end do + + alpha_visc = alpha_visc/max(alpha_visc_sum, sgm_eps) + + end if - if (mpp_lim .and. (model_eqns == 2) .and. (num_fluids > 2)) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids rho_visc = rho_visc + alpha_rho_visc(i) gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) end do - else if ((model_eqns == 2) .and. (num_fluids > 2)) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - rho_visc = rho_visc + alpha_rho_visc(i) - gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) - pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) - end do - else - rho_visc = alpha_rho_visc(1) - gamma_visc = gammas(1) - pi_inf_visc = pi_infs(1) - end if - else - rho_visc = 0._wp - gamma_visc = 0._wp - pi_inf_visc = 0._wp - alpha_visc_sum = 0._wp - - if (mpp_lim) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_visc(i) = max(0._wp, alpha_rho_visc(i)) - alpha_visc(i) = min(max(0._wp, alpha_visc(i)), 1._wp) - alpha_visc_sum = alpha_visc_sum + alpha_visc(i) - end do - - alpha_visc = alpha_visc/max(alpha_visc_sum, sgm_eps) - - end if + if (viscous) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, 2 + Re_visc(i) = dflt_real - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_visc = rho_visc + alpha_rho_visc(i) - gamma_visc = gamma_visc + alpha_visc(i)*gammas(i) - pi_inf_visc = pi_inf_visc + alpha_visc(i)*pi_infs(i) - end do + if (Re_size(i) > 0) Re_visc(i) = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do q = 1, Re_size(i) + Re_visc(i) = alpha_visc(Re_idx(i, q))/Res_viscous(i, q) & + + Re_visc(i) + end do - if (viscous) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, 2 - Re_visc(i) = dflt_real + Re_visc(i) = 1._wp/max(Re_visc(i), sgm_eps) - if (Re_size(i) > 0) Re_visc(i) = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do q = 1, Re_size(i) - Re_visc(i) = alpha_visc(Re_idx(i, q))/Res_viscous(i, q) & - + Re_visc(i) end do - - Re_visc(i) = 1._wp/max(Re_visc(i), sgm_eps) - - end do + end if end if - end if - tau_Re(2, 2) = grad_z_vf(3)%sf(j, k, l)/y_cc(k)/ & - Re_visc(2) + tau_Re(2, 2) = grad_z_vf(3)%sf(j, k, l)/y_cc(k)/ & + Re_visc(2) - tau_Re_vf(momxb + 1)%sf(j, k, l) = & - tau_Re_vf(momxb + 1)%sf(j, k, l) - & - tau_Re(2, 2) + tau_Re_vf(momxb + 1)%sf(j, k, l) = & + tau_Re_vf(momxb + 1)%sf(j, k, l) - & + tau_Re(2, 2) - tau_Re_vf(E_idx)%sf(j, k, l) = & - tau_Re_vf(E_idx)%sf(j, k, l) - & - q_prim_vf(momxb + 1)%sf(j, k, l)*tau_Re(2, 2) + tau_Re_vf(E_idx)%sf(j, k, l) = & + tau_Re_vf(E_idx)%sf(j, k, l) - & + q_prim_vf(momxb + 1)%sf(j, k, l)*tau_Re(2, 2) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end subroutine s_compute_viscous_stress_tensor @@ -596,361 +596,361 @@ contains $:GPU_UPDATE(device='[is1_viscous,is2_viscous,is3_viscous]') #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do k = iy%beg, iy%end - do j = is1_viscous%beg + 1, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dqL_prim_dx_n(1)%vf(i)%sf(j, k, l) = & - (q_prim_qp%vf(i)%sf(j, k, l) - & - q_prim_qp%vf(i)%sf(j - 1, k, l))/ & - (x_cc(j) - x_cc(j - 1)) + do l = is3_viscous%beg, is3_viscous%end + do k = iy%beg, iy%end + do j = is1_viscous%beg + 1, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dqL_prim_dx_n(1)%vf(i)%sf(j, k, l) = & + (q_prim_qp%vf(i)%sf(j, k, l) - & + q_prim_qp%vf(i)%sf(j - 1, k, l))/ & + (x_cc(j) - x_cc(j - 1)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg, is1_viscous%end - 1 - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dqR_prim_dx_n(1)%vf(i)%sf(j, k, l) = & - (q_prim_qp%vf(i)%sf(j + 1, k, l) - & - q_prim_qp%vf(i)%sf(j, k, l))/ & - (x_cc(j + 1) - x_cc(j)) + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg, is1_viscous%end - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dqR_prim_dx_n(1)%vf(i)%sf(j, k, l) = & + (q_prim_qp%vf(i)%sf(j + 1, k, l) - & + q_prim_qp%vf(i)%sf(j, k, l))/ & + (x_cc(j + 1) - x_cc(j)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (n > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do j = is2_viscous%beg + 1, is2_viscous%end - do k = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dqL_prim_dy_n(2)%vf(i)%sf(k, j, l) = & - (q_prim_qp%vf(i)%sf(k, j, l) - & - q_prim_qp%vf(i)%sf(k, j - 1, l))/ & - (y_cc(j) - y_cc(j - 1)) + do l = is3_viscous%beg, is3_viscous%end + do j = is2_viscous%beg + 1, is2_viscous%end + do k = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dqL_prim_dy_n(2)%vf(i)%sf(k, j, l) = & + (q_prim_qp%vf(i)%sf(k, j, l) - & + q_prim_qp%vf(i)%sf(k, j - 1, l))/ & + (y_cc(j) - y_cc(j - 1)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do j = is2_viscous%beg, is2_viscous%end - 1 - do k = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dqR_prim_dy_n(2)%vf(i)%sf(k, j, l) = & - (q_prim_qp%vf(i)%sf(k, j + 1, l) - & - q_prim_qp%vf(i)%sf(k, j, l))/ & - (y_cc(j + 1) - y_cc(j)) + do l = is3_viscous%beg, is3_viscous%end + do j = is2_viscous%beg, is2_viscous%end - 1 + do k = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dqR_prim_dy_n(2)%vf(i)%sf(k, j, l) = & + (q_prim_qp%vf(i)%sf(k, j + 1, l) - & + q_prim_qp%vf(i)%sf(k, j, l))/ & + (y_cc(j + 1) - y_cc(j)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do j = is2_viscous%beg + 1, is2_viscous%end - do k = is1_viscous%beg + 1, is1_viscous%end - 1 - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dqL_prim_dx_n(2)%vf(i)%sf(k, j, l) = & - (dqL_prim_dx_n(1)%vf(i)%sf(k, j, l) + & - dqR_prim_dx_n(1)%vf(i)%sf(k, j, l) + & - dqL_prim_dx_n(1)%vf(i)%sf(k, j - 1, l) + & - dqR_prim_dx_n(1)%vf(i)%sf(k, j - 1, l)) - - dqL_prim_dx_n(2)%vf(i)%sf(k, j, l) = 25.e-2_wp* & - dqL_prim_dx_n(2)%vf(i)%sf(k, j, l) + do l = is3_viscous%beg, is3_viscous%end + do j = is2_viscous%beg + 1, is2_viscous%end + do k = is1_viscous%beg + 1, is1_viscous%end - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dqL_prim_dx_n(2)%vf(i)%sf(k, j, l) = & + (dqL_prim_dx_n(1)%vf(i)%sf(k, j, l) + & + dqR_prim_dx_n(1)%vf(i)%sf(k, j, l) + & + dqL_prim_dx_n(1)%vf(i)%sf(k, j - 1, l) + & + dqR_prim_dx_n(1)%vf(i)%sf(k, j - 1, l)) + + dqL_prim_dx_n(2)%vf(i)%sf(k, j, l) = 25.e-2_wp* & + dqL_prim_dx_n(2)%vf(i)%sf(k, j, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do j = is2_viscous%beg, is2_viscous%end - 1 - do k = is1_viscous%beg + 1, is1_viscous%end - 1 - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dqR_prim_dx_n(2)%vf(i)%sf(k, j, l) = & - (dqL_prim_dx_n(1)%vf(i)%sf(k, j + 1, l) + & - dqR_prim_dx_n(1)%vf(i)%sf(k, j + 1, l) + & - dqL_prim_dx_n(1)%vf(i)%sf(k, j, l) + & - dqR_prim_dx_n(1)%vf(i)%sf(k, j, l)) + do l = is3_viscous%beg, is3_viscous%end + do j = is2_viscous%beg, is2_viscous%end - 1 + do k = is1_viscous%beg + 1, is1_viscous%end - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dqR_prim_dx_n(2)%vf(i)%sf(k, j, l) = & + (dqL_prim_dx_n(1)%vf(i)%sf(k, j + 1, l) + & + dqR_prim_dx_n(1)%vf(i)%sf(k, j + 1, l) + & + dqL_prim_dx_n(1)%vf(i)%sf(k, j, l) + & + dqR_prim_dx_n(1)%vf(i)%sf(k, j, l)) - dqR_prim_dx_n(2)%vf(i)%sf(k, j, l) = 25.e-2_wp* & - dqR_prim_dx_n(2)%vf(i)%sf(k, j, l) + dqR_prim_dx_n(2)%vf(i)%sf(k, j, l) = 25.e-2_wp* & + dqR_prim_dx_n(2)%vf(i)%sf(k, j, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg + 1, is2_viscous%end - 1 - do j = is1_viscous%beg + 1, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dqL_prim_dy_n(1)%vf(i)%sf(j, k, l) = & - (dqL_prim_dy_n(2)%vf(i)%sf(j, k, l) + & - dqR_prim_dy_n(2)%vf(i)%sf(j, k, l) + & - dqL_prim_dy_n(2)%vf(i)%sf(j - 1, k, l) + & - dqR_prim_dy_n(2)%vf(i)%sf(j - 1, k, l)) + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg + 1, is2_viscous%end - 1 + do j = is1_viscous%beg + 1, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dqL_prim_dy_n(1)%vf(i)%sf(j, k, l) = & + (dqL_prim_dy_n(2)%vf(i)%sf(j, k, l) + & + dqR_prim_dy_n(2)%vf(i)%sf(j, k, l) + & + dqL_prim_dy_n(2)%vf(i)%sf(j - 1, k, l) + & + dqR_prim_dy_n(2)%vf(i)%sf(j - 1, k, l)) - dqL_prim_dy_n(1)%vf(i)%sf(j, k, l) = 25.e-2_wp* & - dqL_prim_dy_n(1)%vf(i)%sf(j, k, l) + dqL_prim_dy_n(1)%vf(i)%sf(j, k, l) = 25.e-2_wp* & + dqL_prim_dy_n(1)%vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg + 1, is2_viscous%end - 1 - do j = is1_viscous%beg, is1_viscous%end - 1 - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dqR_prim_dy_n(1)%vf(i)%sf(j, k, l) = & - (dqL_prim_dy_n(2)%vf(i)%sf(j + 1, k, l) + & - dqR_prim_dy_n(2)%vf(i)%sf(j + 1, k, l) + & - dqL_prim_dy_n(2)%vf(i)%sf(j, k, l) + & - dqR_prim_dy_n(2)%vf(i)%sf(j, k, l)) + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg + 1, is2_viscous%end - 1 + do j = is1_viscous%beg, is1_viscous%end - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dqR_prim_dy_n(1)%vf(i)%sf(j, k, l) = & + (dqL_prim_dy_n(2)%vf(i)%sf(j + 1, k, l) + & + dqR_prim_dy_n(2)%vf(i)%sf(j + 1, k, l) + & + dqL_prim_dy_n(2)%vf(i)%sf(j, k, l) + & + dqR_prim_dy_n(2)%vf(i)%sf(j, k, l)) - dqR_prim_dy_n(1)%vf(i)%sf(j, k, l) = 25.e-2_wp* & - dqR_prim_dy_n(1)%vf(i)%sf(j, k, l) + dqR_prim_dy_n(1)%vf(i)%sf(j, k, l) = 25.e-2_wp* & + dqR_prim_dy_n(1)%vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (p > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do j = is3_viscous%beg + 1, is3_viscous%end - do l = is2_viscous%beg, is2_viscous%end - do k = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end + do j = is3_viscous%beg + 1, is3_viscous%end + do l = is2_viscous%beg, is2_viscous%end + do k = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end - dqL_prim_dz_n(3)%vf(i)%sf(k, l, j) = & - (q_prim_qp%vf(i)%sf(k, l, j) - & - q_prim_qp%vf(i)%sf(k, l, j - 1))/ & - (z_cc(j) - z_cc(j - 1)) + dqL_prim_dz_n(3)%vf(i)%sf(k, l, j) = & + (q_prim_qp%vf(i)%sf(k, l, j) - & + q_prim_qp%vf(i)%sf(k, l, j - 1))/ & + (z_cc(j) - z_cc(j - 1)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do j = is3_viscous%beg, is3_viscous%end - 1 - do l = is2_viscous%beg, is2_viscous%end - do k = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end + do j = is3_viscous%beg, is3_viscous%end - 1 + do l = is2_viscous%beg, is2_viscous%end + do k = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end - dqR_prim_dz_n(3)%vf(i)%sf(k, l, j) = & - (q_prim_qp%vf(i)%sf(k, l, j + 1) - & - q_prim_qp%vf(i)%sf(k, l, j))/ & - (z_cc(j + 1) - z_cc(j)) + dqR_prim_dz_n(3)%vf(i)%sf(k, l, j) = & + (q_prim_qp%vf(i)%sf(k, l, j + 1) - & + q_prim_qp%vf(i)%sf(k, l, j))/ & + (z_cc(j + 1) - z_cc(j)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg + 1, is3_viscous%end - 1 - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg + 1, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end + do l = is3_viscous%beg + 1, is3_viscous%end - 1 + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg + 1, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end - dqL_prim_dz_n(1)%vf(i)%sf(j, k, l) = & - (dqL_prim_dz_n(3)%vf(i)%sf(j, k, l) + & - dqR_prim_dz_n(3)%vf(i)%sf(j, k, l) + & - dqL_prim_dz_n(3)%vf(i)%sf(j - 1, k, l) + & - dqR_prim_dz_n(3)%vf(i)%sf(j - 1, k, l)) + dqL_prim_dz_n(1)%vf(i)%sf(j, k, l) = & + (dqL_prim_dz_n(3)%vf(i)%sf(j, k, l) + & + dqR_prim_dz_n(3)%vf(i)%sf(j, k, l) + & + dqL_prim_dz_n(3)%vf(i)%sf(j - 1, k, l) + & + dqR_prim_dz_n(3)%vf(i)%sf(j - 1, k, l)) - dqL_prim_dz_n(1)%vf(i)%sf(j, k, l) = 25.e-2_wp* & - dqL_prim_dz_n(1)%vf(i)%sf(j, k, l) + dqL_prim_dz_n(1)%vf(i)%sf(j, k, l) = 25.e-2_wp* & + dqL_prim_dz_n(1)%vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg + 1, is3_viscous%end - 1 - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg, is1_viscous%end - 1 - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end + do l = is3_viscous%beg + 1, is3_viscous%end - 1 + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg, is1_viscous%end - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end - dqR_prim_dz_n(1)%vf(i)%sf(j, k, l) = & - (dqL_prim_dz_n(3)%vf(i)%sf(j + 1, k, l) + & - dqR_prim_dz_n(3)%vf(i)%sf(j + 1, k, l) + & - dqL_prim_dz_n(3)%vf(i)%sf(j, k, l) + & - dqR_prim_dz_n(3)%vf(i)%sf(j, k, l)) + dqR_prim_dz_n(1)%vf(i)%sf(j, k, l) = & + (dqL_prim_dz_n(3)%vf(i)%sf(j + 1, k, l) + & + dqR_prim_dz_n(3)%vf(i)%sf(j + 1, k, l) + & + dqL_prim_dz_n(3)%vf(i)%sf(j, k, l) + & + dqR_prim_dz_n(3)%vf(i)%sf(j, k, l)) - dqR_prim_dz_n(1)%vf(i)%sf(j, k, l) = 25.e-2_wp* & - dqR_prim_dz_n(1)%vf(i)%sf(j, k, l) + dqR_prim_dz_n(1)%vf(i)%sf(j, k, l) = 25.e-2_wp* & + dqR_prim_dz_n(1)%vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg + 1, is3_viscous%end - 1 - do j = is2_viscous%beg + 1, is2_viscous%end - do k = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end + do l = is3_viscous%beg + 1, is3_viscous%end - 1 + do j = is2_viscous%beg + 1, is2_viscous%end + do k = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end - dqL_prim_dz_n(2)%vf(i)%sf(k, j, l) = & - (dqL_prim_dz_n(3)%vf(i)%sf(k, j, l) + & - dqR_prim_dz_n(3)%vf(i)%sf(k, j, l) + & - dqL_prim_dz_n(3)%vf(i)%sf(k, j - 1, l) + & - dqR_prim_dz_n(3)%vf(i)%sf(k, j - 1, l)) + dqL_prim_dz_n(2)%vf(i)%sf(k, j, l) = & + (dqL_prim_dz_n(3)%vf(i)%sf(k, j, l) + & + dqR_prim_dz_n(3)%vf(i)%sf(k, j, l) + & + dqL_prim_dz_n(3)%vf(i)%sf(k, j - 1, l) + & + dqR_prim_dz_n(3)%vf(i)%sf(k, j - 1, l)) - dqL_prim_dz_n(2)%vf(i)%sf(k, j, l) = 25.e-2_wp* & - dqL_prim_dz_n(2)%vf(i)%sf(k, j, l) + dqL_prim_dz_n(2)%vf(i)%sf(k, j, l) = 25.e-2_wp* & + dqL_prim_dz_n(2)%vf(i)%sf(k, j, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg + 1, is3_viscous%end - 1 - do j = is2_viscous%beg, is2_viscous%end - 1 - do k = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end + do l = is3_viscous%beg + 1, is3_viscous%end - 1 + do j = is2_viscous%beg, is2_viscous%end - 1 + do k = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end - dqR_prim_dz_n(2)%vf(i)%sf(k, j, l) = & - (dqL_prim_dz_n(3)%vf(i)%sf(k, j + 1, l) + & - dqR_prim_dz_n(3)%vf(i)%sf(k, j + 1, l) + & - dqL_prim_dz_n(3)%vf(i)%sf(k, j, l) + & - dqR_prim_dz_n(3)%vf(i)%sf(k, j, l)) + dqR_prim_dz_n(2)%vf(i)%sf(k, j, l) = & + (dqL_prim_dz_n(3)%vf(i)%sf(k, j + 1, l) + & + dqR_prim_dz_n(3)%vf(i)%sf(k, j + 1, l) + & + dqL_prim_dz_n(3)%vf(i)%sf(k, j, l) + & + dqR_prim_dz_n(3)%vf(i)%sf(k, j, l)) - dqR_prim_dz_n(2)%vf(i)%sf(k, j, l) = 25.e-2_wp* & - dqR_prim_dz_n(2)%vf(i)%sf(k, j, l) + dqR_prim_dz_n(2)%vf(i)%sf(k, j, l) = 25.e-2_wp* & + dqR_prim_dz_n(2)%vf(i)%sf(k, j, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do j = is3_viscous%beg + 1, is3_viscous%end - do l = is2_viscous%beg + 1, is2_viscous%end - 1 - do k = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end + do j = is3_viscous%beg + 1, is3_viscous%end + do l = is2_viscous%beg + 1, is2_viscous%end - 1 + do k = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end - dqL_prim_dy_n(3)%vf(i)%sf(k, l, j) = & - (dqL_prim_dy_n(2)%vf(i)%sf(k, l, j) + & - dqR_prim_dy_n(2)%vf(i)%sf(k, l, j) + & - dqL_prim_dy_n(2)%vf(i)%sf(k, l, j - 1) + & - dqR_prim_dy_n(2)%vf(i)%sf(k, l, j - 1)) + dqL_prim_dy_n(3)%vf(i)%sf(k, l, j) = & + (dqL_prim_dy_n(2)%vf(i)%sf(k, l, j) + & + dqR_prim_dy_n(2)%vf(i)%sf(k, l, j) + & + dqL_prim_dy_n(2)%vf(i)%sf(k, l, j - 1) + & + dqR_prim_dy_n(2)%vf(i)%sf(k, l, j - 1)) - dqL_prim_dy_n(3)%vf(i)%sf(k, l, j) = 25.e-2_wp* & - dqL_prim_dy_n(3)%vf(i)%sf(k, l, j) + dqL_prim_dy_n(3)%vf(i)%sf(k, l, j) = 25.e-2_wp* & + dqL_prim_dy_n(3)%vf(i)%sf(k, l, j) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do j = is3_viscous%beg, is3_viscous%end - 1 - do l = is2_viscous%beg + 1, is2_viscous%end - 1 - do k = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end + do j = is3_viscous%beg, is3_viscous%end - 1 + do l = is2_viscous%beg + 1, is2_viscous%end - 1 + do k = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end - dqR_prim_dy_n(3)%vf(i)%sf(k, l, j) = & - (dqL_prim_dy_n(2)%vf(i)%sf(k, l, j + 1) + & - dqR_prim_dy_n(2)%vf(i)%sf(k, l, j + 1) + & - dqL_prim_dy_n(2)%vf(i)%sf(k, l, j) + & - dqR_prim_dy_n(2)%vf(i)%sf(k, l, j)) + dqR_prim_dy_n(3)%vf(i)%sf(k, l, j) = & + (dqL_prim_dy_n(2)%vf(i)%sf(k, l, j + 1) + & + dqR_prim_dy_n(2)%vf(i)%sf(k, l, j + 1) + & + dqL_prim_dy_n(2)%vf(i)%sf(k, l, j) + & + dqR_prim_dy_n(2)%vf(i)%sf(k, l, j)) - dqR_prim_dy_n(3)%vf(i)%sf(k, l, j) = 25.e-2_wp* & - dqR_prim_dy_n(3)%vf(i)%sf(k, l, j) + dqR_prim_dy_n(3)%vf(i)%sf(k, l, j) = 25.e-2_wp* & + dqR_prim_dy_n(3)%vf(i)%sf(k, l, j) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do j = is3_viscous%beg + 1, is3_viscous%end - do l = is2_viscous%beg, is2_viscous%end - do k = is1_viscous%beg + 1, is1_viscous%end - 1 - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end + do j = is3_viscous%beg + 1, is3_viscous%end + do l = is2_viscous%beg, is2_viscous%end + do k = is1_viscous%beg + 1, is1_viscous%end - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end - dqL_prim_dx_n(3)%vf(i)%sf(k, l, j) = & - (dqL_prim_dx_n(1)%vf(i)%sf(k, l, j) + & - dqR_prim_dx_n(1)%vf(i)%sf(k, l, j) + & - dqL_prim_dx_n(1)%vf(i)%sf(k, l, j - 1) + & - dqR_prim_dx_n(1)%vf(i)%sf(k, l, j - 1)) + dqL_prim_dx_n(3)%vf(i)%sf(k, l, j) = & + (dqL_prim_dx_n(1)%vf(i)%sf(k, l, j) + & + dqR_prim_dx_n(1)%vf(i)%sf(k, l, j) + & + dqL_prim_dx_n(1)%vf(i)%sf(k, l, j - 1) + & + dqR_prim_dx_n(1)%vf(i)%sf(k, l, j - 1)) - dqL_prim_dx_n(3)%vf(i)%sf(k, l, j) = 25.e-2_wp* & - dqL_prim_dx_n(3)%vf(i)%sf(k, l, j) + dqL_prim_dx_n(3)%vf(i)%sf(k, l, j) = 25.e-2_wp* & + dqL_prim_dx_n(3)%vf(i)%sf(k, l, j) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL_LOOP(collapse=3) - do j = is3_viscous%beg, is3_viscous%end - 1 - do l = is2_viscous%beg, is2_viscous%end - do k = is1_viscous%beg + 1, is1_viscous%end - 1 - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dqR_prim_dx_n(3)%vf(i)%sf(k, l, j) = & - (dqL_prim_dx_n(1)%vf(i)%sf(k, l, j + 1) + & - dqR_prim_dx_n(1)%vf(i)%sf(k, l, j + 1) + & - dqL_prim_dx_n(1)%vf(i)%sf(k, l, j) + & - dqR_prim_dx_n(1)%vf(i)%sf(k, l, j)) + do j = is3_viscous%beg, is3_viscous%end - 1 + do l = is2_viscous%beg, is2_viscous%end + do k = is1_viscous%beg + 1, is1_viscous%end - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dqR_prim_dx_n(3)%vf(i)%sf(k, l, j) = & + (dqL_prim_dx_n(1)%vf(i)%sf(k, l, j + 1) + & + dqR_prim_dx_n(1)%vf(i)%sf(k, l, j + 1) + & + dqL_prim_dx_n(1)%vf(i)%sf(k, l, j) + & + dqR_prim_dx_n(1)%vf(i)%sf(k, l, j)) - dqR_prim_dx_n(3)%vf(i)%sf(k, l, j) = 25.e-2_wp* & - dqR_prim_dx_n(3)%vf(i)%sf(k, l, j) + dqR_prim_dx_n(3)%vf(i)%sf(k, l, j) = 25.e-2_wp* & + dqR_prim_dx_n(3)%vf(i)%sf(k, l, j) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP do i = iv%beg, iv%end @@ -1044,42 +1044,42 @@ contains if (weno_Re_flux) then if (norm_dir == 2) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3_viscous%beg, is3_viscous%end - do j = is1_viscous%beg, is1_viscous%end - do k = is2_viscous%beg, is2_viscous%end - vL_prim_vf(i)%sf(k, j, l) = vL_y(j, k, l, i) - vR_prim_vf(i)%sf(k, j, l) = vR_y(j, k, l, i) + do i = iv%beg, iv%end + do l = is3_viscous%beg, is3_viscous%end + do j = is1_viscous%beg, is1_viscous%end + do k = is2_viscous%beg, is2_viscous%end + vL_prim_vf(i)%sf(k, j, l) = vL_y(j, k, l, i) + vR_prim_vf(i)%sf(k, j, l) = vR_y(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (norm_dir == 3) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do j = is1_viscous%beg, is1_viscous%end - do k = is2_viscous%beg, is2_viscous%end - do l = is3_viscous%beg, is3_viscous%end - vL_prim_vf(i)%sf(l, k, j) = vL_z(j, k, l, i) - vR_prim_vf(i)%sf(l, k, j) = vR_z(j, k, l, i) + do i = iv%beg, iv%end + do j = is1_viscous%beg, is1_viscous%end + do k = is2_viscous%beg, is2_viscous%end + do l = is3_viscous%beg, is3_viscous%end + vL_prim_vf(i)%sf(l, k, j) = vL_z(j, k, l, i) + vR_prim_vf(i)%sf(l, k, j) = vR_z(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (norm_dir == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg, is1_viscous%end - vL_prim_vf(i)%sf(j, k, l) = vL_x(j, k, l, i) - vR_prim_vf(i)%sf(j, k, l) = vR_x(j, k, l, i) + do i = iv%beg, iv%end + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg, is1_viscous%end + vL_prim_vf(i)%sf(j, k, l) = vL_x(j, k, l, i) + vR_prim_vf(i)%sf(j, k, l) = vR_x(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if @@ -1146,42 +1146,42 @@ contains if (weno_Re_flux) then if (norm_dir == 2) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3_viscous%beg, is3_viscous%end - do j = is1_viscous%beg, is1_viscous%end - do k = is2_viscous%beg, is2_viscous%end - vL_prim_vf(i)%sf(k, j, l) = vL_y(j, k, l, i) - vR_prim_vf(i)%sf(k, j, l) = vR_y(j, k, l, i) + do i = iv%beg, iv%end + do l = is3_viscous%beg, is3_viscous%end + do j = is1_viscous%beg, is1_viscous%end + do k = is2_viscous%beg, is2_viscous%end + vL_prim_vf(i)%sf(k, j, l) = vL_y(j, k, l, i) + vR_prim_vf(i)%sf(k, j, l) = vR_y(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (norm_dir == 3) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do j = is1_viscous%beg, is1_viscous%end - do k = is2_viscous%beg, is2_viscous%end - do l = is3_viscous%beg, is3_viscous%end - vL_prim_vf(i)%sf(l, k, j) = vL_z(j, k, l, i) - vR_prim_vf(i)%sf(l, k, j) = vR_z(j, k, l, i) + do i = iv%beg, iv%end + do j = is1_viscous%beg, is1_viscous%end + do k = is2_viscous%beg, is2_viscous%end + do l = is3_viscous%beg, is3_viscous%end + vL_prim_vf(i)%sf(l, k, j) = vL_z(j, k, l, i) + vR_prim_vf(i)%sf(l, k, j) = vR_z(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (norm_dir == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg, is1_viscous%end - vL_prim_vf(i)%sf(j, k, l) = vL_x(j, k, l, i) - vR_prim_vf(i)%sf(j, k, l) = vR_x(j, k, l, i) + do i = iv%beg, iv%end + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg, is1_viscous%end + vL_prim_vf(i)%sf(j, k, l) = vL_x(j, k, l, i) + vR_prim_vf(i)%sf(j, k, l) = vR_x(j, k, l, i) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if @@ -1237,21 +1237,21 @@ contains ! spatial derivatives inside the cell. #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg + 1, is1_viscous%end - 1 - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dv_ds_vf(i)%sf(j, k, l) = & - 1._wp/((1._wp + wa_flg)*dL(j)) & - *(wa_flg*vL_vf(i)%sf(j + 1, k, l) & - + vR_vf(i)%sf(j, k, l) & - - vL_vf(i)%sf(j, k, l) & - - wa_flg*vR_vf(i)%sf(j - 1, k, l)) + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg + 1, is1_viscous%end - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dv_ds_vf(i)%sf(j, k, l) = & + 1._wp/((1._wp + wa_flg)*dL(j)) & + *(wa_flg*vL_vf(i)%sf(j + 1, k, l) & + + vR_vf(i)%sf(j, k, l) & + - vL_vf(i)%sf(j, k, l) & + - wa_flg*vR_vf(i)%sf(j - 1, k, l)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP ! END: First-Order Spatial Derivatives in x-direction @@ -1266,21 +1266,21 @@ contains ! spatial derivatives inside the cell. #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg + 1, is2_viscous%end - 1 - do j = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dv_ds_vf(i)%sf(j, k, l) = & - 1._wp/((1._wp + wa_flg)*dL(k)) & - *(wa_flg*vL_vf(i)%sf(j, k + 1, l) & - + vR_vf(i)%sf(j, k, l) & - - vL_vf(i)%sf(j, k, l) & - - wa_flg*vR_vf(i)%sf(j, k - 1, l)) + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg + 1, is2_viscous%end - 1 + do j = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dv_ds_vf(i)%sf(j, k, l) = & + 1._wp/((1._wp + wa_flg)*dL(k)) & + *(wa_flg*vL_vf(i)%sf(j, k + 1, l) & + + vR_vf(i)%sf(j, k, l) & + - vL_vf(i)%sf(j, k, l) & + - wa_flg*vR_vf(i)%sf(j, k - 1, l)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP ! END: First-Order Spatial Derivatives in y-direction @@ -1295,21 +1295,21 @@ contains ! spatial derivatives inside the cell. #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg + 1, is3_viscous%end - 1 - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg, is1_viscous%end - $:GPU_LOOP(parallelism='[seq]') - do i = iv%beg, iv%end - dv_ds_vf(i)%sf(j, k, l) = & - 1._wp/((1._wp + wa_flg)*dL(l)) & - *(wa_flg*vL_vf(i)%sf(j, k, l + 1) & - + vR_vf(i)%sf(j, k, l) & - - vL_vf(i)%sf(j, k, l) & - - wa_flg*vR_vf(i)%sf(j, k, l - 1)) + do l = is3_viscous%beg + 1, is3_viscous%end - 1 + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg, is1_viscous%end + $:GPU_LOOP(parallelism='[seq]') + do i = iv%beg, iv%end + dv_ds_vf(i)%sf(j, k, l) = & + 1._wp/((1._wp + wa_flg)*dL(l)) & + *(wa_flg*vL_vf(i)%sf(j, k, l + 1) & + + vR_vf(i)%sf(j, k, l) & + - vL_vf(i)%sf(j, k, l) & + - wa_flg*vR_vf(i)%sf(j, k, l - 1)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1351,148 +1351,148 @@ contains $:GPU_UPDATE(device='[is1_viscous,is2_viscous,is3_viscous]') #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg, is1_viscous%end - grad_x%sf(j, k, l) = & - (var%sf(j + 1, k, l) - var%sf(j - 1, k, l))/ & - (x_cc(j + 1) - x_cc(j - 1)) + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg, is1_viscous%end + grad_x%sf(j, k, l) = & + (var%sf(j + 1, k, l) - var%sf(j - 1, k, l))/ & + (x_cc(j + 1) - x_cc(j - 1)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (n > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg, is1_viscous%end - grad_y%sf(j, k, l) = & - (var%sf(j, k + 1, l) - var%sf(j, k - 1, l))/ & - (y_cc(k + 1) - y_cc(k - 1)) + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg, is1_viscous%end + grad_y%sf(j, k, l) = & + (var%sf(j, k + 1, l) - var%sf(j, k - 1, l))/ & + (y_cc(k + 1) - y_cc(k - 1)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (p > 0) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = is3_viscous%beg, is3_viscous%end - do k = is2_viscous%beg, is2_viscous%end - do j = is1_viscous%beg, is1_viscous%end - grad_z%sf(j, k, l) = & - (var%sf(j, k, l + 1) - var%sf(j, k, l - 1))/ & - (z_cc(l + 1) - z_cc(l - 1)) + do l = is3_viscous%beg, is3_viscous%end + do k = is2_viscous%beg, is2_viscous%end + do j = is1_viscous%beg, is1_viscous%end + grad_z%sf(j, k, l) = & + (var%sf(j, k, l + 1) - var%sf(j, k, l - 1))/ & + (z_cc(l + 1) - z_cc(l - 1)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:call GPU_PARALLEL_LOOP(collapse=2) - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - grad_x%sf(idwbuff(1)%beg, k, l) = & - (-3._wp*var%sf(idwbuff(1)%beg, k, l) + 4._wp*var%sf(idwbuff(1)%beg + 1, k, l) - var%sf(idwbuff(1)%beg + 2, k, l))/ & - (x_cc(idwbuff(1)%beg + 2) - x_cc(idwbuff(1)%beg)) - grad_x%sf(idwbuff(1)%end, k, l) = & - (+3._wp*var%sf(idwbuff(1)%end, k, l) - 4._wp*var%sf(idwbuff(1)%end - 1, k, l) + var%sf(idwbuff(1)%end - 2, k, l))/ & - (x_cc(idwbuff(1)%end) - x_cc(idwbuff(1)%end - 2)) + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + grad_x%sf(idwbuff(1)%beg, k, l) = & + (-3._wp*var%sf(idwbuff(1)%beg, k, l) + 4._wp*var%sf(idwbuff(1)%beg + 1, k, l) - var%sf(idwbuff(1)%beg + 2, k, l))/ & + (x_cc(idwbuff(1)%beg + 2) - x_cc(idwbuff(1)%beg)) + grad_x%sf(idwbuff(1)%end, k, l) = & + (+3._wp*var%sf(idwbuff(1)%end, k, l) - 4._wp*var%sf(idwbuff(1)%end - 1, k, l) + var%sf(idwbuff(1)%end - 2, k, l))/ & + (x_cc(idwbuff(1)%end) - x_cc(idwbuff(1)%end - 2)) + end do end do - end do #:endcall GPU_PARALLEL_LOOP if (n > 0) then #:call GPU_PARALLEL_LOOP(collapse=2) - do l = idwbuff(3)%beg, idwbuff(3)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - grad_y%sf(j, idwbuff(2)%beg, l) = & - (-3._wp*var%sf(j, idwbuff(2)%beg, l) + 4._wp*var%sf(j, idwbuff(2)%beg + 1, l) - var%sf(j, idwbuff(2)%beg + 2, l))/ & - (y_cc(idwbuff(2)%beg + 2) - y_cc(idwbuff(2)%beg)) - grad_y%sf(j, idwbuff(2)%end, l) = & - (+3._wp*var%sf(j, idwbuff(2)%end, l) - 4._wp*var%sf(j, idwbuff(2)%end - 1, l) + var%sf(j, idwbuff(2)%end - 2, l))/ & - (y_cc(idwbuff(2)%end) - y_cc(idwbuff(2)%end - 2)) + do l = idwbuff(3)%beg, idwbuff(3)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + grad_y%sf(j, idwbuff(2)%beg, l) = & + (-3._wp*var%sf(j, idwbuff(2)%beg, l) + 4._wp*var%sf(j, idwbuff(2)%beg + 1, l) - var%sf(j, idwbuff(2)%beg + 2, l))/ & + (y_cc(idwbuff(2)%beg + 2) - y_cc(idwbuff(2)%beg)) + grad_y%sf(j, idwbuff(2)%end, l) = & + (+3._wp*var%sf(j, idwbuff(2)%end, l) - 4._wp*var%sf(j, idwbuff(2)%end - 1, l) + var%sf(j, idwbuff(2)%end - 2, l))/ & + (y_cc(idwbuff(2)%end) - y_cc(idwbuff(2)%end - 2)) + end do end do - end do #:endcall GPU_PARALLEL_LOOP if (p > 0) then #:call GPU_PARALLEL_LOOP(collapse=2) - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - grad_z%sf(j, k, idwbuff(3)%beg) = & - (-3._wp*var%sf(j, k, idwbuff(3)%beg) + 4._wp*var%sf(j, k, idwbuff(3)%beg + 1) - var%sf(j, k, idwbuff(3)%beg + 2))/ & - (z_cc(idwbuff(3)%beg + 2) - z_cc(is3_viscous%beg)) - grad_z%sf(j, k, idwbuff(3)%end) = & - (+3._wp*var%sf(j, k, idwbuff(3)%end) - 4._wp*var%sf(j, k, idwbuff(3)%end - 1) + var%sf(j, k, idwbuff(3)%end - 2))/ & - (z_cc(idwbuff(3)%end) - z_cc(idwbuff(3)%end - 2)) + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + grad_z%sf(j, k, idwbuff(3)%beg) = & + (-3._wp*var%sf(j, k, idwbuff(3)%beg) + 4._wp*var%sf(j, k, idwbuff(3)%beg + 1) - var%sf(j, k, idwbuff(3)%beg + 2))/ & + (z_cc(idwbuff(3)%beg + 2) - z_cc(is3_viscous%beg)) + grad_z%sf(j, k, idwbuff(3)%end) = & + (+3._wp*var%sf(j, k, idwbuff(3)%end) - 4._wp*var%sf(j, k, idwbuff(3)%end - 1) + var%sf(j, k, idwbuff(3)%end - 2))/ & + (z_cc(idwbuff(3)%end) - z_cc(idwbuff(3)%end - 2)) + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if if (bc_x%beg <= BC_GHOST_EXTRAP) then #:call GPU_PARALLEL_LOOP(collapse=2) - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - grad_x%sf(0, k, l) = (-3._wp*var%sf(0, k, l) + 4._wp*var%sf(1, k, l) - var%sf(2, k, l))/ & - (x_cc(2) - x_cc(0)) + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + grad_x%sf(0, k, l) = (-3._wp*var%sf(0, k, l) + 4._wp*var%sf(1, k, l) - var%sf(2, k, l))/ & + (x_cc(2) - x_cc(0)) + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (bc_x%end <= BC_GHOST_EXTRAP) then #:call GPU_PARALLEL_LOOP(collapse=2) - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - grad_x%sf(m, k, l) = (3._wp*var%sf(m, k, l) - 4._wp*var%sf(m - 1, k, l) + var%sf(m - 2, k, l))/ & - (x_cc(m) - x_cc(m - 2)) + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + grad_x%sf(m, k, l) = (3._wp*var%sf(m, k, l) - 4._wp*var%sf(m - 1, k, l) + var%sf(m - 2, k, l))/ & + (x_cc(m) - x_cc(m - 2)) + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (n > 0) then if (bc_y%beg <= BC_GHOST_EXTRAP .and. bc_y%beg /= BC_NULL) then #:call GPU_PARALLEL_LOOP(collapse=2) - do l = idwbuff(3)%beg, idwbuff(3)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - grad_y%sf(j, 0, l) = (-3._wp*var%sf(j, 0, l) + 4._wp*var%sf(j, 1, l) - var%sf(j, 2, l))/ & - (y_cc(2) - y_cc(0)) + do l = idwbuff(3)%beg, idwbuff(3)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + grad_y%sf(j, 0, l) = (-3._wp*var%sf(j, 0, l) + 4._wp*var%sf(j, 1, l) - var%sf(j, 2, l))/ & + (y_cc(2) - y_cc(0)) + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (bc_y%end <= BC_GHOST_EXTRAP) then #:call GPU_PARALLEL_LOOP(collapse=2) - do l = idwbuff(3)%beg, idwbuff(3)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - grad_y%sf(j, n, l) = (3._wp*var%sf(j, n, l) - 4._wp*var%sf(j, n - 1, l) + var%sf(j, n - 2, l))/ & - (y_cc(n) - y_cc(n - 2)) + do l = idwbuff(3)%beg, idwbuff(3)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + grad_y%sf(j, n, l) = (3._wp*var%sf(j, n, l) - 4._wp*var%sf(j, n - 1, l) + var%sf(j, n - 2, l))/ & + (y_cc(n) - y_cc(n - 2)) + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (p > 0) then if (bc_z%beg <= BC_GHOST_EXTRAP) then #:call GPU_PARALLEL_LOOP(collapse=2) - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - grad_z%sf(j, k, 0) = & - (-3._wp*var%sf(j, k, 0) + 4._wp*var%sf(j, k, 1) - var%sf(j, k, 2))/ & - (z_cc(2) - z_cc(0)) + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + grad_z%sf(j, k, 0) = & + (-3._wp*var%sf(j, k, 0) + 4._wp*var%sf(j, k, 1) - var%sf(j, k, 2))/ & + (z_cc(2) - z_cc(0)) + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if if (bc_z%end <= BC_GHOST_EXTRAP) then #:call GPU_PARALLEL_LOOP(collapse=2) - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - grad_z%sf(j, k, p) = & - (3._wp*var%sf(j, k, p) - 4._wp*var%sf(j, k, p - 1) + var%sf(j, k, p - 2))/ & - (z_cc(p) - z_cc(p - 2)) + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + grad_z%sf(j, k, p) = & + (3._wp*var%sf(j, k, p) - 4._wp*var%sf(j, k, p - 1) + var%sf(j, k, p - 2))/ & + (z_cc(p) - z_cc(p - 2)) + end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if diff --git a/src/simulation/m_weno.fpp b/src/simulation/m_weno.fpp index 9dd9dcfbf7..bbaf3648a3 100644 --- a/src/simulation/m_weno.fpp +++ b/src/simulation/m_weno.fpp @@ -669,120 +669,120 @@ contains if (weno_order == 1) then if (weno_dir == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, ubound(v_vf, 1) - do l = is3_weno%beg, is3_weno%end - do k = is2_weno%beg, is2_weno%end - do j = is1_weno%beg, is1_weno%end - vL_rs_vf_x(j, k, l, i) = v_vf(i)%sf(j, k, l) - vR_rs_vf_x(j, k, l, i) = v_vf(i)%sf(j, k, l) + do i = 1, ubound(v_vf, 1) + do l = is3_weno%beg, is3_weno%end + do k = is2_weno%beg, is2_weno%end + do j = is1_weno%beg, is1_weno%end + vL_rs_vf_x(j, k, l, i) = v_vf(i)%sf(j, k, l) + vR_rs_vf_x(j, k, l, i) = v_vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else if (weno_dir == 2) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, ubound(v_vf, 1) - do l = is3_weno%beg, is3_weno%end - do k = is2_weno%beg, is2_weno%end - do j = is1_weno%beg, is1_weno%end - vL_rs_vf_y(j, k, l, i) = v_vf(i)%sf(k, j, l) - vR_rs_vf_y(j, k, l, i) = v_vf(i)%sf(k, j, l) + do i = 1, ubound(v_vf, 1) + do l = is3_weno%beg, is3_weno%end + do k = is2_weno%beg, is2_weno%end + do j = is1_weno%beg, is1_weno%end + vL_rs_vf_y(j, k, l, i) = v_vf(i)%sf(k, j, l) + vR_rs_vf_y(j, k, l, i) = v_vf(i)%sf(k, j, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else if (weno_dir == 3) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, ubound(v_vf, 1) - do l = is3_weno%beg, is3_weno%end - do k = is2_weno%beg, is2_weno%end - do j = is1_weno%beg, is1_weno%end - vL_rs_vf_z(j, k, l, i) = v_vf(i)%sf(l, k, j) - vR_rs_vf_z(j, k, l, i) = v_vf(i)%sf(l, k, j) + do i = 1, ubound(v_vf, 1) + do l = is3_weno%beg, is3_weno%end + do k = is2_weno%beg, is2_weno%end + do j = is1_weno%beg, is1_weno%end + vL_rs_vf_z(j, k, l, i) = v_vf(i)%sf(l, k, j) + vR_rs_vf_z(j, k, l, i) = v_vf(i)%sf(l, k, j) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if elseif (weno_order == 3) then #:for WENO_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (weno_dir == ${WENO_DIR}$) then #:call GPU_PARALLEL_LOOP(collapse=4,private='[beta,dvd,poly,omega,alpha,tau]') - do l = is3_weno%beg, is3_weno%end - do k = is2_weno%beg, is2_weno%end - do j = is1_weno%beg, is1_weno%end - do i = 1, v_size - ! reconstruct from left side - - dvd(0) = v_rs_ws_${XYZ}$ (j + 1, k, l, i) & - - v_rs_ws_${XYZ}$ (j, k, l, i) - dvd(-1) = v_rs_ws_${XYZ}$ (j, k, l, i) & - - v_rs_ws_${XYZ}$ (j - 1, k, l, i) - - poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbL_${XYZ}$ (j, 0, 0)*dvd(0) - poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbL_${XYZ}$ (j, 1, 0)*dvd(-1) - - beta(0) = beta_coef_${XYZ}$ (j, 0, 0)*dvd(0)*dvd(0) & - + weno_eps - beta(1) = beta_coef_${XYZ}$ (j, 1, 0)*dvd(-1)*dvd(-1) & - + weno_eps - - if (wenojs) then - alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) - - elseif (mapped_weno) then - alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) - omega = alpha/sum(alpha) - alpha = (d_cbL_${XYZ}$ (:, j)*(1._wp + d_cbL_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & - *(omega/(d_cbL_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbL_${XYZ}$ (:, j)))) + do l = is3_weno%beg, is3_weno%end + do k = is2_weno%beg, is2_weno%end + do j = is1_weno%beg, is1_weno%end + do i = 1, v_size + ! reconstruct from left side - elseif (wenoz) then - ! Borges, et al. (2008) + dvd(0) = v_rs_ws_${XYZ}$ (j + 1, k, l, i) & + - v_rs_ws_${XYZ}$ (j, k, l, i) + dvd(-1) = v_rs_ws_${XYZ}$ (j, k, l, i) & + - v_rs_ws_${XYZ}$ (j - 1, k, l, i) - tau = abs(beta(1) - beta(0)) - alpha = d_cbL_${XYZ}$ (:, j)*(1._wp + tau/beta) + poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbL_${XYZ}$ (j, 0, 0)*dvd(0) + poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbL_${XYZ}$ (j, 1, 0)*dvd(-1) - end if + beta(0) = beta_coef_${XYZ}$ (j, 0, 0)*dvd(0)*dvd(0) & + + weno_eps + beta(1) = beta_coef_${XYZ}$ (j, 1, 0)*dvd(-1)*dvd(-1) & + + weno_eps - omega = alpha/sum(alpha) + if (wenojs) then + alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) - vL_rs_vf_${XYZ}$ (j, k, l, i) = omega(0)*poly(0) + omega(1)*poly(1) + elseif (mapped_weno) then + alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) + omega = alpha/sum(alpha) + alpha = (d_cbL_${XYZ}$ (:, j)*(1._wp + d_cbL_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & + *(omega/(d_cbL_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbL_${XYZ}$ (:, j)))) - ! reconstruct from right side + elseif (wenoz) then + ! Borges, et al. (2008) - poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbR_${XYZ}$ (j, 0, 0)*dvd(0) - poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbR_${XYZ}$ (j, 1, 0)*dvd(-1) + tau = abs(beta(1) - beta(0)) + alpha = d_cbL_${XYZ}$ (:, j)*(1._wp + tau/beta) - if (wenojs) then - alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) + end if - elseif (mapped_weno) then - alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) omega = alpha/sum(alpha) - alpha = (d_cbR_${XYZ}$ (:, j)*(1._wp + d_cbR_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & - *(omega/(d_cbR_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbR_${XYZ}$ (:, j)))) - elseif (wenoz) then + vL_rs_vf_${XYZ}$ (j, k, l, i) = omega(0)*poly(0) + omega(1)*poly(1) + + ! reconstruct from right side + + poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbR_${XYZ}$ (j, 0, 0)*dvd(0) + poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbR_${XYZ}$ (j, 1, 0)*dvd(-1) + + if (wenojs) then + alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) + + elseif (mapped_weno) then + alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) + omega = alpha/sum(alpha) + alpha = (d_cbR_${XYZ}$ (:, j)*(1._wp + d_cbR_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & + *(omega/(d_cbR_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbR_${XYZ}$ (:, j)))) + + elseif (wenoz) then - alpha = d_cbR_${XYZ}$ (:, j)*(1._wp + tau/beta) + alpha = d_cbR_${XYZ}$ (:, j)*(1._wp + tau/beta) - end if + end if - omega = alpha/sum(alpha) + omega = alpha/sum(alpha) - vR_rs_vf_${XYZ}$ (j, k, l, i) = omega(0)*poly(0) + omega(1)*poly(1) + vR_rs_vf_${XYZ}$ (j, k, l, i) = omega(0)*poly(0) + omega(1)*poly(1) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:endfor @@ -790,114 +790,114 @@ contains #:for WENO_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (weno_dir == ${WENO_DIR}$) then #:call GPU_PARALLEL_LOOP(collapse=3,private='[dvd,poly,beta,alpha,omega,tau,delta]') - do l = is3_weno%beg, is3_weno%end - do k = is2_weno%beg, is2_weno%end - do j = is1_weno%beg, is1_weno%end - $:GPU_LOOP(parallelism='[seq]') - do i = 1, v_size - ! reconstruct from left side - - dvd(1) = v_rs_ws_${XYZ}$ (j + 2, k, l, i) & - - v_rs_ws_${XYZ}$ (j + 1, k, l, i) - dvd(0) = v_rs_ws_${XYZ}$ (j + 1, k, l, i) & - - v_rs_ws_${XYZ}$ (j, k, l, i) - dvd(-1) = v_rs_ws_${XYZ}$ (j, k, l, i) & - - v_rs_ws_${XYZ}$ (j - 1, k, l, i) - dvd(-2) = v_rs_ws_${XYZ}$ (j - 1, k, l, i) & - - v_rs_ws_${XYZ}$ (j - 2, k, l, i) - - poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbL_${XYZ}$ (j, 0, 0)*dvd(1) & - + poly_coef_cbL_${XYZ}$ (j, 0, 1)*dvd(0) - poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbL_${XYZ}$ (j, 1, 0)*dvd(0) & - + poly_coef_cbL_${XYZ}$ (j, 1, 1)*dvd(-1) - poly(2) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbL_${XYZ}$ (j, 2, 0)*dvd(-1) & - + poly_coef_cbL_${XYZ}$ (j, 2, 1)*dvd(-2) - - beta(0) = beta_coef_${XYZ}$ (j, 0, 0)*dvd(1)*dvd(1) & - + beta_coef_${XYZ}$ (j, 0, 1)*dvd(1)*dvd(0) & - + beta_coef_${XYZ}$ (j, 0, 2)*dvd(0)*dvd(0) & - + weno_eps - beta(1) = beta_coef_${XYZ}$ (j, 1, 0)*dvd(0)*dvd(0) & - + beta_coef_${XYZ}$ (j, 1, 1)*dvd(0)*dvd(-1) & - + beta_coef_${XYZ}$ (j, 1, 2)*dvd(-1)*dvd(-1) & - + weno_eps - beta(2) = beta_coef_${XYZ}$ (j, 2, 0)*dvd(-1)*dvd(-1) & - + beta_coef_${XYZ}$ (j, 2, 1)*dvd(-1)*dvd(-2) & - + beta_coef_${XYZ}$ (j, 2, 2)*dvd(-2)*dvd(-2) & - + weno_eps - - if (wenojs) then - alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) - - elseif (mapped_weno) then - alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) - omega = alpha/sum(alpha) - alpha = (d_cbL_${XYZ}$ (:, j)*(1._wp + d_cbL_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & - *(omega/(d_cbL_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbL_${XYZ}$ (:, j)))) + do l = is3_weno%beg, is3_weno%end + do k = is2_weno%beg, is2_weno%end + do j = is1_weno%beg, is1_weno%end + $:GPU_LOOP(parallelism='[seq]') + do i = 1, v_size + ! reconstruct from left side - elseif (wenoz) then - ! Borges, et al. (2008) + dvd(1) = v_rs_ws_${XYZ}$ (j + 2, k, l, i) & + - v_rs_ws_${XYZ}$ (j + 1, k, l, i) + dvd(0) = v_rs_ws_${XYZ}$ (j + 1, k, l, i) & + - v_rs_ws_${XYZ}$ (j, k, l, i) + dvd(-1) = v_rs_ws_${XYZ}$ (j, k, l, i) & + - v_rs_ws_${XYZ}$ (j - 1, k, l, i) + dvd(-2) = v_rs_ws_${XYZ}$ (j - 1, k, l, i) & + - v_rs_ws_${XYZ}$ (j - 2, k, l, i) - tau = abs(beta(2) - beta(0)) ! Equation 25 - alpha = d_cbL_${XYZ}$ (:, j)*(1._wp + tau/beta) ! Equation 28 (note: weno_eps was already added to beta) + poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbL_${XYZ}$ (j, 0, 0)*dvd(1) & + + poly_coef_cbL_${XYZ}$ (j, 0, 1)*dvd(0) + poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbL_${XYZ}$ (j, 1, 0)*dvd(0) & + + poly_coef_cbL_${XYZ}$ (j, 1, 1)*dvd(-1) + poly(2) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbL_${XYZ}$ (j, 2, 0)*dvd(-1) & + + poly_coef_cbL_${XYZ}$ (j, 2, 1)*dvd(-2) - elseif (teno) then - ! Fu, et al. (2016) - ! Fu''s code: https://dx.doi.org/10.13140/RG.2.2.36250.34247 - tau = abs(beta(2) - beta(0)) - alpha = 1._wp + tau/beta ! Equation 22 (reuse alpha as gamma; pick C=1 & q=6) - alpha = (alpha*alpha*alpha)**2._wp ! Equation 22 cont. (some CPU compilers cannot optimize x**6.0) - omega = alpha/sum(alpha) ! Equation 25 (reuse omega as xi) - delta = merge(0._wp, 1._wp, omega < teno_CT)! Equation 26 - alpha = delta*d_cbL_${XYZ}$ (:, j) ! Equation 27 + beta(0) = beta_coef_${XYZ}$ (j, 0, 0)*dvd(1)*dvd(1) & + + beta_coef_${XYZ}$ (j, 0, 1)*dvd(1)*dvd(0) & + + beta_coef_${XYZ}$ (j, 0, 2)*dvd(0)*dvd(0) & + + weno_eps + beta(1) = beta_coef_${XYZ}$ (j, 1, 0)*dvd(0)*dvd(0) & + + beta_coef_${XYZ}$ (j, 1, 1)*dvd(0)*dvd(-1) & + + beta_coef_${XYZ}$ (j, 1, 2)*dvd(-1)*dvd(-1) & + + weno_eps + beta(2) = beta_coef_${XYZ}$ (j, 2, 0)*dvd(-1)*dvd(-1) & + + beta_coef_${XYZ}$ (j, 2, 1)*dvd(-1)*dvd(-2) & + + beta_coef_${XYZ}$ (j, 2, 2)*dvd(-2)*dvd(-2) & + + weno_eps - end if + if (wenojs) then + alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) - omega = alpha/sum(alpha) + elseif (mapped_weno) then + alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) + omega = alpha/sum(alpha) + alpha = (d_cbL_${XYZ}$ (:, j)*(1._wp + d_cbL_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & + *(omega/(d_cbL_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbL_${XYZ}$ (:, j)))) - vL_rs_vf_${XYZ}$ (j, k, l, i) = sum(omega*poly) + elseif (wenoz) then + ! Borges, et al. (2008) - ! reconstruct from right side + tau = abs(beta(2) - beta(0)) ! Equation 25 + alpha = d_cbL_${XYZ}$ (:, j)*(1._wp + tau/beta) ! Equation 28 (note: weno_eps was already added to beta) - poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbR_${XYZ}$ (j, 0, 0)*dvd(1) & - + poly_coef_cbR_${XYZ}$ (j, 0, 1)*dvd(0) - poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbR_${XYZ}$ (j, 1, 0)*dvd(0) & - + poly_coef_cbR_${XYZ}$ (j, 1, 1)*dvd(-1) - poly(2) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbR_${XYZ}$ (j, 2, 0)*dvd(-1) & - + poly_coef_cbR_${XYZ}$ (j, 2, 1)*dvd(-2) + elseif (teno) then + ! Fu, et al. (2016) + ! Fu''s code: https://dx.doi.org/10.13140/RG.2.2.36250.34247 + tau = abs(beta(2) - beta(0)) + alpha = 1._wp + tau/beta ! Equation 22 (reuse alpha as gamma; pick C=1 & q=6) + alpha = (alpha*alpha*alpha)**2._wp ! Equation 22 cont. (some CPU compilers cannot optimize x**6.0) + omega = alpha/sum(alpha) ! Equation 25 (reuse omega as xi) + delta = merge(0._wp, 1._wp, omega < teno_CT)! Equation 26 + alpha = delta*d_cbL_${XYZ}$ (:, j) ! Equation 27 - if (wenojs) then - alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) + end if - elseif (mapped_weno) then - alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) omega = alpha/sum(alpha) - alpha = (d_cbR_${XYZ}$ (:, j)*(1._wp + d_cbR_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & - *(omega/(d_cbR_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbR_${XYZ}$ (:, j)))) - elseif (wenoz) then + vL_rs_vf_${XYZ}$ (j, k, l, i) = sum(omega*poly) + + ! reconstruct from right side + + poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbR_${XYZ}$ (j, 0, 0)*dvd(1) & + + poly_coef_cbR_${XYZ}$ (j, 0, 1)*dvd(0) + poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbR_${XYZ}$ (j, 1, 0)*dvd(0) & + + poly_coef_cbR_${XYZ}$ (j, 1, 1)*dvd(-1) + poly(2) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbR_${XYZ}$ (j, 2, 0)*dvd(-1) & + + poly_coef_cbR_${XYZ}$ (j, 2, 1)*dvd(-2) + + if (wenojs) then + alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) + + elseif (mapped_weno) then + alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) + omega = alpha/sum(alpha) + alpha = (d_cbR_${XYZ}$ (:, j)*(1._wp + d_cbR_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & + *(omega/(d_cbR_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbR_${XYZ}$ (:, j)))) + + elseif (wenoz) then - alpha = d_cbR_${XYZ}$ (:, j)*(1._wp + tau/beta) + alpha = d_cbR_${XYZ}$ (:, j)*(1._wp + tau/beta) - elseif (teno) then - alpha = delta*d_cbR_${XYZ}$ (:, j) + elseif (teno) then + alpha = delta*d_cbR_${XYZ}$ (:, j) - end if + end if - omega = alpha/sum(alpha) + omega = alpha/sum(alpha) - vR_rs_vf_${XYZ}$ (j, k, l, i) = sum(omega*poly) + vR_rs_vf_${XYZ}$ (j, k, l, i) = sum(omega*poly) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (mp_weno) then @@ -910,190 +910,190 @@ contains #:for WENO_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (weno_dir == ${WENO_DIR}$) then #:call GPU_PARALLEL_LOOP(collapse=3,private='[poly,beta,alpha,omega,tau,delta,dvd,v]') - do l = is3_weno%beg, is3_weno%end - do k = is2_weno%beg, is2_weno%end - do j = is1_weno%beg, is1_weno%end - $:GPU_LOOP(parallelism='[seq]') - do i = 1, v_size - - if (teno) v = v_rs_ws_${XYZ}$ (j - 3:j + 3, k, l, i) ! temporary field value array for clarity - - if (.not. teno) then - dvd(2) = v_rs_ws_${XYZ}$ (j + 3, k, l, i) & - - v_rs_ws_${XYZ}$ (j + 2, k, l, i) - dvd(1) = v_rs_ws_${XYZ}$ (j + 2, k, l, i) & - - v_rs_ws_${XYZ}$ (j + 1, k, l, i) - dvd(0) = v_rs_ws_${XYZ}$ (j + 1, k, l, i) & - - v_rs_ws_${XYZ}$ (j, k, l, i) - dvd(-1) = v_rs_ws_${XYZ}$ (j, k, l, i) & - - v_rs_ws_${XYZ}$ (j - 1, k, l, i) - dvd(-2) = v_rs_ws_${XYZ}$ (j - 1, k, l, i) & - - v_rs_ws_${XYZ}$ (j - 2, k, l, i) - dvd(-3) = v_rs_ws_${XYZ}$ (j - 2, k, l, i) & - - v_rs_ws_${XYZ}$ (j - 3, k, l, i) - - poly(3) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbL_${XYZ}$ (j, 0, 0)*dvd(2) & - + poly_coef_cbL_${XYZ}$ (j, 0, 1)*dvd(1) & - + poly_coef_cbL_${XYZ}$ (j, 0, 2)*dvd(0) - poly(2) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbL_${XYZ}$ (j, 1, 0)*dvd(1) & - + poly_coef_cbL_${XYZ}$ (j, 1, 1)*dvd(0) & - + poly_coef_cbL_${XYZ}$ (j, 1, 2)*dvd(-1) - poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbL_${XYZ}$ (j, 2, 0)*dvd(0) & - + poly_coef_cbL_${XYZ}$ (j, 2, 1)*dvd(-1) & - + poly_coef_cbL_${XYZ}$ (j, 2, 2)*dvd(-2) - poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbL_${XYZ}$ (j, 3, 0)*dvd(-1) & - + poly_coef_cbL_${XYZ}$ (j, 3, 1)*dvd(-2) & - + poly_coef_cbL_${XYZ}$ (j, 3, 2)*dvd(-3) - - else - ! (Fu, et al., 2016) Table 1 - ! Note: Unlike TENO5, TENO7 stencils differ from WENO7 stencils - ! See Figure 2 (right) for right-sided flux (at i+1/2) - ! Here we need the left-sided flux, so we flip the weights with respect to the x=i point - ! But we need to keep the stencil order to reuse the beta coefficients - poly(0) = ( 2._wp*v(-1) + 5._wp*v( 0) - 1._wp*v( 1)) / 6._wp !& - poly(1) = (11._wp*v( 0) - 7._wp*v( 1) + 2._wp*v( 2)) / 6._wp !& - poly(2) = (-1._wp*v(-2) + 5._wp*v(-1) + 2._wp*v( 0)) / 6._wp !& - poly(3) = (25._wp*v( 0) - 23._wp*v( 1) + 13._wp*v( 2) - 3._wp*v( 3)) / 12._wp !& - poly(4) = ( 1._wp*v(-3) - 5._wp*v(-2) + 13._wp*v(-1) + 3._wp*v( 0)) / 12._wp !& - end if - - if (.not. teno) then - - beta(3) = beta_coef_${XYZ}$ (j, 0, 0)*dvd(2)*dvd(2) & - + beta_coef_${XYZ}$ (j, 0, 1)*dvd(2)*dvd(1) & - + beta_coef_${XYZ}$ (j, 0, 2)*dvd(2)*dvd(0) & - + beta_coef_${XYZ}$ (j, 0, 3)*dvd(1)*dvd(1) & - + beta_coef_${XYZ}$ (j, 0, 4)*dvd(1)*dvd(0) & - + beta_coef_${XYZ}$ (j, 0, 5)*dvd(0)*dvd(0) & - + weno_eps - - beta(2) = beta_coef_${XYZ}$ (j, 1, 0)*dvd(1)*dvd(1) & - + beta_coef_${XYZ}$ (j, 1, 1)*dvd(1)*dvd(0) & - + beta_coef_${XYZ}$ (j, 1, 2)*dvd(1)*dvd(-1) & - + beta_coef_${XYZ}$ (j, 1, 3)*dvd(0)*dvd(0) & - + beta_coef_${XYZ}$ (j, 1, 4)*dvd(0)*dvd(-1) & - + beta_coef_${XYZ}$ (j, 1, 5)*dvd(-1)*dvd(-1) & - + weno_eps + do l = is3_weno%beg, is3_weno%end + do k = is2_weno%beg, is2_weno%end + do j = is1_weno%beg, is1_weno%end + $:GPU_LOOP(parallelism='[seq]') + do i = 1, v_size + + if (teno) v = v_rs_ws_${XYZ}$ (j - 3:j + 3, k, l, i) ! temporary field value array for clarity + + if (.not. teno) then + dvd(2) = v_rs_ws_${XYZ}$ (j + 3, k, l, i) & + - v_rs_ws_${XYZ}$ (j + 2, k, l, i) + dvd(1) = v_rs_ws_${XYZ}$ (j + 2, k, l, i) & + - v_rs_ws_${XYZ}$ (j + 1, k, l, i) + dvd(0) = v_rs_ws_${XYZ}$ (j + 1, k, l, i) & + - v_rs_ws_${XYZ}$ (j, k, l, i) + dvd(-1) = v_rs_ws_${XYZ}$ (j, k, l, i) & + - v_rs_ws_${XYZ}$ (j - 1, k, l, i) + dvd(-2) = v_rs_ws_${XYZ}$ (j - 1, k, l, i) & + - v_rs_ws_${XYZ}$ (j - 2, k, l, i) + dvd(-3) = v_rs_ws_${XYZ}$ (j - 2, k, l, i) & + - v_rs_ws_${XYZ}$ (j - 3, k, l, i) + + poly(3) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbL_${XYZ}$ (j, 0, 0)*dvd(2) & + + poly_coef_cbL_${XYZ}$ (j, 0, 1)*dvd(1) & + + poly_coef_cbL_${XYZ}$ (j, 0, 2)*dvd(0) + poly(2) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbL_${XYZ}$ (j, 1, 0)*dvd(1) & + + poly_coef_cbL_${XYZ}$ (j, 1, 1)*dvd(0) & + + poly_coef_cbL_${XYZ}$ (j, 1, 2)*dvd(-1) + poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbL_${XYZ}$ (j, 2, 0)*dvd(0) & + + poly_coef_cbL_${XYZ}$ (j, 2, 1)*dvd(-1) & + + poly_coef_cbL_${XYZ}$ (j, 2, 2)*dvd(-2) + poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbL_${XYZ}$ (j, 3, 0)*dvd(-1) & + + poly_coef_cbL_${XYZ}$ (j, 3, 1)*dvd(-2) & + + poly_coef_cbL_${XYZ}$ (j, 3, 2)*dvd(-3) + + else + ! (Fu, et al., 2016) Table 1 + ! Note: Unlike TENO5, TENO7 stencils differ from WENO7 stencils + ! See Figure 2 (right) for right-sided flux (at i+1/2) + ! Here we need the left-sided flux, so we flip the weights with respect to the x=i point + ! But we need to keep the stencil order to reuse the beta coefficients + poly(0) = ( 2._wp*v(-1) + 5._wp*v( 0) - 1._wp*v( 1)) / 6._wp !& + poly(1) = (11._wp*v( 0) - 7._wp*v( 1) + 2._wp*v( 2)) / 6._wp !& + poly(2) = (-1._wp*v(-2) + 5._wp*v(-1) + 2._wp*v( 0)) / 6._wp !& + poly(3) = (25._wp*v( 0) - 23._wp*v( 1) + 13._wp*v( 2) - 3._wp*v( 3)) / 12._wp !& + poly(4) = ( 1._wp*v(-3) - 5._wp*v(-2) + 13._wp*v(-1) + 3._wp*v( 0)) / 12._wp !& + end if + + if (.not. teno) then + + beta(3) = beta_coef_${XYZ}$ (j, 0, 0)*dvd(2)*dvd(2) & + + beta_coef_${XYZ}$ (j, 0, 1)*dvd(2)*dvd(1) & + + beta_coef_${XYZ}$ (j, 0, 2)*dvd(2)*dvd(0) & + + beta_coef_${XYZ}$ (j, 0, 3)*dvd(1)*dvd(1) & + + beta_coef_${XYZ}$ (j, 0, 4)*dvd(1)*dvd(0) & + + beta_coef_${XYZ}$ (j, 0, 5)*dvd(0)*dvd(0) & + + weno_eps + + beta(2) = beta_coef_${XYZ}$ (j, 1, 0)*dvd(1)*dvd(1) & + + beta_coef_${XYZ}$ (j, 1, 1)*dvd(1)*dvd(0) & + + beta_coef_${XYZ}$ (j, 1, 2)*dvd(1)*dvd(-1) & + + beta_coef_${XYZ}$ (j, 1, 3)*dvd(0)*dvd(0) & + + beta_coef_${XYZ}$ (j, 1, 4)*dvd(0)*dvd(-1) & + + beta_coef_${XYZ}$ (j, 1, 5)*dvd(-1)*dvd(-1) & + + weno_eps + + beta(1) = beta_coef_${XYZ}$ (j, 2, 0)*dvd(0)*dvd(0) & + + beta_coef_${XYZ}$ (j, 2, 1)*dvd(0)*dvd(-1) & + + beta_coef_${XYZ}$ (j, 2, 2)*dvd(0)*dvd(-2) & + + beta_coef_${XYZ}$ (j, 2, 3)*dvd(-1)*dvd(-1) & + + beta_coef_${XYZ}$ (j, 2, 4)*dvd(-1)*dvd(-2) & + + beta_coef_${XYZ}$ (j, 2, 5)*dvd(-2)*dvd(-2) & + + weno_eps + + beta(0) = beta_coef_${XYZ}$ (j, 3, 0)*dvd(-1)*dvd(-1) & + + beta_coef_${XYZ}$ (j, 3, 1)*dvd(-1)*dvd(-2) & + + beta_coef_${XYZ}$ (j, 3, 2)*dvd(-1)*dvd(-3) & + + beta_coef_${XYZ}$ (j, 3, 3)*dvd(-2)*dvd(-2) & + + beta_coef_${XYZ}$ (j, 3, 4)*dvd(-2)*dvd(-3) & + + beta_coef_${XYZ}$ (j, 3, 5)*dvd(-3)*dvd(-3) & + + weno_eps + + else ! TENO + ! High-Order Low-Dissipation Targeted ENO Schemes for Ideal Magnetohydrodynamics (Fu & Tang, 2019) Section 3.2 + beta(0) = 13._wp/12._wp*(v(-1) - 2._wp*v( 0) + v( 1))**2._wp + (( v(-1) - v( 1))**2._wp)/4._wp + weno_eps !& + beta(1) = 13._wp/12._wp*(v( 0) - 2._wp*v( 1) + v( 2))**2._wp + ((3._wp*v( 0) - 4._wp*v( 1) + v( 2))**2._wp)/4._wp + weno_eps !& + beta(2) = 13._wp/12._wp*(v(-2) - 2._wp*v(-1) + v( 0))**2._wp + (( v(-2) - 4._wp*v(-1) + 3._wp*v( 0))**2._wp)/4._wp + weno_eps !& + + beta(3) = ( v( 0)*(2107._wp*v( 0) - 9402._wp*v( 1) + 7042._wp*v( 2) - 1854._wp*v( 3)) & !& + + v( 1)*( 11003._wp*v( 1) - 17246._wp*v( 2) + 4642._wp*v( 3)) & !& + + v( 2)*( 7043._wp*v( 2) - 3882._wp*v( 3)) & !& + + v( 3)*( 547._wp*v( 3)) ) / 240._wp & !& + + weno_eps !& + + beta(4) = ( v(-3)*(547._wp*v(-3) - 3882._wp*v(-2) + 4642._wp*v(-1) - 1854._wp*v( 0)) & !& + + v(-2)*( 7043._wp*v(-2) - 17246._wp*v(-1) + 7042._wp*v( 0)) & !& + + v(-1)*( 11003._wp*v(-1) - 9402._wp*v( 0)) & !& + + v( 0)*( 2107._wp*v( 0)) ) / 240._wp & !& + + weno_eps !& + end if + + if (wenojs) then + alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) + + elseif (mapped_weno) then + alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) + omega = alpha/sum(alpha) + alpha = (d_cbL_${XYZ}$ (:, j)*(1._wp + d_cbL_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & + *(omega/(d_cbL_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbL_${XYZ}$ (:, j)))) + + elseif (wenoz) then + ! Castro, et al. (2010) + ! Don & Borges (2013) also helps + tau = abs(beta(3) - beta(0)) ! Equation 50 + alpha = d_cbL_${XYZ}$ (:, j)*(1._wp + (tau/beta)**wenoz_q) ! q = 2,3,4 for stability + + elseif (teno) then + tau = abs(beta(4) - beta(3)) ! Note the reordering of stencils + alpha = 1._wp + tau/beta + alpha = (alpha*alpha*alpha)**2._wp ! some CPU compilers cannot optimize x**6.0 + omega = alpha/sum(alpha) + delta = merge(0._wp, 1._wp, omega < teno_CT) + alpha = delta*d_cbL_${XYZ}$ (:, j) + + end if - beta(1) = beta_coef_${XYZ}$ (j, 2, 0)*dvd(0)*dvd(0) & - + beta_coef_${XYZ}$ (j, 2, 1)*dvd(0)*dvd(-1) & - + beta_coef_${XYZ}$ (j, 2, 2)*dvd(0)*dvd(-2) & - + beta_coef_${XYZ}$ (j, 2, 3)*dvd(-1)*dvd(-1) & - + beta_coef_${XYZ}$ (j, 2, 4)*dvd(-1)*dvd(-2) & - + beta_coef_${XYZ}$ (j, 2, 5)*dvd(-2)*dvd(-2) & - + weno_eps - - beta(0) = beta_coef_${XYZ}$ (j, 3, 0)*dvd(-1)*dvd(-1) & - + beta_coef_${XYZ}$ (j, 3, 1)*dvd(-1)*dvd(-2) & - + beta_coef_${XYZ}$ (j, 3, 2)*dvd(-1)*dvd(-3) & - + beta_coef_${XYZ}$ (j, 3, 3)*dvd(-2)*dvd(-2) & - + beta_coef_${XYZ}$ (j, 3, 4)*dvd(-2)*dvd(-3) & - + beta_coef_${XYZ}$ (j, 3, 5)*dvd(-3)*dvd(-3) & - + weno_eps - - else ! TENO - ! High-Order Low-Dissipation Targeted ENO Schemes for Ideal Magnetohydrodynamics (Fu & Tang, 2019) Section 3.2 - beta(0) = 13._wp/12._wp*(v(-1) - 2._wp*v( 0) + v( 1))**2._wp + (( v(-1) - v( 1))**2._wp)/4._wp + weno_eps !& - beta(1) = 13._wp/12._wp*(v( 0) - 2._wp*v( 1) + v( 2))**2._wp + ((3._wp*v( 0) - 4._wp*v( 1) + v( 2))**2._wp)/4._wp + weno_eps !& - beta(2) = 13._wp/12._wp*(v(-2) - 2._wp*v(-1) + v( 0))**2._wp + (( v(-2) - 4._wp*v(-1) + 3._wp*v( 0))**2._wp)/4._wp + weno_eps !& - - beta(3) = ( v( 0)*(2107._wp*v( 0) - 9402._wp*v( 1) + 7042._wp*v( 2) - 1854._wp*v( 3)) & !& - + v( 1)*( 11003._wp*v( 1) - 17246._wp*v( 2) + 4642._wp*v( 3)) & !& - + v( 2)*( 7043._wp*v( 2) - 3882._wp*v( 3)) & !& - + v( 3)*( 547._wp*v( 3)) ) / 240._wp & !& - + weno_eps !& - - beta(4) = ( v(-3)*(547._wp*v(-3) - 3882._wp*v(-2) + 4642._wp*v(-1) - 1854._wp*v( 0)) & !& - + v(-2)*( 7043._wp*v(-2) - 17246._wp*v(-1) + 7042._wp*v( 0)) & !& - + v(-1)*( 11003._wp*v(-1) - 9402._wp*v( 0)) & !& - + v( 0)*( 2107._wp*v( 0)) ) / 240._wp & !& - + weno_eps !& - end if - - if (wenojs) then - alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) - - elseif (mapped_weno) then - alpha = d_cbL_${XYZ}$ (:, j)/(beta*beta) - omega = alpha/sum(alpha) - alpha = (d_cbL_${XYZ}$ (:, j)*(1._wp + d_cbL_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & - *(omega/(d_cbL_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbL_${XYZ}$ (:, j)))) - - elseif (wenoz) then - ! Castro, et al. (2010) - ! Don & Borges (2013) also helps - tau = abs(beta(3) - beta(0)) ! Equation 50 - alpha = d_cbL_${XYZ}$ (:, j)*(1._wp + (tau/beta)**wenoz_q) ! q = 2,3,4 for stability - - elseif (teno) then - tau = abs(beta(4) - beta(3)) ! Note the reordering of stencils - alpha = 1._wp + tau/beta - alpha = (alpha*alpha*alpha)**2._wp ! some CPU compilers cannot optimize x**6.0 omega = alpha/sum(alpha) - delta = merge(0._wp, 1._wp, omega < teno_CT) - alpha = delta*d_cbL_${XYZ}$ (:, j) - - end if - omega = alpha/sum(alpha) + vL_rs_vf_${XYZ}$ (j, k, l, i) = sum(omega*poly) + + if (.not. teno) then + poly(3) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbR_${XYZ}$ (j, 0, 0)*dvd(2) & + + poly_coef_cbR_${XYZ}$ (j, 0, 1)*dvd(1) & + + poly_coef_cbR_${XYZ}$ (j, 0, 2)*dvd(0) + poly(2) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbR_${XYZ}$ (j, 1, 0)*dvd(1) & + + poly_coef_cbR_${XYZ}$ (j, 1, 1)*dvd(0) & + + poly_coef_cbR_${XYZ}$ (j, 1, 2)*dvd(-1) + poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbR_${XYZ}$ (j, 2, 0)*dvd(0) & + + poly_coef_cbR_${XYZ}$ (j, 2, 1)*dvd(-1) & + + poly_coef_cbR_${XYZ}$ (j, 2, 2)*dvd(-2) + poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & + + poly_coef_cbR_${XYZ}$ (j, 3, 0)*dvd(-1) & + + poly_coef_cbR_${XYZ}$ (j, 3, 1)*dvd(-2) & + + poly_coef_cbR_${XYZ}$ (j, 3, 2)*dvd(-3) + else + poly(0) = (-1._wp*v(-1) + 5._wp*v( 0) + 2._wp*v( 1)) / 6._wp !& + poly(1) = ( 2._wp*v( 0) + 5._wp*v( 1) - 1._wp*v( 2)) / 6._wp !& + poly(2) = ( 2._wp*v(-2) - 7._wp*v(-1) + 11._wp*v( 0)) / 6._wp !& + poly(3) = ( 3._wp*v( 0) + 13._wp*v( 1) - 5._wp*v( 2) + 1._wp*v( 3)) / 12._wp !& + poly(4) = (-3._wp*v(-3) + 13._wp*v(-2) - 23._wp*v(-1) + 25._wp*v( 0)) / 12._wp !& + end if + + if (wenojs) then + alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) + + elseif (mapped_weno) then + alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) + omega = alpha/sum(alpha) + alpha = (d_cbR_${XYZ}$ (:, j)*(1._wp + d_cbR_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & + *(omega/(d_cbR_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbR_${XYZ}$ (:, j)))) + + elseif (wenoz) then + alpha = d_cbR_${XYZ}$ (:, j)*(1._wp + (tau/beta)**wenoz_q) + + elseif (teno) then + alpha = delta*d_cbR_${XYZ}$ (:, j) + + end if - vL_rs_vf_${XYZ}$ (j, k, l, i) = sum(omega*poly) - - if (.not. teno) then - poly(3) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbR_${XYZ}$ (j, 0, 0)*dvd(2) & - + poly_coef_cbR_${XYZ}$ (j, 0, 1)*dvd(1) & - + poly_coef_cbR_${XYZ}$ (j, 0, 2)*dvd(0) - poly(2) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbR_${XYZ}$ (j, 1, 0)*dvd(1) & - + poly_coef_cbR_${XYZ}$ (j, 1, 1)*dvd(0) & - + poly_coef_cbR_${XYZ}$ (j, 1, 2)*dvd(-1) - poly(1) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbR_${XYZ}$ (j, 2, 0)*dvd(0) & - + poly_coef_cbR_${XYZ}$ (j, 2, 1)*dvd(-1) & - + poly_coef_cbR_${XYZ}$ (j, 2, 2)*dvd(-2) - poly(0) = v_rs_ws_${XYZ}$ (j, k, l, i) & - + poly_coef_cbR_${XYZ}$ (j, 3, 0)*dvd(-1) & - + poly_coef_cbR_${XYZ}$ (j, 3, 1)*dvd(-2) & - + poly_coef_cbR_${XYZ}$ (j, 3, 2)*dvd(-3) - else - poly(0) = (-1._wp*v(-1) + 5._wp*v( 0) + 2._wp*v( 1)) / 6._wp !& - poly(1) = ( 2._wp*v( 0) + 5._wp*v( 1) - 1._wp*v( 2)) / 6._wp !& - poly(2) = ( 2._wp*v(-2) - 7._wp*v(-1) + 11._wp*v( 0)) / 6._wp !& - poly(3) = ( 3._wp*v( 0) + 13._wp*v( 1) - 5._wp*v( 2) + 1._wp*v( 3)) / 12._wp !& - poly(4) = (-3._wp*v(-3) + 13._wp*v(-2) - 23._wp*v(-1) + 25._wp*v( 0)) / 12._wp !& - end if - - if (wenojs) then - alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) - - elseif (mapped_weno) then - alpha = d_cbR_${XYZ}$ (:, j)/(beta*beta) omega = alpha/sum(alpha) - alpha = (d_cbR_${XYZ}$ (:, j)*(1._wp + d_cbR_${XYZ}$ (:, j) - 3._wp*omega) + omega**2._wp) & - *(omega/(d_cbR_${XYZ}$ (:, j)**2._wp + omega*(1._wp - 2._wp*d_cbR_${XYZ}$ (:, j)))) - - elseif (wenoz) then - alpha = d_cbR_${XYZ}$ (:, j)*(1._wp + (tau/beta)**wenoz_q) - elseif (teno) then - alpha = delta*d_cbR_${XYZ}$ (:, j) - - end if - - omega = alpha/sum(alpha) - - vR_rs_vf_${XYZ}$ (j, k, l, i) = sum(omega*poly) + vR_rs_vf_${XYZ}$ (j, k, l, i) = sum(omega*poly) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1133,15 +1133,15 @@ contains if (weno_dir == 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do j = 1, v_size - do q = is3_weno%beg, is3_weno%end - do l = is2_weno%beg, is2_weno%end - do k = is1_weno%beg - weno_polyn, is1_weno%end + weno_polyn - v_rs_ws_x(k, l, q, j) = v_vf(j)%sf(k, l, q) + do j = 1, v_size + do q = is3_weno%beg, is3_weno%end + do l = is2_weno%beg, is2_weno%end + do k = is1_weno%beg - weno_polyn, is1_weno%end + weno_polyn + v_rs_ws_x(k, l, q, j) = v_vf(j)%sf(k, l, q) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1227,130 +1227,130 @@ contains real(wp), parameter :: beta_mp = 4._wp/3._wp #:call GPU_PARALLEL_LOOP(collapse=4,private='[d]') - do l = is3_weno%beg, is3_weno%end - do k = is2_weno%beg, is2_weno%end - do j = is1_weno%beg, is1_weno%end - do i = 1, v_size - d(-1) = v_rs_ws(j, k, l, i) & - + v_rs_ws(j - 2, k, l, i) & - - v_rs_ws(j - 1, k, l, i) & - *2._wp - d(0) = v_rs_ws(j + 1, k, l, i) & - + v_rs_ws(j - 1, k, l, i) & - - v_rs_ws(j, k, l, i) & - *2._wp - d(1) = v_rs_ws(j + 2, k, l, i) & - + v_rs_ws(j, k, l, i) & - - v_rs_ws(j + 1, k, l, i) & - *2._wp - - d_MD = (sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, 4._wp*d(0) - d(-1))) & - *abs((sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, d(-1))) & - *(sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, d(0)))) & - *min(abs(4._wp*d(-1) - d(0)), abs(d(-1)), & - abs(4._wp*d(0) - d(-1)), abs(d(0)))/8._wp - - d_LC = (sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, 4._wp*d(1) - d(0))) & - *abs((sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, d(0))) & - *(sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, d(1)))) & - *min(abs(4._wp*d(0) - d(1)), abs(d(0)), & - abs(4._wp*d(1) - d(0)), abs(d(1)))/8._wp - - vL_UL = v_rs_ws(j, k, l, i) & - - (v_rs_ws(j + 1, k, l, i) & - - v_rs_ws(j, k, l, i))*alpha_mp - - vL_MD = (v_rs_ws(j, k, l, i) & - + v_rs_ws(j - 1, k, l, i) & - - d_MD)*5.e-1_wp - - vL_LC = v_rs_ws(j, k, l, i) & - - (v_rs_ws(j + 1, k, l, i) & - - v_rs_ws(j, k, l, i))*5.e-1_wp + beta_mp*d_LC - - vL_min = max(min(v_rs_ws(j, k, l, i), & - v_rs_ws(j - 1, k, l, i), & - vL_MD), & - min(v_rs_ws(j, k, l, i), & - vL_UL, & - vL_LC)) - - vL_max = min(max(v_rs_ws(j, k, l, i), & - v_rs_ws(j - 1, k, l, i), & - vL_MD), & - max(v_rs_ws(j, k, l, i), & - vL_UL, & - vL_LC)) - - vL_rs_vf(j, k, l, i) = vL_rs_vf(j, k, l, i) & - + (sign(5.e-1_wp, vL_min - vL_rs_vf(j, k, l, i)) & - + sign(5.e-1_wp, vL_max - vL_rs_vf(j, k, l, i))) & - *min(abs(vL_min - vL_rs_vf(j, k, l, i)), & - abs(vL_max - vL_rs_vf(j, k, l, i))) - ! END: Left Monotonicity Preserving Bound - - ! Right Monotonicity Preserving Bound - d(-1) = v_rs_ws(j, k, l, i) & - + v_rs_ws(j - 2, k, l, i) & - - v_rs_ws(j - 1, k, l, i) & - *2._wp - d(0) = v_rs_ws(j + 1, k, l, i) & - + v_rs_ws(j - 1, k, l, i) & - - v_rs_ws(j, k, l, i) & - *2._wp - d(1) = v_rs_ws(j + 2, k, l, i) & - + v_rs_ws(j, k, l, i) & - - v_rs_ws(j + 1, k, l, i) & - *2._wp - - d_MD = (sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, 4._wp*d(1) - d(0))) & - *abs((sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, d(0))) & - *(sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, d(1)))) & - *min(abs(4._wp*d(0) - d(1)), abs(d(0)), & - abs(4._wp*d(1) - d(0)), abs(d(1)))/8._wp - - d_LC = (sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, 4._wp*d(0) - d(-1))) & - *abs((sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, d(-1))) & - *(sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, d(0)))) & - *min(abs(4._wp*d(-1) - d(0)), abs(d(-1)), & - abs(4._wp*d(0) - d(-1)), abs(d(0)))/8._wp - - vR_UL = v_rs_ws(j, k, l, i) & - + (v_rs_ws(j, k, l, i) & - - v_rs_ws(j - 1, k, l, i))*alpha_mp - - vR_MD = (v_rs_ws(j, k, l, i) & - + v_rs_ws(j + 1, k, l, i) & - - d_MD)*5.e-1_wp - - vR_LC = v_rs_ws(j, k, l, i) & - + (v_rs_ws(j, k, l, i) & - - v_rs_ws(j - 1, k, l, i))*5.e-1_wp + beta_mp*d_LC - - vR_min = max(min(v_rs_ws(j, k, l, i), & - v_rs_ws(j + 1, k, l, i), & - vR_MD), & - min(v_rs_ws(j, k, l, i), & - vR_UL, & - vR_LC)) - - vR_max = min(max(v_rs_ws(j, k, l, i), & - v_rs_ws(j + 1, k, l, i), & - vR_MD), & - max(v_rs_ws(j, k, l, i), & - vR_UL, & - vR_LC)) - - vR_rs_vf(j, k, l, i) = vR_rs_vf(j, k, l, i) & - + (sign(5.e-1_wp, vR_min - vR_rs_vf(j, k, l, i)) & - + sign(5.e-1_wp, vR_max - vR_rs_vf(j, k, l, i))) & - *min(abs(vR_min - vR_rs_vf(j, k, l, i)), & - abs(vR_max - vR_rs_vf(j, k, l, i))) - ! END: Right Monotonicity Preserving Bound + do l = is3_weno%beg, is3_weno%end + do k = is2_weno%beg, is2_weno%end + do j = is1_weno%beg, is1_weno%end + do i = 1, v_size + d(-1) = v_rs_ws(j, k, l, i) & + + v_rs_ws(j - 2, k, l, i) & + - v_rs_ws(j - 1, k, l, i) & + *2._wp + d(0) = v_rs_ws(j + 1, k, l, i) & + + v_rs_ws(j - 1, k, l, i) & + - v_rs_ws(j, k, l, i) & + *2._wp + d(1) = v_rs_ws(j + 2, k, l, i) & + + v_rs_ws(j, k, l, i) & + - v_rs_ws(j + 1, k, l, i) & + *2._wp + + d_MD = (sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, 4._wp*d(0) - d(-1))) & + *abs((sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, d(-1))) & + *(sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, d(0)))) & + *min(abs(4._wp*d(-1) - d(0)), abs(d(-1)), & + abs(4._wp*d(0) - d(-1)), abs(d(0)))/8._wp + + d_LC = (sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, 4._wp*d(1) - d(0))) & + *abs((sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, d(0))) & + *(sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, d(1)))) & + *min(abs(4._wp*d(0) - d(1)), abs(d(0)), & + abs(4._wp*d(1) - d(0)), abs(d(1)))/8._wp + + vL_UL = v_rs_ws(j, k, l, i) & + - (v_rs_ws(j + 1, k, l, i) & + - v_rs_ws(j, k, l, i))*alpha_mp + + vL_MD = (v_rs_ws(j, k, l, i) & + + v_rs_ws(j - 1, k, l, i) & + - d_MD)*5.e-1_wp + + vL_LC = v_rs_ws(j, k, l, i) & + - (v_rs_ws(j + 1, k, l, i) & + - v_rs_ws(j, k, l, i))*5.e-1_wp + beta_mp*d_LC + + vL_min = max(min(v_rs_ws(j, k, l, i), & + v_rs_ws(j - 1, k, l, i), & + vL_MD), & + min(v_rs_ws(j, k, l, i), & + vL_UL, & + vL_LC)) + + vL_max = min(max(v_rs_ws(j, k, l, i), & + v_rs_ws(j - 1, k, l, i), & + vL_MD), & + max(v_rs_ws(j, k, l, i), & + vL_UL, & + vL_LC)) + + vL_rs_vf(j, k, l, i) = vL_rs_vf(j, k, l, i) & + + (sign(5.e-1_wp, vL_min - vL_rs_vf(j, k, l, i)) & + + sign(5.e-1_wp, vL_max - vL_rs_vf(j, k, l, i))) & + *min(abs(vL_min - vL_rs_vf(j, k, l, i)), & + abs(vL_max - vL_rs_vf(j, k, l, i))) + ! END: Left Monotonicity Preserving Bound + + ! Right Monotonicity Preserving Bound + d(-1) = v_rs_ws(j, k, l, i) & + + v_rs_ws(j - 2, k, l, i) & + - v_rs_ws(j - 1, k, l, i) & + *2._wp + d(0) = v_rs_ws(j + 1, k, l, i) & + + v_rs_ws(j - 1, k, l, i) & + - v_rs_ws(j, k, l, i) & + *2._wp + d(1) = v_rs_ws(j + 2, k, l, i) & + + v_rs_ws(j, k, l, i) & + - v_rs_ws(j + 1, k, l, i) & + *2._wp + + d_MD = (sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, 4._wp*d(1) - d(0))) & + *abs((sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, d(0))) & + *(sign(1._wp, 4._wp*d(0) - d(1)) + sign(1._wp, d(1)))) & + *min(abs(4._wp*d(0) - d(1)), abs(d(0)), & + abs(4._wp*d(1) - d(0)), abs(d(1)))/8._wp + + d_LC = (sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, 4._wp*d(0) - d(-1))) & + *abs((sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, d(-1))) & + *(sign(1._wp, 4._wp*d(-1) - d(0)) + sign(1._wp, d(0)))) & + *min(abs(4._wp*d(-1) - d(0)), abs(d(-1)), & + abs(4._wp*d(0) - d(-1)), abs(d(0)))/8._wp + + vR_UL = v_rs_ws(j, k, l, i) & + + (v_rs_ws(j, k, l, i) & + - v_rs_ws(j - 1, k, l, i))*alpha_mp + + vR_MD = (v_rs_ws(j, k, l, i) & + + v_rs_ws(j + 1, k, l, i) & + - d_MD)*5.e-1_wp + + vR_LC = v_rs_ws(j, k, l, i) & + + (v_rs_ws(j, k, l, i) & + - v_rs_ws(j - 1, k, l, i))*5.e-1_wp + beta_mp*d_LC + + vR_min = max(min(v_rs_ws(j, k, l, i), & + v_rs_ws(j + 1, k, l, i), & + vR_MD), & + min(v_rs_ws(j, k, l, i), & + vR_UL, & + vR_LC)) + + vR_max = min(max(v_rs_ws(j, k, l, i), & + v_rs_ws(j + 1, k, l, i), & + vR_MD), & + max(v_rs_ws(j, k, l, i), & + vR_UL, & + vR_LC)) + + vR_rs_vf(j, k, l, i) = vR_rs_vf(j, k, l, i) & + + (sign(5.e-1_wp, vR_min - vR_rs_vf(j, k, l, i)) & + + sign(5.e-1_wp, vR_max - vR_rs_vf(j, k, l, i))) & + *min(abs(vR_min - vR_rs_vf(j, k, l, i)), & + abs(vR_max - vR_rs_vf(j, k, l, i))) + ! END: Right Monotonicity Preserving Bound + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end subroutine s_preserve_monotonicity From cec9867b75c5fb0a36ce358c9fc4d0e60aa85d72 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Mon, 21 Jul 2025 18:01:02 -0400 Subject: [PATCH 010/199] Fixed some issues with matching start and end of parallel loop macros, started work on enter and exit data, compiles --- src/common/include/acc_macros.fpp | 34 ++ src/common/include/omp_macros.fpp | 36 +- src/common/include/parallel_macros.fpp | 20 +- src/simulation/m_rhs.fpp | 574 +++++++++--------- src/simulation/m_time_steppers.fpp | 798 ++++++++++++------------- 5 files changed, 766 insertions(+), 696 deletions(-) diff --git a/src/common/include/acc_macros.fpp b/src/common/include/acc_macros.fpp index 4da5ab0231..77e896f91e 100644 --- a/src/common/include/acc_macros.fpp +++ b/src/common/include/acc_macros.fpp @@ -140,4 +140,38 @@ $:code $:end_acc_directive #:enddef + +#:def ACC_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraAccArgs=None) + #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') + #:set create_val = GEN_CREATE_STR(create) + #:set attach_val = GEN_ATTACH_STR(attach) + #! #:set to_val = GEN_TO_STR(copyin) + #! #:set alloc_val = GEN_ALLOC_STR(create) + #! #:set alloc_val2 = GEN_ALLOC_STR(attach) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #! #:set extraMpArgs_val = '' + #:set acc_clause_val = copyin_val.strip('\n') + create_val.strip('\n') + attach_val.strip('\n') + #! #:set mp_clause_val = to_val.strip('\n') + alloc_val.strip('\n') + alloc_val2.strip('\n') + #:set acc_directive = '!$acc enter data ' + acc_clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef + +#:def ACC_EXIT_DATA(copyout=None, delete=None, detach=None, extraAccArgs=None) + #:set copyout_val = GEN_COPYOUT_STR(copyout) + #:set delete_val = GEN_DELETE_STR(delete) + #:set detach_val = GEN_DETACH_STR(detach) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = copyout_val.strip('\n') + delete_val.strip('\n') + detach_val.strip('\n') + #:set acc_directive = '!$acc exit data ' + clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef + +#:def ACC_UPDATE(host=None, device=None, extraAccArgs=None) + #:set host_val = GEN_HOST_STR(host) + #:set device_val = GEN_DEVICE_STR(device) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = host_val.strip('\n') + device_val.strip('\n') + #:set acc_directive = '!$acc update ' + clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef ! New line at end of file is required for FYPP \ No newline at end of file diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 04b1c25465..af89d0b5a8 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -48,6 +48,11 @@ $:create_val #:enddef +#:def OMP_DELETE_STR(delete) + #:set create_val = OMP_MAP_STR('release', delete) + $:create_val +#:enddef + #:def OMP_NOCREATE_STR(no_create) #:if no_create is not None #:stop 'no_create is not supported yet' @@ -76,7 +81,7 @@ #:def OMP_TO_STR(to) #! Not yet implemented - #:set to_val = '' + #:set to_val = GEN_PARENTHESES_CLAUSE('to', to) $:to_val #:enddef @@ -214,4 +219,33 @@ $:code $:end_omp_directive #:enddef + +#:def OMP_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraOmpArgs=None) + #:set copyin_val = OMP_COPYIN_STR(copyin).strip('\n') + OMP_COPYIN_STR(copyinReadOnly).strip('\n') + #:set create_val = OMP_CREATE_STR(create) + #:set attach_val = OMP_MAP_STR('to', attach) + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) + #:set omp_clause_val = to_val.strip('\n') + alloc_val.strip('\n') + alloc_val2.strip('\n') + #:set omp_directive = '!$omp target enter data ' + omp_clause_val + extraOmpArgs_val.strip('\n') + $:omp_directive +#:enddef + +#:def OMP_EXIT_DATA(copyout=None, delete=None, detach=None, extraOmpArgs=None) + #:set copyout_val = OMP_COPYOUT_STR(copyout) + #:set delete_val = OMP_DELETE_STR(delete) + #:set detach_val = OMP_MAP_STR('from', detach) + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) + #:set clause_val = copyout_val.strip('\n') + delete_val.strip('\n') + detach_val.strip('\n') + #:set omp_directive = '!$omp target exit data ' + clause_val + extraOmpArgs.strip('\n') + $:omp_directive +#:enddef + +#:def OMP_UPDATE(host=None, device=None, extraAccArgs=None) + #:set host_val = OMP_FROM_STR(host) + #:set device_val = OMP_TO_STR(device) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = host_val.strip('\n') + device_val.strip('\n') + #:set acc_directive = '!$acc update ' + clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef ! New line at end of file is required for FYPP \ No newline at end of file diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index a2199f9cfd..5f0f95b3a6 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -274,6 +274,17 @@ $:end_acc_directive #:enddef +#:def TEMP_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraAccArgs=None, extraOmpArgs=None) + #:set acc_code = ACC_ENTER_DATA(copy=copy, copyin=copyin, copyinReadOnly=copyinReadOnly, create=create, no_create=no_create, attach=attach, extraAccArgs=extraAccArgs) + #:set omp_code = OMP_ENTER_DATA(copy=copy, copyin=copyin, copyinReadOnly=copyinReadOnly, create=create, no_create=no_create, attach=attach, extraOmpArgs=extraOmpArgs) + +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#endif +#:enddef + #:def GPU_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraAccArgs=None) #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') #:set create_val = GEN_CREATE_STR(create) @@ -286,7 +297,6 @@ #:set acc_clause_val = copyin_val.strip('\n') + create_val.strip('\n') + attach_val.strip('\n') #! #:set mp_clause_val = to_val.strip('\n') + alloc_val.strip('\n') + alloc_val2.strip('\n') #:set acc_directive = '!$acc enter data ' + acc_clause_val + extraAccArgs_val.strip('\n') - #! #:set mp_directive = '!$omp target enter data ' + mp_clause_val + extraMpArgs_val.strip('\n') $:acc_directive #:enddef @@ -300,14 +310,6 @@ $:acc_directive #:enddef -#:def GPU_CACHE(cache, extraAccArgs=None) - #:set cache_val = GEN_PARENTHESES_CLAUSE('cache', cache) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = cache_val.strip('\n') - #:set acc_directive = '!$acc ' + clause_val + extraAccArgs_val.strip('\n') - $:acc_directive -#:enddef - #:def GPU_ATOMIC(atomic, extraAccArgs=None) #:assert isinstance(atomic, str) #:assert (atomic == 'read' or atomic == 'write' or atomic == 'update' or atomic == 'capture') diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index 9761f469ef..cf3822dbf3 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -1318,155 +1318,155 @@ contains rhs_vf_arg(j_adv)%sf(k_idx, l_idx, q_idx) = rhs_vf_arg(j_adv)%sf(k_idx, l_idx, q_idx) + & local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) end do; end do; end do - #:endcall GPU_PARALLEL_LOOP + end do + #:endcall GPU_PARALLEL_LOOP + end if + end if + + case (2) ! y-direction: loops q_idx (x), k_idx (y), l_idx (z); sf(q_idx, k_idx, l_idx); dy(k_idx); Kterm(q_idx,k_idx,l_idx) + use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) + if (use_standard_riemann) then + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') + do j_adv = advxb, advxe + do l_idx = 0, p ! z_extent + do k_idx = 0, n ! y_extent + do q_idx = 0, m ! x_extent + local_inv_ds = 1._wp/dy(k_idx) + local_term_coeff = q_prim_vf_arg%vf(contxe + current_idir)%sf(q_idx, k_idx, l_idx) + local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx - 1, l_idx) + local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) + rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do end do - end if + end do + end do + #:endcall GPU_PARALLEL_LOOP + else ! Other Riemann solvers + if (alt_soundspeed) then + if (bubbles_euler .neqv. .true.) then + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') + do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m + local_inv_ds = 1._wp/dy(k_idx) + local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(q_idx, k_idx, l_idx) + local_k_term_val = Kterm_arg(q_idx, k_idx, l_idx) ! Access is safe + local_term_coeff = local_q_cons_val - local_k_term_val + local_flux1 = flux_src_n_vf_arg%vf(advxe)%sf(q_idx, k_idx, l_idx) + local_flux2 = flux_src_n_vf_arg%vf(advxe)%sf(q_idx, k_idx - 1, l_idx) + rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + if (cyl_coord) then + rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) - & + (local_k_term_val/(2._wp*y_cc(k_idx)))*(local_flux1 + local_flux2) + end if + end do; end do; end do + #:endcall GPU_PARALLEL_LOOP + + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val,local_term_coeff, local_flux1, local_flux2]') + do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m + local_inv_ds = 1._wp/dy(k_idx) + local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(q_idx, k_idx, l_idx) + local_k_term_val = Kterm_arg(q_idx, k_idx, l_idx) ! Access is safe + local_term_coeff = local_q_cons_val + local_k_term_val + local_flux1 = flux_src_n_vf_arg%vf(advxb)%sf(q_idx, k_idx, l_idx) + local_flux2 = flux_src_n_vf_arg%vf(advxb)%sf(q_idx, k_idx - 1, l_idx) + rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + if (cyl_coord) then + rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) + & + (local_k_term_val/(2._wp*y_cc(k_idx)))*(local_flux1 + local_flux2) + end if + end do; end do; end do + #:endcall GPU_PARALLEL_LOOP end if + else ! NOT alt_soundspeed + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') + do j_adv = advxb, advxe + do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m + local_inv_ds = 1._wp/dy(k_idx) + local_term_coeff = q_cons_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) + local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) + local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx - 1, l_idx) + rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do + end do + #:endcall GPU_PARALLEL_LOOP + end if + end if + + case (3) ! z-direction: loops l_idx (x), q_idx (y), k_idx (z); sf(l_idx, q_idx, k_idx); dz(k_idx); Kterm(l_idx,q_idx,k_idx) + if (grid_geometry == 3) then + use_standard_riemann = (riemann_solver == 1) + else + use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) + end if - case (2) ! y-direction: loops q_idx (x), k_idx (y), l_idx (z); sf(q_idx, k_idx, l_idx); dy(k_idx); Kterm(q_idx,k_idx,l_idx) - use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) - if (use_standard_riemann) then - #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') - do j_adv = advxb, advxe - do l_idx = 0, p ! z_extent - do k_idx = 0, n ! y_extent - do q_idx = 0, m ! x_extent - local_inv_ds = 1._wp/dy(k_idx) - local_term_coeff = q_prim_vf_arg%vf(contxe + current_idir)%sf(q_idx, k_idx, l_idx) - local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx - 1, l_idx) - local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) - rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do - end do + if (use_standard_riemann) then + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') + do j_adv = advxb, advxe + do k_idx = 0, p ! z_extent + do q_idx = 0, n ! y_extent + do l_idx = 0, m ! x_extent + local_inv_ds = 1._wp/dz(k_idx) + local_term_coeff = q_prim_vf_arg%vf(contxe + current_idir)%sf(l_idx, q_idx, k_idx) + local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx - 1) + local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) + rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) end do end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + else ! Other Riemann solvers + if (alt_soundspeed) then + if (bubbles_euler .neqv. .true.) then + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds,local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') + do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m + local_inv_ds = 1._wp/dz(k_idx) + local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx) + local_k_term_val = Kterm_arg(l_idx, q_idx, k_idx) ! Access is safe + local_term_coeff = local_q_cons_val - local_k_term_val + local_flux1 = flux_src_n_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx) + local_flux2 = flux_src_n_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx - 1) + rhs_vf_arg(advxe)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(advxe)%sf(l_idx, q_idx, k_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do #:endcall GPU_PARALLEL_LOOP - else ! Other Riemann solvers - if (alt_soundspeed) then - if (bubbles_euler .neqv. .true.) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') - do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m - local_inv_ds = 1._wp/dy(k_idx) - local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(q_idx, k_idx, l_idx) - local_k_term_val = Kterm_arg(q_idx, k_idx, l_idx) ! Access is safe - local_term_coeff = local_q_cons_val - local_k_term_val - local_flux1 = flux_src_n_vf_arg%vf(advxe)%sf(q_idx, k_idx, l_idx) - local_flux2 = flux_src_n_vf_arg%vf(advxe)%sf(q_idx, k_idx - 1, l_idx) - rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - if (cyl_coord) then - rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxe)%sf(q_idx, k_idx, l_idx) - & - (local_k_term_val/(2._wp*y_cc(k_idx)))*(local_flux1 + local_flux2) - end if - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - - #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val,local_term_coeff, local_flux1, local_flux2]') - do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m - local_inv_ds = 1._wp/dy(k_idx) - local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(q_idx, k_idx, l_idx) - local_k_term_val = Kterm_arg(q_idx, k_idx, l_idx) ! Access is safe - local_term_coeff = local_q_cons_val + local_k_term_val - local_flux1 = flux_src_n_vf_arg%vf(advxb)%sf(q_idx, k_idx, l_idx) - local_flux2 = flux_src_n_vf_arg%vf(advxb)%sf(q_idx, k_idx - 1, l_idx) - rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - if (cyl_coord) then - rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(advxb)%sf(q_idx, k_idx, l_idx) + & - (local_k_term_val/(2._wp*y_cc(k_idx)))*(local_flux1 + local_flux2) - end if - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - end if - else ! NOT alt_soundspeed - #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') - do j_adv = advxb, advxe - do l_idx = 0, p; do k_idx = 0, n; do q_idx = 0, m - local_inv_ds = 1._wp/dy(k_idx) - local_term_coeff = q_cons_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) - local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx, l_idx) - local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(q_idx, k_idx - 1, l_idx) - rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) = rhs_vf_arg(j_adv)%sf(q_idx, k_idx, l_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - end do - end if - end if - - case (3) ! z-direction: loops l_idx (x), q_idx (y), k_idx (z); sf(l_idx, q_idx, k_idx); dz(k_idx); Kterm(l_idx,q_idx,k_idx) - if (grid_geometry == 3) then - use_standard_riemann = (riemann_solver == 1) - else - use_standard_riemann = (riemann_solver == 1 .or. riemann_solver == 4) - end if - - if (use_standard_riemann) then - #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') - do j_adv = advxb, advxe - do k_idx = 0, p ! z_extent - do q_idx = 0, n ! y_extent - do l_idx = 0, m ! x_extent - local_inv_ds = 1._wp/dz(k_idx) - local_term_coeff = q_prim_vf_arg%vf(contxe + current_idir)%sf(l_idx, q_idx, k_idx) - local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx - 1) - local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) - rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - else ! Other Riemann solvers - if (alt_soundspeed) then - if (bubbles_euler .neqv. .true.) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds,local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') - do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m - local_inv_ds = 1._wp/dz(k_idx) - local_q_cons_val = q_cons_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx) - local_k_term_val = Kterm_arg(l_idx, q_idx, k_idx) ! Access is safe - local_term_coeff = local_q_cons_val - local_k_term_val - local_flux1 = flux_src_n_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx) - local_flux2 = flux_src_n_vf_arg%vf(advxe)%sf(l_idx, q_idx, k_idx - 1) - rhs_vf_arg(advxe)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(advxe)%sf(l_idx, q_idx, k_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - - #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') - do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m - local_inv_ds = 1._wp/dz(k_idx) - local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx) - local_k_term_val = Kterm_arg(l_idx, q_idx, k_idx) ! Access is safe - local_term_coeff = local_q_cons_val + local_k_term_val - local_flux1 = flux_src_n_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx) - local_flux2 = flux_src_n_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx - 1) - rhs_vf_arg(advxb)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(advxb)%sf(l_idx, q_idx, k_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - end if - else ! NOT alt_soundspeed - #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') - do j_adv = advxb, advxe - do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m - local_inv_ds = 1._wp/dz(k_idx) - local_term_coeff = q_cons_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) - local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) - local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx - 1) - rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) + & - local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) - end do; end do; end do - #:endcall GPU_PARALLEL_LOOP - end do - end if - end if - end select - end subroutine s_add_directional_advection_source_terms - end subroutine s_compute_advection_source_term + #:call GPU_PARALLEL_LOOP(collapse=3, private='[local_inv_ds, local_q_cons_val, local_k_term_val, local_term_coeff, local_flux1, local_flux2]') + do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m + local_inv_ds = 1._wp/dz(k_idx) + local_q_cons_val = q_cons_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx) + local_k_term_val = Kterm_arg(l_idx, q_idx, k_idx) ! Access is safe + local_term_coeff = local_q_cons_val + local_k_term_val + local_flux1 = flux_src_n_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx) + local_flux2 = flux_src_n_vf_arg%vf(advxb)%sf(l_idx, q_idx, k_idx - 1) + rhs_vf_arg(advxb)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(advxb)%sf(l_idx, q_idx, k_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do + #:endcall GPU_PARALLEL_LOOP + end if + else ! NOT alt_soundspeed + #:call GPU_PARALLEL_LOOP(collapse=4,private='[local_inv_ds, local_term_coeff,local_flux1,local_flux2]') + do j_adv = advxb, advxe + do k_idx = 0, p; do q_idx = 0, n; do l_idx = 0, m + local_inv_ds = 1._wp/dz(k_idx) + local_term_coeff = q_cons_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) + local_flux1 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx) + local_flux2 = flux_src_n_vf_arg%vf(j_adv)%sf(l_idx, q_idx, k_idx - 1) + rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) = rhs_vf_arg(j_adv)%sf(l_idx, q_idx, k_idx) + & + local_inv_ds*local_term_coeff*(local_flux1 - local_flux2) + end do; end do; end do + end do + #:endcall GPU_PARALLEL_LOOP + end if + end if + end select + end subroutine s_add_directional_advection_source_terms + + end subroutine s_compute_advection_source_term subroutine s_compute_additional_physics_rhs(idir, q_prim_vf, rhs_vf, flux_src_n_in, & dq_prim_dx_vf, dq_prim_dy_vf, dq_prim_dz_vf) @@ -1477,9 +1477,9 @@ contains type(scalar_field), dimension(sys_size), intent(in) :: flux_src_n_in type(scalar_field), dimension(sys_size), intent(in) :: dq_prim_dx_vf, dq_prim_dy_vf, dq_prim_dz_vf - integer :: i, j, k, l + integer :: i, j, k, l - if (idir == 1) then ! x-direction + if (idir == 1) then ! x-direction if (surface_tension) then #:call GPU_PARALLEL_LOOP(collapse=3) @@ -1513,7 +1513,7 @@ contains end do #:endcall GPU_PARALLEL_LOOP - elseif (idir == 2) then ! y-direction + elseif (idir == 2) then ! y-direction if (surface_tension) then #:call GPU_PARALLEL_LOOP(collapse=3) @@ -1549,21 +1549,21 @@ contains idwbuff(1), idwbuff(2), idwbuff(3)) end if - #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - rhs_vf(i)%sf(j, 0, l) = & - rhs_vf(i)%sf(j, 0, l) + 1._wp/(y_cc(1) - y_cc(-1))* & - (tau_Re_vf(i)%sf(j, -1, l) & - - tau_Re_vf(i)%sf(j, 1, l)) - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - - end if + #:call GPU_PARALLEL_LOOP(collapse=2) + do l = 0, p + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + rhs_vf(i)%sf(j, 0, l) = & + rhs_vf(i)%sf(j, 0, l) + 1._wp/(y_cc(1) - y_cc(-1))* & + (tau_Re_vf(i)%sf(j, -1, l) & + - tau_Re_vf(i)%sf(j, 1, l)) + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + + end if #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p @@ -1620,21 +1620,21 @@ contains end do #:endcall GPU_PARALLEL_LOOP - if (viscous) then - #:call GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - rhs_vf(i)%sf(j, 0, l) = & - rhs_vf(i)%sf(j, 0, l) - 1._wp/y_cc(0)* & - tau_Re_vf(i)%sf(j, 0, l) - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if - else + if (viscous) then + #:call GPU_PARALLEL_LOOP(collapse=2) + do l = 0, p + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + rhs_vf(i)%sf(j, 0, l) = & + rhs_vf(i)%sf(j, 0, l) - 1._wp/y_cc(0)* & + tau_Re_vf(i)%sf(j, 0, l) + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if + else #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p @@ -1654,7 +1654,7 @@ contains end if end if - elseif (idir == 3) then ! z-direction + elseif (idir == 3) then ! z-direction if (surface_tension) then #:call GPU_PARALLEL_LOOP(collapse=3) @@ -1709,16 +1709,16 @@ contains end if end if - end subroutine s_compute_additional_physics_rhs + end subroutine s_compute_additional_physics_rhs - !> The purpose of this procedure is to infinitely relax + !> The purpose of this procedure is to infinitely relax !! the pressures from the internal-energy equations to a !! unique pressure, from which the corresponding volume !! fraction of each phase are recomputed. For conservation !! purpose, this pressure is finally corrected using the !! mixture-total-energy equation. - !> The purpose of this subroutine is to WENO-reconstruct the + !> The purpose of this subroutine is to WENO-reconstruct the !! left and the right cell-boundary values, including values !! at the Gaussian quadrature points, from the cell-averaged !! variables. @@ -1728,34 +1728,34 @@ contains !! @param vR_qp Right WENO-reconstructed, cell-boundary values including !! the values at the quadrature points, of the cell-average variables !! @param norm_dir Splitting coordinate direction - subroutine s_reconstruct_cell_boundary_values(v_vf, vL_x, vL_y, vL_z, vR_x, vR_y, vR_z, & - norm_dir) + subroutine s_reconstruct_cell_boundary_values(v_vf, vL_x, vL_y, vL_z, vR_x, vR_y, vR_z, & + norm_dir) - type(scalar_field), dimension(iv%beg:iv%end), intent(in) :: v_vf - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vL_x, vL_y, vL_z - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vR_x, vR_y, vR_z - integer, intent(in) :: norm_dir + type(scalar_field), dimension(iv%beg:iv%end), intent(in) :: v_vf + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vL_x, vL_y, vL_z + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vR_x, vR_y, vR_z + integer, intent(in) :: norm_dir - integer :: weno_dir !< Coordinate direction of the WENO reconstruction + integer :: weno_dir !< Coordinate direction of the WENO reconstruction - ! Reconstruction in s1-direction + ! Reconstruction in s1-direction - if (norm_dir == 1) then - is1 = idwbuff(1); is2 = idwbuff(2); is3 = idwbuff(3) - weno_dir = 1; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn + if (norm_dir == 1) then + is1 = idwbuff(1); is2 = idwbuff(2); is3 = idwbuff(3) + weno_dir = 1; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn - elseif (norm_dir == 2) then - is1 = idwbuff(2); is2 = idwbuff(1); is3 = idwbuff(3) - weno_dir = 2; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn + elseif (norm_dir == 2) then + is1 = idwbuff(2); is2 = idwbuff(1); is3 = idwbuff(3) + weno_dir = 2; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn - else - is1 = idwbuff(3); is2 = idwbuff(2); is3 = idwbuff(1) - weno_dir = 3; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn + else + is1 = idwbuff(3); is2 = idwbuff(2); is3 = idwbuff(1) + weno_dir = 3; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn - end if + end if if (n > 0) then if (p > 0) then @@ -1776,89 +1776,89 @@ contains is1, is2, is3) end if - end subroutine s_reconstruct_cell_boundary_values - - subroutine s_reconstruct_cell_boundary_values_first_order(v_vf, vL_x, vL_y, vL_z, vR_x, vR_y, vR_z, & - norm_dir) - - type(scalar_field), dimension(iv%beg:iv%end), intent(in) :: v_vf - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vL_x, vL_y, vL_z - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vR_x, vR_y, vR_z - integer, intent(in) :: norm_dir - - integer :: recon_dir !< Coordinate direction of the WENO reconstruction - - integer :: i, j, k, l - ! Reconstruction in s1-direction - - if (norm_dir == 1) then - is1 = idwbuff(1); is2 = idwbuff(2); is3 = idwbuff(3) - recon_dir = 1; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn - - elseif (norm_dir == 2) then - is1 = idwbuff(2); is2 = idwbuff(1); is3 = idwbuff(3) - recon_dir = 2; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn - - else - is1 = idwbuff(3); is2 = idwbuff(2); is3 = idwbuff(1) - recon_dir = 3; is1%beg = is1%beg + weno_polyn - is1%end = is1%end - weno_polyn - - end if - - $:GPU_UPDATE(device='[is1,is2,is3,iv]') - - if (recon_dir == 1) then - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - vL_x(j, k, l, i) = v_vf(i)%sf(j, k, l) - vR_x(j, k, l, i) = v_vf(i)%sf(j, k, l) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - else if (recon_dir == 2) then - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - vL_y(j, k, l, i) = v_vf(i)%sf(k, j, l) - vR_y(j, k, l, i) = v_vf(i)%sf(k, j, l) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - else if (recon_dir == 3) then - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = iv%beg, iv%end - do l = is3%beg, is3%end - do k = is2%beg, is2%end - do j = is1%beg, is1%end - vL_z(j, k, l, i) = v_vf(i)%sf(l, k, j) - vR_z(j, k, l, i) = v_vf(i)%sf(l, k, j) - end do - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP - end if - - end subroutine s_reconstruct_cell_boundary_values_first_order - - !> Module deallocation and/or disassociation procedures - impure subroutine s_finalize_rhs_module - - integer :: i, j, l - - call s_finalize_pressure_relaxation_module + end subroutine s_reconstruct_cell_boundary_values + + subroutine s_reconstruct_cell_boundary_values_first_order(v_vf, vL_x, vL_y, vL_z, vR_x, vR_y, vR_z, & + norm_dir) + + type(scalar_field), dimension(iv%beg:iv%end), intent(in) :: v_vf + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vL_x, vL_y, vL_z + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:), intent(inout) :: vR_x, vR_y, vR_z + integer, intent(in) :: norm_dir + + integer :: recon_dir !< Coordinate direction of the WENO reconstruction + + integer :: i, j, k, l + ! Reconstruction in s1-direction + + if (norm_dir == 1) then + is1 = idwbuff(1); is2 = idwbuff(2); is3 = idwbuff(3) + recon_dir = 1; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn + + elseif (norm_dir == 2) then + is1 = idwbuff(2); is2 = idwbuff(1); is3 = idwbuff(3) + recon_dir = 2; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn + + else + is1 = idwbuff(3); is2 = idwbuff(2); is3 = idwbuff(1) + recon_dir = 3; is1%beg = is1%beg + weno_polyn + is1%end = is1%end - weno_polyn + + end if + + $:GPU_UPDATE(device='[is1,is2,is3,iv]') + + if (recon_dir == 1) then + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = iv%beg, iv%end + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + vL_x(j, k, l, i) = v_vf(i)%sf(j, k, l) + vR_x(j, k, l, i) = v_vf(i)%sf(j, k, l) + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + else if (recon_dir == 2) then + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = iv%beg, iv%end + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + vL_y(j, k, l, i) = v_vf(i)%sf(k, j, l) + vR_y(j, k, l, i) = v_vf(i)%sf(k, j, l) + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + else if (recon_dir == 3) then + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = iv%beg, iv%end + do l = is3%beg, is3%end + do k = is2%beg, is2%end + do j = is1%beg, is1%end + vL_z(j, k, l, i) = v_vf(i)%sf(l, k, j) + vR_z(j, k, l, i) = v_vf(i)%sf(l, k, j) + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if + + end subroutine s_reconstruct_cell_boundary_values_first_order + + !> Module deallocation and/or disassociation procedures + impure subroutine s_finalize_rhs_module + + integer :: i, j, l + + call s_finalize_pressure_relaxation_module if (.not. igr) then do j = cont_idx%beg, cont_idx%end @@ -1975,8 +1975,8 @@ contains deallocate (alf_sum%sf) end if - @:DEALLOCATE(dqL_prim_dx_n, dqL_prim_dy_n, dqL_prim_dz_n) - @:DEALLOCATE(dqR_prim_dx_n, dqR_prim_dy_n, dqR_prim_dz_n) + @:DEALLOCATE(dqL_prim_dx_n, dqL_prim_dy_n, dqL_prim_dz_n) + @:DEALLOCATE(dqR_prim_dx_n, dqR_prim_dy_n, dqR_prim_dz_n) if (.not. igr) then do i = num_dims, 1, -1 @@ -2017,7 +2017,7 @@ contains @:DEALLOCATE(flux_n, flux_src_n, flux_gsrc_n) end if - end subroutine s_finalize_rhs_module + end subroutine s_finalize_rhs_module - end module m_rhs +end module m_rhs diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index 66c85751ff..cef74f406d 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -529,147 +529,147 @@ contains end do end do end do - end if - #:endcall GPU_PARALLEL_LOOP - - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(2)%sf(j, k, l, q, i) = & - mv_ts(1)%sf(j, k, l, q, i) & - + dt*rhs_mv(j, k, l, q, i) - end do - end do + #:endcall GPU_PARALLEL_LOOP + end if + + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(2)%sf(j, k, l, q, i) = & + mv_ts(1)%sf(j, k, l, q, i) & + + dt*rhs_mv(j, k, l, q, i) end do end do end do - #:endcall GPU_PARALLEL_LOOP - end if + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) - if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) - end if + if (model_eqns == 3 .and. (.not. relax)) then + call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) + end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) - if (ib) then - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) - else - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) - end if - end if + if (ib) then + if (qbmm .and. .not. polytropic) then + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) + else + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) + end if + end if - ! Stage 2 of 2 + ! Stage 2 of 2 - call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) + call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) - if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) + if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_ts(1)%vf(i)%sf(j, k, l) = & - (q_cons_ts(1)%vf(i)%sf(j, k, l) & - + q_cons_ts(2)%vf(i)%sf(j, k, l) & - + dt*rhs_vf(i)%sf(j, k, l))/2._wp - end do - end do + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(1)%vf(i)%sf(j, k, l) = & + (q_cons_ts(1)%vf(i)%sf(j, k, l) & + + q_cons_ts(2)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l))/2._wp end do end do - #:endcall GPU_PARALLEL_LOOP - - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - pb_ts(1)%sf(j, k, l, q, i) = & - (pb_ts(1)%sf(j, k, l, q, i) & - + pb_ts(2)%sf(j, k, l, q, i) & - + dt*rhs_pb(j, k, l, q, i))/2._wp - end do - end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + pb_ts(1)%sf(j, k, l, q, i) = & + (pb_ts(1)%sf(j, k, l, q, i) & + + pb_ts(2)%sf(j, k, l, q, i) & + + dt*rhs_pb(j, k, l, q, i))/2._wp end do end do end do - #:endcall GPU_PARALLEL_LOOP - end if + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(1)%sf(j, k, l, q, i) = & - (mv_ts(1)%sf(j, k, l, q, i) & - + mv_ts(2)%sf(j, k, l, q, i) & - + dt*rhs_mv(j, k, l, q, i))/2._wp - end do - end do + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(1)%sf(j, k, l, q, i) = & + (mv_ts(1)%sf(j, k, l, q, i) & + + mv_ts(2)%sf(j, k, l, q, i) & + + dt*rhs_mv(j, k, l, q, i))/2._wp end do end do end do - #:endcall GPU_PARALLEL_LOOP - end if + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(1)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(1)%vf) - if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(1)%vf) - end if + if (model_eqns == 3 .and. (.not. relax)) then + call s_pressure_relaxation_procedure(q_cons_ts(1)%vf) + end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(1)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(1)%vf) - if (ib) then - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) - else - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) - end if - end if + if (ib) then + if (qbmm .and. .not. polytropic) then + call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) + else + call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) + end if + end if - call nvtxEndRange + call nvtxEndRange - call cpu_time(finish) + call cpu_time(finish) - end subroutine s_2nd_order_tvd_rk + end subroutine s_2nd_order_tvd_rk - !> 3rd order TVD RK time-stepping algorithm + !> 3rd order TVD RK time-stepping algorithm !! @param t_step Current time-step - impure subroutine s_3rd_order_tvd_rk(t_step, time_avg) + impure subroutine s_3rd_order_tvd_rk(t_step, time_avg) - integer, intent(IN) :: t_step - real(wp), intent(INOUT) :: time_avg + integer, intent(IN) :: t_step + real(wp), intent(INOUT) :: time_avg - integer :: i, j, k, l, q !< Generic loop iterator + integer :: i, j, k, l, q !< Generic loop iterator - real(wp) :: start, finish + real(wp) :: start, finish - ! Stage 1 of 3 + ! Stage 1 of 3 - if (.not. adap_dt) then - call cpu_time(start) - call nvtxStartRange("TIMESTEP") - end if + if (.not. adap_dt) then + call cpu_time(start) + call nvtxStartRange("TIMESTEP") + end if - call s_compute_rhs(q_cons_ts(1)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(1)%sf, rhs_pb, mv_ts(1)%sf, rhs_mv, t_step, time_avg, 1) + call s_compute_rhs(q_cons_ts(1)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(1)%sf, rhs_pb, mv_ts(1)%sf, rhs_mv, t_step, time_avg, 1) if (run_time_info) then if (igr) then @@ -679,338 +679,338 @@ contains end if end if - if (probe_wrt) then - call s_time_step_cycling(t_step) - end if + if (probe_wrt) then + call s_time_step_cycling(t_step) + end if - if (cfl_dt) then - if (mytime >= t_stop) return - else - if (t_step == t_step_stop) return - end if + if (cfl_dt) then + if (mytime >= t_stop) return + else + if (t_step == t_step_stop) return + end if - if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) + if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_ts(2)%vf(i)%sf(j, k, l) = & - q_cons_ts(1)%vf(i)%sf(j, k, l) & - + dt*rhs_vf(i)%sf(j, k, l) - end do - end do + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(2)%vf(i)%sf(j, k, l) = & + q_cons_ts(1)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l) end do end do - #:endcall GPU_PARALLEL_LOOP - - !Evolve pb and mv for non-polytropic qbmm - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - pb_ts(2)%sf(j, k, l, q, i) = & - pb_ts(1)%sf(j, k, l, q, i) & - + dt*rhs_pb(j, k, l, q, i) - end do - end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + + !Evolve pb and mv for non-polytropic qbmm + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + pb_ts(2)%sf(j, k, l, q, i) = & + pb_ts(1)%sf(j, k, l, q, i) & + + dt*rhs_pb(j, k, l, q, i) end do end do end do - #:endcall GPU_PARALLEL_LOOP - end if + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(2)%sf(j, k, l, q, i) = & - mv_ts(1)%sf(j, k, l, q, i) & - + dt*rhs_mv(j, k, l, q, i) - end do - end do + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(2)%sf(j, k, l, q, i) = & + mv_ts(1)%sf(j, k, l, q, i) & + + dt*rhs_mv(j, k, l, q, i) end do end do end do - #:endcall GPU_PARALLEL_LOOP - end if + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) - if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) - end if + if (model_eqns == 3 .and. (.not. relax)) then + call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) + end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) - if (ib) then - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) - else - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) - end if - end if + if (ib) then + if (qbmm .and. .not. polytropic) then + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) + else + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) + end if + end if - ! Stage 2 of 3 + ! Stage 2 of 3 - call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) + call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) - if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) + if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_ts(2)%vf(i)%sf(j, k, l) = & - (3._wp*q_cons_ts(1)%vf(i)%sf(j, k, l) & - + q_cons_ts(2)%vf(i)%sf(j, k, l) & - + dt*rhs_vf(i)%sf(j, k, l))/4._wp - end do - end do + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(2)%vf(i)%sf(j, k, l) = & + (3._wp*q_cons_ts(1)%vf(i)%sf(j, k, l) & + + q_cons_ts(2)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l))/4._wp end do end do - #:endcall GPU_PARALLEL_LOOP - - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - pb_ts(2)%sf(j, k, l, q, i) = & - (3._wp*pb_ts(1)%sf(j, k, l, q, i) & - + pb_ts(2)%sf(j, k, l, q, i) & - + dt*rhs_pb(j, k, l, q, i))/4._wp - end do - end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + pb_ts(2)%sf(j, k, l, q, i) = & + (3._wp*pb_ts(1)%sf(j, k, l, q, i) & + + pb_ts(2)%sf(j, k, l, q, i) & + + dt*rhs_pb(j, k, l, q, i))/4._wp end do end do end do - #:endcall GPU_PARALLEL_LOOP - end if + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(2)%sf(j, k, l, q, i) = & - (3._wp*mv_ts(1)%sf(j, k, l, q, i) & - + mv_ts(2)%sf(j, k, l, q, i) & - + dt*rhs_mv(j, k, l, q, i))/4._wp - end do - end do + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(2)%sf(j, k, l, q, i) = & + (3._wp*mv_ts(1)%sf(j, k, l, q, i) & + + mv_ts(2)%sf(j, k, l, q, i) & + + dt*rhs_mv(j, k, l, q, i))/4._wp end do end do end do - #:endcall GPU_PARALLEL_LOOP - end if + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt/4._wp) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt/4._wp) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) - if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) - end if + if (model_eqns == 3 .and. (.not. relax)) then + call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) + end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) - if (ib) then - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) - else - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) - end if - end if + if (ib) then + if (qbmm .and. .not. polytropic) then + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) + else + call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) + end if + end if - ! Stage 3 of 3 - call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 3) + ! Stage 3 of 3 + call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 3) - if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=3) + if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=3) - #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_ts(1)%vf(i)%sf(j, k, l) = & - (q_cons_ts(1)%vf(i)%sf(j, k, l) & - + 2._wp*q_cons_ts(2)%vf(i)%sf(j, k, l) & - + 2._wp*dt*rhs_vf(i)%sf(j, k, l))/3._wp - end do - end do + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(1)%vf(i)%sf(j, k, l) = & + (q_cons_ts(1)%vf(i)%sf(j, k, l) & + + 2._wp*q_cons_ts(2)%vf(i)%sf(j, k, l) & + + 2._wp*dt*rhs_vf(i)%sf(j, k, l))/3._wp end do end do - #:endcall GPU_PARALLEL_LOOP - - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - pb_ts(1)%sf(j, k, l, q, i) = & - (pb_ts(1)%sf(j, k, l, q, i) & - + 2._wp*pb_ts(2)%sf(j, k, l, q, i) & - + 2._wp*dt*rhs_pb(j, k, l, q, i))/3._wp - end do - end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + pb_ts(1)%sf(j, k, l, q, i) = & + (pb_ts(1)%sf(j, k, l, q, i) & + + 2._wp*pb_ts(2)%sf(j, k, l, q, i) & + + 2._wp*dt*rhs_pb(j, k, l, q, i))/3._wp end do end do end do - #:endcall GPU_PARALLEL_LOOP - end if + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (qbmm .and. (.not. polytropic)) then - #:call GPU_PARALLEL_LOOP(collapse=5) - do i = 1, nb - do l = 0, p - do k = 0, n - do j = 0, m - do q = 1, nnode - mv_ts(1)%sf(j, k, l, q, i) = & - (mv_ts(1)%sf(j, k, l, q, i) & - + 2._wp*mv_ts(2)%sf(j, k, l, q, i) & - + 2._wp*dt*rhs_mv(j, k, l, q, i))/3._wp - end do - end do + if (qbmm .and. (.not. polytropic)) then + #:call GPU_PARALLEL_LOOP(collapse=5) + do i = 1, nb + do l = 0, p + do k = 0, n + do j = 0, m + do q = 1, nnode + mv_ts(1)%sf(j, k, l, q, i) = & + (mv_ts(1)%sf(j, k, l, q, i) & + + 2._wp*mv_ts(2)%sf(j, k, l, q, i) & + + 2._wp*dt*rhs_mv(j, k, l, q, i))/3._wp end do end do end do - #:endcall GPU_PARALLEL_LOOP - end if + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(1)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(1)%vf) - if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(1)%vf) - end if + if (model_eqns == 3 .and. (.not. relax)) then + call s_pressure_relaxation_procedure(q_cons_ts(1)%vf) + end if - call nvtxStartRange("RHS-ELASTIC") - if (hyperelasticity) call s_hyperelastic_rmt_stress_update(q_cons_ts(1)%vf, q_prim_vf) - call nvtxEndRange + call nvtxStartRange("RHS-ELASTIC") + if (hyperelasticity) call s_hyperelastic_rmt_stress_update(q_cons_ts(1)%vf, q_prim_vf) + call nvtxEndRange - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(1)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(1)%vf) - if (ib) then - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) - else - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) - end if - end if + if (ib) then + if (qbmm .and. .not. polytropic) then + call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) + else + call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) + end if + end if - if (.not. adap_dt) then - call nvtxEndRange - call cpu_time(finish) + if (.not. adap_dt) then + call nvtxEndRange + call cpu_time(finish) - time = time + (finish - start) - end if - end subroutine s_3rd_order_tvd_rk + time = time + (finish - start) + end if + end subroutine s_3rd_order_tvd_rk - !> Strang splitting scheme with 3rd order TVD RK time-stepping algorithm for + !> Strang splitting scheme with 3rd order TVD RK time-stepping algorithm for !! the flux term and adaptive time stepping algorithm for !! the source term !! @param t_step Current time-step - subroutine s_strang_splitting(t_step, time_avg) + subroutine s_strang_splitting(t_step, time_avg) - integer, intent(in) :: t_step - real(wp), intent(inout) :: time_avg + integer, intent(in) :: t_step + real(wp), intent(inout) :: time_avg - real(wp) :: start, finish + real(wp) :: start, finish - call cpu_time(start) + call cpu_time(start) - call nvtxStartRange("TIMESTEP") + call nvtxStartRange("TIMESTEP") - ! Stage 1 of 3 - call s_adaptive_dt_bubble(1) + ! Stage 1 of 3 + call s_adaptive_dt_bubble(1) - ! Stage 2 of 3 - call s_3rd_order_tvd_rk(t_step, time_avg) + ! Stage 2 of 3 + call s_3rd_order_tvd_rk(t_step, time_avg) - ! Stage 3 of 3 - call s_adaptive_dt_bubble(3) + ! Stage 3 of 3 + call s_adaptive_dt_bubble(3) - call nvtxEndRange + call nvtxEndRange - call cpu_time(finish) + call cpu_time(finish) - time = time + (finish - start) + time = time + (finish - start) - end subroutine s_strang_splitting + end subroutine s_strang_splitting - !> Bubble source part in Strang operator splitting scheme + !> Bubble source part in Strang operator splitting scheme !! @param t_step Current time-step - impure subroutine s_adaptive_dt_bubble(stage) + impure subroutine s_adaptive_dt_bubble(stage) - integer, intent(in) :: stage + integer, intent(in) :: stage - type(vector_field) :: gm_alpha_qp + type(vector_field) :: gm_alpha_qp - call s_convert_conservative_to_primitive_variables( & - q_cons_ts(1)%vf, & - q_T_sf, & - q_prim_vf, & - idwint) + call s_convert_conservative_to_primitive_variables( & + q_cons_ts(1)%vf, & + q_T_sf, & + q_prim_vf, & + idwint) - if (bubbles_euler) then + if (bubbles_euler) then call s_compute_bubble_EE_source(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, divu) call s_comp_alpha_from_n(q_cons_ts(1)%vf) - elseif (bubbles_lagrange) then - - call s_populate_variables_buffers(bc_type, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) - call s_compute_bubble_EL_dynamics(q_prim_vf, stage) - call s_transfer_data_to_tmp() - call s_smear_voidfraction() - if (stage == 3) then - if (lag_params%write_bubbles_stats) call s_calculate_lag_bubble_stats() - if (lag_params%write_bubbles) then - $:GPU_UPDATE(host='[gas_p,gas_mv,intfc_rad,intfc_vel]') - call s_write_lag_particles(mytime) - end if - call s_write_void_evol(mytime) - end if - + elseif (bubbles_lagrange) then + + call s_populate_variables_buffers(bc_type, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) + call s_compute_bubble_EL_dynamics(q_prim_vf, stage) + call s_transfer_data_to_tmp() + call s_smear_voidfraction() + if (stage == 3) then + if (lag_params%write_bubbles_stats) call s_calculate_lag_bubble_stats() + if (lag_params%write_bubbles) then + $:GPU_UPDATE(host='[gas_p,gas_mv,intfc_rad,intfc_vel]') + call s_write_lag_particles(mytime) end if + call s_write_void_evol(mytime) + end if - end subroutine s_adaptive_dt_bubble + end if + + end subroutine s_adaptive_dt_bubble - impure subroutine s_compute_dt() + impure subroutine s_compute_dt() - real(wp) :: rho !< Cell-avg. density - real(wp), dimension(num_vels) :: vel !< Cell-avg. velocity - real(wp) :: vel_sum !< Cell-avg. velocity sum - real(wp) :: pres !< Cell-avg. pressure - real(wp), dimension(num_fluids) :: alpha !< Cell-avg. volume fraction - real(wp) :: gamma !< Cell-avg. sp. heat ratio - real(wp) :: pi_inf !< Cell-avg. liquid stiffness function - real(wp) :: c !< Cell-avg. sound speed - real(wp) :: H !< Cell-avg. enthalpy - real(wp), dimension(2) :: Re !< Cell-avg. Reynolds numbers - type(vector_field) :: gm_alpha_qp + real(wp) :: rho !< Cell-avg. density + real(wp), dimension(num_vels) :: vel !< Cell-avg. velocity + real(wp) :: vel_sum !< Cell-avg. velocity sum + real(wp) :: pres !< Cell-avg. pressure + real(wp), dimension(num_fluids) :: alpha !< Cell-avg. volume fraction + real(wp) :: gamma !< Cell-avg. sp. heat ratio + real(wp) :: pi_inf !< Cell-avg. liquid stiffness function + real(wp) :: c !< Cell-avg. sound speed + real(wp) :: H !< Cell-avg. enthalpy + real(wp), dimension(2) :: Re !< Cell-avg. Reynolds numbers + type(vector_field) :: gm_alpha_qp - real(wp) :: dt_local - integer :: j, k, l !< Generic loop iterators + real(wp) :: dt_local + integer :: j, k, l !< Generic loop iterators if (.not. igr) then call s_convert_conservative_to_primitive_variables( & @@ -1030,30 +1030,30 @@ contains call s_compute_enthalpy(q_prim_vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) end if - ! Compute mixture sound speed - call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, alpha, vel_sum, 0._wp, c) + ! Compute mixture sound speed + call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, alpha, vel_sum, 0._wp, c) - call s_compute_dt_from_cfl(vel, c, max_dt, rho, Re, j, k, l) - end do - end do + call s_compute_dt_from_cfl(vel, c, max_dt, rho, Re, j, k, l) end do - #:endcall GPU_PARALLEL_LOOP + end do + end do + #:endcall GPU_PARALLEL_LOOP #:call GPU_PARALLEL(copyout='[dt_local]', copyin='[max_dt]') dt_local = minval(max_dt) #:endcall GPU_PARALLEL - if (num_procs == 1) then - dt = dt_local - else - call s_mpi_allreduce_min(dt_local, dt) - end if + if (num_procs == 1) then + dt = dt_local + else + call s_mpi_allreduce_min(dt_local, dt) + end if - $:GPU_UPDATE(device='[dt]') + $:GPU_UPDATE(device='[dt]') - end subroutine s_compute_dt + end subroutine s_compute_dt - !> This subroutine applies the body forces source term at each + !> This subroutine applies the body forces source term at each !! Runge-Kutta stage subroutine s_apply_bodyforces(q_cons_vf, q_prim_vf_in, rhs_vf_in, ldt) @@ -1061,9 +1061,9 @@ contains type(scalar_field), dimension(1:sys_size), intent(in) :: q_prim_vf_in type(scalar_field), dimension(1:sys_size), intent(inout) :: rhs_vf_in - real(wp), intent(in) :: ldt !< local dt + real(wp), intent(in) :: ldt !< local dt - integer :: i, j, k, l + integer :: i, j, k, l call nvtxStartRange("RHS-BODYFORCES") call s_compute_body_forces_rhs(q_prim_vf_in, q_cons_vf, rhs_vf_in) @@ -1081,16 +1081,16 @@ contains end do #:endcall GPU_PARALLEL_LOOP - call nvtxEndRange + call nvtxEndRange - end subroutine s_apply_bodyforces + end subroutine s_apply_bodyforces - !> This subroutine saves the temporary q_prim_vf vector + !> This subroutine saves the temporary q_prim_vf vector !! into the q_prim_ts vector that is then used in p_main !! @param t_step current time-step - subroutine s_time_step_cycling(t_step) + subroutine s_time_step_cycling(t_step) - integer, intent(in) :: t_step + integer, intent(in) :: t_step integer :: i, j, k, l !< Generic loop iterator @@ -1159,12 +1159,12 @@ contains #:endcall GPU_PARALLEL_LOOP end if - end subroutine s_time_step_cycling + end subroutine s_time_step_cycling - !> Module deallocation and/or disassociation procedures - impure subroutine s_finalize_time_steppers_module + !> Module deallocation and/or disassociation procedures + impure subroutine s_finalize_time_steppers_module - integer :: i, j !< Generic loop iterators + integer :: i, j !< Generic loop iterators ! Deallocating the cell-average conservative variables do i = 1, num_ts @@ -1175,18 +1175,18 @@ contains @:DEALLOCATE(q_cons_ts(i)%vf) end do - @:DEALLOCATE(q_cons_ts) + @:DEALLOCATE(q_cons_ts) - ! Deallocating the cell-average primitive ts variables - if (probe_wrt) then - do i = 0, 3 - do j = 1, sys_size - @:DEALLOCATE(q_prim_ts(i)%vf(j)%sf) - end do - @:DEALLOCATE(q_prim_ts(i)%vf) - end do - @:DEALLOCATE(q_prim_ts) - end if + ! Deallocating the cell-average primitive ts variables + if (probe_wrt) then + do i = 0, 3 + do j = 1, sys_size + @:DEALLOCATE(q_prim_ts(i)%vf(j)%sf) + end do + @:DEALLOCATE(q_prim_ts(i)%vf) + end do + @:DEALLOCATE(q_prim_ts) + end if if (.not. igr) then ! Deallocating the cell-average primitive variables @@ -1229,20 +1229,20 @@ contains end if end if - @:DEALLOCATE(q_prim_vf) + @:DEALLOCATE(q_prim_vf) - ! Deallocating the cell-average RHS variables - do i = 1, sys_size - @:DEALLOCATE(rhs_vf(i)%sf) - end do + ! Deallocating the cell-average RHS variables + do i = 1, sys_size + @:DEALLOCATE(rhs_vf(i)%sf) + end do - @:DEALLOCATE(rhs_vf) + @:DEALLOCATE(rhs_vf) - ! Writing the footer of and closing the run-time information file - if (proc_rank == 0 .and. run_time_info) then - call s_close_run_time_information_file() - end if + ! Writing the footer of and closing the run-time information file + if (proc_rank == 0 .and. run_time_info) then + call s_close_run_time_information_file() + end if - end subroutine s_finalize_time_steppers_module + end subroutine s_finalize_time_steppers_module - end module m_time_steppers +end module m_time_steppers From 33eca5ff17fd2a7c76160e8ef8862cbe2ffea090 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Mon, 21 Jul 2025 19:11:35 -0400 Subject: [PATCH 011/199] Moved macro code to their corresponding file, and finished enter data, exit data, and update --- src/common/include/acc_macros.fpp | 60 +++++++ src/common/include/omp_macros.fpp | 16 +- src/common/include/parallel_macros.fpp | 158 +++--------------- src/common/include/shared_parallel_macros.fpp | 8 + 4 files changed, 98 insertions(+), 144 deletions(-) diff --git a/src/common/include/acc_macros.fpp b/src/common/include/acc_macros.fpp index 77e896f91e..c70d065f90 100644 --- a/src/common/include/acc_macros.fpp +++ b/src/common/include/acc_macros.fpp @@ -1,5 +1,65 @@ #:include 'shared_parallel_macros.fpp' +#:def GEN_COPY_STR(copy) + #:set copy_val = GEN_PARENTHESES_CLAUSE('copy', copy) + $:copy_val +#:enddef + +#:def GEN_COPYIN_STR(copyin, readonly) + #:assert isinstance(readonly, bool) + #:set copyin_val = GEN_PARENTHESES_CLAUSE('copyin', copyin) + #:if copyin is not None and readonly == True + #:set index = copyin_val.find('copyin(') + len('copyin(') + #:set copyin_val = copyin_val[:index] + 'readonly:' + copyin_val[index:] + #:endif + $:copyin_val +#:enddef + +#:def GEN_COPYOUT_STR(copyout) + #:set copyout_val = GEN_PARENTHESES_CLAUSE('copyout', copyout) + $:copyout_val +#:enddef + +#:def GEN_CREATE_STR(create) + #:set create_val = GEN_PARENTHESES_CLAUSE('create', create) + $:create_val +#:enddef + +#:def GEN_NOCREATE_STR(no_create) + #:set nocreate_val = GEN_PARENTHESES_CLAUSE('no_create', no_create) + $:nocreate_val +#:enddef + +#:def GEN_DELETE_STR(delete) + #:set delete_val = GEN_PARENTHESES_CLAUSE('delete', delete) + $:delete_val +#:enddef + +#:def GEN_PRESENT_STR(present) + #:set present_val = GEN_PARENTHESES_CLAUSE('present', present) + $:present_val +#:enddef + +#:def GEN_DEVICEPTR_STR(deviceptr) + #:set deviceptr_val = GEN_PARENTHESES_CLAUSE('deviceptr', deviceptr) + $:deviceptr_val +#:enddef + +#:def GEN_ATTACH_STR(attach) + #:set attach_val = GEN_PARENTHESES_CLAUSE('attach', attach) + $:attach_val +#:enddef + +#:def GEN_DETACH_STR(detach) + #:set detach_val = GEN_PARENTHESES_CLAUSE('detach', detach) + $:detach_val +#:enddef + +#:def GEN_LINK_STR(link) + #:set link_val = GEN_PARENTHESES_CLAUSE('link', link) + $:link_val +#:enddef + #:def ACC_PARALLEL(code, private=None, default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index af89d0b5a8..70786ad38a 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -80,11 +80,15 @@ #:enddef #:def OMP_TO_STR(to) - #! Not yet implemented #:set to_val = GEN_PARENTHESES_CLAUSE('to', to) $:to_val #:enddef +#:def OMP_FROM_STR(to) + #:set from_val = GEN_PARENTHESES_CLAUSE('from', to) + $:from_val +#:enddef + #:def OMP_PARALLELISM_STR(parallelism) #:set temp = '' $:temp @@ -225,7 +229,7 @@ #:set create_val = OMP_CREATE_STR(create) #:set attach_val = OMP_MAP_STR('to', attach) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) - #:set omp_clause_val = to_val.strip('\n') + alloc_val.strip('\n') + alloc_val2.strip('\n') + #:set omp_clause_val = copyin_val.strip('\n') + create_val.strip('\n') + attach_val.strip('\n') #:set omp_directive = '!$omp target enter data ' + omp_clause_val + extraOmpArgs_val.strip('\n') $:omp_directive #:enddef @@ -236,16 +240,16 @@ #:set detach_val = OMP_MAP_STR('from', detach) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set clause_val = copyout_val.strip('\n') + delete_val.strip('\n') + detach_val.strip('\n') - #:set omp_directive = '!$omp target exit data ' + clause_val + extraOmpArgs.strip('\n') + #:set omp_directive = '!$omp target exit data ' + clause_val + extraOmpArgs_val.strip('\n') $:omp_directive #:enddef -#:def OMP_UPDATE(host=None, device=None, extraAccArgs=None) +#:def OMP_UPDATE(host=None, device=None, extraOmpArgs=None) #:set host_val = OMP_FROM_STR(host) #:set device_val = OMP_TO_STR(device) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set clause_val = host_val.strip('\n') + device_val.strip('\n') - #:set acc_directive = '!$acc update ' + clause_val + extraAccArgs_val.strip('\n') + #:set acc_directive = '!$omp target update ' + clause_val + extraOmpArgs_val.strip('\n') $:acc_directive #:enddef ! New line at end of file is required for FYPP \ No newline at end of file diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index 5f0f95b3a6..7dfacd0829 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -2,112 +2,6 @@ #:include 'omp_macros.fpp' #:include 'acc_macros.fpp' -#:def ASSERT_LIST(data, datatype) - #:assert data is not None - #:assert isinstance(data, list) - #:assert len(data) != 0 - #:assert all(isinstance(element, datatype) for element in data) -#:enddef - -#:def GEN_PARENTHESES_CLAUSE(clause_name, clause_str) - #:set clause_regex = re.compile(',(?![^(]*\\))') - #:assert isinstance(clause_name, str) - #:if clause_str is not None - #:set count = 0 - #:assert isinstance(clause_str, str) - #:assert clause_str[0] == '[' and clause_str[-1] == ']' - #:for c in clause_str - #:if c == '(' - #:set count = count + 1 - #:elif c == ')' - #:set count = count - 1 - #:endif - #:if c == ',' and count > 1 - #:stop 'Nested parentheses with comma inside is not supported. Incorrect clause: {}'.format(clause_str) - #:elif count < 0 - #:stop 'Missing parentheses. Incorrect clause: {}'.format(clause_str) - #:endif - #:endfor - #:set clause_str = re.sub(clause_regex, ';', clause_str) - #:set clause_list = [x.strip() for x in clause_str.strip('[]').split(';')] - $:ASSERT_LIST(clause_list, str) - #:set clause_str = clause_name + '(' + ', '.join(clause_list) + ') ' - #:else - #:set clause_str = '' - #:endif - $:clause_str -#:enddef - -#:def GEN_PRIVATE_STR(private, initialized_values) - #:assert isinstance(initialized_values, bool) - #:if initialized_values == True - #:set private_val = GEN_PARENTHESES_CLAUSE('firstprivate', private) - #:else - #:set private_val = GEN_PARENTHESES_CLAUSE('private', private) - #:endif - $:private_val -#:enddef - -#:def GEN_COPY_STR(copy) - #:set copy_val = GEN_PARENTHESES_CLAUSE('copy', copy) - $:copy_val -#:enddef - -#:def GEN_COPYIN_STR(copyin, readonly) - #:assert isinstance(readonly, bool) - #:set copyin_val = GEN_PARENTHESES_CLAUSE('copyin', copyin) - #:if copyin is not None and readonly == True - #:set index = copyin_val.find('copyin(') + len('copyin(') - #:set copyin_val = copyin_val[:index] + 'readonly:' + copyin_val[index:] - #:endif - $:copyin_val -#:enddef - -#:def GEN_COPYOUT_STR(copyout) - #:set copyout_val = GEN_PARENTHESES_CLAUSE('copyout', copyout) - $:copyout_val -#:enddef - -#:def GEN_CREATE_STR(create) - #:set create_val = GEN_PARENTHESES_CLAUSE('create', create) - $:create_val -#:enddef - -#:def GEN_NOCREATE_STR(no_create) - #:set nocreate_val = GEN_PARENTHESES_CLAUSE('no_create', no_create) - $:nocreate_val -#:enddef - -#:def GEN_DELETE_STR(delete) - #:set delete_val = GEN_PARENTHESES_CLAUSE('delete', delete) - $:delete_val -#:enddef - -#:def GEN_PRESENT_STR(present) - #:set present_val = GEN_PARENTHESES_CLAUSE('present', present) - $:present_val -#:enddef - -#:def GEN_DEVICEPTR_STR(deviceptr) - #:set deviceptr_val = GEN_PARENTHESES_CLAUSE('deviceptr', deviceptr) - $:deviceptr_val -#:enddef - -#:def GEN_ATTACH_STR(attach) - #:set attach_val = GEN_PARENTHESES_CLAUSE('attach', attach) - $:attach_val -#:enddef - -#:def GEN_DETACH_STR(detach) - #:set detach_val = GEN_PARENTHESES_CLAUSE('detach', detach) - $:detach_val -#:enddef - -#:def GEN_LINK_STR(link) - #:set link_val = GEN_PARENTHESES_CLAUSE('link', link) - $:link_val -#:enddef - #:def GEN_PARALLELISM_STR(parallelism) #:if parallelism is not None #:assert isinstance(parallelism, str) @@ -274,9 +168,9 @@ $:end_acc_directive #:enddef -#:def TEMP_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraAccArgs=None, extraOmpArgs=None) - #:set acc_code = ACC_ENTER_DATA(copy=copy, copyin=copyin, copyinReadOnly=copyinReadOnly, create=create, no_create=no_create, attach=attach, extraAccArgs=extraAccArgs) - #:set omp_code = OMP_ENTER_DATA(copy=copy, copyin=copyin, copyinReadOnly=copyinReadOnly, create=create, no_create=no_create, attach=attach, extraOmpArgs=extraOmpArgs) +#:def GPU_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraAccArgs=None, extraOmpArgs=None) + #:set acc_code = ACC_ENTER_DATA(copyin=copyin, copyinReadOnly=copyinReadOnly, create=create, attach=attach, extraAccArgs=extraAccArgs) + #:set omp_code = OMP_ENTER_DATA(copyin=copyin, copyinReadOnly=copyinReadOnly, create=create, attach=attach, extraOmpArgs=extraOmpArgs) #if defined(MFC_OpenACC) $:acc_code @@ -285,29 +179,15 @@ #endif #:enddef -#:def GPU_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraAccArgs=None) - #:set copyin_val = GEN_COPYIN_STR(copyin, False).strip('\n') + GEN_COPYIN_STR(copyinReadOnly, True).strip('\n') - #:set create_val = GEN_CREATE_STR(create) - #:set attach_val = GEN_ATTACH_STR(attach) - #! #:set to_val = GEN_TO_STR(copyin) - #! #:set alloc_val = GEN_ALLOC_STR(create) - #! #:set alloc_val2 = GEN_ALLOC_STR(attach) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #! #:set extraMpArgs_val = '' - #:set acc_clause_val = copyin_val.strip('\n') + create_val.strip('\n') + attach_val.strip('\n') - #! #:set mp_clause_val = to_val.strip('\n') + alloc_val.strip('\n') + alloc_val2.strip('\n') - #:set acc_directive = '!$acc enter data ' + acc_clause_val + extraAccArgs_val.strip('\n') - $:acc_directive -#:enddef +#:def GPU_EXIT_DATA(copyout=None, delete=None, detach=None, extraAccArgs=None, extraOmpArgs=None) + #:set acc_code = ACC_EXIT_DATA(copyout=copyout, delete=delete, detach=detach, extraAccArgs=extraAccArgs) + #:set omp_code = OMP_EXIT_DATA(copyout=copyout, delete=delete, detach=detach, extraOmpArgs=extraOmpArgs) -#:def GPU_EXIT_DATA(copyout=None, delete=None, detach=None, extraAccArgs=None) - #:set copyout_val = GEN_COPYOUT_STR(copyout) - #:set delete_val = GEN_DELETE_STR(delete) - #:set detach_val = GEN_DETACH_STR(detach) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = copyout_val.strip('\n') + delete_val.strip('\n') + detach_val.strip('\n') - #:set acc_directive = '!$acc exit data ' + clause_val + extraAccArgs_val.strip('\n') - $:acc_directive +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#endif #:enddef #:def GPU_ATOMIC(atomic, extraAccArgs=None) @@ -320,13 +200,15 @@ $:acc_directive #:enddef -#:def GPU_UPDATE(host=None, device=None, extraAccArgs=None) - #:set host_val = GEN_HOST_STR(host) - #:set device_val = GEN_DEVICE_STR(device) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = host_val.strip('\n') + device_val.strip('\n') - #:set acc_directive = '!$acc update ' + clause_val + extraAccArgs_val.strip('\n') - $:acc_directive +#:def GPU_UPDATE(host=None, device=None, extraAccArgs=None, extraOmpArgs=None) + #:set acc_code = ACC_UPDATE(host=host, device=device, extraAccArgs=extraAccArgs) + #:set omp_code = OMP_UPDATE(host=host, device=device, extraOmpArgs=extraOmpArgs) + +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#endif #:enddef #:def GPU_WAIT(extraAccArgs=None) diff --git a/src/common/include/shared_parallel_macros.fpp b/src/common/include/shared_parallel_macros.fpp index eadb2211f4..d82f671d5a 100644 --- a/src/common/include/shared_parallel_macros.fpp +++ b/src/common/include/shared_parallel_macros.fpp @@ -1,3 +1,10 @@ +#:def ASSERT_LIST(data, datatype) + #:assert data is not None + #:assert isinstance(data, list) + #:assert len(data) != 0 + #:assert all(isinstance(element, datatype) for element in data) +#:enddef + #:def GEN_CLAUSE(clause_name, clause_str) #:set clause_regex = re.compile(',(?![^(]*\\))') #:assert isinstance(clause_name, str) @@ -39,6 +46,7 @@ $:clause_str #:enddef + #:def GEN_PRIVATE_STR(private, initialized_values) #:assert isinstance(initialized_values, bool) #:if initialized_values == True From 11822f5f27ba31abe501c58fe20fdf06f341f627 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Mon, 21 Jul 2025 21:46:29 -0400 Subject: [PATCH 012/199] remove line that sets default_val to empty string --- src/common/include/omp_macros.fpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 70786ad38a..5632a34fc3 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -132,7 +132,6 @@ #:set collapse_val = GEN_COLLAPSE_STR(collapse) #:set parallelism_val = OMP_PARALLELISM_STR(parallelism) #:set default_val = OMP_DEFAULT_STR(default) - #:set default_val = '' #:set private_val = GEN_PRIVATE_STR(private, False).strip('\n') + GEN_PRIVATE_STR(firstprivate, True).strip('\n') #:set reduction_val = GEN_REDUCTION_STR(reduction, reductionOp) #:set copy_val = OMP_COPY_STR(copy) From 314fa1393dcd7d954d579d95f21f91932de44adf Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Tue, 22 Jul 2025 14:53:24 -0400 Subject: [PATCH 013/199] Fixed GPU_PARALLEL for omp and ran formatter --- src/common/include/omp_macros.fpp | 8 +- src/common/include/shared_parallel_macros.fpp | 1 - src/common/m_boundary_common.fpp | 230 +- src/common/m_variables_conversion.fpp | 42 +- src/simulation/m_derived_variables.fpp | 418 +- src/simulation/m_igr.fpp | 3472 ++++++++--------- src/simulation/m_rhs.fpp | 286 +- src/simulation/m_surface_tension.fpp | 34 +- src/simulation/m_time_steppers.fpp | 96 +- src/simulation/m_weno.fpp | 28 +- 10 files changed, 2315 insertions(+), 2300 deletions(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 5632a34fc3..5566dba088 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -17,8 +17,8 @@ #:assert isinstance(default, str) #:assert (default == 'present' or default == 'none') #:if default == 'present' - #! #:set default_val = 'defaultmap(present:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer)' - #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(tofrom:allocatable) defaultmap(tofrom:pointer)' + #! #:set default_val = 'defaultmap(present:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer) ' + #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(tofrom:allocatable) defaultmap(tofrom:pointer) ' #:elif default == 'none' #:stop 'Not Supported Yet' #:endif @@ -113,12 +113,12 @@ & copy_val.strip('\n') + copyin_val.strip('\n') + & & copyout_val.strip('\n') + create_val.strip('\n') + & & no_create_val.strip('\n') + present_val.strip('\n') + & - & deviceptr_val.strip('\n') + attach_val.strip('\n')) + & deviceptr_val.strip('\n') + attach_val.strip('\n') #:set omp_clause_val = omp_clause_val.strip('\n') #:set omp_directive = '!$omp target teams ' + omp_clause_val + extraOmpArgs_val.strip('\n') - #:set end_omp_directive = '!$omp end target teams' + #:set omp_end_directive = '!$omp end target teams' $:omp_directive $:code $:omp_end_directive diff --git a/src/common/include/shared_parallel_macros.fpp b/src/common/include/shared_parallel_macros.fpp index d82f671d5a..a2039fd2a4 100644 --- a/src/common/include/shared_parallel_macros.fpp +++ b/src/common/include/shared_parallel_macros.fpp @@ -46,7 +46,6 @@ $:clause_str #:enddef - #:def GEN_PRIVATE_STR(private, initialized_values) #:assert isinstance(initialized_values, bool) #:if initialized_values == True diff --git a/src/common/m_boundary_common.fpp b/src/common/m_boundary_common.fpp index bb92ec70c1..3c21279314 100644 --- a/src/common/m_boundary_common.fpp +++ b/src/common/m_boundary_common.fpp @@ -1482,56 +1482,59 @@ contains integer :: j, k, l - #:call GPU_PARALLEL() - jac_sf(1)%sf => jac - #:endcall GPU_PARALLEL + jac_sf(1)%sf => jac + $:GPU_UPDATE(device='[jac_sf(1)%sf]') if (bc_x%beg >= 0) then call s_mpi_sendrecv_variables_buffers(jac_sf, 1, -1, 1) else - $:GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = 0, n - select case (bc_type(1, -1)%sf(0, k, l)) - case (BC_PERIODIC) - do j = 1, buff_size - jac(-j, k, l) = jac(m - j + 1, k, l) - end do - case (BC_REFLECTIVE) - do j = 1, buff_size - jac(-j, k, l) = jac(j - 1, k, l) - end do - case default - do j = 1, buff_size - jac(-j, k, l) = jac(0, k, l) - end do - end select + #:call GPU_PARALLEL_LOOP(collapse=2) + do l = 0, p + do k = 0, n + select case (bc_type(1, -1)%sf(0, k, l)) + case (BC_PERIODIC) + do j = 1, buff_size + jac(-j, k, l) = jac(m - j + 1, k, l) + end do + case (BC_REFLECTIVE) + do j = 1, buff_size + jac(-j, k, l) = jac(j - 1, k, l) + end do + case default + do j = 1, buff_size + jac(-j, k, l) = jac(0, k, l) + end do + end select + end do end do - end do + #:endcall GPU_PARALLEL_LOOP + end if if (bc_x%end >= 0) then call s_mpi_sendrecv_variables_buffers(jac_sf, 1, 1, 1) else - $:GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = 0, n - select case (bc_type(1, 1)%sf(0, k, l)) - case (BC_PERIODIC) - do j = 1, buff_size - jac(m + j, k, l) = jac(j - 1, k, l) - end do - case (BC_REFLECTIVE) - do j = 1, buff_size - jac(m + j, k, l) = jac(m - (j - 1), k, l) - end do - case default - do j = 1, buff_size - jac(m + j, k, l) = jac(m, k, l) - end do - end select + #:call GPU_PARALLEL_LOOP(collapse=2) + do l = 0, p + do k = 0, n + select case (bc_type(1, 1)%sf(0, k, l)) + case (BC_PERIODIC) + do j = 1, buff_size + jac(m + j, k, l) = jac(j - 1, k, l) + end do + case (BC_REFLECTIVE) + do j = 1, buff_size + jac(m + j, k, l) = jac(m - (j - 1), k, l) + end do + case default + do j = 1, buff_size + jac(m + j, k, l) = jac(m, k, l) + end do + end select + end do end do - end do + #:endcall GPU_PARALLEL_LOOP + end if if (n == 0) then @@ -1539,49 +1542,52 @@ contains else if (bc_y%beg >= 0) then call s_mpi_sendrecv_variables_buffers(jac_sf, 2, -1, 1) else - $:GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = idwbuff(1)%beg, idwbuff(1)%end - select case (bc_type(2, -1)%sf(k, 0, l)) - case (BC_PERIODIC) - do j = 1, buff_size - jac(k, -j, l) = jac(k, n - j + 1, l) - end do - case (BC_REFLECTIVE) - do j = 1, buff_size - jac(k, -j, l) = jac(k, j - 1, l) - end do - case default - do j = 1, buff_size - jac(k, -j, l) = jac(k, 0, l) - end do - end select + #:call GPU_PARALLEL_LOOP(collapse=2) + do l = 0, p + do k = idwbuff(1)%beg, idwbuff(1)%end + select case (bc_type(2, -1)%sf(k, 0, l)) + case (BC_PERIODIC) + do j = 1, buff_size + jac(k, -j, l) = jac(k, n - j + 1, l) + end do + case (BC_REFLECTIVE) + do j = 1, buff_size + jac(k, -j, l) = jac(k, j - 1, l) + end do + case default + do j = 1, buff_size + jac(k, -j, l) = jac(k, 0, l) + end do + end select + end do end do - end do + #:endcall GPU_PARALLEL_LOOP + end if if (bc_y%end >= 0) then call s_mpi_sendrecv_variables_buffers(jac_sf, 2, 1, 1) else - $:GPU_PARALLEL_LOOP(collapse=2) - do l = 0, p - do k = idwbuff(1)%beg, idwbuff(1)%end - select case (bc_type(2, 1)%sf(k, 0, l)) - case (BC_PERIODIC) - do j = 1, buff_size - jac(k, n + j, l) = jac(k, j - 1, l) - end do - case (BC_REFLECTIVE) - do j = 1, buff_size - jac(k, n + j, l) = jac(k, n - (j - 1), l) - end do - case default - do j = 1, buff_size - jac(k, n + j, l) = jac(k, n, l) - end do - end select + #:call GPU_PARALLEL_LOOP(collapse=2) + do l = 0, p + do k = idwbuff(1)%beg, idwbuff(1)%end + select case (bc_type(2, 1)%sf(k, 0, l)) + case (BC_PERIODIC) + do j = 1, buff_size + jac(k, n + j, l) = jac(k, j - 1, l) + end do + case (BC_REFLECTIVE) + do j = 1, buff_size + jac(k, n + j, l) = jac(k, n - (j - 1), l) + end do + case default + do j = 1, buff_size + jac(k, n + j, l) = jac(k, n, l) + end do + end select + end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if if (p == 0) then @@ -1589,49 +1595,51 @@ contains else if (bc_z%beg >= 0) then call s_mpi_sendrecv_variables_buffers(jac_sf, 3, -1, 1) else - $:GPU_PARALLEL_LOOP(collapse=2) - do l = idwbuff(2)%beg, idwbuff(2)%end - do k = idwbuff(1)%beg, idwbuff(1)%end - select case (bc_type(3, -1)%sf(k, l, 0)) - case (BC_PERIODIC) - do j = 1, buff_size - jac(k, l, -j) = jac(k, l, p - j + 1) - end do - case (BC_REFLECTIVE) - do j = 1, buff_size - jac(k, l, -j) = jac(k, l, j - 1) - end do - case default - do j = 1, buff_size - jac(k, l, -j) = jac(k, l, 0) - end do - end select + #:call GPU_PARALLEL_LOOP(collapse=2) + do l = idwbuff(2)%beg, idwbuff(2)%end + do k = idwbuff(1)%beg, idwbuff(1)%end + select case (bc_type(3, -1)%sf(k, l, 0)) + case (BC_PERIODIC) + do j = 1, buff_size + jac(k, l, -j) = jac(k, l, p - j + 1) + end do + case (BC_REFLECTIVE) + do j = 1, buff_size + jac(k, l, -j) = jac(k, l, j - 1) + end do + case default + do j = 1, buff_size + jac(k, l, -j) = jac(k, l, 0) + end do + end select + end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if if (bc_z%end >= 0) then call s_mpi_sendrecv_variables_buffers(jac_sf, 3, 1, 1) else - $:GPU_PARALLEL_LOOP(collapse=2) - do l = idwbuff(2)%beg, idwbuff(2)%end - do k = idwbuff(1)%beg, idwbuff(1)%end - select case (bc_type(3, 1)%sf(k, l, 0)) - case (BC_PERIODIC) - do j = 1, buff_size - jac(k, l, p + j) = jac(k, l, j - 1) - end do - case (BC_REFLECTIVE) - do j = 1, buff_size - jac(k, l, p + j) = jac(k, l, p - (j - 1)) - end do - case default - do j = 1, buff_size - jac(k, l, p + j) = jac(k, l, p) - end do - end select + #:call GPU_PARALLEL_LOOP(collapse=2) + do l = idwbuff(2)%beg, idwbuff(2)%end + do k = idwbuff(1)%beg, idwbuff(1)%end + select case (bc_type(3, 1)%sf(k, l, 0)) + case (BC_PERIODIC) + do j = 1, buff_size + jac(k, l, p + j) = jac(k, l, j - 1) + end do + case (BC_REFLECTIVE) + do j = 1, buff_size + jac(k, l, p + j) = jac(k, l, p - (j - 1)) + end do + case default + do j = 1, buff_size + jac(k, l, p + j) = jac(k, l, p) + end do + end select + end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_populate_F_igr_buffers diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index 1a49e7e5b6..0bffeee879 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -879,27 +879,27 @@ contains do j = ibounds(1)%beg, ibounds(1)%end dyn_pres_K = 0._wp - if (igr) then - if (num_fluids == 1) then - alpha_rho_K(1) = qK_cons_vf(contxb)%sf(j, k, l) - alpha_K(1) = qK_cons_vf(advxb)%sf(j, k, l) - else - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - alpha_rho_K(i) = qK_cons_vf(i)%sf(j, k, l) - alpha_K(i) = qK_cons_vf(advxb + i - 1)%sf(j, k, l) - end do - - alpha_rho_K(num_fluids) = qK_cons_vf(num_fluids)%sf(j, k, l) - alpha_K(num_fluids) = 1._wp - sum(alpha_K(1:num_fluids - 1)) - end if - else - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_K(i) = qK_cons_vf(i)%sf(j, k, l) - alpha_K(i) = qK_cons_vf(advxb + i - 1)%sf(j, k, l) - end do - end if + if (igr) then + if (num_fluids == 1) then + alpha_rho_K(1) = qK_cons_vf(contxb)%sf(j, k, l) + alpha_K(1) = qK_cons_vf(advxb)%sf(j, k, l) + else + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + alpha_rho_K(i) = qK_cons_vf(i)%sf(j, k, l) + alpha_K(i) = qK_cons_vf(advxb + i - 1)%sf(j, k, l) + end do + + alpha_rho_K(num_fluids) = qK_cons_vf(num_fluids)%sf(j, k, l) + alpha_K(num_fluids) = 1._wp - sum(alpha_K(1:num_fluids - 1)) + end if + else + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_K(i) = qK_cons_vf(i)%sf(j, k, l) + alpha_K(i) = qK_cons_vf(advxb + i - 1)%sf(j, k, l) + end do + end if if (model_eqns /= 4) then #ifdef MFC_SIMULATION diff --git a/src/simulation/m_derived_variables.fpp b/src/simulation/m_derived_variables.fpp index 18c88f85c3..f4653a9366 100644 --- a/src/simulation/m_derived_variables.fpp +++ b/src/simulation/m_derived_variables.fpp @@ -146,23 +146,24 @@ contains z_accel) end if - $:GPU_PARALLEL_LOOP(collapse=3) - do k = 0, p - do j = 0, n - do i = 0, m - if (p > 0) then - accel_mag(i, j, k) = sqrt(x_accel(i, j, k)**2._wp + & - y_accel(i, j, k)**2._wp + & - z_accel(i, j, k)**2._wp) - elseif (n > 0) then - accel_mag(i, j, k) = sqrt(x_accel(i, j, k)**2._wp + & - y_accel(i, j, k)**2._wp) - else - accel_mag(i, j, k) = x_accel(i, j, k) - end if + #:call GPU_PARALLEL_LOOP(collapse=3) + do k = 0, p + do j = 0, n + do i = 0, m + if (p > 0) then + accel_mag(i, j, k) = sqrt(x_accel(i, j, k)**2._wp + & + y_accel(i, j, k)**2._wp + & + z_accel(i, j, k)**2._wp) + elseif (n > 0) then + accel_mag(i, j, k) = sqrt(x_accel(i, j, k)**2._wp + & + y_accel(i, j, k)**2._wp) + else + accel_mag(i, j, k) = x_accel(i, j, k) + end if + end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP $:GPU_UPDATE(host='[accel_mag]') @@ -203,66 +204,35 @@ contains ! Computing the acceleration component in the x-coordinate direction if (i == 1) then - $:GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - q_sf(j, k, l) = (11._wp*q_prim_vf0(momxb)%sf(j, k, l) & - - 18._wp*q_prim_vf1(momxb)%sf(j, k, l) & - + 9._wp*q_prim_vf2(momxb)%sf(j, k, l) & - - 2._wp*q_prim_vf3(momxb)%sf(j, k, l))/(6._wp*dt) - end do - end do - end do - - if (n == 0) then - $:GPU_PARALLEL_LOOP(collapse=4) - do l = 0, p - do k = 0, n - do j = 0, m - do r = -fd_number, fd_number - q_sf(j, k, l) = q_sf(j, k, l) & - + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & - q_prim_vf0(momxb)%sf(r + j, k, l) - end do - end do - end do - end do - elseif (p == 0) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m - do r = -fd_number, fd_number - q_sf(j, k, l) = q_sf(j, k, l) & - + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & - q_prim_vf0(momxb)%sf(r + j, k, l) & - + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & - q_prim_vf0(momxb)%sf(j, r + k, l) - end do + q_sf(j, k, l) = (11._wp*q_prim_vf0(momxb)%sf(j, k, l) & + - 18._wp*q_prim_vf1(momxb)%sf(j, k, l) & + + 9._wp*q_prim_vf2(momxb)%sf(j, k, l) & + - 2._wp*q_prim_vf3(momxb)%sf(j, k, l))/(6._wp*dt) end do end do end do - else - if (grid_geometry == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:endcall GPU_PARALLEL_LOOP + + if (n == 0) then + #:call GPU_PARALLEL_LOOP(collapse=4) do l = 0, p do k = 0, n do j = 0, m do r = -fd_number, fd_number q_sf(j, k, l) = q_sf(j, k, l) & + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & - q_prim_vf0(momxb)%sf(r + j, k, l) & - + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & - q_prim_vf0(momxb)%sf(j, r + k, l) & - + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & - q_prim_vf0(momxb)%sf(j, k, r + l)/y_cc(k) + q_prim_vf0(momxb)%sf(r + j, k, l) end do end do end do end do - else - $:GPU_PARALLEL_LOOP(collapse=4) + #:endcall GPU_PARALLEL_LOOP + elseif (p == 0) then + #:call GPU_PARALLEL_LOOP(collapse=4) do l = 0, p do k = 0, n do j = 0, m @@ -271,47 +241,68 @@ contains + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & q_prim_vf0(momxb)%sf(r + j, k, l) & + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & - q_prim_vf0(momxb)%sf(j, r + k, l) & - + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & - q_prim_vf0(momxb)%sf(j, k, r + l) + q_prim_vf0(momxb)%sf(j, r + k, l) end do end do end do end do + #:endcall GPU_PARALLEL_LOOP + else + if (grid_geometry == 3) then + #:call GPU_PARALLEL_LOOP(collapse=4) + do l = 0, p + do k = 0, n + do j = 0, m + do r = -fd_number, fd_number + q_sf(j, k, l) = q_sf(j, k, l) & + + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & + q_prim_vf0(momxb)%sf(r + j, k, l) & + + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & + q_prim_vf0(momxb)%sf(j, r + k, l) & + + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & + q_prim_vf0(momxb)%sf(j, k, r + l)/y_cc(k) + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + else + #:call GPU_PARALLEL_LOOP(collapse=4) + do l = 0, p + do k = 0, n + do j = 0, m + do r = -fd_number, fd_number + q_sf(j, k, l) = q_sf(j, k, l) & + + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & + q_prim_vf0(momxb)%sf(r + j, k, l) & + + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & + q_prim_vf0(momxb)%sf(j, r + k, l) & + + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & + q_prim_vf0(momxb)%sf(j, k, r + l) + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP end if end if ! Computing the acceleration component in the y-coordinate direction elseif (i == 2) then - $:GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - q_sf(j, k, l) = (11._wp*q_prim_vf0(momxb + 1)%sf(j, k, l) & - - 18._wp*q_prim_vf1(momxb + 1)%sf(j, k, l) & - + 9._wp*q_prim_vf2(momxb + 1)%sf(j, k, l) & - - 2._wp*q_prim_vf3(momxb + 1)%sf(j, k, l))/(6._wp*dt) - end do - end do - end do - - if (p == 0) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:call GPU_PARALLEL_LOOP(collapse=3) do l = 0, p do k = 0, n do j = 0, m - do r = -fd_number, fd_number - q_sf(j, k, l) = q_sf(j, k, l) & - + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & - q_prim_vf0(momxb + 1)%sf(r + j, k, l) & - + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & - q_prim_vf0(momxb + 1)%sf(j, r + k, l) - end do + q_sf(j, k, l) = (11._wp*q_prim_vf0(momxb + 1)%sf(j, k, l) & + - 18._wp*q_prim_vf1(momxb + 1)%sf(j, k, l) & + + 9._wp*q_prim_vf2(momxb + 1)%sf(j, k, l) & + - 2._wp*q_prim_vf3(momxb + 1)%sf(j, k, l))/(6._wp*dt) end do end do end do - else - if (grid_geometry == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) + #:endcall GPU_PARALLEL_LOOP + + if (p == 0) then + #:call GPU_PARALLEL_LOOP(collapse=4) do l = 0, p do k = 0, n do j = 0, m @@ -320,83 +311,105 @@ contains + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & q_prim_vf0(momxb + 1)%sf(r + j, k, l) & + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & - q_prim_vf0(momxb + 1)%sf(j, r + k, l) & - + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & - q_prim_vf0(momxb + 1)%sf(j, k, r + l)/y_cc(k) & - - (q_prim_vf0(momxe)%sf(j, k, l)**2._wp)/y_cc(k) + q_prim_vf0(momxb + 1)%sf(j, r + k, l) end do end do end do end do + #:endcall GPU_PARALLEL_LOOP + else + if (grid_geometry == 3) then + #:call GPU_PARALLEL_LOOP(collapse=4) + do l = 0, p + do k = 0, n + do j = 0, m + do r = -fd_number, fd_number + q_sf(j, k, l) = q_sf(j, k, l) & + + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & + q_prim_vf0(momxb + 1)%sf(r + j, k, l) & + + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & + q_prim_vf0(momxb + 1)%sf(j, r + k, l) & + + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & + q_prim_vf0(momxb + 1)%sf(j, k, r + l)/y_cc(k) & + - (q_prim_vf0(momxe)%sf(j, k, l)**2._wp)/y_cc(k) + end do + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=4) - do l = 0, p - do k = 0, n - do j = 0, m - do r = -fd_number, fd_number - q_sf(j, k, l) = q_sf(j, k, l) & - + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & - q_prim_vf0(momxb + 1)%sf(r + j, k, l) & - + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & - q_prim_vf0(momxb + 1)%sf(j, r + k, l) & - + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & - q_prim_vf0(momxb + 1)%sf(j, k, r + l) + #:call GPU_PARALLEL_LOOP(collapse=4) + do l = 0, p + do k = 0, n + do j = 0, m + do r = -fd_number, fd_number + q_sf(j, k, l) = q_sf(j, k, l) & + + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & + q_prim_vf0(momxb + 1)%sf(r + j, k, l) & + + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & + q_prim_vf0(momxb + 1)%sf(j, r + k, l) & + + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & + q_prim_vf0(momxb + 1)%sf(j, k, r + l) + end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if end if ! Computing the acceleration component in the z-coordinate direction else - $:GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - q_sf(j, k, l) = (11._wp*q_prim_vf0(momxe)%sf(j, k, l) & - - 18._wp*q_prim_vf1(momxe)%sf(j, k, l) & - + 9._wp*q_prim_vf2(momxe)%sf(j, k, l) & - - 2._wp*q_prim_vf3(momxe)%sf(j, k, l))/(6._wp*dt) + #:call GPU_PARALLEL_LOOP(collapse=3) + do l = 0, p + do k = 0, n + do j = 0, m + q_sf(j, k, l) = (11._wp*q_prim_vf0(momxe)%sf(j, k, l) & + - 18._wp*q_prim_vf1(momxe)%sf(j, k, l) & + + 9._wp*q_prim_vf2(momxe)%sf(j, k, l) & + - 2._wp*q_prim_vf3(momxe)%sf(j, k, l))/(6._wp*dt) + end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP if (grid_geometry == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) - do l = 0, p - do k = 0, n - do j = 0, m - do r = -fd_number, fd_number - q_sf(j, k, l) = q_sf(j, k, l) & - + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & - q_prim_vf0(momxe)%sf(r + j, k, l) & - + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & - q_prim_vf0(momxe)%sf(j, r + k, l) & - + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & - q_prim_vf0(momxe)%sf(j, k, r + l)/y_cc(k) & - + (q_prim_vf0(momxe)%sf(j, k, l)* & - q_prim_vf0(momxb + 1)%sf(j, k, l))/y_cc(k) + #:call GPU_PARALLEL_LOOP(collapse=4) + do l = 0, p + do k = 0, n + do j = 0, m + do r = -fd_number, fd_number + q_sf(j, k, l) = q_sf(j, k, l) & + + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & + q_prim_vf0(momxe)%sf(r + j, k, l) & + + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & + q_prim_vf0(momxe)%sf(j, r + k, l) & + + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & + q_prim_vf0(momxe)%sf(j, k, r + l)/y_cc(k) & + + (q_prim_vf0(momxe)%sf(j, k, l)* & + q_prim_vf0(momxb + 1)%sf(j, k, l))/y_cc(k) + end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP else - $:GPU_PARALLEL_LOOP(collapse=4) - do l = 0, p - do k = 0, n - do j = 0, m - do r = -fd_number, fd_number - q_sf(j, k, l) = q_sf(j, k, l) & - + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & - q_prim_vf0(momxe)%sf(r + j, k, l) & - + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & - q_prim_vf0(momxe)%sf(j, r + k, l) & - + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & - q_prim_vf0(momxe)%sf(j, k, r + l) + #:call GPU_PARALLEL_LOOP(collapse=4) + do l = 0, p + do k = 0, n + do j = 0, m + do r = -fd_number, fd_number + q_sf(j, k, l) = q_sf(j, k, l) & + + q_prim_vf0(momxb)%sf(j, k, l)*fd_coeff_x(r, j)* & + q_prim_vf0(momxe)%sf(r + j, k, l) & + + q_prim_vf0(momxb + 1)%sf(j, k, l)*fd_coeff_y(r, k)* & + q_prim_vf0(momxe)%sf(j, r + k, l) & + + q_prim_vf0(momxe)%sf(j, k, l)*fd_coeff_z(r, l)* & + q_prim_vf0(momxe)%sf(j, k, r + l) + end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if end if @@ -425,78 +438,81 @@ contains end do if (n == 0) then !1D simulation - $:GPU_PARALLEL_LOOP(collapse=3,private='[dV]') - do l = 0, p !Loop over grid - do k = 0, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids !Loop over individual fluids - dV = dx(j) - ! Mass - $:GPU_ATOMIC(atomic='update') - c_m(i, 1) = c_m(i, 1) + q_vf(i)%sf(j, k, l)*dV - ! x-location weighted - $:GPU_ATOMIC(atomic='update') - c_m(i, 2) = c_m(i, 2) + q_vf(i)%sf(j, k, l)*dV*x_cc(j) - ! Volume fraction - $:GPU_ATOMIC(atomic='update') - c_m(i, 5) = c_m(i, 5) + q_vf(i + advxb - 1)%sf(j, k, l)*dV + #:call GPU_PARALLEL_LOOP(collapse=3,private='[dV]') + do l = 0, p !Loop over grid + do k = 0, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids !Loop over individual fluids + dV = dx(j) + ! Mass + $:GPU_ATOMIC(atomic='update') + c_m(i, 1) = c_m(i, 1) + q_vf(i)%sf(j, k, l)*dV + ! x-location weighted + $:GPU_ATOMIC(atomic='update') + c_m(i, 2) = c_m(i, 2) + q_vf(i)%sf(j, k, l)*dV*x_cc(j) + ! Volume fraction + $:GPU_ATOMIC(atomic='update') + c_m(i, 5) = c_m(i, 5) + q_vf(i + advxb - 1)%sf(j, k, l)*dV + end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP elseif (p == 0) then !2D simulation - $:GPU_PARALLEL_LOOP(collapse=3,private='[dV]') - do l = 0, p !Loop over grid - do k = 0, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids !Loop over individual fluids - dV = dx(j)*dy(k) - ! Mass - $:GPU_ATOMIC(atomic='update') - c_m(i, 1) = c_m(i, 1) + q_vf(i)%sf(j, k, l)*dV - ! x-location weighted - $:GPU_ATOMIC(atomic='update') - c_m(i, 2) = c_m(i, 2) + q_vf(i)%sf(j, k, l)*dV*x_cc(j) - ! y-location weighted - $:GPU_ATOMIC(atomic='update') - c_m(i, 3) = c_m(i, 3) + q_vf(i)%sf(j, k, l)*dV*y_cc(k) - ! Volume fraction - $:GPU_ATOMIC(atomic='update') - c_m(i, 5) = c_m(i, 5) + q_vf(i + advxb - 1)%sf(j, k, l)*dV + #:call GPU_PARALLEL_LOOP(collapse=3,private='[dV]') + do l = 0, p !Loop over grid + do k = 0, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids !Loop over individual fluids + dV = dx(j)*dy(k) + ! Mass + $:GPU_ATOMIC(atomic='update') + c_m(i, 1) = c_m(i, 1) + q_vf(i)%sf(j, k, l)*dV + ! x-location weighted + $:GPU_ATOMIC(atomic='update') + c_m(i, 2) = c_m(i, 2) + q_vf(i)%sf(j, k, l)*dV*x_cc(j) + ! y-location weighted + $:GPU_ATOMIC(atomic='update') + c_m(i, 3) = c_m(i, 3) + q_vf(i)%sf(j, k, l)*dV*y_cc(k) + ! Volume fraction + $:GPU_ATOMIC(atomic='update') + c_m(i, 5) = c_m(i, 5) + q_vf(i + advxb - 1)%sf(j, k, l)*dV + end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP else !3D simulation - $:GPU_PARALLEL_LOOP(collapse=3,private='[dV]') - do l = 0, p !Loop over grid - do k = 0, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids !Loop over individual fluids - - dV = dx(j)*dy(k)*dz(l) - ! Mass - $:GPU_ATOMIC(atomic='update') - c_m(i, 1) = c_m(i, 1) + q_vf(i)%sf(j, k, l)*dV - ! x-location weighted - $:GPU_ATOMIC(atomic='update') - c_m(i, 2) = c_m(i, 2) + q_vf(i)%sf(j, k, l)*dV*x_cc(j) - ! y-location weighted - $:GPU_ATOMIC(atomic='update') - c_m(i, 3) = c_m(i, 3) + q_vf(i)%sf(j, k, l)*dV*y_cc(k) - ! z-location weighted - $:GPU_ATOMIC(atomic='update') - c_m(i, 4) = c_m(i, 4) + q_vf(i)%sf(j, k, l)*dV*z_cc(l) - ! Volume fraction - $:GPU_ATOMIC(atomic='update') - c_m(i, 5) = c_m(i, 5) + q_vf(i + advxb - 1)%sf(j, k, l)*dV + #:call GPU_PARALLEL_LOOP(collapse=3,private='[dV]') + do l = 0, p !Loop over grid + do k = 0, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids !Loop over individual fluids + + dV = dx(j)*dy(k)*dz(l) + ! Mass + $:GPU_ATOMIC(atomic='update') + c_m(i, 1) = c_m(i, 1) + q_vf(i)%sf(j, k, l)*dV + ! x-location weighted + $:GPU_ATOMIC(atomic='update') + c_m(i, 2) = c_m(i, 2) + q_vf(i)%sf(j, k, l)*dV*x_cc(j) + ! y-location weighted + $:GPU_ATOMIC(atomic='update') + c_m(i, 3) = c_m(i, 3) + q_vf(i)%sf(j, k, l)*dV*y_cc(k) + ! z-location weighted + $:GPU_ATOMIC(atomic='update') + c_m(i, 4) = c_m(i, 4) + q_vf(i)%sf(j, k, l)*dV*z_cc(l) + ! Volume fraction + $:GPU_ATOMIC(atomic='update') + c_m(i, 5) = c_m(i, 5) + q_vf(i + advxb - 1)%sf(j, k, l)*dV + end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if $:GPU_UPDATE(host='[c_m]') diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index db80bb8346..59684c9e05 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -104,15 +104,16 @@ contains idwbuff(3)%beg:idwbuff(3)%end)) end if - $:GPU_PARALLEL_LOOP(collapse=3) - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - jac(j, k, l) = 0._wp - if (igr_iter_solver == 1) jac_old(j, k, l) = 0._wp + #:call GPU_PARALLEL_LOOP(collapse=3) + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + jac(j, k, l) = 0._wp + if (igr_iter_solver == 1) jac_old(j, k, l) = 0._wp + end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP if (p == 0) then alf_igr = alf_factor*max(dx(1), dy(1))**2._wp @@ -181,82 +182,83 @@ contains end if do q = 1, num_iters - $:GPU_PARALLEL_LOOP(collapse=3, private='[rho_lx, rho_rx, rho_ly, & - & rho_ry, rho_lz, rho_rz, fd_coeff]') - do l = 0, p - do k = 0, n - do j = 0, m - rho_lx = 0._wp - rho_rx = 0._wp - rho_ly = 0._wp - rho_ry = 0._wp - rho_lz = 0._wp - rho_rz = 0._wp - fd_coeff = 0._wp - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - rho_lx = rho_lx + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j - 1, k, l))/2._wp - rho_rx = rho_rx + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j + 1, k, l))/2._wp - rho_ly = rho_ly + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k - 1, l))/2._wp - rho_ry = rho_ry + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k + 1, l))/2._wp - if (p > 0) then - rho_lz = rho_lz + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k, l - 1))/2._wp - rho_rz = rho_rz + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k, l + 1))/2._wp - end if - fd_coeff = fd_coeff + q_cons_vf(i)%sf(j, k, l) - end do + #:call GPU_PARALLEL_LOOP(collapse=3, private='[rho_lx, rho_rx, rho_ly, rho_ry, rho_lz, rho_rz, fd_coeff]') + do l = 0, p + do k = 0, n + do j = 0, m + rho_lx = 0._wp + rho_rx = 0._wp + rho_ly = 0._wp + rho_ry = 0._wp + rho_lz = 0._wp + rho_rz = 0._wp + fd_coeff = 0._wp - fd_coeff = 1._wp/fd_coeff + alf_igr* & - ((1._wp/dx(j)**2._wp)*(1._wp/rho_lx + 1._wp/rho_rx) + & - (1._wp/dy(k)**2._wp)*(1._wp/rho_ly + 1._wp/rho_ry)) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + rho_lx = rho_lx + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j - 1, k, l))/2._wp + rho_rx = rho_rx + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j + 1, k, l))/2._wp + rho_ly = rho_ly + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k - 1, l))/2._wp + rho_ry = rho_ry + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k + 1, l))/2._wp + if (p > 0) then + rho_lz = rho_lz + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k, l - 1))/2._wp + rho_rz = rho_rz + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k, l + 1))/2._wp + end if + fd_coeff = fd_coeff + q_cons_vf(i)%sf(j, k, l) + end do - if (num_dims == 3) then - fd_coeff = fd_coeff + alf_igr*(1._wp/dz(l)**2._wp)*(1._wp/rho_lz + 1._wp/rho_rz) - end if + fd_coeff = 1._wp/fd_coeff + alf_igr* & + ((1._wp/dx(j)**2._wp)*(1._wp/rho_lx + 1._wp/rho_rx) + & + (1._wp/dy(k)**2._wp)*(1._wp/rho_ly + 1._wp/rho_ry)) - if (igr_iter_solver == 1) then ! Jacobi iteration if (num_dims == 3) then - jac(j, k, l) = (alf_igr/fd_coeff)* & - ((1._wp/dx(j)**2._wp)*(jac_old(j - 1, k, l)/rho_lx + jac_old(j + 1, k, l)/rho_rx) + & - (1._wp/dy(k)**2._wp)*(jac_old(j, k - 1, l)/rho_ly + jac_old(j, k + 1, l)/rho_ry) + & - (1._wp/dz(l)**2._wp)*(jac_old(j, k, l - 1)/rho_lz + jac_old(j, k, l + 1)/rho_rz)) + & - jac_rhs(j, k, l)/fd_coeff - else - jac(j, k, l) = (alf_igr/fd_coeff)* & - ((1._wp/dx(j)**2._wp)*(jac_old(j - 1, k, l)/rho_lx + jac_old(j + 1, k, l)/rho_rx) + & - (1._wp/dy(k)**2._wp)*(jac_old(j, k - 1, l)/rho_ly + jac_old(j, k + 1, l)/rho_ry)) + & - jac_rhs(j, k, l)/fd_coeff + fd_coeff = fd_coeff + alf_igr*(1._wp/dz(l)**2._wp)*(1._wp/rho_lz + 1._wp/rho_rz) end if - else ! Gauss Seidel iteration - if (num_dims == 3) then - jac(j, k, l) = (alf_igr/fd_coeff)* & - ((1._wp/dx(j)**2._wp)*(jac(j - 1, k, l)/rho_lx + jac(j + 1, k, l)/rho_rx) + & - (1._wp/dy(k)**2._wp)*(jac(j, k - 1, l)/rho_ly + jac(j, k + 1, l)/rho_ry) + & - (1._wp/dz(l)**2._wp)*(jac(j, k, l - 1)/rho_lz + jac(j, k, l + 1)/rho_rz)) + & - jac_rhs(j, k, l)/fd_coeff - else - jac(j, k, l) = (alf_igr/fd_coeff)* & - ((1._wp/dx(j)**2._wp)*(jac(j - 1, k, l)/rho_lx + jac(j + 1, k, l)/rho_rx) + & - (1._wp/dy(k)**2._wp)*(jac(j, k - 1, l)/rho_ly + jac(j, k + 1, l)/rho_ry)) + & - jac_rhs(j, k, l)/fd_coeff + + if (igr_iter_solver == 1) then ! Jacobi iteration + if (num_dims == 3) then + jac(j, k, l) = (alf_igr/fd_coeff)* & + ((1._wp/dx(j)**2._wp)*(jac_old(j - 1, k, l)/rho_lx + jac_old(j + 1, k, l)/rho_rx) + & + (1._wp/dy(k)**2._wp)*(jac_old(j, k - 1, l)/rho_ly + jac_old(j, k + 1, l)/rho_ry) + & + (1._wp/dz(l)**2._wp)*(jac_old(j, k, l - 1)/rho_lz + jac_old(j, k, l + 1)/rho_rz)) + & + jac_rhs(j, k, l)/fd_coeff + else + jac(j, k, l) = (alf_igr/fd_coeff)* & + ((1._wp/dx(j)**2._wp)*(jac_old(j - 1, k, l)/rho_lx + jac_old(j + 1, k, l)/rho_rx) + & + (1._wp/dy(k)**2._wp)*(jac_old(j, k - 1, l)/rho_ly + jac_old(j, k + 1, l)/rho_ry)) + & + jac_rhs(j, k, l)/fd_coeff + end if + else ! Gauss Seidel iteration + if (num_dims == 3) then + jac(j, k, l) = (alf_igr/fd_coeff)* & + ((1._wp/dx(j)**2._wp)*(jac(j - 1, k, l)/rho_lx + jac(j + 1, k, l)/rho_rx) + & + (1._wp/dy(k)**2._wp)*(jac(j, k - 1, l)/rho_ly + jac(j, k + 1, l)/rho_ry) + & + (1._wp/dz(l)**2._wp)*(jac(j, k, l - 1)/rho_lz + jac(j, k, l + 1)/rho_rz)) + & + jac_rhs(j, k, l)/fd_coeff + else + jac(j, k, l) = (alf_igr/fd_coeff)* & + ((1._wp/dx(j)**2._wp)*(jac(j - 1, k, l)/rho_lx + jac(j + 1, k, l)/rho_rx) + & + (1._wp/dy(k)**2._wp)*(jac(j, k - 1, l)/rho_ly + jac(j, k + 1, l)/rho_ry)) + & + jac_rhs(j, k, l)/fd_coeff + end if end if - end if + end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP call s_populate_F_igr_buffers(bc_type, jac) if (igr_iter_solver == 1) then ! Jacobi iteration - $:GPU_PARALLEL_LOOP(collapse=3) - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - jac_old(j, k, l) = jac(j, k, l) + #:call GPU_PARALLEL_LOOP(collapse=3) + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + jac_old(j, k, l) = jac(j, k, l) + end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if end do @@ -276,58 +278,58 @@ contains real(wp) :: F_L, vel_L, rho_L, F_R, vel_R, rho_R real(wp), dimension(num_fluids) :: alpha_rho_L, alpha_rho_R - $:GPU_PARALLEL_LOOP(collapse=3, private='[F_L, vel_L, alpha_rho_L, & - & F_R, vel_R, alpha_rho_R]') - do l = 0, p - do k = 0, n - do j = -1, m + #:call GPU_PARALLEL_LOOP(collapse=3, private='[F_L, vel_L, alpha_rho_L, F_R, vel_R, alpha_rho_R]') + do l = 0, p + do k = 0, n + do j = -1, m - F_L = 0._wp; F_R = 0._wp - alpha_rho_L = 0._wp; alpha_rho_R = 0._wp - vel_L = 0._wp; vel_R = 0._wp + F_L = 0._wp; F_R = 0._wp + alpha_rho_L = 0._wp; alpha_rho_R = 0._wp + vel_L = 0._wp; vel_R = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb + 1, vidxe $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j + q, k, l) - end do + do q = vidxb + 1, vidxe + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j + q, k, l) + end do - vel_L = vel_L + coeff_L(q)*q_cons_vf(momxb)%sf(j + q, k, l) - F_L = F_L + coeff_L(q)*jac(j + q, k, l) - end do + vel_L = vel_L + coeff_L(q)*q_cons_vf(momxb)%sf(j + q, k, l) + F_L = F_L + coeff_L(q)*jac(j + q, k, l) + end do - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - 1 $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j + q, k, l) + do q = vidxb, vidxe - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j + q, k, l) + end do + + vel_R = vel_R + coeff_R(q)*q_cons_vf(momxb)%sf(j + q, k, l) + F_R = F_R + coeff_R(q)*jac(j + q, k, l) end do - vel_R = vel_R + coeff_R(q)*q_cons_vf(momxb)%sf(j + q, k, l) - F_R = F_R + coeff_R(q)*jac(j + q, k, l) - end do + vel_L = vel_L/sum(alpha_rho_L) + vel_R = vel_R/sum(alpha_rho_R) - vel_L = vel_L/sum(alpha_rho_L) - vel_R = vel_R/sum(alpha_rho_R) - - #:for LR in ['L', 'R'] - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) + & - 0.5_wp*F_${LR}$*(1._wp/dx(j + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) + & - 0.5_wp*vel_${LR}$*F_${LR}$*(1._wp/dx(j + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - 0.5_wp*F_${LR}$*(1._wp/dx(j)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - 0.5_wp*vel_${LR}$*F_${LR}$*(1._wp/dx(j)) - #:endfor + #:for LR in ['L', 'R'] + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) + & + 0.5_wp*F_${LR}$*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) + & + 0.5_wp*vel_${LR}$*F_${LR}$*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & + 0.5_wp*F_${LR}$*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & + 0.5_wp*vel_${LR}$*F_${LR}$*(1._wp/dx(j)) + #:endfor + end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_igr_sigma_x @@ -355,1244 +357,1688 @@ contains if (idir == 1) then if (p == 0) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[rho_L, rho_R, gamma_L, & - & gamma_R, pi_inf_L, pi_inf_R, mu_L, mu_R, vel_L, vel_R, & - & pres_L, pres_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, & - & F_L, F_R, E_L, E_R, cfl, dvel, dvel_small, rho_sf_small, & - & vflux_L_arr, vflux_R_arr]') - do l = 0, p - do k = 0, n - do j = -1, m + #:call GPU_PARALLEL_LOOP(collapse=3, private='[rho_L, rho_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, mu_L, mu_R, vel_L, vel_R, pres_L, pres_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, F_L, F_R, E_L, E_R, cfl, dvel, dvel_small, rho_sf_small, vflux_L_arr, vflux_R_arr]') + do l = 0, p + do k = 0, n + do j = -1, m - dvel = 0._wp - vflux_L_arr = 0._wp - vflux_R_arr = 0._wp + dvel = 0._wp + vflux_L_arr = 0._wp + vflux_R_arr = 0._wp - #:if MFC_CASE_OPTIMIZATION - #:if igr_order == 5 - !DIR$ unroll 6 - #:elif igr_order == 3 - !DIR$ unroll 4 + #:if MFC_CASE_OPTIMIZATION + #:if igr_order == 5 + !DIR$ unroll 6 + #:elif igr_order == 3 + !DIR$ unroll 4 + #:endif #:endif - #:endif - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - dvel_small = 0._wp - !x-direction contributions $:GPU_LOOP(parallelism='[seq]') - do i = -1, 1 - rho_L = 0._wp + do q = vidxb, vidxe + dvel_small = 0._wp + !x-direction contributions + $:GPU_LOOP(parallelism='[seq]') + do i = -1, 1 + rho_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do r = 1, num_fluids + rho_L = rho_L + q_cons_vf(r)%sf(j + i + q, k, l) + end do + rho_sf_small(i) = rho_L + end do + + dvel_small(1) = (1/(2._wp*dx(j)))*( & + 1._wp*q_cons_vf(momxb)%sf(j + 1 + q, k, l)/rho_sf_small(1) - & + 1._wp*q_cons_vf(momxb)%sf(j - 1 + q, k, l)/rho_sf_small(-1)) + dvel_small(2) = (1/(2._wp*dx(j)))*( & + q_cons_vf(momxb + 1)%sf(j + 1 + q, k, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j - 1 + q, k, l)/rho_sf_small(-1)) + + if (q == 0) dvel(:, 1) = dvel_small + if (q > vidxb) then + vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(2)) + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(4._wp*dvel_small(1))/3._wp + end if + if (q < vidxe) then + vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(2)) + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(4._wp*dvel_small(1))/3._wp + end if + + !y-direction contributions $:GPU_LOOP(parallelism='[seq]') - do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j + i + q, k, l) + do i = -1, 1 + rho_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do r = 1, num_fluids + rho_L = rho_L + q_cons_vf(r)%sf(j + q, k + i, l) + end do + rho_sf_small(i) = rho_L end do - rho_sf_small(i) = rho_L + + dvel_small(1) = (1/(2._wp*dy(k)))*( & + q_cons_vf(momxb)%sf(j + q, k + 1, l)/rho_sf_small(1) - & + q_cons_vf(momxb)%sf(j + q, k - 1, l)/rho_sf_small(-1)) + dvel_small(2) = (1/(2._wp*dy(k)))*( & + q_cons_vf(momxb + 1)%sf(j + q, k + 1, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j + q, k - 1, l)/rho_sf_small(-1)) + + if (q == 0) dvel(:, 2) = dvel_small + + if (q > vidxb) then + vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(1)) + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(2))/3._wp + end if + if (q < vidxe) then + vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(1)) + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(2))/3._wp + end if + + if (q == 0) then + jac_rhs(j, k, l) = alf_igr*(2._wp*(dvel(1, 2)*dvel(2, 1)) & + + dvel(1, 1)**2._wp + dvel(2, 2)**2._wp & + + (dvel(1, 1) + dvel(2, 2))**2._wp) + end if end do - dvel_small(1) = (1/(2._wp*dx(j)))*( & - 1._wp*q_cons_vf(momxb)%sf(j + 1 + q, k, l)/rho_sf_small(1) - & - 1._wp*q_cons_vf(momxb)%sf(j - 1 + q, k, l)/rho_sf_small(-1)) - dvel_small(2) = (1/(2._wp*dx(j)))*( & - q_cons_vf(momxb + 1)%sf(j + 1 + q, k, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j - 1 + q, k, l)/rho_sf_small(-1)) - - if (q == 0) dvel(:, 1) = dvel_small - if (q > vidxb) then - vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(2)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(4._wp*dvel_small(1))/3._wp - end if - if (q < vidxe) then - vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(2)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(4._wp*dvel_small(1))/3._wp - end if + alpha_rho_L = 0._wp; alpha_rho_R = 0._wp + alpha_L = 0._wp; alpha_R = 0._wp + vel_L = 0._wp; vel_R = 0._wp - !y-direction contributions $:GPU_LOOP(parallelism='[seq]') - do i = -1, 1 - rho_L = 0._wp + do q = vidxb + 1, vidxe + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j + q, k, l) + end do + + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j + q, k, l) + end do + else + alpha_L(1) = 1._wp + end if + $:GPU_LOOP(parallelism='[seq]') - do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j + q, k + i, l) + do i = 1, num_dims + vel_L(i) = vel_L(i) + coeff_L(q)*q_cons_vf(momxb + i - 1)%sf(j + q, k, l) end do - rho_sf_small(i) = rho_L end do - dvel_small(1) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb)%sf(j + q, k + 1, l)/rho_sf_small(1) - & - q_cons_vf(momxb)%sf(j + q, k - 1, l)/rho_sf_small(-1)) - dvel_small(2) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb + 1)%sf(j + q, k + 1, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j + q, k - 1, l)/rho_sf_small(-1)) + $:GPU_LOOP(parallelism='[seq]') + do q = vidxb, vidxe - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j + q, k, l) + end do - if (q == 0) dvel(:, 2) = dvel_small + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + alpha_R(i) = alpha_R(i) + coeff_R(q)*q_cons_vf(E_idx + i)%sf(j + q, k, l) + end do + else + alpha_R(1) = 1._wp + end if - if (q > vidxb) then - vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(1)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(2))/3._wp - end if - if (q < vidxe) then - vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(1)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(2))/3._wp - end if + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + vel_R(i) = vel_R(i) + coeff_R(q)*q_cons_vf(momxb + i - 1)%sf(j + q, k, l) + end do + end do - if (q == 0) then - jac_rhs(j, k, l) = alf_igr*(2._wp*(dvel(1, 2)*dvel(2, 1)) & - + dvel(1, 1)**2._wp + dvel(2, 2)**2._wp & - + (dvel(1, 1) + dvel(2, 2))**2._wp) + if (num_fluids > 1) then + alpha_L(num_fluids) = 1._wp - sum(alpha_L(1:num_fluids - 1)) + alpha_R(num_fluids) = 1._wp - sum(alpha_R(1:num_fluids - 1)) end if - end do - alpha_rho_L = 0._wp; alpha_rho_R = 0._wp - alpha_L = 0._wp; alpha_R = 0._wp - vel_L = 0._wp; vel_R = 0._wp + rho_L = sum(alpha_rho_L) + gamma_L = sum(alpha_L*gammas) + pi_inf_L = sum(alpha_L*pi_infs) - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb + 1, vidxe - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j + q, k, l) - end do + rho_R = sum(alpha_rho_R) + gamma_R = sum(alpha_R*gammas) + pi_inf_R = sum(alpha_R*pi_infs) - if (num_fluids > 1) then + vel_L = vel_L/rho_L + vel_R = vel_R/rho_R + + if (viscous) then + mu_L = 0._wp; mu_R = 0._wp $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j + q, k, l) + do i = 1, num_fluids + mu_L = alpha_L(i)/Res(1, i) + mu_L + mu_R = alpha_R(i)/Res(1, i) + mu_R end do - else - alpha_L(1) = 1._wp + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) - & + 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & + 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(2)*(1._wp/dx(j + 1)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(2)*(1._wp/dx(j)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) - & + 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & + 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(2)*(1._wp/dx(j + 1)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(2)*(1._wp/dx(j)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) - & + 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & + 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(1)*(1._wp/dx(j + 1)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(1)*(1._wp/dx(j)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) - & + 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & + 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(1)*(1._wp/dx(j + 1)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(1)*(1._wp/dx(j)) end if + E_L = 0._wp; E_R = 0._wp + $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_L(i) = vel_L(i) + coeff_L(q)*q_cons_vf(momxb + i - 1)%sf(j + q, k, l) + do q = vidxb + 1, vidxe + E_L = E_L + coeff_L(q)*q_cons_vf(E_idx)%sf(j + q, k, l) end do - end do - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - 1 $:GPU_LOOP(parallelism='[seq]') + do q = vidxb, vidxe - 1 + E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j + q, k, l) + end do + + call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & + E_R, gamma_R, pi_inf_R, rho_R, vel_R, & + pres_L, pres_R, cfl) + do i = 1, num_fluids - alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j + q, k, l) + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j + 1, k, l) = rhs_vf(i)%sf(j + 1, k, l) + & + (0.5_wp*(alpha_rho_L(i)* & + vel_L(1))*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & + (0.5_wp*(alpha_rho_L(i)* & + vel_L(1))*(1._wp/dx(j)) - & + 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dx(j))) end do if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 - alpha_R(i) = alpha_R(i) + coeff_R(q)*q_cons_vf(E_idx + i)%sf(j + q, k, l) + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) + & + (0.5_wp*(alpha_L(i)* & + vel_L(1))*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(alpha_L(i))*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) & + - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j + 1, k, l)*vel_L(1)*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & + (0.5_wp*(alpha_L(i)* & + vel_L(1))*(1._wp/dx(j)) - & + 0.5_wp*cfl*(alpha_L(i))*(1._wp/dx(j))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & + + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_L(1)*(1._wp/dx(j))) end do - else - alpha_R(1) = 1._wp end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_R(i) = vel_R(i) + coeff_R(q)*q_cons_vf(momxb + i - 1)%sf(j + q, k, l) - end do - end do + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) + & + (0.5_wp*(rho_L*(vel_L(1))**2.0 + & + pres_L)*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dx(j + 1))) - if (num_fluids > 1) then - alpha_L(num_fluids) = 1._wp - sum(alpha_L(1:num_fluids - 1)) - alpha_R(num_fluids) = 1._wp - sum(alpha_R(1:num_fluids - 1)) - end if + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) + & + (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dx(j + 1))) - rho_L = sum(alpha_rho_L) - gamma_L = sum(alpha_L*gammas) - pi_inf_L = sum(alpha_L*pi_infs) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) + & + (0.5_wp*(vel_L(1)*(E_L + & + pres_L))*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(E_L)*(1._wp/dx(j + 1))) - rho_R = sum(alpha_rho_R) - gamma_R = sum(alpha_R*gammas) - pi_inf_R = sum(alpha_R*pi_infs) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & + (0.5_wp*(rho_L*(vel_L(1))**2.0 + & + pres_L)*(1._wp/dx(j)) - & + 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dx(j))) - vel_L = vel_L/rho_L - vel_R = vel_R/rho_R + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & + (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dx(j)) - & + 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dx(j))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & + (0.5_wp*(vel_L(1)*(E_L + & + pres_L))*(1._wp/dx(j)) - & + 0.5_wp*cfl*(E_L)*(1._wp/dx(j))) - if (viscous) then - mu_L = 0._wp; mu_R = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - mu_L = alpha_L(i)/Res(1, i) + mu_L - mu_R = alpha_R(i)/Res(1, i) + mu_R + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j + 1, k, l) = rhs_vf(i)%sf(j + 1, k, l) + & + (0.5_wp*(alpha_rho_R(i)* & + vel_R(1))*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & + (0.5_wp*(alpha_rho_R(i)* & + vel_R(1))*(1._wp/dx(j)) + & + 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dx(j))) end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) - & - 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dx(j + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & - 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(2)*(1._wp/dx(j + 1)) + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) + & + (0.5_wp*(alpha_R(i)* & + vel_R(1))*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(alpha_R(i))*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) & + - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j + 1, k, l)*vel_R(1)*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & + (0.5_wp*(alpha_R(i)* & + vel_R(1))*(1._wp/dx(j)) + & + 0.5_wp*cfl*(alpha_R(i))*(1._wp/dx(j))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dx(j)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(2)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & + + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_R(1)*(1._wp/dx(j))) + end do + end if $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) - & - 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dx(j + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & - 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(2)*(1._wp/dx(j + 1)) + rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) + & + (0.5_wp*(rho_R*(vel_R(1))**2.0 + & + pres_R)*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dx(j + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dx(j)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(2)*(1._wp/dx(j)) + rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) + & + (0.5_wp*rho_R*vel_R(1)*vel_R(2)*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dx(j + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) - & - 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dx(j + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & - 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(1)*(1._wp/dx(j + 1)) + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) + & + (0.5_wp*(vel_R(1)*(E_R + & + pres_R))*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(E_R)*(1._wp/dx(j + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dx(j)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(1)*(1._wp/dx(j)) + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & + (0.5_wp*(rho_R*(vel_R(1))**2.0 + & + pres_R)*(1._wp/dx(j)) + & + 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dx(j))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) - & - 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dx(j + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & - 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(1)*(1._wp/dx(j + 1)) + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & + (0.5_wp*rho_R*vel_R(1)*vel_R(2)*(1._wp/dx(j)) + & + 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dx(j))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dx(j)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(1)*(1._wp/dx(j)) - end if - - E_L = 0._wp; E_R = 0._wp - - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb + 1, vidxe - E_L = E_L + coeff_L(q)*q_cons_vf(E_idx)%sf(j + q, k, l) - end do + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & + (0.5_wp*(vel_R(1)*(E_R + & + pres_R))*(1._wp/dx(j)) + & + 0.5_wp*cfl*(E_R)*(1._wp/dx(j))) - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - 1 - E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j + q, k, l) end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + else + #:call GPU_PARALLEL_LOOP(collapse=3, private='[rho_L, rho_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, mu_L, mu_R, vel_L, vel_R, pres_L, pres_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, F_L, F_R, E_L, E_R, cfl, dvel, dvel_small, rho_sf_small, vflux_L_arr, vflux_R_arr]') + do l = 0, p + do k = 0, n + do j = -1, m - call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & - E_R, gamma_R, pi_inf_R, rho_R, vel_R, & - pres_L, pres_R, cfl) + dvel = 0._wp + vflux_L_arr = 0._wp + vflux_R_arr = 0._wp - do i = 1, num_fluids - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j + 1, k, l) = rhs_vf(i)%sf(j + 1, k, l) + & - (0.5_wp*(alpha_rho_L(i)* & - vel_L(1))*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dx(j + 1))) + #:if MFC_CASE_OPTIMIZATION + #:if igr_order == 5 + !DIR$ unroll 6 + #:elif igr_order == 3 + !DIR$ unroll 4 + #:endif + #:endif + $:GPU_LOOP(parallelism='[seq]') + do q = vidxb, vidxe + dvel_small = 0._wp + !x-direction contributions + $:GPU_LOOP(parallelism='[seq]') + do i = -1, 1 + rho_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do r = 1, num_fluids + rho_L = rho_L + q_cons_vf(r)%sf(j + i + q, k, l) + end do + rho_sf_small(i) = rho_L + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & - (0.5_wp*(alpha_rho_L(i)* & - vel_L(1))*(1._wp/dx(j)) - & - 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dx(j))) - end do + dvel_small(1) = (1/(2._wp*dx(j)))*( & + q_cons_vf(momxb)%sf(j + 1 + q, k, l)/rho_sf_small(1) - & + q_cons_vf(momxb)%sf(j - 1 + q, k, l)/rho_sf_small(-1)) + dvel_small(2) = (1/(2._wp*dx(j)))*( & + q_cons_vf(momxb + 1)%sf(j + 1 + q, k, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j - 1 + q, k, l)/rho_sf_small(-1)) + dvel_small(3) = (1/(2._wp*dx(j)))*( & + q_cons_vf(momxb + 2)%sf(j + 1 + q, k, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 2)%sf(j - 1 + q, k, l)/rho_sf_small(-1)) - if (num_fluids > 1) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) + & - (0.5_wp*(alpha_L(i)* & - vel_L(1))*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(alpha_L(i))*(1._wp/dx(j + 1))) + if (q == 0) dvel(:, 1) = dvel_small + if (q > vidxb) then + vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(2)) + vflux_L_arr(2) = vflux_L_arr(2) + coeff_L(q)*(dvel_small(3)) + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(4._wp*dvel_small(1))/3._wp + end if + if (q < vidxe) then + vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(2)) + vflux_R_arr(2) = vflux_R_arr(2) + coeff_R(q)*(dvel_small(3)) + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(4._wp*dvel_small(1))/3._wp + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) & - - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j + 1, k, l)*vel_L(1)*(1._wp/dx(j + 1))) + !y-direction contributions + $:GPU_LOOP(parallelism='[seq]') + do i = -1, 1 + rho_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do r = 1, num_fluids + rho_L = rho_L + q_cons_vf(r)%sf(j + q, k + i, l) + end do + rho_sf_small(i) = rho_L + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & - (0.5_wp*(alpha_L(i)* & - vel_L(1))*(1._wp/dx(j)) - & - 0.5_wp*cfl*(alpha_L(i))*(1._wp/dx(j))) + dvel_small(1) = (1/(2._wp*dy(k)))*( & + q_cons_vf(momxb)%sf(j + q, k + 1, l)/rho_sf_small(1) - & + q_cons_vf(momxb)%sf(j + q, k - 1, l)/rho_sf_small(-1)) + dvel_small(2) = (1/(2._wp*dy(k)))*( & + q_cons_vf(momxb + 1)%sf(j + q, k + 1, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j + q, k - 1, l)/rho_sf_small(-1)) + if (q == 0) dvel_small(3) = (1/(2._wp*dy(k)))*( & + q_cons_vf(momxb + 2)%sf(j + q, k + 1, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 2)%sf(j + q, k - 1, l)/rho_sf_small(-1)) + if (q == 0) dvel(:, 2) = dvel_small - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & - + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_L(1)*(1._wp/dx(j))) - end do - end if + if (q > vidxb) then + vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(1)) + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(2))/3._wp + end if + if (q < vidxe) then + vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(1)) + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(2))/3._wp + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) + & - (0.5_wp*(rho_L*(vel_L(1))**2.0 + & - pres_L)*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dx(j + 1))) + !z-direction contributions + $:GPU_LOOP(parallelism='[seq]') + do i = -1, 1 + rho_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do r = 1, num_fluids + rho_L = rho_L + q_cons_vf(r)%sf(j + q, k, l + i) + end do + rho_sf_small(i) = rho_L + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) + & - (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dx(j + 1))) + dvel_small(1) = (1/(2._wp*dz(l)))*( & + q_cons_vf(momxb)%sf(j + q, k, l + 1)/rho_sf_small(1) - & + q_cons_vf(momxb)%sf(j + q, k, l - 1)/rho_sf_small(-1)) + if (q == 0) dvel_small(2) = (1/(2._wp*dz(l)))*( & + q_cons_vf(momxb + 1)%sf(j + q, k, l + 1)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j + q, k, l - 1)/rho_sf_small(-1)) + dvel_small(3) = (1/(2._wp*dz(l)))*( & + q_cons_vf(momxb + 2)%sf(j + q, k, l + 1)/rho_sf_small(1) - & + q_cons_vf(momxb + 2)%sf(j + q, k, l - 1)/rho_sf_small(-1)) + if (q == 0) dvel(:, 3) = dvel_small - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) + & - (0.5_wp*(vel_L(1)*(E_L + & - pres_L))*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(E_L)*(1._wp/dx(j + 1))) + if (q > vidxb) then + vflux_L_arr(2) = vflux_L_arr(2) + coeff_L(q)*(dvel_small(1)) + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(3))/3._wp + end if + if (q < vidxe) then + vflux_R_arr(2) = vflux_R_arr(2) + coeff_R(q)*(dvel_small(1)) + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(3))/3._wp + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - (0.5_wp*(rho_L*(vel_L(1))**2.0 + & - pres_L)*(1._wp/dx(j)) - & - 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dx(j))) + if (q == 0) then + jac_rhs(j, k, l) = alf_igr*(2._wp*(dvel(1, 2)*dvel(2, 1) & + + dvel(1, 3)*dvel(3, 1) & + + dvel(2, 3)*dvel(3, 2)) & + + dvel(1, 1)**2._wp + dvel(2, 2)**2._wp & + + dvel(3, 3)**2._wp & + + (dvel(1, 1) + dvel(2, 2) + dvel(3, 3))**2._wp) + end if + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & - (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dx(j)) - & - 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dx(j))) + alpha_rho_L = 0._wp; alpha_rho_R = 0._wp + alpha_L = 0._wp; alpha_R = 0._wp + vel_L = 0._wp; vel_R = 0._wp - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - (0.5_wp*(vel_L(1)*(E_L + & - pres_L))*(1._wp/dx(j)) - & - 0.5_wp*cfl*(E_L)*(1._wp/dx(j))) + $:GPU_LOOP(parallelism='[seq]') + do q = vidxb + 1, vidxe + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j + q, k, l) + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j + 1, k, l) = rhs_vf(i)%sf(j + 1, k, l) + & - (0.5_wp*(alpha_rho_R(i)* & - vel_R(1))*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dx(j + 1))) + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j + q, k, l) + end do + else + alpha_L(1) = 1._wp + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & - (0.5_wp*(alpha_rho_R(i)* & - vel_R(1))*(1._wp/dx(j)) + & - 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dx(j))) - end do + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + vel_L(i) = vel_L(i) + coeff_L(q)*q_cons_vf(momxb + i - 1)%sf(j + q, k, l) + end do + end do - if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) + & - (0.5_wp*(alpha_R(i)* & - vel_R(1))*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(alpha_R(i))*(1._wp/dx(j + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) & - - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j + 1, k, l)*vel_R(1)*(1._wp/dx(j + 1))) + do q = vidxb, vidxe - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j + q, k, l) + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & - (0.5_wp*(alpha_R(i)* & - vel_R(1))*(1._wp/dx(j)) + & - 0.5_wp*cfl*(alpha_R(i))*(1._wp/dx(j))) + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + alpha_R(i) = alpha_R(i) + coeff_R(q)*q_cons_vf(E_idx + i)%sf(j + q, k, l) + end do + else + alpha_R(1) = 1._wp + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & - + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_R(1)*(1._wp/dx(j))) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + vel_R(i) = vel_R(i) + coeff_R(q)*q_cons_vf(momxb + i - 1)%sf(j + q, k, l) + end do end do - end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) + & - (0.5_wp*(rho_R*(vel_R(1))**2.0 + & - pres_R)*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dx(j + 1))) + if (num_fluids > 1) then + alpha_L(num_fluids) = 1._wp - sum(alpha_L(1:num_fluids - 1)) + alpha_R(num_fluids) = 1._wp - sum(alpha_R(1:num_fluids - 1)) + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) + & - (0.5_wp*rho_R*vel_R(1)*vel_R(2)*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dx(j + 1))) + rho_L = sum(alpha_rho_L) + gamma_L = sum(alpha_L*gammas) + pi_inf_L = sum(alpha_L*pi_infs) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) + & - (0.5_wp*(vel_R(1)*(E_R + & - pres_R))*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(E_R)*(1._wp/dx(j + 1))) + rho_R = sum(alpha_rho_R) + gamma_R = sum(alpha_R*gammas) + pi_inf_R = sum(alpha_R*pi_infs) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - (0.5_wp*(rho_R*(vel_R(1))**2.0 + & - pres_R)*(1._wp/dx(j)) + & - 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dx(j))) + vel_L = vel_L/rho_L + vel_R = vel_R/rho_R - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & - (0.5_wp*rho_R*vel_R(1)*vel_R(2)*(1._wp/dx(j)) + & - 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dx(j))) + if (viscous) then + mu_L = 0._wp + mu_R = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + mu_L = alpha_L(i)/Res(1, i) + mu_L + mu_R = alpha_R(i)/Res(1, i) + mu_R + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - (0.5_wp*(vel_R(1)*(E_R + & - pres_R))*(1._wp/dx(j)) + & - 0.5_wp*cfl*(E_R)*(1._wp/dx(j))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) - & + 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & + 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(2)*(1._wp/dx(j + 1)) - end do - end do - end do - else - $:GPU_PARALLEL_LOOP(collapse=3, private='[rho_L, rho_R, gamma_L, & - & gamma_R, pi_inf_L, pi_inf_R, mu_L, mu_R, vel_L, vel_R, & - & pres_L, pres_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, & - & F_L, F_R, E_L, E_R, cfl, dvel, dvel_small, rho_sf_small, & - & vflux_L_arr, vflux_R_arr]') - do l = 0, p - do k = 0, n - do j = -1, m + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(2)*(1._wp/dx(j)) - dvel = 0._wp - vflux_L_arr = 0._wp - vflux_R_arr = 0._wp + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) - & + 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & + 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(2)*(1._wp/dx(j + 1)) - #:if MFC_CASE_OPTIMIZATION - #:if igr_order == 5 - !DIR$ unroll 6 - #:elif igr_order == 3 - !DIR$ unroll 4 - #:endif - #:endif - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - dvel_small = 0._wp - !x-direction contributions - $:GPU_LOOP(parallelism='[seq]') - do i = -1, 1 - rho_L = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j + i + q, k, l) - end do - rho_sf_small(i) = rho_L - end do + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(2)*(1._wp/dx(j)) - dvel_small(1) = (1/(2._wp*dx(j)))*( & - q_cons_vf(momxb)%sf(j + 1 + q, k, l)/rho_sf_small(1) - & - q_cons_vf(momxb)%sf(j - 1 + q, k, l)/rho_sf_small(-1)) - dvel_small(2) = (1/(2._wp*dx(j)))*( & - q_cons_vf(momxb + 1)%sf(j + 1 + q, k, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j - 1 + q, k, l)/rho_sf_small(-1)) - dvel_small(3) = (1/(2._wp*dx(j)))*( & - q_cons_vf(momxb + 2)%sf(j + 1 + q, k, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 2)%sf(j - 1 + q, k, l)/rho_sf_small(-1)) - - if (q == 0) dvel(:, 1) = dvel_small - if (q > vidxb) then - vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(2)) - vflux_L_arr(2) = vflux_L_arr(2) + coeff_L(q)*(dvel_small(3)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(4._wp*dvel_small(1))/3._wp - end if - if (q < vidxe) then - vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(2)) - vflux_R_arr(2) = vflux_R_arr(2) + coeff_R(q)*(dvel_small(3)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(4._wp*dvel_small(1))/3._wp - end if + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j + 1, k, l) = rhs_vf(momxb + 2)%sf(j + 1, k, l) - & + 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & + 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(3)*(1._wp/dx(j + 1)) - !y-direction contributions - $:GPU_LOOP(parallelism='[seq]') - do i = -1, 1 - rho_L = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j + q, k + i, l) - end do - rho_sf_small(i) = rho_L - end do + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(3)*(1._wp/dx(j)) - dvel_small(1) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb)%sf(j + q, k + 1, l)/rho_sf_small(1) - & - q_cons_vf(momxb)%sf(j + q, k - 1, l)/rho_sf_small(-1)) - dvel_small(2) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb + 1)%sf(j + q, k + 1, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j + q, k - 1, l)/rho_sf_small(-1)) - if (q == 0) dvel_small(3) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb + 2)%sf(j + q, k + 1, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 2)%sf(j + q, k - 1, l)/rho_sf_small(-1)) - if (q == 0) dvel(:, 2) = dvel_small - - if (q > vidxb) then - vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(1)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(2))/3._wp - end if - if (q < vidxe) then - vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(1)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(2))/3._wp - end if + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j + 1, k, l) = rhs_vf(momxb + 2)%sf(j + 1, k, l) - & + 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & + 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(3)*(1._wp/dx(j + 1)) - !z-direction contributions - $:GPU_LOOP(parallelism='[seq]') - do i = -1, 1 - rho_L = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j + q, k, l + i) - end do - rho_sf_small(i) = rho_L - end do + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(3)*(1._wp/dx(j)) - dvel_small(1) = (1/(2._wp*dz(l)))*( & - q_cons_vf(momxb)%sf(j + q, k, l + 1)/rho_sf_small(1) - & - q_cons_vf(momxb)%sf(j + q, k, l - 1)/rho_sf_small(-1)) - if (q == 0) dvel_small(2) = (1/(2._wp*dz(l)))*( & - q_cons_vf(momxb + 1)%sf(j + q, k, l + 1)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j + q, k, l - 1)/rho_sf_small(-1)) - dvel_small(3) = (1/(2._wp*dz(l)))*( & - q_cons_vf(momxb + 2)%sf(j + q, k, l + 1)/rho_sf_small(1) - & - q_cons_vf(momxb + 2)%sf(j + q, k, l - 1)/rho_sf_small(-1)) - if (q == 0) dvel(:, 3) = dvel_small - - if (q > vidxb) then - vflux_L_arr(2) = vflux_L_arr(2) + coeff_L(q)*(dvel_small(1)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(3))/3._wp - end if - if (q < vidxe) then - vflux_R_arr(2) = vflux_R_arr(2) + coeff_R(q)*(dvel_small(1)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(3))/3._wp - end if + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) - & + 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & + 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(1)*(1._wp/dx(j + 1)) - if (q == 0) then - jac_rhs(j, k, l) = alf_igr*(2._wp*(dvel(1, 2)*dvel(2, 1) & - + dvel(1, 3)*dvel(3, 1) & - + dvel(2, 3)*dvel(3, 2)) & - + dvel(1, 1)**2._wp + dvel(2, 2)**2._wp & - + dvel(3, 3)**2._wp & - + (dvel(1, 1) + dvel(2, 2) + dvel(3, 3))**2._wp) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(1)*(1._wp/dx(j)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) - & + 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dx(j + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & + 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(1)*(1._wp/dx(j + 1)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dx(j)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(1)*(1._wp/dx(j)) end if - end do - alpha_rho_L = 0._wp; alpha_rho_R = 0._wp - alpha_L = 0._wp; alpha_R = 0._wp - vel_L = 0._wp; vel_R = 0._wp + E_L = 0._wp; E_R = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb + 1, vidxe $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j + q, k, l) + do q = vidxb + 1, vidxe + E_L = E_L + coeff_L(q)*q_cons_vf(E_idx)%sf(j + q, k, l) end do - if (num_fluids > 1) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j + q, k, l) - end do - else - alpha_L(1) = 1._wp - end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_L(i) = vel_L(i) + coeff_L(q)*q_cons_vf(momxb + i - 1)%sf(j + q, k, l) + do q = vidxb, vidxe - 1 + E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j + q, k, l) end do - end do - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - 1 + call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & + E_R, gamma_R, pi_inf_R, rho_R, vel_R, & + pres_L, pres_R, cfl) + $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j + q, k, l) + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j + 1, k, l) = rhs_vf(i)%sf(j + 1, k, l) + & + (0.5_wp*(alpha_rho_L(i)* & + vel_L(1))*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & + (0.5_wp*(alpha_rho_L(i)* & + vel_L(1))*(1._wp/dx(j)) - & + 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dx(j))) end do if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 - alpha_R(i) = alpha_R(i) + coeff_R(q)*q_cons_vf(E_idx + i)%sf(j + q, k, l) + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) + & + (0.5_wp*(alpha_L(i)* & + vel_L(1))*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(alpha_L(i))*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) & + - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j + 1, k, l)*vel_L(1)*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & + (0.5_wp*(alpha_L(i)* & + vel_L(1))*(1._wp/dx(j)) - & + 0.5_wp*cfl*(alpha_L(i))*(1._wp/dx(j))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & + + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_L(1)*(1._wp/dx(j))) end do - else - alpha_R(1) = 1._wp end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_R(i) = vel_R(i) + coeff_R(q)*q_cons_vf(momxb + i - 1)%sf(j + q, k, l) - end do - end do - - if (num_fluids > 1) then - alpha_L(num_fluids) = 1._wp - sum(alpha_L(1:num_fluids - 1)) - alpha_R(num_fluids) = 1._wp - sum(alpha_R(1:num_fluids - 1)) - end if - - rho_L = sum(alpha_rho_L) - gamma_L = sum(alpha_L*gammas) - pi_inf_L = sum(alpha_L*pi_infs) - - rho_R = sum(alpha_rho_R) - gamma_R = sum(alpha_R*gammas) - pi_inf_R = sum(alpha_R*pi_infs) - - vel_L = vel_L/rho_L - vel_R = vel_R/rho_R - - if (viscous) then - mu_L = 0._wp - mu_R = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - mu_L = alpha_L(i)/Res(1, i) + mu_L - mu_R = alpha_R(i)/Res(1, i) + mu_R - end do - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) - & - 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dx(j + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & - 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(2)*(1._wp/dx(j + 1)) + rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) + & + (0.5_wp*(rho_L*(vel_L(1))**2.0 + & + pres_L)*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dx(j + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dx(j)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(2)*(1._wp/dx(j)) + rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) + & + (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dx(j + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) - & - 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dx(j + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & - 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(2)*(1._wp/dx(j + 1)) + rhs_vf(momxb + 2)%sf(j + 1, k, l) = rhs_vf(momxb + 2)%sf(j + 1, k, l) + & + (0.5_wp*rho_L*vel_L(1)*vel_L(3)*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dx(j + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dx(j)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(2)*(1._wp/dx(j)) + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) + & + (0.5_wp*(vel_L(1)*(E_L + & + pres_L))*(1._wp/dx(j + 1)) - & + 0.5_wp*cfl*(E_L)*(1._wp/dx(j + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j + 1, k, l) = rhs_vf(momxb + 2)%sf(j + 1, k, l) - & - 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dx(j + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & - 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(3)*(1._wp/dx(j + 1)) + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & + (0.5_wp*(rho_L*(vel_L(1))**2.0 + & + pres_L)*(1._wp/dx(j)) - & + 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dx(j))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dx(j)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(3)*(1._wp/dx(j)) + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & + (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dx(j)) - & + 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dx(j))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j + 1, k, l) = rhs_vf(momxb + 2)%sf(j + 1, k, l) - & - 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dx(j + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & - 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(3)*(1._wp/dx(j + 1)) + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & + (0.5_wp*rho_L*vel_L(1)*vel_L(3)*(1._wp/dx(j)) - & + 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dx(j))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dx(j)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(3)*(1._wp/dx(j)) + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & + (0.5_wp*(vel_L(1)*(E_L + & + pres_L))*(1._wp/dx(j)) - & + 0.5_wp*cfl*(E_L)*(1._wp/dx(j))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) - & - 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dx(j + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & - 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(1)*(1._wp/dx(j + 1)) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j + 1, k, l) = rhs_vf(i)%sf(j + 1, k, l) + & + (0.5_wp*(alpha_rho_R(i)* & + vel_R(1))*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & + (0.5_wp*(alpha_rho_R(i)* & + vel_R(1))*(1._wp/dx(j)) + & + 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dx(j))) + end do + + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) + & + (0.5_wp*(alpha_R(i)* & + vel_R(1))*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(alpha_R(i))*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) & + - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j + 1, k, l)*vel_R(1)*(1._wp/dx(j + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & + (0.5_wp*(alpha_R(i)* & + vel_R(1))*(1._wp/dx(j)) + & + 0.5_wp*cfl*(alpha_R(i))*(1._wp/dx(j))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & + + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_R(1)*(1._wp/dx(j))) + end do + end if $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dx(j)) + rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) + & + (0.5_wp*(rho_R*(vel_R(1))**2.0 + & + pres_R)*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dx(j + 1))) + $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(1)*(1._wp/dx(j)) + rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) + & + (0.5_wp*rho_R*vel_R(1)*vel_R(2)*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dx(j + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) - & - 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dx(j + 1)) + rhs_vf(momxb + 2)%sf(j + 1, k, l) = rhs_vf(momxb + 2)%sf(j + 1, k, l) + & + (0.5_wp*rho_R*vel_R(1)*vel_R(3)*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dx(j + 1))) + $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) - & - 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(1)*(1._wp/dx(j + 1)) + rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) + & + (0.5_wp*(vel_R(1)*(E_R + & + pres_R))*(1._wp/dx(j + 1)) + & + 0.5_wp*cfl*(E_R)*(1._wp/dx(j + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dx(j)) + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & + (0.5_wp*(rho_R*(vel_R(1))**2.0 + & + pres_R)*(1._wp/dx(j)) + & + 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dx(j))) + $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(1)*(1._wp/dx(j)) - end if + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & + (0.5_wp*rho_R*vel_R(1)*vel_R(2)*(1._wp/dx(j)) + & + 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dx(j))) - E_L = 0._wp; E_R = 0._wp + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & + (0.5_wp*rho_R*vel_R(1)*vel_R(3)*(1._wp/dx(j)) + & + 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dx(j))) - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb + 1, vidxe - E_L = E_L + coeff_L(q)*q_cons_vf(E_idx)%sf(j + q, k, l) - end do + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & + (0.5_wp*(vel_R(1)*(E_R + & + pres_R))*(1._wp/dx(j)) + & + 0.5_wp*cfl*(E_R)*(1._wp/dx(j))) - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - 1 - E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j + q, k, l) end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + end if + else if (idir == 2) then + if (p == 0) then + #:call GPU_PARALLEL_LOOP(collapse=3, private='[rho_L, rho_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, mu_L, mu_R, vel_L, vel_R, pres_L, pres_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, F_L, F_R, E_L, E_R, cfl, dvel_small, rho_sf_small, vflux_L_arr, vflux_R_arr]') + do l = 0, p + do k = -1, n + do j = 0, m + + if (viscous) then + vflux_L_arr = 0._wp + vflux_R_arr = 0._wp + + #:if MFC_CASE_OPTIMIZATION + #:if igr_order == 5 + !DIR$ unroll 6 + #:elif igr_order == 3 + !DIR$ unroll 4 + #:endif + #:endif + $:GPU_LOOP(parallelism='[seq]') + do q = vidxb, vidxe + dvel_small = 0._wp + !x-direction contributions + $:GPU_LOOP(parallelism='[seq]') + do i = -1, 1 + rho_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do r = 1, num_fluids + rho_L = rho_L + q_cons_vf(r)%sf(j + i, k + q, l) + end do + rho_sf_small(i) = rho_L + end do - call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & - E_R, gamma_R, pi_inf_R, rho_R, vel_R, & - pres_L, pres_R, cfl) + dvel_small(1) = (1/(2._wp*dx(j)))*( & + q_cons_vf(momxb)%sf(j + 1, k + q, l)/rho_sf_small(1) - & + q_cons_vf(momxb)%sf(j - 1, k + q, l)/rho_sf_small(-1)) + dvel_small(2) = (1/(2._wp*dx(j)))*( & + q_cons_vf(momxb + 1)%sf(j + 1, k + q, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j - 1, k + q, l)/rho_sf_small(-1)) + + if (q > vidxb) then + vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(2)) + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(1))/3._wp + end if + if (q < vidxe) then + vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(2)) + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(1))/3._wp + end if + + !y-direction contributions + $:GPU_LOOP(parallelism='[seq]') + do i = -1, 1 + rho_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do r = 1, num_fluids + rho_L = rho_L + q_cons_vf(r)%sf(j, k + i + q, l) + end do + rho_sf_small(i) = rho_L + end do - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j + 1, k, l) = rhs_vf(i)%sf(j + 1, k, l) + & - (0.5_wp*(alpha_rho_L(i)* & - vel_L(1))*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dx(j + 1))) + dvel_small(1) = (1/(2._wp*dy(k)))*( & + q_cons_vf(momxb)%sf(j, k + 1 + q, l)/rho_sf_small(1) - & + q_cons_vf(momxb)%sf(j, k - 1 + q, l)/rho_sf_small(-1)) + dvel_small(2) = (1/(2._wp*dy(k)))*( & + q_cons_vf(momxb + 1)%sf(j, k + 1 + q, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j, k - 1 + q, l)/rho_sf_small(-1)) + + if (q > vidxb) then + vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(1)) + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(4._wp*dvel_small(2))/3._wp + end if + if (q < vidxe) then + vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(1)) + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(4._wp*dvel_small(2))/3._wp + end if + end do + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & - (0.5_wp*(alpha_rho_L(i)* & - vel_L(1))*(1._wp/dx(j)) - & - 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dx(j))) - end do + alpha_rho_L = 0._wp; alpha_rho_R = 0._wp + alpha_L = 0._wp; alpha_R = 0._wp + vel_L = 0._wp; vel_R = 0._wp - if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) + & - (0.5_wp*(alpha_L(i)* & - vel_L(1))*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(alpha_L(i))*(1._wp/dx(j + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) & - - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j + 1, k, l)*vel_L(1)*(1._wp/dx(j + 1))) + do q = vidxb + 1, vidxe + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j, k + q, l) + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & - (0.5_wp*(alpha_L(i)* & - vel_L(1))*(1._wp/dx(j)) - & - 0.5_wp*cfl*(alpha_L(i))*(1._wp/dx(j))) + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j, k + q, l) + end do + else + alpha_L(1) = 1._wp + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & - + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_L(1)*(1._wp/dx(j))) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + vel_L(i) = vel_L(i) + coeff_L(q)*q_cons_vf(momxb + i - 1)%sf(j, k + q, l) + end do end do - end if - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) + & - (0.5_wp*(rho_L*(vel_L(1))**2.0 + & - pres_L)*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dx(j + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) + & - (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dx(j + 1))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j + 1, k, l) = rhs_vf(momxb + 2)%sf(j + 1, k, l) + & - (0.5_wp*rho_L*vel_L(1)*vel_L(3)*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dx(j + 1))) + $:GPU_LOOP(parallelism='[seq]') + do q = vidxb, vidxe - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j, k + q, l) + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) + & - (0.5_wp*(vel_L(1)*(E_L + & - pres_L))*(1._wp/dx(j + 1)) - & - 0.5_wp*cfl*(E_L)*(1._wp/dx(j + 1))) + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + alpha_R(i) = alpha_R(i) + coeff_R(q)*q_cons_vf(E_idx + i)%sf(j, k + q, l) + end do + else + alpha_R(1) = 1._wp + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - (0.5_wp*(rho_L*(vel_L(1))**2.0 + & - pres_L)*(1._wp/dx(j)) - & - 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dx(j))) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + vel_R(i) = vel_R(i) + coeff_R(q)*q_cons_vf(momxb + i - 1)%sf(j, k + q, l) + end do + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & - (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dx(j)) - & - 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dx(j))) + if (num_fluids > 1) then + alpha_L(num_fluids) = 1._wp - sum(alpha_L(1:num_fluids - 1)) + alpha_R(num_fluids) = 1._wp - sum(alpha_R(1:num_fluids - 1)) + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & - (0.5_wp*rho_L*vel_L(1)*vel_L(3)*(1._wp/dx(j)) - & - 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dx(j))) + rho_L = sum(alpha_rho_L) + gamma_L = sum(alpha_L*gammas) + pi_inf_L = sum(alpha_L*pi_infs) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - (0.5_wp*(vel_L(1)*(E_L + & - pres_L))*(1._wp/dx(j)) - & - 0.5_wp*cfl*(E_L)*(1._wp/dx(j))) + rho_R = sum(alpha_rho_R) + gamma_R = sum(alpha_R*gammas) + pi_inf_R = sum(alpha_R*pi_infs) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j + 1, k, l) = rhs_vf(i)%sf(j + 1, k, l) + & - (0.5_wp*(alpha_rho_R(i)* & - vel_R(1))*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dx(j + 1))) + vel_L = vel_L/rho_L + vel_R = vel_R/rho_R - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & - (0.5_wp*(alpha_rho_R(i)* & - vel_R(1))*(1._wp/dx(j)) + & - 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dx(j))) - end do + if (viscous) then + mu_L = 0._wp + mu_R = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + mu_L = alpha_L(i)/Res(1, i) + mu_L + mu_R = alpha_R(i)/Res(1, i) + mu_R + end do - if (num_fluids > 1) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) + & - (0.5_wp*(alpha_R(i)* & - vel_R(1))*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(alpha_R(i))*(1._wp/dx(j + 1))) - + rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) - & + 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dy(k + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j + 1, k, l) = rhs_vf(advxb + i - 1)%sf(j + 1, k, l) & - - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j + 1, k, l)*vel_R(1)*(1._wp/dx(j + 1))) + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & + 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dy(k + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & - (0.5_wp*(alpha_R(i)* & - vel_R(1))*(1._wp/dx(j)) + & - 0.5_wp*cfl*(alpha_R(i))*(1._wp/dx(j))) - + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dy(k)) $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & - + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_R(1)*(1._wp/dx(j))) - end do - end if - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j + 1, k, l) = rhs_vf(momxb)%sf(j + 1, k, l) + & - (0.5_wp*(rho_R*(vel_R(1))**2.0 + & - pres_R)*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dx(j + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j + 1, k, l) = rhs_vf(momxb + 1)%sf(j + 1, k, l) + & - (0.5_wp*rho_R*vel_R(1)*vel_R(2)*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dx(j + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j + 1, k, l) = rhs_vf(momxb + 2)%sf(j + 1, k, l) + & - (0.5_wp*rho_R*vel_R(1)*vel_R(3)*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dx(j + 1))) + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dy(k)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j + 1, k, l) = rhs_vf(E_idx)%sf(j + 1, k, l) + & - (0.5_wp*(vel_R(1)*(E_R + & - pres_R))*(1._wp/dx(j + 1)) + & - 0.5_wp*cfl*(E_R)*(1._wp/dx(j + 1))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) - & + 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dy(k + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & + 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dy(k + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - (0.5_wp*(rho_R*(vel_R(1))**2.0 + & - pres_R)*(1._wp/dx(j)) + & - 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dx(j))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dy(k)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dy(k)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & - (0.5_wp*rho_R*vel_R(1)*vel_R(2)*(1._wp/dx(j)) + & - 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dx(j))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) - & + 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dy(k + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & + 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(2)*(1._wp/dy(k + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & - (0.5_wp*rho_R*vel_R(1)*vel_R(3)*(1._wp/dx(j)) + & - 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dx(j))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dy(k)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(2)*(1._wp/dy(k)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - (0.5_wp*(vel_R(1)*(E_R + & - pres_R))*(1._wp/dx(j)) + & - 0.5_wp*cfl*(E_R)*(1._wp/dx(j))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) - & + 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dy(k + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & + 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(2)*(1._wp/dy(k + 1)) - end do - end do - end do - end if - else if (idir == 2) then - if (p == 0) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[rho_L, rho_R, gamma_L, & - & gamma_R, pi_inf_L, pi_inf_R, mu_L, mu_R, vel_L, vel_R, & - & pres_L, pres_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, & - & F_L, F_R, E_L, E_R, cfl, dvel_small, rho_sf_small, & - & vflux_L_arr, vflux_R_arr]') - do l = 0, p - do k = -1, n - do j = 0, m + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dy(k)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(2)*(1._wp/dy(k)) + end if - if (viscous) then - vflux_L_arr = 0._wp - vflux_R_arr = 0._wp + E_L = 0._wp; E_R = 0._wp + F_L = 0._wp; F_R = 0._wp - #:if MFC_CASE_OPTIMIZATION - #:if igr_order == 5 - !DIR$ unroll 6 - #:elif igr_order == 3 - !DIR$ unroll 4 - #:endif - #:endif $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - dvel_small = 0._wp - !x-direction contributions - $:GPU_LOOP(parallelism='[seq]') - do i = -1, 1 - rho_L = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j + i, k + q, l) - end do - rho_sf_small(i) = rho_L - end do - - dvel_small(1) = (1/(2._wp*dx(j)))*( & - q_cons_vf(momxb)%sf(j + 1, k + q, l)/rho_sf_small(1) - & - q_cons_vf(momxb)%sf(j - 1, k + q, l)/rho_sf_small(-1)) - dvel_small(2) = (1/(2._wp*dx(j)))*( & - q_cons_vf(momxb + 1)%sf(j + 1, k + q, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j - 1, k + q, l)/rho_sf_small(-1)) - - if (q > vidxb) then - vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(2)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(1))/3._wp - end if - if (q < vidxe) then - vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(2)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(1))/3._wp - end if - - !y-direction contributions - $:GPU_LOOP(parallelism='[seq]') - do i = -1, 1 - rho_L = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j, k + i + q, l) - end do - rho_sf_small(i) = rho_L - end do - - dvel_small(1) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb)%sf(j, k + 1 + q, l)/rho_sf_small(1) - & - q_cons_vf(momxb)%sf(j, k - 1 + q, l)/rho_sf_small(-1)) - dvel_small(2) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb + 1)%sf(j, k + 1 + q, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j, k - 1 + q, l)/rho_sf_small(-1)) + do q = vidxb + 1, vidxe + E_L = E_L + coeff_L(q)*q_cons_vf(E_idx)%sf(j, k + q, l) + F_L = F_L + coeff_L(q)*jac(j, k + q, l) + end do - if (q > vidxb) then - vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(1)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(4._wp*dvel_small(2))/3._wp - end if - if (q < vidxe) then - vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(1)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(4._wp*dvel_small(2))/3._wp - end if + $:GPU_LOOP(parallelism='[seq]') + do q = vidxb, vidxe - 1 + E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j, k + q, l) + F_R = F_R + coeff_R(q)*jac(j, k + q, l) end do - end if - alpha_rho_L = 0._wp; alpha_rho_R = 0._wp - alpha_L = 0._wp; alpha_R = 0._wp - vel_L = 0._wp; vel_R = 0._wp + call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & + E_R, gamma_R, pi_inf_R, rho_R, vel_R, & + pres_L, pres_R, cfl) - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb + 1, vidxe $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j, k + q, l) + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j, k + 1, l) = rhs_vf(i)%sf(j, k + 1, l) + & + (0.5_wp*(alpha_rho_L(i)* & + vel_L(2))*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & + (0.5_wp*(alpha_rho_L(i)* & + vel_L(2))*(1._wp/dy(k)) - & + 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dy(k))) end do if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 - alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j, k + q, l) + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) + & + (0.5_wp*(alpha_L(i)* & + vel_L(2))*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(alpha_L(i))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) & + - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k + 1, l)*vel_L(2)*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & + (0.5_wp*(alpha_L(i)* & + vel_L(2))*(1._wp/dy(k)) - & + 0.5_wp*cfl*(alpha_L(i))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & + + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_L(2)*(1._wp/dy(k))) end do - else - alpha_L(1) = 1._wp end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_L(i) = vel_L(i) + coeff_L(q)*q_cons_vf(momxb + i - 1)%sf(j, k + q, l) - end do - end do + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) + & + (0.5_wp*(rho_L*(vel_L(2))**2.0 + & + pres_L + F_L)*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) + & + (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) + & + (0.5_wp*(vel_L(2)*(E_L + & + pres_L + F_L))*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(E_L)*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & + (0.5_wp*(rho_L*(vel_L(2))**2.0 + & + pres_L + F_L)*(1._wp/dy(k)) - & + 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & + (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dy(k)) - & + 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & + (0.5_wp*(vel_L(2)*(E_L + & + pres_L + F_L))*(1._wp/dy(k)) - & + 0.5_wp*cfl*(E_L)*(1._wp/dy(k))) - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - 1 $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j, k + q, l) + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j, k + 1, l) = rhs_vf(i)%sf(j, k + 1, l) + & + (0.5_wp*(alpha_rho_R(i)* & + vel_R(2))*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dy(k + 1))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & + (0.5_wp*(alpha_rho_R(i)* & + vel_R(2))*(1._wp/dy(k)) + & + 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dy(k))) end do if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 - alpha_R(i) = alpha_R(i) + coeff_R(q)*q_cons_vf(E_idx + i)%sf(j, k + q, l) + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) + & + (0.5_wp*(alpha_R(i)* & + vel_R(2))*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(alpha_R(i))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) & + - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k + 1, l)*vel_R(2)*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & + (0.5_wp*(alpha_R(i)* & + vel_R(2))*(1._wp/dy(k)) + & + 0.5_wp*cfl*(alpha_R(i))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & + + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_R(2)*(1._wp/dy(k))) end do - else - alpha_R(1) = 1._wp end if - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_R(i) = vel_R(i) + coeff_R(q)*q_cons_vf(momxb + i - 1)%sf(j, k + q, l) - end do + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) + & + (0.5_wp*(rho_R*(vel_R(2))**2.0 + & + pres_R + F_R)*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dy(k + 1))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) + & + (0.5_wp*rho_R*vel_R(2)*vel_R(1)*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dy(k + 1))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) + & + (0.5_wp*(vel_R(2)*(E_R + & + pres_R + F_R))*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(E_R)*(1._wp/dy(k + 1))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & + (0.5_wp*(rho_R*(vel_R(2))**2.0 + & + pres_R + F_R)*(1._wp/dy(k)) + & + 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dy(k))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & + (0.5_wp*rho_R*vel_R(2)*vel_R(1)*(1._wp/dy(k)) + & + 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dy(k))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & + (0.5_wp*(vel_R(2)*(E_R + & + pres_R + F_R))*(1._wp/dy(k)) + & + 0.5_wp*cfl*(E_R)*(1._wp/dy(k))) end do + end do + end do + #:endcall GPU_PARALLEL_LOOP + else + #:call GPU_PARALLEL_LOOP(collapse=3, private='[rho_L, rho_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, mu_L, mu_R, vel_L, vel_R, pres_L, pres_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, F_L, F_R, E_L, E_R, cfl, dvel_small, rho_sf_small, vflux_L_arr, vflux_R_arr]') + do l = 0, p + do k = -1, n + do j = 0, m + + if (viscous) then + vflux_L_arr = 0._wp + vflux_R_arr = 0._wp + + #:if MFC_CASE_OPTIMIZATION + #:if igr_order == 5 + !DIR$ unroll 6 + #:elif igr_order == 3 + !DIR$ unroll 4 + #:endif + #:endif + $:GPU_LOOP(parallelism='[seq]') + do q = vidxb, vidxe + dvel_small = 0._wp + !x-direction contributions + $:GPU_LOOP(parallelism='[seq]') + do i = -1, 1 + rho_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do r = 1, num_fluids + rho_L = rho_L + q_cons_vf(r)%sf(j + i, k + q, l) + end do + rho_sf_small(i) = rho_L + end do - if (num_fluids > 1) then - alpha_L(num_fluids) = 1._wp - sum(alpha_L(1:num_fluids - 1)) - alpha_R(num_fluids) = 1._wp - sum(alpha_R(1:num_fluids - 1)) - end if + dvel_small(1) = (1/(2._wp*dx(j)))*( & + q_cons_vf(momxb)%sf(j + 1, k + q, l)/rho_sf_small(1) - & + q_cons_vf(momxb)%sf(j - 1, k + q, l)/rho_sf_small(-1)) + dvel_small(2) = (1/(2._wp*dx(j)))*( & + q_cons_vf(momxb + 1)%sf(j + 1, k + q, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j - 1, k + q, l)/rho_sf_small(-1)) + + if (q > vidxb) then + vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(2)) + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(1))/3._wp + end if + if (q < vidxe) then + vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(2)) + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(1))/3._wp + end if + + !y-direction contributions + $:GPU_LOOP(parallelism='[seq]') + do i = -1, 1 + rho_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do r = 1, num_fluids + rho_L = rho_L + q_cons_vf(r)%sf(j, k + i + q, l) + end do + rho_sf_small(i) = rho_L + end do - rho_L = sum(alpha_rho_L) - gamma_L = sum(alpha_L*gammas) - pi_inf_L = sum(alpha_L*pi_infs) + dvel_small(1) = (1/(2._wp*dy(k)))*( & + q_cons_vf(momxb)%sf(j, k + 1 + q, l)/rho_sf_small(1) - & + q_cons_vf(momxb)%sf(j, k - 1 + q, l)/rho_sf_small(-1)) + dvel_small(2) = (1/(2._wp*dy(k)))*( & + q_cons_vf(momxb + 1)%sf(j, k + 1 + q, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j, k - 1 + q, l)/rho_sf_small(-1)) + dvel_small(3) = (1/(2._wp*dy(k)))*( & + q_cons_vf(momxb + 2)%sf(j, k + 1 + q, l)/rho_sf_small(1) - & + q_cons_vf(momxb + 2)%sf(j, k - 1 + q, l)/rho_sf_small(-1)) + + if (q > vidxb) then + vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(1)) + vflux_L_arr(2) = vflux_L_arr(2) + coeff_L(q)*(dvel_small(3)) + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(4._wp*dvel_small(2))/3._wp + end if + if (q < vidxe) then + vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(1)) + vflux_R_arr(2) = vflux_R_arr(2) + coeff_R(q)*(dvel_small(3)) + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(4._wp*dvel_small(2))/3._wp + end if + + !z-direction contributions + $:GPU_LOOP(parallelism='[seq]') + do i = -1, 1 + rho_L = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do r = 1, num_fluids + rho_L = rho_L + q_cons_vf(r)%sf(j, k + q, l + i) + end do + rho_sf_small(i) = rho_L + end do - rho_R = sum(alpha_rho_R) - gamma_R = sum(alpha_R*gammas) - pi_inf_R = sum(alpha_R*pi_infs) + dvel_small(2) = (1/(2._wp*dz(l)))*( & + q_cons_vf(momxb + 1)%sf(j, k + q, l + 1)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j, k + q, l - 1)/rho_sf_small(-1)) + dvel_small(3) = (1/(2._wp*dz(l)))*( & + q_cons_vf(momxb + 2)%sf(j, k + q, l + 1)/rho_sf_small(1) - & + q_cons_vf(momxb + 2)%sf(j, k + q, l - 1)/rho_sf_small(-1)) + if (q > vidxb) then + vflux_L_arr(2) = vflux_L_arr(2) + coeff_L(q)*(dvel_small(2)) + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(3))/3._wp + end if + if (q < vidxe) then + vflux_R_arr(2) = vflux_R_arr(2) + coeff_R(q)*(dvel_small(2)) + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(3))/3._wp + end if + end do + end if - vel_L = vel_L/rho_L - vel_R = vel_R/rho_R + alpha_rho_L = 0._wp; alpha_rho_R = 0._wp + alpha_L = 0._wp; alpha_R = 0._wp + vel_L = 0._wp; vel_R = 0._wp - if (viscous) then - mu_L = 0._wp - mu_R = 0._wp $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - mu_L = alpha_L(i)/Res(1, i) + mu_L - mu_R = alpha_R(i)/Res(1, i) + mu_R + do q = vidxb + 1, vidxe + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j, k + q, l) + end do + + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j, k + q, l) + end do + else + alpha_L(1) = 1._wp + end if + + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + vel_L(i) = vel_L(i) + coeff_L(q)*q_cons_vf(momxb + i - 1)%sf(j, k + q, l) + end do end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) - & - 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dy(k + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & - 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dy(k + 1)) + $:GPU_LOOP(parallelism='[seq]') + do q = vidxb, vidxe - 1 + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j, k + q, l) + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dy(k)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dy(k)) + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + alpha_R(i) = alpha_R(i) + coeff_R(q)*q_cons_vf(E_idx + i)%sf(j, k + q, l) + end do + else + alpha_R(1) = 1._wp + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) - & - 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dy(k + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & - 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dy(k + 1)) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + vel_R(i) = vel_R(i) + coeff_R(q)*q_cons_vf(momxb + i - 1)%sf(j, k + q, l) + end do + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dy(k)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dy(k)) + if (num_fluids > 1) then + alpha_L(num_fluids) = 1._wp - sum(alpha_L(1:num_fluids - 1)) + alpha_R(num_fluids) = 1._wp - sum(alpha_R(1:num_fluids - 1)) + end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) - & - 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dy(k + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & - 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(2)*(1._wp/dy(k + 1)) + rho_L = sum(alpha_rho_L) + gamma_L = sum(alpha_L*gammas) + pi_inf_L = sum(alpha_L*pi_infs) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dy(k)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(2)*(1._wp/dy(k)) + rho_R = sum(alpha_rho_R) + gamma_R = sum(alpha_R*gammas) + pi_inf_R = sum(alpha_R*pi_infs) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) - & - 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dy(k + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & - 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(2)*(1._wp/dy(k + 1)) + vel_L = vel_L/rho_L + vel_R = vel_R/rho_R - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dy(k)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(2)*(1._wp/dy(k)) - end if + if (viscous) then + mu_L = 0._wp + mu_R = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + mu_L = alpha_L(i)/Res(1, i) + mu_L + mu_R = alpha_R(i)/Res(1, i) + mu_R + end do - E_L = 0._wp; E_R = 0._wp - F_L = 0._wp; F_R = 0._wp + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) - & + 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dy(k + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & + 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dy(k + 1)) - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb + 1, vidxe - E_L = E_L + coeff_L(q)*q_cons_vf(E_idx)%sf(j, k + q, l) - F_L = F_L + coeff_L(q)*jac(j, k + q, l) - end do + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dy(k)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dy(k)) - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - 1 - E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j, k + q, l) - F_R = F_R + coeff_R(q)*jac(j, k + q, l) - end do + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) - & + 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dy(k + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & + 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dy(k + 1)) - call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & - E_R, gamma_R, pi_inf_R, rho_R, vel_R, & - pres_L, pres_R, cfl) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dy(k)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dy(k)) - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k + 1, l) = rhs_vf(i)%sf(j, k + 1, l) + & - (0.5_wp*(alpha_rho_L(i)* & - vel_L(2))*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dy(k + 1))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j, k + 1, l) = rhs_vf(momxb + 2)%sf(j, k + 1, l) - & + 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dy(k + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & + 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(3)*(1._wp/dy(k + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & - (0.5_wp*(alpha_rho_L(i)* & - vel_L(2))*(1._wp/dy(k)) - & - 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dy(k))) - end do + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dy(k)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(3)*(1._wp/dy(k)) - if (num_fluids > 1) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) + & - (0.5_wp*(alpha_L(i)* & - vel_L(2))*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(alpha_L(i))*(1._wp/dy(k + 1))) + rhs_vf(momxb + 2)%sf(j, k + 1, l) = rhs_vf(momxb + 2)%sf(j, k + 1, l) - & + 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dy(k + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & + 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(3)*(1._wp/dy(k + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) & - - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k + 1, l)*vel_L(2)*(1._wp/dy(k + 1))) + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dy(k)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(3)*(1._wp/dy(k)) $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & - (0.5_wp*(alpha_L(i)* & - vel_L(2))*(1._wp/dy(k)) - & - 0.5_wp*cfl*(alpha_L(i))*(1._wp/dy(k))) + rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) - & + 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dy(k + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & + 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(2)*(1._wp/dy(k + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & - + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_L(2)*(1._wp/dy(k))) + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dy(k)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(2)*(1._wp/dy(k)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) - & + 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dy(k + 1)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & + 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(2)*(1._wp/dy(k + 1)) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dy(k)) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(2)*(1._wp/dy(k)) + end if + + E_L = 0._wp; E_R = 0._wp + F_L = 0._wp; F_R = 0._wp + + $:GPU_LOOP(parallelism='[seq]') + do q = vidxb + 1, vidxe + E_L = E_L + coeff_L(q)*q_cons_vf(E_idx)%sf(j, k + q, l) + F_L = F_L + coeff_L(q)*jac(j, k + q, l) end do - end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) + & - (0.5_wp*(rho_L*(vel_L(2))**2.0 + & - pres_L + F_L)*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dy(k + 1))) + $:GPU_LOOP(parallelism='[seq]') + do q = vidxb, vidxe - 1 + E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j, k + q, l) + F_R = F_R + coeff_R(q)*jac(j, k + q, l) + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) + & - (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dy(k + 1))) + call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & + E_R, gamma_R, pi_inf_R, rho_R, vel_R, & + pres_L, pres_R, cfl) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) + & - (0.5_wp*(vel_L(2)*(E_L + & - pres_L + F_L))*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(E_L)*(1._wp/dy(k + 1))) + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j, k + 1, l) = rhs_vf(i)%sf(j, k + 1, l) + & + (0.5_wp*(alpha_rho_L(i)* & + vel_L(2))*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dy(k + 1))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & - (0.5_wp*(rho_L*(vel_L(2))**2.0 + & - pres_L + F_L)*(1._wp/dy(k)) - & - 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dy(k))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & + (0.5_wp*(alpha_rho_L(i)* & + vel_L(2))*(1._wp/dy(k)) - & + 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dy(k))) + end do - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dy(k)) - & - 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dy(k))) + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) + & + (0.5_wp*(alpha_L(i)* & + vel_L(2))*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(alpha_L(i))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) & + - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k + 1, l)*vel_L(2)*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & + (0.5_wp*(alpha_L(i)* & + vel_L(2))*(1._wp/dy(k)) - & + 0.5_wp*cfl*(alpha_L(i))*(1._wp/dy(k))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - (0.5_wp*(vel_L(2)*(E_L + & - pres_L + F_L))*(1._wp/dy(k)) - & - 0.5_wp*cfl*(E_L)*(1._wp/dy(k))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & + + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_L(2)*(1._wp/dy(k))) + end do + end if - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k + 1, l) = rhs_vf(i)%sf(j, k + 1, l) + & - (0.5_wp*(alpha_rho_R(i)* & - vel_R(2))*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dy(k + 1))) + rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) + & + (0.5_wp*(rho_L*(vel_L(2))**2.0 + & + pres_L + F_L)*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dy(k + 1))) + $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & - (0.5_wp*(alpha_rho_R(i)* & - vel_R(2))*(1._wp/dy(k)) + & - 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dy(k))) - end do + rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) + & + (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j, k + 1, l) = rhs_vf(momxb + 2)%sf(j, k + 1, l) + & + (0.5_wp*rho_L*vel_L(3)*vel_L(2)*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) + & + (0.5_wp*(vel_L(2)*(E_L + & + pres_L + F_L))*(1._wp/dy(k + 1)) - & + 0.5_wp*cfl*(E_L)*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & + (0.5_wp*(rho_L*(vel_L(2))**2.0 + & + pres_L + F_L)*(1._wp/dy(k)) - & + 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & + (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dy(k)) - & + 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & + (0.5_wp*rho_L*vel_L(3)*vel_L(2)*(1._wp/dy(k)) - & + 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & + (0.5_wp*(vel_L(2)*(E_L + & + pres_L + F_L))*(1._wp/dy(k)) - & + 0.5_wp*cfl*(E_L)*(1._wp/dy(k))) - if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 + do i = 1, num_fluids $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) + & - (0.5_wp*(alpha_R(i)* & - vel_R(2))*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(alpha_R(i))*(1._wp/dy(k + 1))) + rhs_vf(i)%sf(j, k + 1, l) = rhs_vf(i)%sf(j, k + 1, l) + & + (0.5_wp*(alpha_rho_R(i)* & + vel_R(2))*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dy(k + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) & - - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k + 1, l)*vel_R(2)*(1._wp/dy(k + 1))) + rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & + (0.5_wp*(alpha_rho_R(i)* & + vel_R(2))*(1._wp/dy(k)) + & + 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dy(k))) + end do + + if (num_fluids > 1) then + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_fluids - 1 + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) + & + (0.5_wp*(alpha_R(i)* & + vel_R(2))*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(alpha_R(i))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) & + - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k + 1, l)*vel_R(2)*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & + (0.5_wp*(alpha_R(i)* & + vel_R(2))*(1._wp/dy(k)) + & + 0.5_wp*cfl*(alpha_R(i))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & + + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_R(2)*(1._wp/dy(k))) + end do + end if + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) + & + (0.5_wp*(rho_R*(vel_R(2))**2.0 + & + pres_R + F_R)*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) + & + (0.5_wp*rho_R*vel_R(2)*vel_R(1)*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dy(k + 1))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j, k + 1, l) = rhs_vf(momxb + 2)%sf(j, k + 1, l) + & + (0.5_wp*rho_R*vel_R(2)*vel_R(3)*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dy(k + 1))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & - (0.5_wp*(alpha_R(i)* & - vel_R(2))*(1._wp/dy(k)) + & - 0.5_wp*cfl*(alpha_R(i))*(1._wp/dy(k))) + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) + & + (0.5_wp*(vel_R(2)*(E_R + & + pres_R + F_R))*(1._wp/dy(k + 1)) + & + 0.5_wp*cfl*(E_R)*(1._wp/dy(k + 1))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & - + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_R(2)*(1._wp/dy(k))) - end do - end if - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) + & + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & (0.5_wp*(rho_R*(vel_R(2))**2.0 + & - pres_R + F_R)*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dy(k + 1))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) + & - (0.5_wp*rho_R*vel_R(2)*vel_R(1)*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dy(k + 1))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) + & + pres_R + F_R)*(1._wp/dy(k)) + & + 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & + (0.5_wp*rho_R*vel_R(2)*vel_R(1)*(1._wp/dy(k)) + & + 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & + (0.5_wp*rho_R*vel_R(2)*vel_R(3)*(1._wp/dy(k)) + & + 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dy(k))) + + $:GPU_ATOMIC(atomic='update') + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & (0.5_wp*(vel_R(2)*(E_R + & - pres_R + F_R))*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(E_R)*(1._wp/dy(k + 1))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & - (0.5_wp*(rho_R*(vel_R(2))**2.0 + & - pres_R + F_R)*(1._wp/dy(k)) + & - 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dy(k))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - (0.5_wp*rho_R*vel_R(2)*vel_R(1)*(1._wp/dy(k)) + & - 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dy(k))) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - (0.5_wp*(vel_R(2)*(E_R + & - pres_R + F_R))*(1._wp/dy(k)) + & - 0.5_wp*cfl*(E_R)*(1._wp/dy(k))) + pres_R + F_R))*(1._wp/dy(k)) + & + 0.5_wp*cfl*(E_R)*(1._wp/dy(k))) + + end do end do end do - end do - else - $:GPU_PARALLEL_LOOP(collapse=3, private='[rho_L, rho_R, gamma_L, & - & gamma_R, pi_inf_L, pi_inf_R, mu_L, mu_R, vel_L, vel_R, & - & pres_L, pres_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, & - & F_L, F_R, E_L, E_R, cfl, dvel_small, rho_sf_small, & - & vflux_L_arr, vflux_R_arr]') - do l = 0, p - do k = -1, n + #:endcall GPU_PARALLEL_LOOP + end if + elseif (idir == 3) then + #:call GPU_PARALLEL_LOOP(collapse=3, private='[rho_L, rho_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, mu_L, mu_R, vel_L, vel_R, pres_L, pres_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, F_L, F_R, E_L, E_R, cfl, dvel_small, rho_sf_small, vflux_L_arr, vflux_R_arr]') + do l = -1, p + do k = 0, n do j = 0, m if (viscous) then @@ -1615,24 +2061,24 @@ contains rho_L = 0._wp $:GPU_LOOP(parallelism='[seq]') do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j + i, k + q, l) + rho_L = rho_L + q_cons_vf(r)%sf(j + i, k, l + q) end do rho_sf_small(i) = rho_L end do dvel_small(1) = (1/(2._wp*dx(j)))*( & - q_cons_vf(momxb)%sf(j + 1, k + q, l)/rho_sf_small(1) - & - q_cons_vf(momxb)%sf(j - 1, k + q, l)/rho_sf_small(-1)) - dvel_small(2) = (1/(2._wp*dx(j)))*( & - q_cons_vf(momxb + 1)%sf(j + 1, k + q, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j - 1, k + q, l)/rho_sf_small(-1)) + q_cons_vf(momxb)%sf(j + 1, k, l + q)/rho_sf_small(1) - & + q_cons_vf(momxb)%sf(j - 1, k, l + q)/rho_sf_small(-1)) + dvel_small(3) = (1/(2._wp*dx(j)))*( & + q_cons_vf(momxb + 2)%sf(j + 1, k, l + q)/rho_sf_small(1) - & + q_cons_vf(momxb + 2)%sf(j - 1, k, l + q)/rho_sf_small(-1)) if (q > vidxb) then - vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(2)) + vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(3)) vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(1))/3._wp end if if (q < vidxe) then - vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(2)) + vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(3)) vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(1))/3._wp end if @@ -1642,30 +2088,25 @@ contains rho_L = 0._wp $:GPU_LOOP(parallelism='[seq]') do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j, k + i + q, l) + rho_L = rho_L + q_cons_vf(r)%sf(j, k + i, l + q) end do rho_sf_small(i) = rho_L end do - dvel_small(1) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb)%sf(j, k + 1 + q, l)/rho_sf_small(1) - & - q_cons_vf(momxb)%sf(j, k - 1 + q, l)/rho_sf_small(-1)) dvel_small(2) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb + 1)%sf(j, k + 1 + q, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j, k - 1 + q, l)/rho_sf_small(-1)) + q_cons_vf(momxb + 1)%sf(j, k + 1, l + q)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j, k - 1, l + q)/rho_sf_small(-1)) dvel_small(3) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb + 2)%sf(j, k + 1 + q, l)/rho_sf_small(1) - & - q_cons_vf(momxb + 2)%sf(j, k - 1 + q, l)/rho_sf_small(-1)) + q_cons_vf(momxb + 2)%sf(j, k + 1, l + q)/rho_sf_small(1) - & + q_cons_vf(momxb + 2)%sf(j, k - 1, l + q)/rho_sf_small(-1)) if (q > vidxb) then - vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(1)) vflux_L_arr(2) = vflux_L_arr(2) + coeff_L(q)*(dvel_small(3)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(4._wp*dvel_small(2))/3._wp + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(2))/3._wp end if if (q < vidxe) then - vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(1)) vflux_R_arr(2) = vflux_R_arr(2) + coeff_R(q)*(dvel_small(3)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(4._wp*dvel_small(2))/3._wp + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(2))/3._wp end if !z-direction contributions @@ -1674,24 +2115,28 @@ contains rho_L = 0._wp $:GPU_LOOP(parallelism='[seq]') do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j, k + q, l + i) + rho_L = rho_L + q_cons_vf(r)%sf(j, k, l + i + q) end do rho_sf_small(i) = rho_L end do - + dvel_small(1) = (1/(2._wp*dz(l)))*( & + q_cons_vf(momxb)%sf(j, k, l + 1 + q)/rho_sf_small(1) - & + q_cons_vf(momxb)%sf(j, k, l - 1 + q)/rho_sf_small(-1)) dvel_small(2) = (1/(2._wp*dz(l)))*( & - q_cons_vf(momxb + 1)%sf(j, k + q, l + 1)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j, k + q, l - 1)/rho_sf_small(-1)) + q_cons_vf(momxb + 1)%sf(j, k, l + 1 + q)/rho_sf_small(1) - & + q_cons_vf(momxb + 1)%sf(j, k, l - 1 + q)/rho_sf_small(-1)) dvel_small(3) = (1/(2._wp*dz(l)))*( & - q_cons_vf(momxb + 2)%sf(j, k + q, l + 1)/rho_sf_small(1) - & - q_cons_vf(momxb + 2)%sf(j, k + q, l - 1)/rho_sf_small(-1)) + q_cons_vf(momxb + 2)%sf(j, k, l + 1 + q)/rho_sf_small(1) - & + q_cons_vf(momxb + 2)%sf(j, k, l - 1 + q)/rho_sf_small(-1)) if (q > vidxb) then + vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(1)) vflux_L_arr(2) = vflux_L_arr(2) + coeff_L(q)*(dvel_small(2)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(3))/3._wp + vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(4._wp*dvel_small(3))/3._wp end if if (q < vidxe) then + vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(1)) vflux_R_arr(2) = vflux_R_arr(2) + coeff_R(q)*(dvel_small(2)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(3))/3._wp + vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(4._wp*dvel_small(3))/3._wp end if end do end if @@ -1704,13 +2149,13 @@ contains do q = vidxb + 1, vidxe $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j, k + q, l) + alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j, k, l + q) end do if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 - alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j, k + q, l) + alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j, k, l + q) end do else alpha_L(1) = 1._wp @@ -1718,7 +2163,7 @@ contains $:GPU_LOOP(parallelism='[seq]') do i = 1, num_dims - vel_L(i) = vel_L(i) + coeff_L(q)*q_cons_vf(momxb + i - 1)%sf(j, k + q, l) + vel_L(i) = vel_L(i) + coeff_L(q)*q_cons_vf(momxb + i - 1)%sf(j, k, l + q) end do end do @@ -1726,13 +2171,13 @@ contains do q = vidxb, vidxe - 1 $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j, k + q, l) + alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j, k, l + q) end do if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 - alpha_R(i) = alpha_R(i) + coeff_R(q)*q_cons_vf(E_idx + i)%sf(j, k + q, l) + alpha_R(i) = alpha_R(i) + coeff_R(q)*q_cons_vf(E_idx + i)%sf(j, k, l + q) end do else alpha_R(1) = 1._wp @@ -1740,7 +2185,7 @@ contains $:GPU_LOOP(parallelism='[seq]') do i = 1, num_dims - vel_R(i) = vel_R(i) + coeff_R(q)*q_cons_vf(momxb + i - 1)%sf(j, k + q, l) + vel_R(i) = vel_R(i) + coeff_R(q)*q_cons_vf(momxb + i - 1)%sf(j, k, l + q) end do end do @@ -1770,88 +2215,88 @@ contains end do $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) - & - 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dy(k + 1)) + rhs_vf(momxb)%sf(j, k, l + 1) = rhs_vf(momxb)%sf(j, k, l + 1) - & + 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & - 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dy(k + 1)) + rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & + 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dy(k)) + 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dy(k)) + 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) - & - 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dy(k + 1)) + rhs_vf(momxb)%sf(j, k, l + 1) = rhs_vf(momxb)%sf(j, k, l + 1) - & + 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & - 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dy(k + 1)) + rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & + 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dy(k)) + 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dy(k)) + 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k + 1, l) = rhs_vf(momxb + 2)%sf(j, k + 1, l) - & - 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dy(k + 1)) + rhs_vf(momxb + 1)%sf(j, k, l + 1) = rhs_vf(momxb + 1)%sf(j, k, l + 1) - & + 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & - 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(3)*(1._wp/dy(k + 1)) + rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & + 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(2)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dy(k)) + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(3)*(1._wp/dy(k)) + 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(2)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k + 1, l) = rhs_vf(momxb + 2)%sf(j, k + 1, l) - & - 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dy(k + 1)) + rhs_vf(momxb + 1)%sf(j, k, l + 1) = rhs_vf(momxb + 1)%sf(j, k, l + 1) - & + 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & - 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(3)*(1._wp/dy(k + 1)) + rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & + 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(2)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dy(k)) + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(3)*(1._wp/dy(k)) + 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(2)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) - & - 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dy(k + 1)) + rhs_vf(momxb + 2)%sf(j, k, l + 1) = rhs_vf(momxb + 2)%sf(j, k, l + 1) - & + 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & - 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(2)*(1._wp/dy(k + 1)) + rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & + 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(3)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dy(k)) + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & + 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(2)*(1._wp/dy(k)) + 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(3)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) - & - 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dy(k + 1)) + rhs_vf(momxb + 2)%sf(j, k, l + 1) = rhs_vf(momxb + 2)%sf(j, k, l + 1) - & + 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) - & - 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(2)*(1._wp/dy(k + 1)) + rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & + 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(3)*(1._wp/dz(l + 1)) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dy(k)) + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & + 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dz(l)) $:GPU_ATOMIC(atomic='update') rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(2)*(1._wp/dy(k)) + 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(3)*(1._wp/dz(l)) end if E_L = 0._wp; E_R = 0._wp @@ -1859,14 +2304,14 @@ contains $:GPU_LOOP(parallelism='[seq]') do q = vidxb + 1, vidxe - E_L = E_L + coeff_L(q)*q_cons_vf(E_idx)%sf(j, k + q, l) - F_L = F_L + coeff_L(q)*jac(j, k + q, l) + E_L = E_L + coeff_L(q)*q_cons_vf(E_idx)%sf(j, k, l + q) + F_L = F_L + coeff_L(q)*jac(j, k, l + q) end do $:GPU_LOOP(parallelism='[seq]') do q = vidxb, vidxe - 1 - E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j, k + q, l) - F_R = F_R + coeff_R(q)*jac(j, k + q, l) + E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j, k, l + q) + F_R = F_R + coeff_R(q)*jac(j, k, l + q) end do call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & @@ -1876,633 +2321,175 @@ contains $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k + 1, l) = rhs_vf(i)%sf(j, k + 1, l) + & + rhs_vf(i)%sf(j, k, l + 1) = rhs_vf(i)%sf(j, k, l + 1) + & (0.5_wp*(alpha_rho_L(i)* & - vel_L(2))*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dy(k + 1))) + vel_L(3))*(1._wp/dz(l + 1)) - & + 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & (0.5_wp*(alpha_rho_L(i)* & - vel_L(2))*(1._wp/dy(k)) - & - 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dy(k))) + vel_L(3))*(1._wp/dz(l)) - & + 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dz(l))) end do if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) + & + rhs_vf(advxb + i - 1)%sf(j, k, l + 1) = rhs_vf(advxb + i - 1)%sf(j, k, l + 1) + & (0.5_wp*(alpha_L(i)* & - vel_L(2))*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(alpha_L(i))*(1._wp/dy(k + 1))) + vel_L(3))*(1._wp/dz(l + 1)) - & + 0.5_wp*cfl*(alpha_L(i))*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) & - - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k + 1, l)*vel_L(2)*(1._wp/dy(k + 1))) + rhs_vf(advxb + i - 1)%sf(j, k, l + 1) = rhs_vf(advxb + i - 1)%sf(j, k, l + 1) & + - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l + 1)*vel_L(3)*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & (0.5_wp*(alpha_L(i)* & - vel_L(2))*(1._wp/dy(k)) - & - 0.5_wp*cfl*(alpha_L(i))*(1._wp/dy(k))) + vel_L(3))*(1._wp/dz(l)) - & + 0.5_wp*cfl*(alpha_L(i))*(1._wp/dz(l))) $:GPU_ATOMIC(atomic='update') rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & - + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_L(2)*(1._wp/dy(k))) + + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_L(3)*(1._wp/dz(l))) end do end if $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) + & - (0.5_wp*(rho_L*(vel_L(2))**2.0 + & - pres_L + F_L)*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dy(k + 1))) + rhs_vf(momxb + 2)%sf(j, k, l + 1) = rhs_vf(momxb + 2)%sf(j, k, l + 1) + & + (0.5_wp*(rho_L*(vel_L(3))**2.0 + & + pres_L + F_L)*(1._wp/dz(l + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) + & - (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dy(k + 1))) + rhs_vf(momxb)%sf(j, k, l + 1) = rhs_vf(momxb)%sf(j, k, l + 1) + & + (0.5_wp*rho_L*vel_L(1)*vel_L(3)*(1._wp/dz(l + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k + 1, l) = rhs_vf(momxb + 2)%sf(j, k + 1, l) + & - (0.5_wp*rho_L*vel_L(3)*vel_L(2)*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dy(k + 1))) + rhs_vf(momxb + 1)%sf(j, k, l + 1) = rhs_vf(momxb + 1)%sf(j, k, l + 1) + & + (0.5_wp*rho_L*vel_L(2)*vel_L(3)*(1._wp/dz(l + 1)) - & + 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) + & - (0.5_wp*(vel_L(2)*(E_L + & - pres_L + F_L))*(1._wp/dy(k + 1)) - & - 0.5_wp*cfl*(E_L)*(1._wp/dy(k + 1))) + rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) + & + (0.5_wp*(vel_L(3)*(E_L + & + pres_L + F_L))*(1._wp/dz(l + 1)) - & + 0.5_wp*cfl*(E_L)*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & - (0.5_wp*(rho_L*(vel_L(2))**2.0 + & - pres_L + F_L)*(1._wp/dy(k)) - & - 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dy(k))) + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & + (0.5_wp*(rho_L*(vel_L(3))**2.0 + & + pres_L + F_L)*(1._wp/dz(l)) - & + 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dz(l))) $:GPU_ATOMIC(atomic='update') rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - (0.5_wp*rho_L*vel_L(1)*vel_L(2)*(1._wp/dy(k)) - & - 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dy(k))) + (0.5_wp*rho_L*vel_L(1)*vel_L(3)*(1._wp/dz(l)) - & + 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dz(l))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & - (0.5_wp*rho_L*vel_L(3)*vel_L(2)*(1._wp/dy(k)) - & - 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dy(k))) + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & + (0.5_wp*rho_L*vel_L(2)*vel_L(3)*(1._wp/dz(l)) - & + 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dz(l))) $:GPU_ATOMIC(atomic='update') rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - (0.5_wp*(vel_L(2)*(E_L + & - pres_L + F_L))*(1._wp/dy(k)) - & - 0.5_wp*cfl*(E_L)*(1._wp/dy(k))) + (0.5_wp*(vel_L(3)*(E_L + & + pres_L + F_L))*(1._wp/dz(l)) - & + 0.5_wp*cfl*(E_L)*(1._wp/dz(l))) $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k + 1, l) = rhs_vf(i)%sf(j, k + 1, l) + & + rhs_vf(i)%sf(j, k, l + 1) = rhs_vf(i)%sf(j, k, l + 1) + & (0.5_wp*(alpha_rho_R(i)* & - vel_R(2))*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dy(k + 1))) + vel_R(3))*(1._wp/dz(l + 1)) + & + 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & (0.5_wp*(alpha_rho_R(i)* & - vel_R(2))*(1._wp/dy(k)) + & - 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dy(k))) + vel_R(3))*(1._wp/dz(l)) + & + 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dz(l))) end do if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) + & + rhs_vf(advxb + i - 1)%sf(j, k, l + 1) = rhs_vf(advxb + i - 1)%sf(j, k, l + 1) + & (0.5_wp*(alpha_R(i)* & - vel_R(2))*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(alpha_R(i))*(1._wp/dy(k + 1))) + vel_R(3))*(1._wp/dz(l + 1)) + & + 0.5_wp*cfl*(alpha_R(i))*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k + 1, l) = rhs_vf(advxb + i - 1)%sf(j, k + 1, l) & - - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k + 1, l)*vel_R(2)*(1._wp/dy(k + 1))) + rhs_vf(advxb + i - 1)%sf(j, k, l + 1) = rhs_vf(advxb + i - 1)%sf(j, k, l + 1) & + - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l + 1)*vel_R(3)*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & (0.5_wp*(alpha_R(i)* & - vel_R(2))*(1._wp/dy(k)) + & - 0.5_wp*cfl*(alpha_R(i))*(1._wp/dy(k))) + vel_R(3))*(1._wp/dz(l)) + & + 0.5_wp*cfl*(alpha_R(i))*(1._wp/dz(l))) $:GPU_ATOMIC(atomic='update') rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & - + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_R(2)*(1._wp/dy(k))) + + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_R(3)*(1._wp/dz(l))) end do end if $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k + 1, l) = rhs_vf(momxb + 1)%sf(j, k + 1, l) + & - (0.5_wp*(rho_R*(vel_R(2))**2.0 + & - pres_R + F_R)*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dy(k + 1))) + rhs_vf(momxb + 2)%sf(j, k, l + 1) = rhs_vf(momxb + 2)%sf(j, k, l + 1) + & + (0.5_wp*(rho_R*(vel_R(3))**2.0 + & + pres_R + F_R)*(1._wp/dz(l + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k + 1, l) = rhs_vf(momxb)%sf(j, k + 1, l) + & - (0.5_wp*rho_R*vel_R(2)*vel_R(1)*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dy(k + 1))) + rhs_vf(momxb)%sf(j, k, l + 1) = rhs_vf(momxb)%sf(j, k, l + 1) + & + (0.5_wp*rho_R*vel_R(1)*vel_R(3)*(1._wp/dz(l + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k + 1, l) = rhs_vf(momxb + 2)%sf(j, k + 1, l) + & - (0.5_wp*rho_R*vel_R(2)*vel_R(3)*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dy(k + 1))) + rhs_vf(momxb + 1)%sf(j, k, l + 1) = rhs_vf(momxb + 1)%sf(j, k, l + 1) + & + (0.5_wp*rho_R*vel_R(2)*vel_R(3)*(1._wp/dz(l + 1)) + & + 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k + 1, l) = rhs_vf(E_idx)%sf(j, k + 1, l) + & - (0.5_wp*(vel_R(2)*(E_R + & - pres_R + F_R))*(1._wp/dy(k + 1)) + & - 0.5_wp*cfl*(E_R)*(1._wp/dy(k + 1))) + rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) + & + (0.5_wp*(vel_R(3)*(E_R + & + pres_R + F_R))*(1._wp/dz(l + 1)) + & + 0.5_wp*cfl*(E_R)*(1._wp/dz(l + 1))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & - (0.5_wp*(rho_R*(vel_R(2))**2.0 + & - pres_R + F_R)*(1._wp/dy(k)) + & - 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dy(k))) + rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & + (0.5_wp*(rho_R*(vel_R(3))**2.0 + & + pres_R + F_R)*(1._wp/dz(l)) + & + 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dz(l))) $:GPU_ATOMIC(atomic='update') rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - (0.5_wp*rho_R*vel_R(2)*vel_R(1)*(1._wp/dy(k)) + & - 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dy(k))) + (0.5_wp*rho_R*vel_R(1)*vel_R(3)*(1._wp/dz(l)) + & + 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dz(l))) $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & - (0.5_wp*rho_R*vel_R(2)*vel_R(3)*(1._wp/dy(k)) + & - 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dy(k))) + rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & + (0.5_wp*rho_R*vel_R(2)*vel_R(3)*(1._wp/dz(l)) + & + 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dz(l))) $:GPU_ATOMIC(atomic='update') rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - (0.5_wp*(vel_R(2)*(E_R + & - pres_R + F_R))*(1._wp/dy(k)) + & - 0.5_wp*cfl*(E_R)*(1._wp/dy(k))) - - end do - end do - end do - end if - elseif (idir == 3) then - $:GPU_PARALLEL_LOOP(collapse=3, private='[rho_L, rho_R, gamma_L, & - & gamma_R, pi_inf_L, pi_inf_R, mu_L, mu_R, vel_L, vel_R, & - & pres_L, pres_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, & - & F_L, F_R, E_L, E_R, cfl, dvel_small, rho_sf_small, & - & vflux_L_arr, vflux_R_arr]') - do l = -1, p - do k = 0, n - do j = 0, m - - if (viscous) then - vflux_L_arr = 0._wp - vflux_R_arr = 0._wp - - #:if MFC_CASE_OPTIMIZATION - #:if igr_order == 5 - !DIR$ unroll 6 - #:elif igr_order == 3 - !DIR$ unroll 4 - #:endif - #:endif - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - dvel_small = 0._wp - !x-direction contributions - $:GPU_LOOP(parallelism='[seq]') - do i = -1, 1 - rho_L = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j + i, k, l + q) - end do - rho_sf_small(i) = rho_L - end do - - dvel_small(1) = (1/(2._wp*dx(j)))*( & - q_cons_vf(momxb)%sf(j + 1, k, l + q)/rho_sf_small(1) - & - q_cons_vf(momxb)%sf(j - 1, k, l + q)/rho_sf_small(-1)) - dvel_small(3) = (1/(2._wp*dx(j)))*( & - q_cons_vf(momxb + 2)%sf(j + 1, k, l + q)/rho_sf_small(1) - & - q_cons_vf(momxb + 2)%sf(j - 1, k, l + q)/rho_sf_small(-1)) - - if (q > vidxb) then - vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(3)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(1))/3._wp - end if - if (q < vidxe) then - vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(3)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(1))/3._wp - end if - - !y-direction contributions - $:GPU_LOOP(parallelism='[seq]') - do i = -1, 1 - rho_L = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j, k + i, l + q) - end do - rho_sf_small(i) = rho_L - end do - - dvel_small(2) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb + 1)%sf(j, k + 1, l + q)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j, k - 1, l + q)/rho_sf_small(-1)) - dvel_small(3) = (1/(2._wp*dy(k)))*( & - q_cons_vf(momxb + 2)%sf(j, k + 1, l + q)/rho_sf_small(1) - & - q_cons_vf(momxb + 2)%sf(j, k - 1, l + q)/rho_sf_small(-1)) - - if (q > vidxb) then - vflux_L_arr(2) = vflux_L_arr(2) + coeff_L(q)*(dvel_small(3)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(-2._wp*dvel_small(2))/3._wp - end if - if (q < vidxe) then - vflux_R_arr(2) = vflux_R_arr(2) + coeff_R(q)*(dvel_small(3)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(-2._wp*dvel_small(2))/3._wp - end if - - !z-direction contributions - $:GPU_LOOP(parallelism='[seq]') - do i = -1, 1 - rho_L = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do r = 1, num_fluids - rho_L = rho_L + q_cons_vf(r)%sf(j, k, l + i + q) - end do - rho_sf_small(i) = rho_L - end do - dvel_small(1) = (1/(2._wp*dz(l)))*( & - q_cons_vf(momxb)%sf(j, k, l + 1 + q)/rho_sf_small(1) - & - q_cons_vf(momxb)%sf(j, k, l - 1 + q)/rho_sf_small(-1)) - dvel_small(2) = (1/(2._wp*dz(l)))*( & - q_cons_vf(momxb + 1)%sf(j, k, l + 1 + q)/rho_sf_small(1) - & - q_cons_vf(momxb + 1)%sf(j, k, l - 1 + q)/rho_sf_small(-1)) - dvel_small(3) = (1/(2._wp*dz(l)))*( & - q_cons_vf(momxb + 2)%sf(j, k, l + 1 + q)/rho_sf_small(1) - & - q_cons_vf(momxb + 2)%sf(j, k, l - 1 + q)/rho_sf_small(-1)) - if (q > vidxb) then - vflux_L_arr(1) = vflux_L_arr(1) + coeff_L(q)*(dvel_small(1)) - vflux_L_arr(2) = vflux_L_arr(2) + coeff_L(q)*(dvel_small(2)) - vflux_L_arr(3) = vflux_L_arr(3) + coeff_L(q)*(4._wp*dvel_small(3))/3._wp - end if - if (q < vidxe) then - vflux_R_arr(1) = vflux_R_arr(1) + coeff_R(q)*(dvel_small(1)) - vflux_R_arr(2) = vflux_R_arr(2) + coeff_R(q)*(dvel_small(2)) - vflux_R_arr(3) = vflux_R_arr(3) + coeff_R(q)*(4._wp*dvel_small(3))/3._wp - end if - end do - end if - - alpha_rho_L = 0._wp; alpha_rho_R = 0._wp - alpha_L = 0._wp; alpha_R = 0._wp - vel_L = 0._wp; vel_R = 0._wp - - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb + 1, vidxe - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_L(i) = alpha_rho_L(i) + coeff_L(q)*q_cons_vf(i)%sf(j, k, l + q) - end do - - if (num_fluids > 1) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j, k, l + q) - end do - else - alpha_L(1) = 1._wp - end if - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_L(i) = vel_L(i) + coeff_L(q)*q_cons_vf(momxb + i - 1)%sf(j, k, l + q) - end do - end do - - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - 1 - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - alpha_rho_R(i) = alpha_rho_R(i) + coeff_R(q)*q_cons_vf(i)%sf(j, k, l + q) - end do - - if (num_fluids > 1) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - alpha_R(i) = alpha_R(i) + coeff_R(q)*q_cons_vf(E_idx + i)%sf(j, k, l + q) - end do - else - alpha_R(1) = 1._wp - end if - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims - vel_R(i) = vel_R(i) + coeff_R(q)*q_cons_vf(momxb + i - 1)%sf(j, k, l + q) - end do - end do - - if (num_fluids > 1) then - alpha_L(num_fluids) = 1._wp - sum(alpha_L(1:num_fluids - 1)) - alpha_R(num_fluids) = 1._wp - sum(alpha_R(1:num_fluids - 1)) - end if - - rho_L = sum(alpha_rho_L) - gamma_L = sum(alpha_L*gammas) - pi_inf_L = sum(alpha_L*pi_infs) - - rho_R = sum(alpha_rho_R) - gamma_R = sum(alpha_R*gammas) - pi_inf_R = sum(alpha_R*pi_infs) - - vel_L = vel_L/rho_L - vel_R = vel_R/rho_R - - if (viscous) then - mu_L = 0._wp - mu_R = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - mu_L = alpha_L(i)/Res(1, i) + mu_L - mu_R = alpha_R(i)/Res(1, i) + mu_R - end do - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l + 1) = rhs_vf(momxb)%sf(j, k, l + 1) - & - 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dz(l + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & - 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dz(l + 1)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(1)*(1._wp/dz(l)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(1)*vel_L(1)*(1._wp/dz(l)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l + 1) = rhs_vf(momxb)%sf(j, k, l + 1) - & - 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dz(l + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & - 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dz(l + 1)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(1)*(1._wp/dz(l)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(1)*vel_R(1)*(1._wp/dz(l)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l + 1) = rhs_vf(momxb + 1)%sf(j, k, l + 1) - & - 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dz(l + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & - 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(2)*(1._wp/dz(l + 1)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(2)*(1._wp/dz(l)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(2)*vel_L(2)*(1._wp/dz(l)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l + 1) = rhs_vf(momxb + 1)%sf(j, k, l + 1) - & - 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dz(l + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & - 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(2)*(1._wp/dz(l + 1)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(2)*(1._wp/dz(l)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(2)*vel_R(2)*(1._wp/dz(l)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l + 1) = rhs_vf(momxb + 2)%sf(j, k, l + 1) - & - 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dz(l + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & - 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(3)*(1._wp/dz(l + 1)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(3)*(1._wp/dz(l)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_L*vflux_L_arr(3)*vel_L(3)*(1._wp/dz(l)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l + 1) = rhs_vf(momxb + 2)%sf(j, k, l + 1) - & - 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dz(l + 1)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) - & - 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(3)*(1._wp/dz(l + 1)) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(3)*(1._wp/dz(l)) - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + & - 0.5_wp*mu_R*vflux_R_arr(3)*vel_R(3)*(1._wp/dz(l)) - end if - - E_L = 0._wp; E_R = 0._wp - F_L = 0._wp; F_R = 0._wp - - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb + 1, vidxe - E_L = E_L + coeff_L(q)*q_cons_vf(E_idx)%sf(j, k, l + q) - F_L = F_L + coeff_L(q)*jac(j, k, l + q) - end do - - $:GPU_LOOP(parallelism='[seq]') - do q = vidxb, vidxe - 1 - E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j, k, l + q) - F_R = F_R + coeff_R(q)*jac(j, k, l + q) - end do - - call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & - E_R, gamma_R, pi_inf_R, rho_R, vel_R, & - pres_L, pres_R, cfl) - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k, l + 1) = rhs_vf(i)%sf(j, k, l + 1) + & - (0.5_wp*(alpha_rho_L(i)* & - vel_L(3))*(1._wp/dz(l + 1)) - & - 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & - (0.5_wp*(alpha_rho_L(i)* & - vel_L(3))*(1._wp/dz(l)) - & - 0.5_wp*cfl*(alpha_rho_L(i))*(1._wp/dz(l))) - end do - - if (num_fluids > 1) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l + 1) = rhs_vf(advxb + i - 1)%sf(j, k, l + 1) + & - (0.5_wp*(alpha_L(i)* & - vel_L(3))*(1._wp/dz(l + 1)) - & - 0.5_wp*cfl*(alpha_L(i))*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l + 1) = rhs_vf(advxb + i - 1)%sf(j, k, l + 1) & - - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l + 1)*vel_L(3)*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & - (0.5_wp*(alpha_L(i)* & - vel_L(3))*(1._wp/dz(l)) - & - 0.5_wp*cfl*(alpha_L(i))*(1._wp/dz(l))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & - + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_L(3)*(1._wp/dz(l))) - end do - end if - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l + 1) = rhs_vf(momxb + 2)%sf(j, k, l + 1) + & - (0.5_wp*(rho_L*(vel_L(3))**2.0 + & - pres_L + F_L)*(1._wp/dz(l + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l + 1) = rhs_vf(momxb)%sf(j, k, l + 1) + & - (0.5_wp*rho_L*vel_L(1)*vel_L(3)*(1._wp/dz(l + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l + 1) = rhs_vf(momxb + 1)%sf(j, k, l + 1) + & - (0.5_wp*rho_L*vel_L(2)*vel_L(3)*(1._wp/dz(l + 1)) - & - 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) + & - (0.5_wp*(vel_L(3)*(E_L + & - pres_L + F_L))*(1._wp/dz(l + 1)) - & - 0.5_wp*cfl*(E_L)*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & - (0.5_wp*(rho_L*(vel_L(3))**2.0 + & - pres_L + F_L)*(1._wp/dz(l)) - & - 0.5_wp*cfl*(rho_L*vel_L(3))*(1._wp/dz(l))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - (0.5_wp*rho_L*vel_L(1)*vel_L(3)*(1._wp/dz(l)) - & - 0.5_wp*cfl*(rho_L*vel_L(1))*(1._wp/dz(l))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & - (0.5_wp*rho_L*vel_L(2)*vel_L(3)*(1._wp/dz(l)) - & - 0.5_wp*cfl*(rho_L*vel_L(2))*(1._wp/dz(l))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - (0.5_wp*(vel_L(3)*(E_L + & - pres_L + F_L))*(1._wp/dz(l)) - & - 0.5_wp*cfl*(E_L)*(1._wp/dz(l))) - - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k, l + 1) = rhs_vf(i)%sf(j, k, l + 1) + & - (0.5_wp*(alpha_rho_R(i)* & - vel_R(3))*(1._wp/dz(l + 1)) + & - 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(i)%sf(j, k, l) = rhs_vf(i)%sf(j, k, l) - & - (0.5_wp*(alpha_rho_R(i)* & - vel_R(3))*(1._wp/dz(l)) + & - 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dz(l))) - end do - - if (num_fluids > 1) then - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_fluids - 1 - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l + 1) = rhs_vf(advxb + i - 1)%sf(j, k, l + 1) + & - (0.5_wp*(alpha_R(i)* & - vel_R(3))*(1._wp/dz(l + 1)) + & - 0.5_wp*cfl*(alpha_R(i))*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l + 1) = rhs_vf(advxb + i - 1)%sf(j, k, l + 1) & - - (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l + 1)*vel_R(3)*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) - & - (0.5_wp*(alpha_R(i)* & - vel_R(3))*(1._wp/dz(l)) + & - 0.5_wp*cfl*(alpha_R(i))*(1._wp/dz(l))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(advxb + i - 1)%sf(j, k, l) = rhs_vf(advxb + i - 1)%sf(j, k, l) & - + (0.5_wp*q_cons_vf(advxb + i - 1)%sf(j, k, l)*vel_R(3)*(1._wp/dz(l))) - end do - end if - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l + 1) = rhs_vf(momxb + 2)%sf(j, k, l + 1) + & - (0.5_wp*(rho_R*(vel_R(3))**2.0 + & - pres_R + F_R)*(1._wp/dz(l + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l + 1) = rhs_vf(momxb)%sf(j, k, l + 1) + & - (0.5_wp*rho_R*vel_R(1)*vel_R(3)*(1._wp/dz(l + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l + 1) = rhs_vf(momxb + 1)%sf(j, k, l + 1) + & - (0.5_wp*rho_R*vel_R(2)*vel_R(3)*(1._wp/dz(l + 1)) + & - 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l + 1) = rhs_vf(E_idx)%sf(j, k, l + 1) + & (0.5_wp*(vel_R(3)*(E_R + & - pres_R + F_R))*(1._wp/dz(l + 1)) + & - 0.5_wp*cfl*(E_R)*(1._wp/dz(l + 1))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 2)%sf(j, k, l) = rhs_vf(momxb + 2)%sf(j, k, l) - & - (0.5_wp*(rho_R*(vel_R(3))**2.0 + & - pres_R + F_R)*(1._wp/dz(l)) + & - 0.5_wp*cfl*(rho_R*vel_R(3))*(1._wp/dz(l))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb)%sf(j, k, l) = rhs_vf(momxb)%sf(j, k, l) - & - (0.5_wp*rho_R*vel_R(1)*vel_R(3)*(1._wp/dz(l)) + & - 0.5_wp*cfl*(rho_R*vel_R(1))*(1._wp/dz(l))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(momxb + 1)%sf(j, k, l) = rhs_vf(momxb + 1)%sf(j, k, l) - & - (0.5_wp*rho_R*vel_R(2)*vel_R(3)*(1._wp/dz(l)) + & - 0.5_wp*cfl*(rho_R*vel_R(2))*(1._wp/dz(l))) - - $:GPU_ATOMIC(atomic='update') - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) - & - (0.5_wp*(vel_R(3)*(E_R + & - pres_R + F_R))*(1._wp/dz(l)) + & - 0.5_wp*cfl*(E_R)*(1._wp/dz(l))) + pres_R + F_R))*(1._wp/dz(l)) + & + 0.5_wp*cfl*(E_R)*(1._wp/dz(l))) + end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_igr_riemann_solver @@ -2562,46 +2549,49 @@ contains integer, intent(in) :: idir if (idir == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(i)%sf(j, k, l) = 1._wp/dx(j)* & - (flux_vf(i)%sf(j - 1, k, l) & - - flux_vf(i)%sf(j, k, l)) + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(i)%sf(j, k, l) = 1._wp/dx(j)* & + (flux_vf(i)%sf(j - 1, k, l) & + - flux_vf(i)%sf(j, k, l)) + end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP elseif (idir == 2) then - $:GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(i)%sf(j, k, l) = & - rhs_vf(i)%sf(j, k, l) + 1._wp/dy(k)* & - (flux_vf(i)%sf(j, k - 1, l) & - - flux_vf(i)%sf(j, k, l)) + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(i)%sf(j, k, l) = & + rhs_vf(i)%sf(j, k, l) + 1._wp/dy(k)* & + (flux_vf(i)%sf(j, k - 1, l) & + - flux_vf(i)%sf(j, k, l)) + end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP elseif (idir == 3) then - $:GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(i)%sf(j, k, l) = & - rhs_vf(i)%sf(j, k, l) + 1._wp/dz(l)* & - (flux_vf(i)%sf(j, k, l - 1) & - - flux_vf(i)%sf(j, k, l)) + #:call GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(i)%sf(j, k, l) = & + rhs_vf(i)%sf(j, k, l) + 1._wp/dz(l)* & + (flux_vf(i)%sf(j, k, l - 1) & + - flux_vf(i)%sf(j, k, l)) + end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_igr_flux_add diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index cf3822dbf3..910420e10e 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -554,18 +554,19 @@ contains end do end if ! end allocation of viscous variables - $:GPU_PARALLEL_LOOP(collapse=4) - do id = 1, num_dims - do i = 1, sys_size - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - flux_gsrc_n(id)%vf(i)%sf(j, k, l) = 0._wp + #:call GPU_PARALLEL_LOOP(collapse=4) + do id = 1, num_dims + do i = 1, sys_size + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + flux_gsrc_n(id)%vf(i)%sf(j, k, l) = 0._wp + end do end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if ! end allocation for .not. igr @@ -637,37 +638,37 @@ contains if (.not. igr) then ! Association/Population of Working Variables #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - q_cons_qp%vf(i)%sf(j, k, l) = q_cons_vf(i)%sf(j, k, l) + do i = 1, sys_size + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + q_cons_qp%vf(i)%sf(j, k, l) = q_cons_vf(i)%sf(j, k, l) + end do end do end do end do - end do - #:endcall GPU_PARALLEL_LOOP + #:endcall GPU_PARALLEL_LOOP ! Converting Conservative to Primitive Variables if (mpp_lim .and. bubbles_euler) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - alf_sum%sf(j, k, l) = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - 1 - alf_sum%sf(j, k, l) = alf_sum%sf(j, k, l) + q_cons_qp%vf(i)%sf(j, k, l) - end do - $:GPU_LOOP(parallelism='[seq]') - do i = advxb, advxe - 1 - q_cons_qp%vf(i)%sf(j, k, l) = q_cons_qp%vf(i)%sf(j, k, l)*(1._wp - q_cons_qp%vf(alf_idx)%sf(j, k, l)) & - /alf_sum%sf(j, k, l) + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + alf_sum%sf(j, k, l) = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe - 1 + alf_sum%sf(j, k, l) = alf_sum%sf(j, k, l) + q_cons_qp%vf(i)%sf(j, k, l) + end do + $:GPU_LOOP(parallelism='[seq]') + do i = advxb, advxe - 1 + q_cons_qp%vf(i)%sf(j, k, l) = q_cons_qp%vf(i)%sf(j, k, l)*(1._wp - q_cons_qp%vf(alf_idx)%sf(j, k, l)) & + /alf_sum%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if @@ -728,16 +729,17 @@ contains if (igr) then if (id == 1) then - $:GPU_PARALLEL_LOOP(collapse=4) - do l = -1, p + 1 - do k = -1, n + 1 - do j = -1, m + 1 - do i = 1, sys_size - rhs_vf(i)%sf(j, k, l) = 0._wp + #:call GPU_PARALLEL_LOOP(collapse=4) + do l = -1, p + 1 + do k = -1, n + 1 + do j = -1, m + 1 + do i = 1, sys_size + rhs_vf(i)%sf(j, k, l) = 0._wp + end do end do end do end do - end do + #:endcall GPU_PARALLEL_LOOP end if call nvtxStartRange("IGR_RIEMANN") @@ -978,16 +980,16 @@ contains if (run_time_info .or. probe_wrt .or. ib .or. bubbles_lagrange) then if (.not. igr) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = idwbuff(3)%beg, idwbuff(3)%end - do k = idwbuff(2)%beg, idwbuff(2)%end - do j = idwbuff(1)%beg, idwbuff(1)%end - q_prim_vf(i)%sf(j, k, l) = q_prim_qp%vf(i)%sf(j, k, l) + do i = 1, sys_size + do l = idwbuff(3)%beg, idwbuff(3)%end + do k = idwbuff(2)%beg, idwbuff(2)%end + do j = idwbuff(1)%beg, idwbuff(1)%end + q_prim_vf(i)%sf(j, k, l) = q_prim_qp%vf(i)%sf(j, k, l) + end do end do end do end do - end do - #:endcall GPU_PARALLEL_LOOP + #:endcall GPU_PARALLEL_LOOP end if end if @@ -1483,51 +1485,51 @@ contains if (surface_tension) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(c_idx)%sf(j, k, l) = & - rhs_vf(c_idx)%sf(j, k, l) + 1._wp/dx(j)* & - q_prim_vf(c_idx)%sf(j, k, l)* & - (flux_src_n_in(advxb)%sf(j, k, l) - & - flux_src_n_in(advxb)%sf(j - 1, k, l)) + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(c_idx)%sf(j, k, l) = & + rhs_vf(c_idx)%sf(j, k, l) + 1._wp/dx(j)* & + q_prim_vf(c_idx)%sf(j, k, l)* & + (flux_src_n_in(advxb)%sf(j, k, l) - & + flux_src_n_in(advxb)%sf(j - 1, k, l)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - rhs_vf(i)%sf(j, k, l) = & - rhs_vf(i)%sf(j, k, l) + 1._wp/dx(j)* & - (flux_src_n_in(i)%sf(j - 1, k, l) & - - flux_src_n_in(i)%sf(j, k, l)) + do l = 0, p + do k = 0, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + rhs_vf(i)%sf(j, k, l) = & + rhs_vf(i)%sf(j, k, l) + 1._wp/dx(j)* & + (flux_src_n_in(i)%sf(j - 1, k, l) & + - flux_src_n_in(i)%sf(j, k, l)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (idir == 2) then ! y-direction if (surface_tension) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(c_idx)%sf(j, k, l) = & - rhs_vf(c_idx)%sf(j, k, l) + 1._wp/dy(k)* & - q_prim_vf(c_idx)%sf(j, k, l)* & - (flux_src_n_in(advxb)%sf(j, k, l) - & - flux_src_n_in(advxb)%sf(j, k - 1, l)) + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(c_idx)%sf(j, k, l) = & + rhs_vf(c_idx)%sf(j, k, l) + 1._wp/dy(k)* & + q_prim_vf(c_idx)%sf(j, k, l)* & + (flux_src_n_in(advxb)%sf(j, k, l) - & + flux_src_n_in(advxb)%sf(j, k - 1, l)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1566,36 +1568,36 @@ contains end if #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 1, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - rhs_vf(i)%sf(j, k, l) = & - rhs_vf(i)%sf(j, k, l) + 1._wp/dy(k)* & - (flux_src_n_in(i)%sf(j, k - 1, l) & - - flux_src_n_in(i)%sf(j, k, l)) + do l = 0, p + do k = 1, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + rhs_vf(i)%sf(j, k, l) = & + rhs_vf(i)%sf(j, k, l) + 1._wp/dy(k)* & + (flux_src_n_in(i)%sf(j, k - 1, l) & + - flux_src_n_in(i)%sf(j, k, l)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - rhs_vf(i)%sf(j, k, l) = & - rhs_vf(i)%sf(j, k, l) + 1._wp/dy(k)* & - (flux_src_n_in(i)%sf(j, k - 1, l) & - - flux_src_n_in(i)%sf(j, k, l)) + do l = 0, p + do k = 0, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + rhs_vf(i)%sf(j, k, l) = & + rhs_vf(i)%sf(j, k, l) + 1._wp/dy(k)* & + (flux_src_n_in(i)%sf(j, k - 1, l) & + - flux_src_n_in(i)%sf(j, k, l)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if @@ -1605,19 +1607,19 @@ contains if ((bc_y%beg == -2) .or. (bc_y%beg == -14)) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 1, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - rhs_vf(i)%sf(j, k, l) = & - rhs_vf(i)%sf(j, k, l) - 5.e-1_wp/y_cc(k)* & - (flux_src_n_in(i)%sf(j, k - 1, l) & - + flux_src_n_in(i)%sf(j, k, l)) + do l = 0, p + do k = 1, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + rhs_vf(i)%sf(j, k, l) = & + rhs_vf(i)%sf(j, k, l) - 5.e-1_wp/y_cc(k)* & + (flux_src_n_in(i)%sf(j, k - 1, l) & + + flux_src_n_in(i)%sf(j, k, l)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (viscous) then @@ -1637,19 +1639,19 @@ contains else #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - rhs_vf(i)%sf(j, k, l) = & - rhs_vf(i)%sf(j, k, l) - 5.e-1_wp/y_cc(k)* & - (flux_src_n_in(i)%sf(j, k - 1, l) & - + flux_src_n_in(i)%sf(j, k, l)) + do l = 0, p + do k = 0, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + rhs_vf(i)%sf(j, k, l) = & + rhs_vf(i)%sf(j, k, l) - 5.e-1_wp/y_cc(k)* & + (flux_src_n_in(i)%sf(j, k - 1, l) & + + flux_src_n_in(i)%sf(j, k, l)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if @@ -1658,53 +1660,53 @@ contains if (surface_tension) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(c_idx)%sf(j, k, l) = & - rhs_vf(c_idx)%sf(j, k, l) + 1._wp/dz(l)* & - q_prim_vf(c_idx)%sf(j, k, l)* & - (flux_src_n_in(advxb)%sf(j, k, l) - & - flux_src_n_in(advxb)%sf(j, k, l - 1)) + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(c_idx)%sf(j, k, l) = & + rhs_vf(c_idx)%sf(j, k, l) + 1._wp/dz(l)* & + q_prim_vf(c_idx)%sf(j, k, l)* & + (flux_src_n_in(advxb)%sf(j, k, l) - & + flux_src_n_in(advxb)%sf(j, k, l - 1)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do i = momxb, E_idx - rhs_vf(i)%sf(j, k, l) = & - rhs_vf(i)%sf(j, k, l) + 1._wp/dz(l)* & - (flux_src_n_in(i)%sf(j, k, l - 1) & - - flux_src_n_in(i)%sf(j, k, l)) + do l = 0, p + do k = 0, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do i = momxb, E_idx + rhs_vf(i)%sf(j, k, l) = & + rhs_vf(i)%sf(j, k, l) + 1._wp/dz(l)* & + (flux_src_n_in(i)%sf(j, k, l - 1) & + - flux_src_n_in(i)%sf(j, k, l)) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP if (grid_geometry == 3) then #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - rhs_vf(momxb + 1)%sf(j, k, l) = & - rhs_vf(momxb + 1)%sf(j, k, l) + 5.e-1_wp* & - (flux_src_n_in(momxe)%sf(j, k, l - 1) & - + flux_src_n_in(momxe)%sf(j, k, l)) - - rhs_vf(momxe)%sf(j, k, l) = & - rhs_vf(momxe)%sf(j, k, l) - 5.e-1_wp* & - (flux_src_n_in(momxb + 1)%sf(j, k, l - 1) & - + flux_src_n_in(momxb + 1)%sf(j, k, l)) + do l = 0, p + do k = 0, n + do j = 0, m + rhs_vf(momxb + 1)%sf(j, k, l) = & + rhs_vf(momxb + 1)%sf(j, k, l) + 5.e-1_wp* & + (flux_src_n_in(momxe)%sf(j, k, l - 1) & + + flux_src_n_in(momxe)%sf(j, k, l)) + + rhs_vf(momxe)%sf(j, k, l) = & + rhs_vf(momxe)%sf(j, k, l) - 5.e-1_wp* & + (flux_src_n_in(momxb + 1)%sf(j, k, l - 1) & + + flux_src_n_in(momxb + 1)%sf(j, k, l)) + end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if end if diff --git a/src/simulation/m_surface_tension.fpp b/src/simulation/m_surface_tension.fpp index 84c09ab6f5..a1dd5aeda1 100644 --- a/src/simulation/m_surface_tension.fpp +++ b/src/simulation/m_surface_tension.fpp @@ -108,8 +108,8 @@ contains w3 = (w3L + w3R)/2._wp normW = (normWL + normWR)/2._wp - if (normW > capillary_cutoff) then - @:compute_capillary_stress_tensor() + if (normW > capillary_cutoff) then + @:compute_capillary_stress_tensor() do i = 1, num_dims @@ -154,8 +154,8 @@ contains w3 = (w3L + w3R)/2._wp normW = (normWL + normWR)/2._wp - if (normW > capillary_cutoff) then - @:compute_capillary_stress_tensor() + if (normW > capillary_cutoff) then + @:compute_capillary_stress_tensor() do i = 1, num_dims @@ -200,8 +200,8 @@ contains w3 = (w3L + w3R)/2._wp normW = (normWL + normWR)/2._wp - if (normW > capillary_cutoff) then - @:compute_capillary_stress_tensor() + if (normW > capillary_cutoff) then + @:compute_capillary_stress_tensor() do i = 1, num_dims @@ -276,21 +276,21 @@ contains end if #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - c_divs(num_dims + 1)%sf(j, k, l) = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, num_dims + do l = 0, p + do k = 0, n + do j = 0, m + c_divs(num_dims + 1)%sf(j, k, l) = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, num_dims + c_divs(num_dims + 1)%sf(j, k, l) = & + c_divs(num_dims + 1)%sf(j, k, l) + & + c_divs(i)%sf(j, k, l)**2._wp + end do c_divs(num_dims + 1)%sf(j, k, l) = & - c_divs(num_dims + 1)%sf(j, k, l) + & - c_divs(i)%sf(j, k, l)**2._wp + sqrt(c_divs(num_dims + 1)%sf(j, k, l)) end do - c_divs(num_dims + 1)%sf(j, k, l) = & - sqrt(c_divs(num_dims + 1)%sf(j, k, l)) end do end do - end do #:endcall GPU_PARALLEL_LOOP call s_populate_capillary_buffers(c_divs, bc_type) diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index cef74f406d..832c50792f 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -1021,14 +1021,14 @@ contains end if #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') - do l = 0, p - do k = 0, n - do j = 0, m - if (igr) then - call s_compute_enthalpy(q_cons_ts(1)%vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) - else - call s_compute_enthalpy(q_prim_vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) - end if + do l = 0, p + do k = 0, n + do j = 0, m + if (igr) then + call s_compute_enthalpy(q_cons_ts(1)%vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) + else + call s_compute_enthalpy(q_prim_vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) + end if ! Compute mixture sound speed call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, alpha, vel_sum, 0._wp, c) @@ -1069,16 +1069,16 @@ contains call s_compute_body_forces_rhs(q_prim_vf_in, q_cons_vf, rhs_vf_in) #:call GPU_PARALLEL_LOOP(collapse=4) - do i = momxb, E_idx - do l = 0, p - do k = 0, n - do j = 0, m - q_cons_vf(i)%sf(j, k, l) = q_cons_vf(i)%sf(j, k, l) + & - ldt*rhs_vf_in(i)%sf(j, k, l) + do i = momxb, E_idx + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_vf(i)%sf(j, k, l) = q_cons_vf(i)%sf(j, k, l) + & + ldt*rhs_vf_in(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP call nvtxEndRange @@ -1096,66 +1096,66 @@ contains if (t_step == t_step_start) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_prim_ts(3)%vf(i)%sf(j, k, l) = q_prim_vf(i)%sf(j, k, l) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_prim_ts(3)%vf(i)%sf(j, k, l) = q_prim_vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (t_step == t_step_start + 1) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_prim_ts(2)%vf(i)%sf(j, k, l) = q_prim_vf(i)%sf(j, k, l) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_prim_ts(2)%vf(i)%sf(j, k, l) = q_prim_vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (t_step == t_step_start + 2) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_prim_ts(1)%vf(i)%sf(j, k, l) = q_prim_vf(i)%sf(j, k, l) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_prim_ts(1)%vf(i)%sf(j, k, l) = q_prim_vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP elseif (t_step == t_step_start + 3) then #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_prim_ts(0)%vf(i)%sf(j, k, l) = q_prim_vf(i)%sf(j, k, l) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_prim_ts(0)%vf(i)%sf(j, k, l) = q_prim_vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP else ! All other timesteps #:call GPU_PARALLEL_LOOP(collapse=4) - do i = 1, sys_size - do l = 0, p - do k = 0, n - do j = 0, m - q_prim_ts(3)%vf(i)%sf(j, k, l) = q_prim_ts(2)%vf(i)%sf(j, k, l) - q_prim_ts(2)%vf(i)%sf(j, k, l) = q_prim_ts(1)%vf(i)%sf(j, k, l) - q_prim_ts(1)%vf(i)%sf(j, k, l) = q_prim_ts(0)%vf(i)%sf(j, k, l) - q_prim_ts(0)%vf(i)%sf(j, k, l) = q_prim_vf(i)%sf(j, k, l) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_prim_ts(3)%vf(i)%sf(j, k, l) = q_prim_ts(2)%vf(i)%sf(j, k, l) + q_prim_ts(2)%vf(i)%sf(j, k, l) = q_prim_ts(1)%vf(i)%sf(j, k, l) + q_prim_ts(1)%vf(i)%sf(j, k, l) = q_prim_ts(0)%vf(i)%sf(j, k, l) + q_prim_ts(0)%vf(i)%sf(j, k, l) = q_prim_vf(i)%sf(j, k, l) + end do end do end do end do - end do #:endcall GPU_PARALLEL_LOOP end if diff --git a/src/simulation/m_weno.fpp b/src/simulation/m_weno.fpp index bbaf3648a3..7399d84993 100644 --- a/src/simulation/m_weno.fpp +++ b/src/simulation/m_weno.fpp @@ -1150,16 +1150,16 @@ contains if (weno_dir == 2) then #:call GPU_PARALLEL_LOOP(collapse=4) - do j = 1, v_size - do q = is3_weno%beg, is3_weno%end - do l = is2_weno%beg, is2_weno%end - do k = is1_weno%beg - weno_polyn, is1_weno%end + weno_polyn - v_rs_ws_y(k, l, q, j) = v_vf(j)%sf(l, k, q) + do j = 1, v_size + do q = is3_weno%beg, is3_weno%end + do l = is2_weno%beg, is2_weno%end + do k = is1_weno%beg - weno_polyn, is1_weno%end + weno_polyn + v_rs_ws_y(k, l, q, j) = v_vf(j)%sf(l, k, q) + end do end do end do end do - end do - #:endcall GPU_PARALLEL_LOOP + #:endcall GPU_PARALLEL_LOOP end if ! Reshaping/Projecting onto Characteristic Fields in z-direction @@ -1167,16 +1167,16 @@ contains if (weno_dir == 3) then #:call GPU_PARALLEL_LOOP(collapse=4) - do j = 1, v_size - do q = is3_weno%beg, is3_weno%end - do l = is2_weno%beg, is2_weno%end - do k = is1_weno%beg - weno_polyn, is1_weno%end + weno_polyn - v_rs_ws_z(k, l, q, j) = v_vf(j)%sf(q, l, k) + do j = 1, v_size + do q = is3_weno%beg, is3_weno%end + do l = is2_weno%beg, is2_weno%end + do k = is1_weno%beg - weno_polyn, is1_weno%end + weno_polyn + v_rs_ws_z(k, l, q, j) = v_vf(j)%sf(q, l, k) + end do end do end do end do - end do - #:endcall GPU_PARALLEL_LOOP + #:endcall GPU_PARALLEL_LOOP end if end subroutine s_initialize_weno From 9d23036b05af0fa74c0df40d29aea8097ff71315 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Tue, 22 Jul 2025 17:24:16 -0400 Subject: [PATCH 014/199] Add syscheck of OpenMP, add omp support for GPU_HOST_DATA, ATOMIC, and WAIT --- src/common/include/acc_macros.fpp | 33 +++++++++++++ src/common/include/omp_macros.fpp | 44 +++++++++++++++++ src/common/include/parallel_macros.fpp | 67 ++++++++++++++++---------- src/common/m_mpi_common.fpp | 2 +- src/simulation/m_body_forces.fpp | 4 +- src/simulation/m_fftw.fpp | 8 +-- src/simulation/m_global_parameters.fpp | 4 +- src/simulation/m_start_up.fpp | 5 -- src/simulation/m_weno.fpp | 4 +- src/syscheck/syscheck.fpp | 23 +++++++++ 10 files changed, 150 insertions(+), 44 deletions(-) diff --git a/src/common/include/acc_macros.fpp b/src/common/include/acc_macros.fpp index c70d065f90..d5efabb67f 100644 --- a/src/common/include/acc_macros.fpp +++ b/src/common/include/acc_macros.fpp @@ -234,4 +234,37 @@ #:set acc_directive = '!$acc update ' + clause_val + extraAccArgs_val.strip('\n') $:acc_directive #:enddef + +#:def ACC_HOST_DATA(code, use_device=None, extraAccArgs=None) + #:assert code is not None + #:assert isinstance(code, str) + #:if code == '' or code.isspace() + #:stop 'GPU_HOST_DATA macro has no effect on the code as it is not surrounding any code' + #:endif + #:set use_device_val = GEN_USE_DEVICE_STR(use_device) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = use_device_val.strip('\n') + #:set acc_directive = '!$acc host_data ' + clause_val + extraAccArgs_val.strip('\n') + #:set end_acc_directive = '!$acc end host_data' + $:acc_directive + $:code + $:end_acc_directive +#:enddef + +#:def ACC_ATOMIC(atomic, extraAccArgs=None) + #:assert isinstance(atomic, str) + #:assert (atomic == 'read' or atomic == 'write' or atomic == 'update' or atomic == 'capture') + #:set atomic_val = atomic + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = atomic_val.strip('\n') + #:set acc_directive = '!$acc atomic ' + clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef + +#:def ACC_WAIT(extraAccArgs=None) + #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) + #:set clause_val = '' + #:set acc_directive = '!$acc wait ' + clause_val + extraAccArgs_val.strip('\n') + $:acc_directive +#:enddef ! New line at end of file is required for FYPP \ No newline at end of file diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 5566dba088..e37c94ee5f 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -94,6 +94,16 @@ $:temp #:enddef +#:def OMP_USE_DEVICE_ADDR_STR(use_device_addr) + #:set use_device_addr_val = GEN_PARENTHESES_CLAUSE('use_device_addr', use_device_addr) + $:use_device_addr_val +#:enddef + +#:def OMP_USE_DEVICE_PTR_STR(use_device_ptr) + #:set use_device_ptr_val = GEN_PARENTHESES_CLAUSE('use_device_ptr', use_device_ptr) + $:use_device_ptr_val +#:enddef + #:def OMP_PARALLEL(code, private=None, default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & & no_create=None, present=None, deviceptr=None, attach=None, extraOmpArgs=None) @@ -251,4 +261,38 @@ #:set acc_directive = '!$omp target update ' + clause_val + extraOmpArgs_val.strip('\n') $:acc_directive #:enddef + +#:def OMP_HOST_DATA(code, use_device_addr, use_device_ptr, extraOmpArgs) + #:assert code is not None + #:assert isinstance(code, str) + #:if code == '' or code.isspace() + #:stop 'GPU_HOST_DATA macro has no effect on the code as it is not surrounding any code' + #:endif + #:set use_device_addr_val = OMP_USE_DEVICE_ADDR_STR(use_device_addr) + #:set use_device_ptr_val = OMP_USE_DEVICE_PTR_STR(use_device_ptr) + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) + #:set clause_val = use_device_addr_val.strip('\n') + use_device_ptr_val.strip('\n') + #:set omp_directive = '!$omp target data ' + clause_val + extraOmpArgs_val.strip('\n') + #:set omp_end_directive = '!$omp end target data' + $:omp_directive + $:code + $:omp_end_directive +#:enddef + +#:def OMP_ATOMIC(atomic, extraOmpArgs=None) + #:assert isinstance(atomic, str) + #:assert (atomic == 'read' or atomic == 'write' or atomic == 'update' or atomic == 'capture') + #:set atomic_val = atomic + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) + #:set clause_val = atomic_val.strip('\n') + #:set omp_directive = '!$omp atomic ' + clause_val + extraOmpArgs_val.strip('\n') + $:omp_directive +#:enddef + +#:def OMP_WAIT(extraOmpArgs=None) + #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) + #:set clause_val = '' + #:set omp_directive = '!$omp barrier ' + clause_val + extraOmpArgs_val.strip('\n') + $:omp_directive +#:enddef ! New line at end of file is required for FYPP \ No newline at end of file diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index 7dfacd0829..b93035ebbc 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -152,20 +152,32 @@ #endif #:enddef -#:def GPU_HOST_DATA(code, use_device=None, extraAccArgs=None) - #:assert code is not None - #:assert isinstance(code, str) - #:if code == '' or code.isspace() - #:stop 'GPU_HOST_DATA macro has no effect on the code as it is not surrounding any code' +#:def GPU_HOST_DATA(code, use_device_addr=None, use_device_ptr=None, extraAccArgs=None, extraOmpArgs=None) + + #:if use_device_addr is not None and use_device_ptr is not None + #:set use_device_addr_end_index = len(use_device_addr) - 1 + #:set use_device = use_device_addr + use_device_ptr + $:use_device[use_device_addr_end_index] = ',' + $:use_device[use_device_addr_end_index + 1] = ' ' + #:elif use_device_addr is not None or use_device_ptr is not None + #:if use_device_addr is not None + #:set use_device = use_device_addr + #:else + #:set use_device = use_device_ptr + #:endif + #:else + #:set use_device = None #:endif - #:set use_device_val = GEN_USE_DEVICE_STR(use_device) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = use_device_val.strip('\n') - #:set acc_directive = '!$acc host_data ' + clause_val + extraAccArgs_val.strip('\n') - #:set end_acc_directive = '!$acc end host_data' - $:acc_directive + #:set acc_code = ACC_HOST_DATA(code=code, use_device=use_device, extraAccArgs=extraAccArgs) + #:set omp_code = OMP_HOST_DATA(code=code, use_device_addr=use_device_addr, use_device_ptr=use_device_ptr, extraOmpArgs=extraOmpArgs) + +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#else $:code - $:end_acc_directive +#endif #:enddef #:def GPU_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraAccArgs=None, extraOmpArgs=None) @@ -190,14 +202,15 @@ #endif #:enddef -#:def GPU_ATOMIC(atomic, extraAccArgs=None) - #:assert isinstance(atomic, str) - #:assert (atomic == 'read' or atomic == 'write' or atomic == 'update' or atomic == 'capture') - #:set atomic_val = atomic - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = atomic_val.strip('\n') - #:set acc_directive = '!$acc atomic ' + clause_val + extraAccArgs_val.strip('\n') - $:acc_directive +#:def GPU_ATOMIC(atomic, extraAccArgs=None, extraOmpArgs=None) + #:set acc_code = ACC_ATOMIC(atomic=atomic, extraAccArgs=extraAccArgs) + #:set omp_code = OMP_ATOMIC(atomic=atomic, extraOmpArgs=extraOmpArgs) + +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#endif #:enddef #:def GPU_UPDATE(host=None, device=None, extraAccArgs=None, extraOmpArgs=None) @@ -211,11 +224,15 @@ #endif #:enddef -#:def GPU_WAIT(extraAccArgs=None) - #:set extraAccArgs_val = GEN_EXTRA_ARGS_STR(extraAccArgs) - #:set clause_val = '' - #:set acc_directive = '!$acc wait ' + clause_val + extraAccArgs_val.strip('\n') - $:acc_directive +#:def GPU_WAIT(extraAccArgs=None, extraOmpArgs=None) + #:set acc_code = ACC_WAIT(extraAccArgs=extraAccArgs) + #:set omp_code = OMP_WAIT(extraOmpArgs=extraOmpArgs) + +#if defined(MFC_OpenACC) + $:acc_code +#elif defined(MFC_OpenMP) + $:omp_code +#endif #:enddef #:def USE_GPU_MODULE() diff --git a/src/common/m_mpi_common.fpp b/src/common/m_mpi_common.fpp index 098dbe82d6..c2697e475a 100644 --- a/src/common/m_mpi_common.fpp +++ b/src/common/m_mpi_common.fpp @@ -845,7 +845,7 @@ contains #:for rdma_mpi in [False, True] if (rdma_mpi .eqv. ${'.true.' if rdma_mpi else '.false.'}$) then #:if rdma_mpi - #:call GPU_HOST_DATA(use_device='[buff_send, buff_recv]') + #:call GPU_HOST_DATA(use_device_addr='[buff_send, buff_recv]') call nvtxStartRange("RHS-COMM-SENDRECV-RDMA") call MPI_SENDRECV( & diff --git a/src/simulation/m_body_forces.fpp b/src/simulation/m_body_forces.fpp index 213d9b7fc1..a5b95a4b41 100644 --- a/src/simulation/m_body_forces.fpp +++ b/src/simulation/m_body_forces.fpp @@ -10,9 +10,7 @@ module m_body_forces use m_nvtx -#ifdef MFC_OpenACC - use openacc -#endif +! $:USE_GPU_MODULE() implicit none diff --git a/src/simulation/m_fftw.fpp b/src/simulation/m_fftw.fpp index be081f44d9..3211fce682 100644 --- a/src/simulation/m_fftw.fpp +++ b/src/simulation/m_fftw.fpp @@ -166,7 +166,7 @@ contains p_fltr_cmplx => data_fltr_cmplx_gpu #:call GPU_DATA(attach='[p_real, p_cmplx, p_fltr_cmplx]') - #:call GPU_HOST_DATA(use_device='[p_real, p_cmplx, p_fltr_cmplx]') + #:call GPU_HOST_DATA(use_device_ptr='[p_real, p_cmplx, p_fltr_cmplx]') #if defined(__PGI) ierr = cufftExecD2Z(fwd_plan_gpu, data_real_gpu, data_cmplx_gpu) #else @@ -187,7 +187,7 @@ contains end do #:endcall GPU_PARALLEL_LOOP - #:call GPU_HOST_DATA(use_device='[p_real, p_fltr_cmplx]') + #:call GPU_HOST_DATA(use_device_ptr='[p_real, p_fltr_cmplx]') #if defined(__PGI) ierr = cufftExecZ2D(bwd_plan_gpu, data_fltr_cmplx_gpu, data_real_gpu) #else @@ -229,7 +229,7 @@ contains end do #:endcall GPU_PARALLEL_LOOP - #:call GPU_HOST_DATA(use_device='[p_real, p_cmplx]') + #:call GPU_HOST_DATA(use_device_ptr='[p_real, p_cmplx]') #if defined(__PGI) ierr = cufftExecD2Z(fwd_plan_gpu, data_real_gpu, data_cmplx_gpu) #else @@ -251,7 +251,7 @@ contains end do #:endcall GPU_PARALLEL_LOOP - #:call GPU_HOST_DATA(use_device='[p_real, p_fltr_cmplx]') + #:call GPU_HOST_DATA(use_device_ptr='[p_real, p_fltr_cmplx]') #if defined(__PGI) ierr = cufftExecZ2D(bwd_plan_gpu, data_fltr_cmplx_gpu, data_real_gpu) #else diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp index 9ae61c5112..c8a3b09d56 100644 --- a/src/simulation/m_global_parameters.fpp +++ b/src/simulation/m_global_parameters.fpp @@ -21,9 +21,7 @@ module m_global_parameters use m_helper_basic !< Functions to compare floating point numbers -#ifdef MFC_OpenACC - use openacc -#endif + ! $:USE_GPU_MODULE() implicit none diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index 4d83080b19..95c7233738 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -69,11 +69,6 @@ module m_start_up use m_helper_basic !< Functions to compare floating point numbers $:USE_GPU_MODULE() -! #if defined(MFC_OpenACC) -! use openacc -! #elif defined(MFC_OpenMP) -! use omp_lib -! #endif use m_nvtx diff --git a/src/simulation/m_weno.fpp b/src/simulation/m_weno.fpp index 7399d84993..79efa5e6c9 100644 --- a/src/simulation/m_weno.fpp +++ b/src/simulation/m_weno.fpp @@ -24,9 +24,7 @@ module m_weno use m_variables_conversion !< State variables type conversion procedures -#ifdef MFC_OPENACC - use openacc -#endif + ! $:USE_GPU_MODULE() use m_mpi_proxy diff --git a/src/syscheck/syscheck.fpp b/src/syscheck/syscheck.fpp index ca2641057e..dc7a354268 100644 --- a/src/syscheck/syscheck.fpp +++ b/src/syscheck/syscheck.fpp @@ -30,6 +30,15 @@ #endif #:enddef ACCC +#:def OMPC(*args) +#ifdef MFC_OpenMP + @:LOG("[TEST] OMP: ${','.join([ x.replace("'", '') for x in args ])}$") + ${','.join([ x.replace("'", '') for x in args ])}$ +#else + @:LOG("[SKIP] OMP: ${','.join([ x.replace("'", '') for x in args ])}$") +#endif +#:enddef OMPC + #:def MPI(*args) #ifdef MFC_MPI ${','.join([ x.replace("'", '') for x in args ])}$ @@ -42,10 +51,17 @@ #endif #:enddef ACC +#:def OMP(*args) +#ifdef MFC_OpenMP + ${','.join([ x.replace("'", '') for x in args ])}$ +#endif +#:enddef OMP + program syscheck @:MPI(use mpi) @:ACC(use openacc) + @:OMP(use omp_lib) implicit none @@ -55,6 +71,8 @@ program syscheck @:ACC(integer :: i, num_devices) @:ACC(real(8), allocatable, dimension(:) :: arr) @:ACC(integer, parameter :: N = 100) + @:OMP(integer :: num_devices_omp) + @:MPIC(call mpi_init(ierr)) @:MPIC(call mpi_comm_rank(MPI_COMM_WORLD, rank, ierr)) @@ -76,6 +94,11 @@ program syscheck @:ACCC('!$acc update host(arr(1:N))') @:ACCC('!$acc exit data delete(arr)') + @:OMPC('num_devices_omp = omp_get_num_devices()') + @:OMPC(call assert(num_devices_omp > 0)) + @:OMPC(call omp_set_default_device(mod(rank, nRanks))) + + @:MPIC(call mpi_barrier(MPI_COMM_WORLD, ierr)) @:MPIC(call mpi_finalize(ierr)) From de586ad71331cc3c308dcbc6b42db91a4f1bbe7a Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Wed, 23 Jul 2025 14:14:25 -0400 Subject: [PATCH 015/199] Update var name --- src/common/include/omp_macros.fpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index e37c94ee5f..84aa6c9387 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -258,8 +258,8 @@ #:set device_val = OMP_TO_STR(device) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set clause_val = host_val.strip('\n') + device_val.strip('\n') - #:set acc_directive = '!$omp target update ' + clause_val + extraOmpArgs_val.strip('\n') - $:acc_directive + #:set omp_directive = '!$omp target update ' + clause_val + extraOmpArgs_val.strip('\n') + $:omp_directive #:enddef #:def OMP_HOST_DATA(code, use_device_addr, use_device_ptr, extraOmpArgs) From 84ddc012cc73bbfe2be44e8ab66868507ef51280 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Wed, 23 Jul 2025 15:40:32 -0400 Subject: [PATCH 016/199] Change how parallel loop is translated --- src/common/include/omp_macros.fpp | 4 ++-- src/simulation/m_acoustic_src.fpp | 2 +- src/simulation/m_data_output.fpp | 4 ++-- src/simulation/m_start_up.fpp | 6 +++--- src/syscheck/syscheck.fpp | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 84aa6c9387..7719a33411 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -160,9 +160,9 @@ & no_create_val.strip('\n') + present_val.strip('\n') + & & deviceptr_val.strip('\n') + attach_val.strip('\n') #! Hardcoding the parallelism for now - #:set omp_directive = '!$omp target teams distribute parallel do simd ' + & + #:set omp_directive = '!$omp target teams loop bind(teams) ' + & & clause_val + extraOmpArgs_val.strip('\n') - #:set omp_end_directive = '!$omp end target teams distribute parallel do simd' + #:set omp_end_directive = '!$omp end target teams loop' $:omp_directive $:code $:omp_end_directive diff --git a/src/simulation/m_acoustic_src.fpp b/src/simulation/m_acoustic_src.fpp index 8b2efa6bcf..27f9cc504b 100644 --- a/src/simulation/m_acoustic_src.fpp +++ b/src/simulation/m_acoustic_src.fpp @@ -183,7 +183,7 @@ contains ! Keep outer loop sequel because different sources can have very different number of points do ai = 1, num_source ! Skip if the pulse has not started yet for sine and square waves - if (sim_time < delay(ai) .and. (pulse(ai) == 1 .or. pulse(ai) == 3)) cycle + ! if (sim_time < delay(ai) .and. (pulse(ai) == 1 .or. pulse(ai) == 3)) cycle ! Decide if frequency need to be converted from wavelength freq_conv_flag = f_is_default(frequency(ai)) diff --git a/src/simulation/m_data_output.fpp b/src/simulation/m_data_output.fpp index ecae911da3..37af5bd696 100644 --- a/src/simulation/m_data_output.fpp +++ b/src/simulation/m_data_output.fpp @@ -279,7 +279,7 @@ contains integer :: j, k, l ! Computing Stability Criteria at Current Time-step - #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') + ! #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') do l = 0, p do k = 0, n do j = 0, m @@ -296,7 +296,7 @@ contains end do end do end do - #:endcall GPU_PARALLEL_LOOP + ! #:endcall GPU_PARALLEL_LOOP ! end: Computing Stability Criteria at Current Time-step diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index 95c7233738..61e04dee6f 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -1361,9 +1361,9 @@ contains call acc_set_device_num(dev, devtype) #elif defined(MFC_OpenMP) - devNum = omp_get_num_devices() - dev = mod(local_rank, devNum) - call omp_set_default_device(dev) + ! devNum = omp_get_num_devices() + ! dev = mod(local_rank, devNum) + ! call omp_set_default_device(dev) #endif #endif diff --git a/src/syscheck/syscheck.fpp b/src/syscheck/syscheck.fpp index dc7a354268..6a89b3c028 100644 --- a/src/syscheck/syscheck.fpp +++ b/src/syscheck/syscheck.fpp @@ -94,9 +94,9 @@ program syscheck @:ACCC('!$acc update host(arr(1:N))') @:ACCC('!$acc exit data delete(arr)') - @:OMPC('num_devices_omp = omp_get_num_devices()') - @:OMPC(call assert(num_devices_omp > 0)) - @:OMPC(call omp_set_default_device(mod(rank, nRanks))) + ! @:OMPC('num_devices_omp = omp_get_num_devices()') + ! @:OMPC(call assert(num_devices_omp > 0)) + ! @:OMPC(call omp_set_default_device(mod(rank, nRanks))) @:MPIC(call mpi_barrier(MPI_COMM_WORLD, ierr)) From 7246e9b7b74a61aaba8ab62dac276956107e3ba6 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Wed, 23 Jul 2025 15:41:19 -0400 Subject: [PATCH 017/199] Ran formatter --- src/common/include/parallel_macros.fpp | 20 ++++++++++---------- src/simulation/m_data_output.fpp | 22 +++++++++++----------- src/syscheck/syscheck.fpp | 2 -- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index b93035ebbc..7fbb346bb9 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -155,18 +155,18 @@ #:def GPU_HOST_DATA(code, use_device_addr=None, use_device_ptr=None, extraAccArgs=None, extraOmpArgs=None) #:if use_device_addr is not None and use_device_ptr is not None - #:set use_device_addr_end_index = len(use_device_addr) - 1 - #:set use_device = use_device_addr + use_device_ptr - $:use_device[use_device_addr_end_index] = ',' - $:use_device[use_device_addr_end_index + 1] = ' ' + #:set use_device_addr_end_index = len(use_device_addr) - 1 + #:set use_device = use_device_addr + use_device_ptr + $:use_device[use_device_addr_end_index] = ',' + $:use_device[use_device_addr_end_index + 1] = ' ' #:elif use_device_addr is not None or use_device_ptr is not None - #:if use_device_addr is not None - #:set use_device = use_device_addr - #:else - #:set use_device = use_device_ptr - #:endif + #:if use_device_addr is not None + #:set use_device = use_device_addr + #:else + #:set use_device = use_device_ptr + #:endif #:else - #:set use_device = None + #:set use_device = None #:endif #:set acc_code = ACC_HOST_DATA(code=code, use_device=use_device, extraAccArgs=extraAccArgs) #:set omp_code = OMP_HOST_DATA(code=code, use_device_addr=use_device_addr, use_device_ptr=use_device_ptr, extraOmpArgs=extraOmpArgs) diff --git a/src/simulation/m_data_output.fpp b/src/simulation/m_data_output.fpp index 37af5bd696..f39bdfc940 100644 --- a/src/simulation/m_data_output.fpp +++ b/src/simulation/m_data_output.fpp @@ -280,22 +280,22 @@ contains ! Computing Stability Criteria at Current Time-step ! #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') - do l = 0, p - do k = 0, n - do j = 0, m - call s_compute_enthalpy(q_prim_vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) + do l = 0, p + do k = 0, n + do j = 0, m + call s_compute_enthalpy(q_prim_vf, pres, rho, gamma, pi_inf, Re, H, alpha, vel, vel_sum, j, k, l) - call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, alpha, vel_sum, 0._wp, c) + call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, H, alpha, vel_sum, 0._wp, c) - if (viscous) then - call s_compute_stability_from_dt(vel, c, rho, Re, j, k, l, icfl_sf, vcfl_sf, Rc_sf) - else - call s_compute_stability_from_dt(vel, c, rho, Re, j, k, l, icfl_sf) - end if + if (viscous) then + call s_compute_stability_from_dt(vel, c, rho, Re, j, k, l, icfl_sf, vcfl_sf, Rc_sf) + else + call s_compute_stability_from_dt(vel, c, rho, Re, j, k, l, icfl_sf) + end if - end do end do end do + end do ! #:endcall GPU_PARALLEL_LOOP ! end: Computing Stability Criteria at Current Time-step diff --git a/src/syscheck/syscheck.fpp b/src/syscheck/syscheck.fpp index 6a89b3c028..80fe745491 100644 --- a/src/syscheck/syscheck.fpp +++ b/src/syscheck/syscheck.fpp @@ -73,7 +73,6 @@ program syscheck @:ACC(integer, parameter :: N = 100) @:OMP(integer :: num_devices_omp) - @:MPIC(call mpi_init(ierr)) @:MPIC(call mpi_comm_rank(MPI_COMM_WORLD, rank, ierr)) @:MPIC(call mpi_barrier(MPI_COMM_WORLD, ierr)) @@ -98,7 +97,6 @@ program syscheck ! @:OMPC(call assert(num_devices_omp > 0)) ! @:OMPC(call omp_set_default_device(mod(rank, nRanks))) - @:MPIC(call mpi_barrier(MPI_COMM_WORLD, ierr)) @:MPIC(call mpi_finalize(ierr)) From d5381aafd81c66012f4374d5393a1fbb4011a58e Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Wed, 23 Jul 2025 17:58:50 -0400 Subject: [PATCH 018/199] Remove extraneous build flags --- CMakeLists.txt | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c7a35187f..b46571094e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,18 +194,18 @@ elseif ((CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") OR (CMAKE_Fortran_COMPILER_ add_compile_options( $<$:-Mfreeform> $<$:-cpp> - $<$:-Minfo=inline> + # $<$:-Minfo=inline> $<$:-Minfo=accel> ) if (CMAKE_BUILD_TYPE STREQUAL "Debug") add_compile_options( $<$:-O0> - $<$:-C> - $<$:-g> - $<$:-traceback> + # $<$:-C> + # $<$:-g> + # $<$:-traceback> $<$:-Minform=inform> - $<$:-Mbounds> + # $<$:-Mbounds> ) endif() @@ -480,11 +480,19 @@ function(MFC_SETUP_TARGET) if (NOT TARGET OpenMP::OpenMP_Fortran) message(FATAL_ERROR "OpenMP + Fortran is unsupported.") endif() - + set(ENV{OMP_TARGET_OFFLOAD} [MANDATORY]) target_link_libraries(${a_target} PRIVATE OpenMP::OpenMP_Fortran) target_compile_definitions(${a_target} PRIVATE MFC_OpenMP MFC_GPU) + if(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC" OR CMAKE_Fortran_COMPILER_ID STREQUAL "PGI") - target_compile_options(${a_target} PRIVATE "-mp=gpu") + target_compile_options(${a_target} PRIVATE "-target=gpu" "-Minfo=mp") + set_target_properties(${a_target} PROPERTIES Fortran_FLAGS "-mp=gpu -gpu=ccall") + elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") + target_compile_options(${a_target} PRIVATE -fopenmp -fopenmp-targets=spir64) + target_link_options(${a_target} PRIVATE -fopenmp -fopenmp-targets=spir64) + elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") + target_compile_options(${a_target} PRIVATE -fopenmp -fopenmp-targets=spir64 ) + target_link_options(${a_target} PRIVATE -fopenmp -fopenmp-targets=spir64) endif() endif() @@ -502,7 +510,7 @@ function(MFC_SETUP_TARGET) endforeach() target_compile_options(${a_target} - PRIVATE -gpu=keep,ptxinfo,lineinfo + PRIVATE -gpu=lineinfo ) # GH-200 Unified Memory Support @@ -518,7 +526,7 @@ function(MFC_SETUP_TARGET) if (CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_options(${a_target} - PRIVATE -gpu=autocompare,debug + PRIVATE -gpu=debug ) endif() elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") From dbcb6f3cfaa549f00cf48acb4f61f4dbae15975c Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Thu, 24 Jul 2025 11:20:32 -0400 Subject: [PATCH 019/199] Remove thermochem function calls --- src/common/m_chemistry.fpp | 4 +-- src/common/m_variables_conversion.fpp | 12 +++---- src/simulation/include/inline_riemann.fpp | 8 ++--- src/simulation/m_acoustic_src.fpp | 4 +-- src/simulation/m_cbc.fpp | 18 +++++----- src/simulation/m_riemann_solvers.fpp | 40 +++++++++++------------ src/simulation/m_start_up.fpp | 6 ++-- src/syscheck/syscheck.fpp | 6 ++-- 8 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/common/m_chemistry.fpp b/src/common/m_chemistry.fpp index e9e5bc5ee8..92587d9de7 100644 --- a/src/common/m_chemistry.fpp +++ b/src/common/m_chemistry.fpp @@ -99,7 +99,7 @@ contains real(wp), dimension(num_species) :: Ys real(wp), dimension(num_species) :: omega - #:call GPU_PARALLEL_LOOP(collapse=3, private='[Ys, omega]') + ! #:call GPU_PARALLEL_LOOP(collapse=3, private='[Ys, omega]') do z = bounds(3)%beg, bounds(3)%end do y = bounds(2)%beg, bounds(2)%end do x = bounds(1)%beg, bounds(1)%end @@ -126,7 +126,7 @@ contains end do end do end do - #:endcall GPU_PARALLEL_LOOP + ! #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_chemistry_reaction_flux diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index 0bffeee879..e68097df7b 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -181,8 +181,8 @@ contains T_guess = T - call get_temperature(e_Per_Kg - Pdyn_Per_Kg, T_guess, Y_rs, .true., T) - call get_pressure(rho, T, Y_rs, pres) + ! call get_temperature(e_Per_Kg - Pdyn_Per_Kg, T_guess, Y_rs, .true., T) + ! call get_pressure(rho, T, Y_rs, pres) #:endif @@ -1306,9 +1306,9 @@ contains q_cons_vf(i)%sf(j, k, l) = rho*q_prim_vf(i)%sf(j, k, l) end do - call get_mixture_molecular_weight(Ys, mix_mol_weight) + ! call get_mixture_molecular_weight(Ys, mix_mol_weight) T = q_prim_vf(E_idx)%sf(j, k, l)*mix_mol_weight/(gas_constant*rho) - call get_mixture_energy_mass(T, Ys, e_mix) + ! call get_mixture_energy_mass(T, Ys, e_mix) q_cons_vf(E_idx)%sf(j, k, l) = & dyn_pres + rho*e_mix @@ -1534,10 +1534,10 @@ contains Y_K(i - chemxb + 1) = qK_prim_vf(j, k, l, i) end do !Computing the energy from the internal energy of the mixture - call get_mixture_molecular_weight(Y_k, mix_mol_weight) + ! call get_mixture_molecular_weight(Y_k, mix_mol_weight) R_gas = gas_constant/mix_mol_weight T_K = pres_K/rho_K/R_gas - call get_mixture_energy_mass(T_K, Y_K, E_K) + ! call get_mixture_energy_mass(T_K, Y_K, E_K) E_K = rho_K*E_K + 5.e-1_wp*rho_K*vel_K_sum else ! Computing the energy from the pressure diff --git a/src/simulation/include/inline_riemann.fpp b/src/simulation/include/inline_riemann.fpp index 9972799b02..69b79abba5 100644 --- a/src/simulation/include/inline_riemann.fpp +++ b/src/simulation/include/inline_riemann.fpp @@ -34,13 +34,13 @@ if (chemistry) then eps = 0.001_wp - call get_species_enthalpies_rt(T_L, h_iL) - call get_species_enthalpies_rt(T_R, h_iR) + ! call get_species_enthalpies_rt(T_L, h_iL) + ! call get_species_enthalpies_rt(T_R, h_iR) h_iL = h_iL*gas_constant/molecular_weights*T_L h_iR = h_iR*gas_constant/molecular_weights*T_R - call get_species_specific_heats_r(T_L, Cp_iL) - call get_species_specific_heats_r(T_R, Cp_iR) + ! call get_species_specific_heats_r(T_L, Cp_iL) + ! call get_species_specific_heats_r(T_R, Cp_iR) h_avg_2 = (sqrt(rho_L)*h_iL + sqrt(rho_R)*h_iR)/(sqrt(rho_L) + sqrt(rho_R)) Yi_avg = (sqrt(rho_L)*Ys_L + sqrt(rho_R)*Ys_R)/(sqrt(rho_L) + sqrt(rho_R)) diff --git a/src/simulation/m_acoustic_src.fpp b/src/simulation/m_acoustic_src.fpp index 27f9cc504b..e92b61a58f 100644 --- a/src/simulation/m_acoustic_src.fpp +++ b/src/simulation/m_acoustic_src.fpp @@ -201,8 +201,8 @@ contains allocate (phi_rn(1:bb_num_freq(ai))) if (pulse(ai) == 4) then - ! call random_number(phi_rn(1:bb_num_freq(ai))) - phi_rn(1:bb_num_freq(ai)) = 1 + call random_number(phi_rn(1:bb_num_freq(ai))) + ! phi_rn(1:bb_num_freq(ai)) = 1 ! Ensure all the ranks have the same random phase shift call s_mpi_send_random_number(phi_rn, bb_num_freq(ai)) end if diff --git a/src/simulation/m_cbc.fpp b/src/simulation/m_cbc.fpp index 14d81fdf31..020833d6c2 100644 --- a/src/simulation/m_cbc.fpp +++ b/src/simulation/m_cbc.fpp @@ -773,7 +773,7 @@ contains end if ! FD2 or FD4 of RHS at j = 0 - #:call GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, dYs_ds, h_k, Cp_i, Gamma_i, Xs]') + ! #:call GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, dYs_ds, h_k, Cp_i, Gamma_i, Xs]') do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -818,21 +818,21 @@ contains Ys(i - chemxb + 1) = q_prim_rs${XYZ}$_vf(0, k, r, i) end do - call get_mixture_molecular_weight(Ys, Mw) + ! call get_mixture_molecular_weight(Ys, Mw) R_gas = gas_constant/Mw T = pres/rho/R_gas - call get_mixture_specific_heat_cp_mass(T, Ys, Cp) - call get_mixture_energy_mass(T, Ys, e_mix) + ! call get_mixture_specific_heat_cp_mass(T, Ys, Cp) + ! call get_mixture_energy_mass(T, Ys, e_mix) E = rho*e_mix + 5.e-1_wp*rho*vel_K_sum if (chem_params%gamma_method == 1) then !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. - call get_mole_fractions(Mw, Ys, Xs) - call get_species_specific_heats_r(T, Cp_i) + ! call get_mole_fractions(Mw, Ys, Xs) + ! call get_species_specific_heats_r(T, Cp_i) Gamma_i = Cp_i/(Cp_i - 1.0_wp) gamma = sum(Xs(:)/(Gamma_i(:) - 1.0_wp)) else if (chem_params%gamma_method == 2) then !> gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. - call get_mixture_specific_heat_cv_mass(T, Ys, Cv) + ! call get_mixture_specific_heat_cv_mass(T, Ys, Cv) gamma = 1.0_wp/(Cp/Cv - 1.0_wp) end if else @@ -1045,7 +1045,7 @@ contains if (chemistry) then ! Evolution of LODI equation of energy for real gases adjusted to perfect gas, doi:10.1006/jcph.2002.6990 - call get_species_enthalpies_rt(T, h_k) + ! call get_species_enthalpies_rt(T, h_k) sum_Enthalpies = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_species @@ -1104,7 +1104,7 @@ contains end do end do - #:endcall GPU_PARALLEL_LOOP + ! #:endcall GPU_PARALLEL_LOOP end if #:endfor diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index 4a82254c3d..d577f8a8b9 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -477,8 +477,8 @@ contains Ys_R(i - chemxb + 1) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) end do - call get_mixture_molecular_weight(Ys_L, MW_L) - call get_mixture_molecular_weight(Ys_R, MW_R) + ! call get_mixture_molecular_weight(Ys_L, MW_L) + ! call get_mixture_molecular_weight(Ys_R, MW_R) Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) @@ -488,8 +488,8 @@ contains T_L = pres_L/rho_L/R_gas_L T_R = pres_R/rho_R/R_gas_R - call get_species_specific_heats_r(T_L, Cp_iL) - call get_species_specific_heats_r(T_R, Cp_iR) + ! call get_species_specific_heats_r(T_L, Cp_iL) + ! call get_species_specific_heats_r(T_R, Cp_iR) if (chem_params%gamma_method == 1) then ! gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. @@ -500,10 +500,10 @@ contains gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) else if (chem_params%gamma_method == 2) then ! gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. - call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) - call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) - call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) - call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) + ! call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) + ! call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) + ! call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) + ! call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) Gamm_L = Cp_L/Cv_L gamma_L = 1.0_wp/(Gamm_L - 1.0_wp) @@ -511,8 +511,8 @@ contains gamma_R = 1.0_wp/(Gamm_R - 1.0_wp) end if - call get_mixture_energy_mass(T_L, Ys_L, E_L) - call get_mixture_energy_mass(T_R, Ys_R, E_R) + ! call get_mixture_energy_mass(T_L, Ys_L, E_L) + ! call get_mixture_energy_mass(T_R, Ys_R, E_R) E_L = rho_L*E_L + 5.e-1*rho_L*vel_L_rms E_R = rho_R*E_R + 5.e-1*rho_R*vel_R_rms @@ -2445,8 +2445,8 @@ contains Ys_R(i - chemxb + 1) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) end do - call get_mixture_molecular_weight(Ys_L, MW_L) - call get_mixture_molecular_weight(Ys_R, MW_R) + ! call get_mixture_molecular_weight(Ys_L, MW_L) + ! call get_mixture_molecular_weight(Ys_R, MW_R) Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) @@ -2457,8 +2457,8 @@ contains T_L = pres_L/rho_L/R_gas_L T_R = pres_R/rho_R/R_gas_R - call get_species_specific_heats_r(T_L, Cp_iL) - call get_species_specific_heats_r(T_R, Cp_iR) + ! call get_species_specific_heats_r(T_L, Cp_iL) + ! call get_species_specific_heats_r(T_R, Cp_iR) if (chem_params%gamma_method == 1) then !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. @@ -2469,10 +2469,10 @@ contains gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) else if (chem_params%gamma_method == 2) then !> gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. - call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) - call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) - call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) - call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) + ! call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) + ! call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) + ! call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) + ! call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) Gamm_L = Cp_L/Cv_L gamma_L = 1.0_wp/(Gamm_L - 1.0_wp) @@ -2480,8 +2480,8 @@ contains gamma_R = 1.0_wp/(Gamm_R - 1.0_wp) end if - call get_mixture_energy_mass(T_L, Ys_L, E_L) - call get_mixture_energy_mass(T_R, Ys_R, E_R) + ! call get_mixture_energy_mass(T_L, Ys_L, E_L) + ! call get_mixture_energy_mass(T_R, Ys_R, E_R) E_L = rho_L*E_L + 5.e-1*rho_L*vel_L_rms E_R = rho_R*E_R + 5.e-1*rho_R*vel_R_rms diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index 61e04dee6f..b425a3a5cd 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -1361,9 +1361,9 @@ contains call acc_set_device_num(dev, devtype) #elif defined(MFC_OpenMP) - ! devNum = omp_get_num_devices() - ! dev = mod(local_rank, devNum) - ! call omp_set_default_device(dev) + devNum = omp_get_num_devices() + dev = mod(local_rank, devNum) + call omp_set_default_device(dev) #endif #endif diff --git a/src/syscheck/syscheck.fpp b/src/syscheck/syscheck.fpp index 80fe745491..75e18efc33 100644 --- a/src/syscheck/syscheck.fpp +++ b/src/syscheck/syscheck.fpp @@ -93,9 +93,9 @@ program syscheck @:ACCC('!$acc update host(arr(1:N))') @:ACCC('!$acc exit data delete(arr)') - ! @:OMPC('num_devices_omp = omp_get_num_devices()') - ! @:OMPC(call assert(num_devices_omp > 0)) - ! @:OMPC(call omp_set_default_device(mod(rank, nRanks))) + @:OMPC('num_devices_omp = omp_get_num_devices()') + @:OMPC(call assert(num_devices_omp > 0)) + @:OMPC(call omp_set_default_device(mod(rank, nRanks))) @:MPIC(call mpi_barrier(MPI_COMM_WORLD, ierr)) @:MPIC(call mpi_finalize(ierr)) From 94222f4c3a336d9ddca3d30cfe8ab4fa74301d74 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Thu, 24 Jul 2025 14:38:24 -0400 Subject: [PATCH 020/199] Remove LTO add always to data allocation omp, switch delete to release, add mappers to derived types, change how allocate is done --- CMakeLists.txt | 37 +- src/common/include/acc_macros.fpp | 26 ++ src/common/include/macros.fpp | 19 +- src/common/include/omp_macros.fpp | 2 +- src/common/include/parallel_macros.fpp | 38 -- src/common/include/shared_parallel_macros.fpp | 12 + src/common/m_derived_types.fpp | 395 ++++++++++++++---- 7 files changed, 376 insertions(+), 153 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b46571094e..af2941b7ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,18 +194,18 @@ elseif ((CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") OR (CMAKE_Fortran_COMPILER_ add_compile_options( $<$:-Mfreeform> $<$:-cpp> - # $<$:-Minfo=inline> + $<$:-Minfo=inline> $<$:-Minfo=accel> ) if (CMAKE_BUILD_TYPE STREQUAL "Debug") add_compile_options( $<$:-O0> - # $<$:-C> - # $<$:-g> - # $<$:-traceback> + $<$:-C> + $<$:-g> + $<$:-traceback> $<$:-Minform=inform> - # $<$:-Mbounds> + $<$:-Mbounds> ) endif() @@ -234,14 +234,14 @@ if (CMAKE_BUILD_TYPE STREQUAL "Release") elseif(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS "23.11") message(STATUS "LTO/IPO is not supported in NVHPC Version < 23.11. Use a newer version of NVHPC for best performance.") else() - message(STATUS "Performing IPO using -Mextract followed by -Minline") - set(NVHPC_USE_TWO_PASS_IPO TRUE) + # message(STATUS "Performing IPO using -Mextract followed by -Minline") + # set(NVHPC_USE_TWO_PASS_IPO TRUE) endif() else() CHECK_IPO_SUPPORTED(RESULT SUPPORTS_IPO OUTPUT IPO_ERROR) if (SUPPORTS_IPO) message(STATUS "Enabled IPO / LTO") - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + # set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) else() message(STATUS "IPO / LTO is NOT available") endif() @@ -401,14 +401,14 @@ function(MFC_SETUP_TARGET) # Here we need to split into "library" and "executable" to perform IPO on the NVIDIA compiler. # A little hacky, but it *is* an edge-case for *one* compiler. if (NVHPC_USE_TWO_PASS_IPO) - add_library(${ARGS_TARGET}_lib OBJECT ${ARGS_SOURCES}) - target_compile_options(${ARGS_TARGET}_lib PRIVATE - $<$:-Mextract=lib:${ARGS_TARGET}_lib> - $<$:-Minline> - ) - add_dependencies(${ARGS_TARGET} ${ARGS_TARGET}_lib) - target_compile_options(${ARGS_TARGET} PRIVATE -Minline=lib:${ARGS_TARGET}_lib) - list(PREPEND IPO_TARGETS ${ARGS_TARGET}_lib) + # add_library(${ARGS_TARGET}_lib OBJECT ${ARGS_SOURCES}) + # target_compile_options(${ARGS_TARGET}_lib PRIVATE + # $<$:-Mextract=lib:${ARGS_TARGET}_lib> + # $<$:-Minline> + # ) + # add_dependencies(${ARGS_TARGET} ${ARGS_TARGET}_lib) + # target_compile_options(${ARGS_TARGET} PRIVATE -Minline=lib:${ARGS_TARGET}_lib) + # list(PREPEND IPO_TARGETS ${ARGS_TARGET}_lib) endif() foreach (a_target ${IPO_TARGETS}) @@ -481,11 +481,12 @@ function(MFC_SETUP_TARGET) message(FATAL_ERROR "OpenMP + Fortran is unsupported.") endif() set(ENV{OMP_TARGET_OFFLOAD} [MANDATORY]) - target_link_libraries(${a_target} PRIVATE OpenMP::OpenMP_Fortran) + # target_link_libraries(${a_target} PRIVATE OpenMP::OpenMP_Fortran) target_compile_definitions(${a_target} PRIVATE MFC_OpenMP MFC_GPU) if(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC" OR CMAKE_Fortran_COMPILER_ID STREQUAL "PGI") - target_compile_options(${a_target} PRIVATE "-target=gpu" "-Minfo=mp") + target_compile_options(${a_target} PRIVATE "-mp=gpu" "-Minfo=mp") + target_link_options(${a_target} PRIVATE "-mp=gpu") set_target_properties(${a_target} PROPERTIES Fortran_FLAGS "-mp=gpu -gpu=ccall") elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") target_compile_options(${a_target} PRIVATE -fopenmp -fopenmp-targets=spir64) diff --git a/src/common/include/acc_macros.fpp b/src/common/include/acc_macros.fpp index d5efabb67f..acb8672660 100644 --- a/src/common/include/acc_macros.fpp +++ b/src/common/include/acc_macros.fpp @@ -60,6 +60,32 @@ $:link_val #:enddef +#:def GEN_DEFAULT_STR(default) + #:if default is not None + #:assert isinstance(default, str) + #:assert (default == 'present' or default == 'none') + #:set default_val = 'default(' + default + ') ' + #:else + #:set default_val = '' + #:endif + $:default_val +#:enddef + +#:def GEN_HOST_STR(host) + #:set host_val = GEN_PARENTHESES_CLAUSE('host', host) + $:host_val +#:enddef + +#:def GEN_DEVICE_STR(device) + #:set device_val = GEN_PARENTHESES_CLAUSE('device', device) + $:device_val +#:enddef + +#:def GEN_USE_DEVICE_STR(use_device) + #:set use_device_val = GEN_PARENTHESES_CLAUSE('use_device', use_device) + $:use_device_val +#:enddef + #:def ACC_PARALLEL(code, private=None, default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None) diff --git a/src/common/include/macros.fpp b/src/common/include/macros.fpp index c1652388c3..d508d1f98f 100644 --- a/src/common/include/macros.fpp +++ b/src/common/include/macros.fpp @@ -13,10 +13,21 @@ #:enddef #:def ALLOCATE(*args) - @:LOG({'@:ALLOCATE(${re.sub(' +', ' ', ', '.join(args))}$)'}) - #:set allocated_variables = ', '.join(args) - allocate (${allocated_variables}$) - $:GPU_ENTER_DATA(create=('[' + allocated_variables + ']')) + @:LOG({'@:ALLOCATE(${re.sub(' +', ' ', ', '.join(args))}$)'}) + #:set allocated_variables = ', '.join(args) + allocate (${allocated_variables}$) + #:set cleaned = [] + #:for a in args + #:set s = a.rstrip() + #:if s.endswith(')') + #:set rev = s[::-1] + #:set pos = next(i for i, ch, d in ( (j, c, sum(1 if t==')' else -1 if t=='(' else 0 for t in rev[:j+1])) for j, c in enumerate(rev) ) if ch == '(' and d == 0 ) + #:set s = s[:len(s)-1-pos] + #:endif + $:cleaned.append(s) + #:endfor + #:set joined = ', '.join(cleaned) + $:GPU_ENTER_DATA(create='[' + joined + ']') #:enddef ALLOCATE #:def DEALLOCATE(*args) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 7719a33411..1b5bac0126 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -44,7 +44,7 @@ #:enddef #:def OMP_CREATE_STR(create) - #:set create_val = OMP_MAP_STR('alloc', create) + #:set create_val = OMP_MAP_STR('always,alloc', create) $:create_val #:enddef diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index 7fbb346bb9..afc6d83651 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -17,44 +17,6 @@ $:parallelism_val #:enddef -#:def GEN_COLLAPSE_STR(collapse) - #:if collapse is not None - #:set collapse = int(collapse) - #:assert isinstance(collapse, int) - #:assert collapse > 1 - #:set collapse_val = 'collapse(' + str(collapse) + ') ' - #:else - #:set collapse_val = '' - #:endif - $:collapse_val -#:enddef - -#:def GEN_DEFAULT_STR(default) - #:if default is not None - #:assert isinstance(default, str) - #:assert (default == 'present' or default == 'none') - #:set default_val = 'default(' + default + ') ' - #:else - #:set default_val = '' - #:endif - $:default_val -#:enddef - -#:def GEN_HOST_STR(host) - #:set host_val = GEN_PARENTHESES_CLAUSE('host', host) - $:host_val -#:enddef - -#:def GEN_DEVICE_STR(device) - #:set device_val = GEN_PARENTHESES_CLAUSE('device', device) - $:device_val -#:enddef - -#:def GEN_USE_DEVICE_STR(use_device) - #:set use_device_val = GEN_PARENTHESES_CLAUSE('use_device', use_device) - $:use_device_val -#:enddef - #:def GPU_PARALLEL(code, private=None, default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None, extraOmpArgs=None) diff --git a/src/common/include/shared_parallel_macros.fpp b/src/common/include/shared_parallel_macros.fpp index a2039fd2a4..61134a3df3 100644 --- a/src/common/include/shared_parallel_macros.fpp +++ b/src/common/include/shared_parallel_macros.fpp @@ -86,6 +86,18 @@ $:reduction_val #:enddef +#:def GEN_COLLAPSE_STR(collapse) + #:if collapse is not None + #:set collapse = int(collapse) + #:assert isinstance(collapse, int) + #:assert collapse > 1 + #:set collapse_val = 'collapse(' + str(collapse) + ') ' + #:else + #:set collapse_val = '' + #:endif + $:collapse_val +#:enddef + #:def GEN_EXTRA_ARGS_STR(extraArgs) #:if extraArgs is not None #:assert isinstance(extraArgs, str) diff --git a/src/common/m_derived_types.fpp b/src/common/m_derived_types.fpp index 38674af615..e069567bfd 100644 --- a/src/common/m_derived_types.fpp +++ b/src/common/m_derived_types.fpp @@ -1,75 +1,101 @@ !> !! @file m_derived_types.f90 !! @brief Contains module m_derived_types - -#:include "macros.fpp" - +! New line at end of file is required for FYPP# 2 "/storage/home/hcoda1/5/tprathi3/OSPO/MFC-prathi.git/openmp/src/common/include/parallel_macros.fpp" 2 +! New line at end of file is required for FYPP# 2 "/storage/home/hcoda1/5/tprathi3/OSPO/MFC-prathi.git/openmp/src/common/include/omp_macros.fpp" 2 +! New line at end of file is required for FYPP# 3 "/storage/home/hcoda1/5/tprathi3/OSPO/MFC-prathi.git/openmp/src/common/include/parallel_macros.fpp" 2 +! New line at end of file is required for FYPP# 2 "/storage/home/hcoda1/5/tprathi3/OSPO/MFC-prathi.git/openmp/src/common/include/acc_macros.fpp" 2 +! New line at end of file is required for FYPP# 4 "/storage/home/hcoda1/5/tprathi3/OSPO/MFC-prathi.git/openmp/src/common/include/parallel_macros.fpp" 2 +! New line at end of file is required for FYPP +! New line at end of file is required for FYPP !> @brief This file contains the definitions of all of the custom-defined !! types used in the pre-process code. module m_derived_types - use m_constants !< Constants - use m_precision_select use m_thermochem, only: num_species - implicit none - !> Derived type adding the field position (fp) as an attribute type field_position real(wp), allocatable, dimension(:, :, :) :: fp !< Field position end type field_position - +!$omp declare mapper (field_position::x) map ( & +!$omp x%fp & +!$omp ) !> Derived type annexing a scalar field (SF) type scalar_field real(wp), pointer, dimension(:, :, :) :: sf => null() end type scalar_field - +!$omp declare mapper (scalar_field::x) map ( & +!$omp x%sf & +!$omp ) !> Derived type for bubble variables pb and mv at quadrature nodes (qbmm) type pres_field real(wp), pointer, dimension(:, :, :, :, :) :: sf => null() end type pres_field - +!$omp declare mapper (pres_field::x) map ( & +!$omp x%sf & +!$omp ) !> Derived type annexing an integer scalar field (SF) type integer_field integer, pointer, dimension(:, :, :) :: sf => null() end type integer_field - +!$omp declare mapper (integer_field::x) map ( & +!$omp x%sf & +!$omp ) !> Derived type for levelset type levelset_field real(wp), pointer, dimension(:, :, :, :) :: sf => null() end type levelset_field - +!$omp declare mapper (levelset_field::x) map ( & +!$omp x%sf & +!$omp ) !> Derived type for levelset norm type levelset_norm_field real(wp), pointer, dimension(:, :, :, :, :) :: sf => null() end type levelset_norm_field - +!$omp declare mapper (levelset_norm_field::x) map ( & +!$omp x%sf & +!$omp ) type mpi_io_var integer, allocatable, dimension(:) :: view type(scalar_field), allocatable, dimension(:) :: var end type mpi_io_var - +!$omp declare mapper (mpi_io_var::x) map ( & +!$omp x%view & +!$omp , x%var & +!$omp ) type mpi_io_ib_var integer :: view type(integer_field) :: var end type mpi_io_ib_var - +!$omp declare mapper (mpi_io_ib_var::x) map ( & +!$omp x%view & +!$omp , x%var & +!$omp ) type mpi_io_levelset_var integer :: view type(levelset_field) :: var end type mpi_io_levelset_var - +!$omp declare mapper (mpi_io_levelset_var::x) map ( & +!$omp x%view & +!$omp , x%var & +!$omp ) type mpi_io_levelset_norm_var integer :: view type(levelset_norm_field) :: var end type mpi_io_levelset_norm_var - +!$omp declare mapper (mpi_io_levelset_norm_var::x) map ( & +!$omp x%view & +!$omp , x%var & +!$omp ) !> Derived type annexing a vector field (VF) type vector_field type(scalar_field), allocatable, dimension(:) :: vf !< Vector field end type vector_field - +!$omp declare mapper (vector_field::x) map ( & +!$omp x%vf & +!$omp ) !> Generic 3-component vector (e.g., spatial coordinates or field components) !! Named _dt (derived types: x,y,z) to differentiate from t_vec3 (3-component vector) type vec3_dt ! dt for derived types @@ -77,24 +103,33 @@ module m_derived_types real(wp) :: y real(wp) :: z end type vec3_dt - +!$omp declare mapper (vec3_dt::x) map ( & +!$omp x%x & +!$omp , x%y & +!$omp , x%z & +!$omp ) !> Left and right Riemann states type riemann_states real(wp) :: L real(wp) :: R end type riemann_states - +!$omp declare mapper (riemann_states::x) map ( & +!$omp x%L & +!$omp , x%R & +!$omp ) !> Left and right Riemann states for 3-component vectors type riemann_states_vec3 real(wp) :: L(3) real(wp) :: R(3) end type riemann_states_vec3 - +!$omp declare mapper (riemann_states_vec3::x) map ( & +!$omp x%L(3) & +!$omp , x%R(3) & +!$omp ) !> Integer bounds for variables type int_bounds_info integer :: beg integer :: end - real(wp) :: vb1 real(wp) :: vb2 real(wp) :: vb3 @@ -105,9 +140,26 @@ module m_derived_types real(wp), dimension(3) :: vel_in, vel_out real(wp), dimension(num_fluids_max) :: alpha_rho_in, alpha_in logical :: grcbc_in, grcbc_out, grcbc_vel_out - end type int_bounds_info - +!$omp declare mapper (int_bounds_info::x) map ( & +!$omp x%beg & +!$omp , x%end & +!$omp , x%vb1 & +!$omp , x%vb2 & +!$omp , x%vb3 & +!$omp , x%ve1 & +!$omp , x%ve2 & +!$omp , x%ve3 & +!$omp , x%pres_in & +!$omp , x%pres_out & +!$omp , x%vel_in & +!$omp , x%vel_out & +!$omp , x%alpha_rho_in & +!$omp , x%alpha_in & +!$omp , x%grcbc_in & +!$omp , x%grcbc_out & +!$omp , x%grcbc_vel_out & +!$omp ) type bc_patch_parameters integer :: geometry integer :: type @@ -117,13 +169,24 @@ module m_derived_types real(wp), dimension(3) :: length real(wp) :: radius end type bc_patch_parameters - +!$omp declare mapper (bc_patch_parameters::x) map ( & +!$omp x%geometry & +!$omp , x%type & +!$omp , x%dir & +!$omp , x%loc & +!$omp , x%centroid & +!$omp , x%length & +!$omp , x%radius & +!$omp ) !> Derived type adding beginning (beg) and end bounds info as attributes type bounds_info real(wp) :: beg real(wp) :: end end type bounds_info - +!$omp declare mapper (bounds_info::x) map ( & +!$omp x%beg & +!$omp , x%end & +!$omp ) !> bounds for the bubble dynamic variables type bub_bounds_info integer :: beg @@ -135,99 +198,108 @@ module m_derived_types integer, dimension(:, :), allocatable :: moms !< Moment indices for qbmm integer, dimension(:, :, :), allocatable :: fullmom !< Moment indices for qbmm end type bub_bounds_info - +!$omp declare mapper (bub_bounds_info::x) map ( & +!$omp x%beg & +!$omp , x%end & +!$omp , x%rs & +!$omp , x%vs & +!$omp , x%ps & +!$omp , x%ms & +!$omp , x%moms & +!$omp , x%fullmom & +!$omp ) !> Defines parameters for a Model Patch type ic_model_parameters character(LEN=pathlen_max) :: filepath !< !! Path the STL file relative to case_dir. - real(wp), dimension(1:3) :: translate !< !! Translation of the STL object. - real(wp), dimension(1:3) :: scale !< !! Scale factor for the STL object. - real(wp), dimension(1:3) :: rotate !< !! Angle to rotate the STL object along each cartesian coordinate axis, !! in radians. - integer :: spc !< !! Number of samples per cell to use when discretizing the STL object. - real(wp) :: threshold !< !! Threshold to turn on smoothen STL patch. end type ic_model_parameters - +!$omp declare mapper (ic_model_parameters::x) map ( & +!$omp x%filepath & +!$omp , x%translate & +!$omp , x%scale & +!$omp , x%rotate & +!$omp , x%spc & +!$omp , x%threshold & +!$omp ) type :: t_triangle real(wp), dimension(1:3, 1:3) :: v ! Vertices of the triangle real(wp), dimension(1:3) :: n ! Normal vector end type t_triangle - +!$omp declare mapper (t_triangle::x) map ( & +!$omp x%v & +!$omp , x%n & +!$omp ) type :: t_ray real(wp), dimension(1:3) :: o ! Origin real(wp), dimension(1:3) :: d ! Direction end type t_ray - +!$omp declare mapper (t_ray::x) map ( & +!$omp x%o & +!$omp , x%d & +!$omp ) type :: t_bbox real(wp), dimension(1:3) :: min ! Minimum coordinates real(wp), dimension(1:3) :: max ! Maximum coordinates end type t_bbox - +!$omp declare mapper (t_bbox::x) map ( & +!$omp x%min & +!$omp , x%max & +!$omp ) type :: t_model integer :: ntrs ! Number of triangles type(t_triangle), allocatable :: trs(:) ! Triangles end type t_model - +!$omp declare mapper (t_model::x) map ( & +!$omp x%ntrs & +!$omp , x%trs(:) & +!$omp ) !> Derived type adding initial condition (ic) patch parameters as attributes !! NOTE: The requirements for the specification of the above parameters !! are strongly dependent on both the choice of the multicomponent flow !! model as well as the choice of the patch geometry. type ic_patch_parameters - integer :: geometry !< Type of geometry for the patch - real(wp) :: x_centroid, y_centroid, z_centroid !< !! Location of the geometric center, i.e. the centroid, of the patch. It !! is specified through its x-, y- and z-coordinates, respectively. - real(wp) :: length_x, length_y, length_z !< Dimensions of the patch. x,y,z Lengths. real(wp) :: radius !< Dimensions of the patch. radius. - real(wp), dimension(3) :: radii !< !! Vector indicating the various radii for the elliptical and ellipsoidal !! patch geometries. It is specified through its x-, y-, and z-components !! respectively. - real(wp) :: epsilon, beta !< !! The isentropic vortex parameters for the amplitude of the disturbance and !! domain of influence. - real(wp), dimension(2:9) :: a !< !! The parameters needed for the spherical harmonic patch - logical :: non_axis_sym - real(wp), dimension(3) :: normal !< !! Normal vector indicating the orientation of the patch. It is specified !! through its x-, y- and z-components, respectively. - logical, dimension(0:num_patches_max - 1) :: alter_patch !< - !! List of permissions that indicate to the current patch which preceding !! patches it is allowed to overwrite when it is in process of being laid !! out in the domain - logical :: smoothen !< !! Permission indicating to the current patch whether its boundaries will !! be smoothed out across a few cells or whether they are to remain sharp - integer :: smooth_patch_id !< !! Identity (id) of the patch with which current patch is to get smoothed - real(wp) :: smooth_coeff !< !! Smoothing coefficient (coeff) for the size of the stencil of !! cells across which boundaries of the current patch will be smeared out - real(wp), dimension(num_fluids_max) :: alpha_rho real(wp) :: rho real(wp), dimension(3) :: vel @@ -238,88 +310,130 @@ module m_derived_types real(wp) :: cv !< real(wp) :: qv !< real(wp) :: qvp !< - !! Primitive variables associated with the patch. In order, these include !! the partial densities, density, velocity, pressure, volume fractions, !! specific heat ratio function and the liquid stiffness function. - real(wp) :: Bx, By, Bz !< !! Magnetic field components; B%x is not used for 1D - real(wp), dimension(6) :: tau_e !< !! Elastic stresses added to primitive variables if hypoelasticity = True - real(wp) :: R0 !< Bubble size real(wp) :: V0 !< Bubble velocity - real(wp) :: p0 !< Bubble size real(wp) :: m0 !< Bubble velocity - integer :: hcid !! id for hard coded initial condition - real(wp) :: cf_val !! color function value real(wp) :: Y(1:num_species) - !! STL or OBJ model input parameter character(LEN=pathlen_max) :: model_filepath !< !! Path the STL file relative to case_dir. - real(wp), dimension(1:3) :: model_translate !< !! Translation of the STL object. - real(wp), dimension(1:3) :: model_scale !< !! Scale factor for the STL object. - real(wp), dimension(1:3) :: model_rotate !< !! Angle to rotate the STL object along each cartesian coordinate axis, !! in radians. - integer :: model_spc !< !! Number of samples per cell to use when discretizing the STL object. - real(wp) :: model_threshold !< !! Threshold to turn on smoothen STL patch. - end type ic_patch_parameters - +!$omp declare mapper (ic_patch_parameters::x) map ( & +!$omp x%geometry & +!$omp , x%x_centroid & +!$omp , x%y_centroid & +!$omp , x%z_centroid & +!$omp , x%length_x & +!$omp , x%length_y & +!$omp , x%length_z & +!$omp , x%radius & +!$omp , x%radii & +!$omp , x%epsilon & +!$omp , x%beta & +!$omp , x%a & +!$omp , x%non_axis_sym & +!$omp , x%normal & +!$omp , x%alter_patch & +!$omp , x%smoothen & +!$omp , x%smooth_patch_id & +!$omp , x%smooth_coeff & +!$omp , x%alpha_rho & +!$omp , x%rho & +!$omp , x%vel & +!$omp , x%pres & +!$omp , x%alpha & +!$omp , x%gamma & +!$omp , x%pi_inf & +!$omp , x%cv & +!$omp , x%qv & +!$omp , x%qvp & +!$omp , x%Bx & +!$omp , x%By & +!$omp , x%Bz & +!$omp , x%tau_e & +!$omp , x%R0 & +!$omp , x%V0 & +!$omp , x%p0 & +!$omp , x%m0 & +!$omp , x%hcid & +!$omp , x%cf_val & +!$omp , x%Y(1:num_species) & +!$omp , x%model_filepath & +!$omp , x%model_translate & +!$omp , x%model_scale & +!$omp , x%model_rotate & +!$omp , x%model_spc & +!$omp , x%model_threshold & +!$omp ) type ib_patch_parameters - integer :: geometry !< Type of geometry for the patch - real(wp) :: x_centroid, y_centroid, z_centroid !< !! Location of the geometric center, i.e. the centroid, of the patch. It !! is specified through its x-, y- and z-coordinates, respectively. - real(wp) :: c, p, t, m - real(wp) :: length_x, length_y, length_z !< Dimensions of the patch. x,y,z Lengths. real(wp) :: radius !< Dimensions of the patch. radius. real(wp) :: theta - logical :: slip - !! STL or OBJ model input parameter character(LEN=pathlen_max) :: model_filepath !< !! Path the STL file relative to case_dir. - real(wp), dimension(1:3) :: model_translate !< !! Translation of the STL object. - real(wp), dimension(1:3) :: model_scale !< !! Scale factor for the STL object. - real(wp), dimension(1:3) :: model_rotate !< !! Angle to rotate the STL object along each cartesian coordinate axis, !! in radians. - integer :: model_spc !< !! Number of samples per cell to use when discretizing the STL object. - real(wp) :: model_threshold !< !! Threshold to turn on smoothen STL patch. end type ib_patch_parameters - +!$omp declare mapper (ib_patch_parameters::x) map ( & +!$omp x%geometry & +!$omp , x%x_centroid & +!$omp , x%y_centroid & +!$omp , x%z_centroid & +!$omp , x%c & +!$omp , x%p & +!$omp , x%t & +!$omp , x%m & +!$omp , x%length_x & +!$omp , x%length_y & +!$omp , x%length_z & +!$omp , x%radius & +!$omp , x%theta & +!$omp , x%slip & +!$omp , x%model_filepath & +!$omp , x%model_translate & +!$omp , x%model_scale & +!$omp , x%model_rotate & +!$omp , x%model_spc & +!$omp , x%model_threshold & +!$omp ) !> Derived type annexing the physical parameters (PP) of the fluids. These !! include the specific heat ratio function and liquid stiffness function. type physical_parameters @@ -339,12 +453,31 @@ module m_derived_types real(wp) :: cp_v real(wp) :: G end type physical_parameters - +!$omp declare mapper (physical_parameters::x) map ( & +!$omp x%gamma & +!$omp , x%pi_inf & +!$omp , x%Re & +!$omp , x%cv & +!$omp , x%qv & +!$omp , x%qvp & +!$omp , x%mul0 & +!$omp , x%ss & +!$omp , x%pv & +!$omp , x%gamma_v & +!$omp , x%M_v & +!$omp , x%mu_v & +!$omp , x%k_v & +!$omp , x%cp_v & +!$omp , x%G & +!$omp ) type mpi_io_airfoil_ib_var integer, dimension(2) :: view type(vec3_dt), allocatable, dimension(:) :: var end type mpi_io_airfoil_ib_var - +!$omp declare mapper (mpi_io_airfoil_ib_var::x) map ( & +!$omp x%view & +!$omp , x%var & +!$omp ) !> Derived type annexing integral regions type integral_parameters real(wp) :: xmin !< Min. boundary first coordinate direction @@ -354,7 +487,14 @@ module m_derived_types real(wp) :: zmin !< Min. boundary third coordinate direction real(wp) :: zmax !< Max. boundary third coordinate direction end type integral_parameters - +!$omp declare mapper (integral_parameters::x) map ( & +!$omp x%xmin & +!$omp , x%xmax & +!$omp , x%ymin & +!$omp , x%ymax & +!$omp , x%zmin & +!$omp , x%zmax & +!$omp ) !> Acoustic source parameters type acoustic_parameters integer :: pulse !< Type of pulse @@ -382,7 +522,32 @@ module m_derived_types integer :: element_on !< Element in the acoustic array to turn on integer :: bb_num_freq !< Number of frequencies in the broadband wave end type acoustic_parameters - +!$omp declare mapper (acoustic_parameters::x) map ( & +!$omp x%pulse & +!$omp , x%support & +!$omp , x%dipole & +!$omp , x%loc & +!$omp , x%mag & +!$omp , x%length & +!$omp , x%height & +!$omp , x%wavelength & +!$omp , x%frequency & +!$omp , x%gauss_sigma_dist & +!$omp , x%gauss_sigma_time & +!$omp , x%npulse & +!$omp , x%dir & +!$omp , x%delay & +!$omp , x%foc_length & +!$omp , x%aperture & +!$omp , x%element_spacing_angle & +!$omp , x%element_polygon_ratio & +!$omp , x%rotate_angle & +!$omp , x%bb_bandwidth & +!$omp , x%bb_lowest_freq & +!$omp , x%num_elements & +!$omp , x%element_on & +!$omp , x%bb_num_freq & +!$omp ) !> Acoustic source source_spatial pre-calculated values type source_spatial_type integer, dimension(:, :), allocatable :: coord !< List of grid points indices with non-zero source_spatial values @@ -390,7 +555,12 @@ module m_derived_types real(wp), dimension(:), allocatable :: angle !< List of angles with x-axis for mom source term vector real(wp), dimension(:, :), allocatable :: xyz_to_r_ratios !< List of [xyz]/r for mom source term vector end type source_spatial_type - +!$omp declare mapper (source_spatial_type::x) map ( & +!$omp x%coord & +!$omp , x%val & +!$omp , x%angle & +!$omp , x%xyz_to_r_ratios & +!$omp ) !> Ghost Point for Immersed Boundaries type ghost_point integer, dimension(3) :: loc !< Physical location of the ghost point @@ -401,28 +571,40 @@ module m_derived_types logical :: slip integer, dimension(3) :: DB end type ghost_point - +!$omp declare mapper (ghost_point::x) map ( & +!$omp x%loc & +!$omp , x%ip_loc & +!$omp , x%ip_grid & +!$omp , x%interp_coeffs & +!$omp , x%ib_patch_id & +!$omp , x%slip & +!$omp , x%DB & +!$omp ) !> Species parameters type species_parameters character(LEN=name_len) :: name !< Name of species end type species_parameters - +!$omp declare mapper (species_parameters::x) map ( & +!$omp x%name & +!$omp ) !> Chemistry parameters type chemistry_parameters character(LEN=name_len) :: cantera_file !< Path to Cantera file - logical :: diffusion logical :: reactions - !> Method of determining gamma. !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. !> gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. integer :: gamma_method end type chemistry_parameters - +!$omp declare mapper (chemistry_parameters::x) map ( & +!$omp x%cantera_file & +!$omp , x%diffusion & +!$omp , x%reactions & +!$omp , x%gamma_method & +!$omp ) !> Lagrangian bubble parameters type bubbles_lagrange_parameters - integer :: solver_approach !< 1: One-way coupling, 2: two-way coupling integer :: cluster_type !< Cluster model to find p_inf logical :: pressure_corrector !< Cell pressure correction term @@ -440,13 +622,42 @@ module m_derived_types real(wp) :: T0, Thost !< Reference temperature and host temperature real(wp) :: x0 !< Reference length real(wp) :: diffcoefvap !< Vapor diffusivity in the gas - end type bubbles_lagrange_parameters - +!$omp declare mapper (bubbles_lagrange_parameters::x) map ( & +!$omp x%solver_approach & +!$omp , x%cluster_type & +!$omp , x%pressure_corrector & +!$omp , x%smooth_type & +!$omp , x%heatTransfer_model & +!$omp , x%massTransfer_model & +!$omp , x%write_bubbles & +!$omp , x%write_bubbles_stats & +!$omp , x%nBubs_glb & +!$omp , x%epsilonb & +!$omp , x%charwidth & +!$omp , x%valmaxvoid & +!$omp , x%c0 & +!$omp , x%rho0 & +!$omp , x%T0 & +!$omp , x%Thost & +!$omp , x%x0 & +!$omp , x%diffcoefvap & +!$omp ) !> Max and min number of cells in a direction of each combination of x-,y-, and z- type cell_num_bounds integer :: mn_max, np_max, mp_max, mnp_max integer :: mn_min, np_min, mp_min, mnp_min end type cell_num_bounds - +!$omp declare mapper (cell_num_bounds::x) map ( & +!$omp x%mn_max & +!$omp , x%np_max & +!$omp , x%mp_max & +!$omp , x%mnp_max & +!$omp , x%mn_min & +!$omp , x%np_min & +!$omp , x%mp_min & +!$omp , x%mnp_min & +!$omp ) end module m_derived_types + +! Code was translated using: /media/shared/Documents/GitHub/OSPO/intel-application-migration-tool-for-openacc-to-openmp/simulation/src/intel-application-migration-tool-for-openacc-to-openmp -keep-binding-clauses=all simulation/p_main.fpp.f90 From 473d19d8976c3f737bf9cedb90f1e4619238849b Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Thu, 24 Jul 2025 16:26:20 -0400 Subject: [PATCH 021/199] Fixed parallel loop when no OpenMP or OpenACC --- src/common/include/acc_macros.fpp | 15 +++++++++++++++ src/common/include/parallel_macros.fpp | 16 ++-------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/common/include/acc_macros.fpp b/src/common/include/acc_macros.fpp index acb8672660..147473250d 100644 --- a/src/common/include/acc_macros.fpp +++ b/src/common/include/acc_macros.fpp @@ -86,6 +86,21 @@ $:use_device_val #:enddef +#:def GEN_PARALLELISM_STR(parallelism) + #:if parallelism is not None + #:assert isinstance(parallelism, str) + #:assert parallelism[0] == '[' and parallelism[-1] == ']' + #:set parallelism_list = [x.strip() for x in parallelism.strip('[]').split(',')] + $:ASSERT_LIST(parallelism_list, str) + #:assert all((element == 'gang' or element == 'worker' or & + & element == 'vector' or element == 'seq') for element in parallelism_list) + #:set parallelism_val = ' '.join(parallelism_list) + ' ' + #:else + #:set parallelism_val = '' + #:endif + $:parallelism_val +#:enddef + #:def ACC_PARALLEL(code, private=None, default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & & no_create=None, present=None, deviceptr=None, attach=None, extraAccArgs=None) diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index afc6d83651..114ebf7c47 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -2,20 +2,6 @@ #:include 'omp_macros.fpp' #:include 'acc_macros.fpp' -#:def GEN_PARALLELISM_STR(parallelism) - #:if parallelism is not None - #:assert isinstance(parallelism, str) - #:assert parallelism[0] == '[' and parallelism[-1] == ']' - #:set parallelism_list = [x.strip() for x in parallelism.strip('[]').split(',')] - $:ASSERT_LIST(parallelism_list, str) - #:assert all((element == 'gang' or element == 'worker' or & - & element == 'vector' or element == 'seq') for element in parallelism_list) - #:set parallelism_val = ' '.join(parallelism_list) + ' ' - #:else - #:set parallelism_val = '' - #:endif - $:parallelism_val -#:enddef #:def GPU_PARALLEL(code, private=None, default='present', firstprivate=None, reduction=None, reductionOp=None, & & copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, & @@ -46,6 +32,8 @@ $:acc_code #elif defined(MFC_OpenMP) $:omp_code +#else + $:code #endif #:enddef From 5703c19948870a5eda6fafdde1fe9249ca1a0833 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Fri, 25 Jul 2025 10:31:13 -0400 Subject: [PATCH 022/199] Update how allocate macro works, update riemann solver, and parallel loop --- src/common/include/macros.fpp | 30 ++++++++++++++-------------- src/common/include/omp_macros.fpp | 4 ++-- src/simulation/m_rhs.fpp | 8 +++++++- src/simulation/m_riemann_solvers.fpp | 23 +++++++++++---------- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/common/include/macros.fpp b/src/common/include/macros.fpp index d508d1f98f..f44aa96a63 100644 --- a/src/common/include/macros.fpp +++ b/src/common/include/macros.fpp @@ -13,21 +13,21 @@ #:enddef #:def ALLOCATE(*args) - @:LOG({'@:ALLOCATE(${re.sub(' +', ' ', ', '.join(args))}$)'}) - #:set allocated_variables = ', '.join(args) - allocate (${allocated_variables}$) - #:set cleaned = [] - #:for a in args - #:set s = a.rstrip() - #:if s.endswith(')') - #:set rev = s[::-1] - #:set pos = next(i for i, ch, d in ( (j, c, sum(1 if t==')' else -1 if t=='(' else 0 for t in rev[:j+1])) for j, c in enumerate(rev) ) if ch == '(' and d == 0 ) - #:set s = s[:len(s)-1-pos] - #:endif - $:cleaned.append(s) - #:endfor - #:set joined = ', '.join(cleaned) - $:GPU_ENTER_DATA(create='[' + joined + ']') + @:LOG({'@:ALLOCATE(${re.sub(' +', ' ', ', '.join(args))}$)'}) + #:set allocated_variables = ', '.join(args) + allocate (${allocated_variables}$) + #:set cleaned = [] + #:for a in args + #:set s = a.rstrip() + #:if s.endswith(')') + #:set rev = s[::-1] + #:set pos = next(i for i, ch, d in ( (j, c, sum(1 if t==')' else -1 if t=='(' else 0 for t in rev[:j+1])) for j, c in enumerate(rev) ) if ch == '(' and d == 0 ) + #:set s = s[:len(s)-1-pos] + #:endif + $:cleaned.append(s) + #:endfor + #:set joined = ', '.join(cleaned) + $:GPU_ENTER_DATA(create='[' + joined + ']') #:enddef ALLOCATE #:def DEALLOCATE(*args) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 1b5bac0126..e61c56ffac 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -160,7 +160,7 @@ & no_create_val.strip('\n') + present_val.strip('\n') + & & deviceptr_val.strip('\n') + attach_val.strip('\n') #! Hardcoding the parallelism for now - #:set omp_directive = '!$omp target teams loop bind(teams) ' + & + #:set omp_directive = '!$omp target teams loop ' + & & clause_val + extraOmpArgs_val.strip('\n') #:set omp_end_directive = '!$omp end target teams loop' $:omp_directive @@ -201,7 +201,7 @@ #! Not implemented yet #:def OMP_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraOmpArgs=None) #! loop is going to be ignored since all loops right now are seq - #:set temp = '' + #:set temp = '!$omp loop bind(thread)' $:temp #:enddef diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index 910420e10e..3dbf37386b 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -830,6 +830,9 @@ contains irx%beg = 0; iry%beg = 0; irz%beg = -1 end if irx%end = m; iry%end = n; irz%end = p + $:GPU_UPDATE(host='[qL_rsx_vf,qR_rsx_vf]') + print *, "L", qL_rsx_vf(100:300, 0, 0, 1) + print *, "R", qR_rsx_vf(100:300, 0, 0, 1) !Computing Riemann Solver Flux and Source Flux call nvtxStartRange("RHS-RIEMANN-SOLVER") @@ -849,6 +852,8 @@ contains flux_gsrc_n(id)%vf, & id, irx, iry, irz) call nvtxEndRange + $:GPU_UPDATE(host='[flux_n(1)%vf(1)%sf]') + print *, "FLUX", flux_n(1)%vf(1)%sf(100:300, 0, 0) ! Additional physics and source terms ! RHS addition for advection source @@ -1070,7 +1075,8 @@ contains end do end do #:endcall GPU_PARALLEL_LOOP - + $:GPU_UPDATE(host='[rhs_vf(1)%sf]') + print *, "RHS", rhs_vf(1)%sf(100:300, 0, 0) if (model_eqns == 3) then #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, pressure_val,flux_face1,flux_face2]') do q_loop = 0, p diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index d577f8a8b9..0406fd99bb 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -357,9 +357,9 @@ contains #:for NORM_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (norm_dir == ${NORM_DIR}$) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') - do l = is3%beg, is3%end - do k = is2%beg, is2%end + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp]', extraOmpArgs='defaultmap(firstprivate:scalar) bind(teams, parallel)') + do l = is3%beg, is3%end + do k = is2%beg, is2%end do j = is1%beg, is1%end $:GPU_LOOP(parallelism='[seq]') do i = 1, contxe @@ -480,8 +480,8 @@ contains ! call get_mixture_molecular_weight(Ys_L, MW_L) ! call get_mixture_molecular_weight(Ys_R, MW_R) - Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) - Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) + ! Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) + ! Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) R_gas_L = gas_constant/MW_L R_gas_R = gas_constant/MW_R @@ -496,8 +496,8 @@ contains Gamma_iL = Cp_iL/(Cp_iL - 1.0_wp) Gamma_iR = Cp_iR/(Cp_iR - 1.0_wp) - gamma_L = sum(Xs_L(:)/(Gamma_iL(:) - 1.0_wp)) - gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) + ! gamma_L = sum(Xs_L(:)/(Gamma_iL(:) - 1.0_wp)) + ! gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) else if (chem_params%gamma_method == 2) then ! gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. ! call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) @@ -524,8 +524,8 @@ contains vdotB%L = vel_L(1)*B%L(1) + vel_L(2)*B%L(2) + vel_L(3)*B%L(3) vdotB%R = vel_R(1)*B%R(1) + vel_R(2)*B%R(2) + vel_R(3)*B%R(3) - b4%L(1:3) = B%L(1:3)/Ga%L + Ga%L*vel_L(1:3)*vdotB%L - b4%R(1:3) = B%R(1:3)/Ga%R + Ga%R*vel_R(1:3)*vdotB%R + ! b4%L(1:3) = B%L(1:3)/Ga%L + Ga%L*vel_L(1:3)*vdotB%L + ! b4%R(1:3) = B%R(1:3)/Ga%R + Ga%R*vel_R(1:3)*vdotB%R B2%L = B%L(1)**2._wp + B%L(2)**2._wp + B%L(3)**2._wp B2%R = B%R(1)**2._wp + B%R(2)**2._wp + B%R(3)**2._wp @@ -536,8 +536,8 @@ contains H_L = 1._wp + (gamma_L + 1)*pres_L/rho_L H_R = 1._wp + (gamma_R + 1)*pres_R/rho_R - cm%L(1:3) = (rho_L*H_L*Ga%L**2 + B2%L)*vel_L(1:3) - vdotB%L*B%L(1:3) - cm%R(1:3) = (rho_R*H_R*Ga%R**2 + B2%R)*vel_R(1:3) - vdotB%R*B%R(1:3) + ! cm%L(1:3) = (rho_L*H_L*Ga%L**2 + B2%L)*vel_L(1:3) - vdotB%L*B%L(1:3) + ! cm%R(1:3) = (rho_R*H_R*Ga%R**2 + B2%R)*vel_R(1:3) - vdotB%R*B%R(1:3) E_L = rho_L*H_L*Ga%L**2 - pres_L + 0.5_wp*(B2%L + vel_L_rms*B2%L - vdotB%L**2._wp) - rho_L*Ga%L E_R = rho_R*H_R*Ga%R**2 - pres_R + 0.5_wp*(B2%R + vel_R_rms*B2%R - vdotB%R**2._wp) - rho_R*Ga%R @@ -570,6 +570,7 @@ contains G_R = G_R*max((1._wp - qR_prim_rs${XYZ}$_vf(j, k, l, damage_idx)), 0._wp) end if + $:GPU_LOOP(parallelism='[seq]') do i = 1, strxe - strxb + 1 tau_e_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, strxb - 1 + i) tau_e_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, strxb - 1 + i) From 7021690665f870c6fa8eec447e87f9bd2972df28 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Fri, 25 Jul 2025 13:48:12 -0400 Subject: [PATCH 023/199] Passing most 1D cases --- src/common/include/omp_macros.fpp | 2 +- src/common/m_chemistry.fpp | 6 +- src/simulation/m_acoustic_src.fpp | 312 ++++++++++++------------- src/simulation/m_fftw.fpp | 1 - src/simulation/m_global_parameters.fpp | 2 +- src/simulation/m_rhs.fpp | 14 +- src/simulation/m_riemann_solvers.fpp | 18 +- 7 files changed, 177 insertions(+), 178 deletions(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index e61c56ffac..00735eae2c 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -160,7 +160,7 @@ & no_create_val.strip('\n') + present_val.strip('\n') + & & deviceptr_val.strip('\n') + attach_val.strip('\n') #! Hardcoding the parallelism for now - #:set omp_directive = '!$omp target teams loop ' + & + #:set omp_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams)' + & & clause_val + extraOmpArgs_val.strip('\n') #:set omp_end_directive = '!$omp end target teams loop' $:omp_directive diff --git a/src/common/m_chemistry.fpp b/src/common/m_chemistry.fpp index 92587d9de7..97dbcf2632 100644 --- a/src/common/m_chemistry.fpp +++ b/src/common/m_chemistry.fpp @@ -99,7 +99,7 @@ contains real(wp), dimension(num_species) :: Ys real(wp), dimension(num_species) :: omega - ! #:call GPU_PARALLEL_LOOP(collapse=3, private='[Ys, omega]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[Ys, omega]') do z = bounds(3)%beg, bounds(3)%end do y = bounds(2)%beg, bounds(2)%end do x = bounds(1)%beg, bounds(1)%end @@ -112,7 +112,7 @@ contains rho = q_cons_qp(contxe)%sf(x, y, z) T = q_T_sf%sf(x, y, z) - call get_net_production_rates(rho, T, Ys, omega) + ! call get_net_production_rates(rho, T, Ys, omega) $:GPU_LOOP(parallelism='[seq]') do eqn = chemxb, chemxe @@ -126,7 +126,7 @@ contains end do end do end do - ! #:endcall GPU_PARALLEL_LOOP + #:endcall GPU_PARALLEL_LOOP end subroutine s_compute_chemistry_reaction_flux diff --git a/src/simulation/m_acoustic_src.fpp b/src/simulation/m_acoustic_src.fpp index e92b61a58f..39f671ba7f 100644 --- a/src/simulation/m_acoustic_src.fpp +++ b/src/simulation/m_acoustic_src.fpp @@ -183,162 +183,162 @@ contains ! Keep outer loop sequel because different sources can have very different number of points do ai = 1, num_source ! Skip if the pulse has not started yet for sine and square waves - ! if (sim_time < delay(ai) .and. (pulse(ai) == 1 .or. pulse(ai) == 3)) cycle - - ! Decide if frequency need to be converted from wavelength - freq_conv_flag = f_is_default(frequency(ai)) - gauss_conv_flag = f_is_default(gauss_sigma_time(ai)) - - num_points = source_spatials_num_points(ai) ! Use scalar to force firstprivate to prevent GPU bug - - ! Calculate the broadband source - period_BB = 0._wp - sl_BB = 0._wp - ffre_BB = 0._wp - sum_BB = 0._wp - - ! Allocate buffers for random phase shift - allocate (phi_rn(1:bb_num_freq(ai))) - - if (pulse(ai) == 4) then - call random_number(phi_rn(1:bb_num_freq(ai))) - ! phi_rn(1:bb_num_freq(ai)) = 1 - ! Ensure all the ranks have the same random phase shift - call s_mpi_send_random_number(phi_rn, bb_num_freq(ai)) - end if - - $:GPU_LOOP(reduction='[[sum_BB]]', reductionOp='[+]') - do k = 1, bb_num_freq(ai) - ! Acoustic period of the wave at each discrete frequency - period_BB = 1._wp/(bb_lowest_freq(ai) + k*bb_bandwidth(ai)) - ! Spectral level at each frequency - sl_BB = broadband_spectral_level_constant*mag(ai) + k*mag(ai)/broadband_spectral_level_growth_rate - ! Source term corresponding to each frequencies - ffre_BB = sqrt((2._wp*sl_BB*bb_bandwidth(ai)))*cos((sim_time)*2._wp*pi/period_BB + 2._wp*pi*phi_rn(k)) - ! Sum up the source term of each frequency to obtain the total source term for broadband wave - sum_BB = sum_BB + ffre_BB - end do - - deallocate (phi_rn) - - #:call GPU_PARALLEL_LOOP(private='[myalpha,myalpha_rho]') - do i = 1, num_points - j = source_spatials(ai)%coord(1, i) - k = source_spatials(ai)%coord(2, i) - l = source_spatials(ai)%coord(3, i) - - ! Compute speed of sound - myRho = 0._wp - B_tait = 0._wp - small_gamma = 0._wp - - $:GPU_LOOP(parallelism='[seq]') - do q = 1, num_fluids - myalpha_rho(q) = q_cons_vf(q)%sf(j, k, l) - myalpha(q) = q_cons_vf(advxb + q - 1)%sf(j, k, l) - end do - - if (bubbles_euler) then - if (num_fluids > 2) then - $:GPU_LOOP(parallelism='[seq]') - do q = 1, num_fluids - 1 - myRho = myRho + myalpha_rho(q) - B_tait = B_tait + myalpha(q)*pi_infs(q) - small_gamma = small_gamma + myalpha(q)*gammas(q) - end do - else - myRho = myalpha_rho(1) - B_tait = pi_infs(1) - small_gamma = gammas(1) - end if - end if - - if ((.not. bubbles_euler) .or. (mpp_lim .and. (num_fluids > 2))) then - $:GPU_LOOP(parallelism='[seq]') - do q = 1, num_fluids - myRho = myRho + myalpha_rho(q) - B_tait = B_tait + myalpha(q)*pi_infs(q) - small_gamma = small_gamma + myalpha(q)*gammas(q) - end do - end if - - small_gamma = 1._wp/small_gamma + 1._wp - c = sqrt(small_gamma*(q_prim_vf(E_idx)%sf(j, k, l) + ((small_gamma - 1._wp)/small_gamma)*B_tait)/myRho) - - ! Wavelength to frequency conversion - if (pulse(ai) == 1 .or. pulse(ai) == 3) frequency_local = f_frequency_local(freq_conv_flag, ai, c) - if (pulse(ai) == 2) gauss_sigma_time_local = f_gauss_sigma_time_local(gauss_conv_flag, ai, c) - - ! Update momentum source term - call s_source_temporal(sim_time, c, ai, mom_label, frequency_local, gauss_sigma_time_local, source_temporal, sum_BB) - mom_src_diff = source_temporal*source_spatials(ai)%val(i) - - if (dipole(ai)) then ! Double amplitude & No momentum source term (only works for Planar) - mass_src(j, k, l) = mass_src(j, k, l) + 2._wp*mom_src_diff/c - if (model_eqns /= 4) E_src(j, k, l) = E_src(j, k, l) + 2._wp*mom_src_diff*c/(small_gamma - 1._wp) - cycle - end if - - if (n == 0) then ! 1D - mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*sign(1._wp, dir(ai)) ! Left or right-going wave - - elseif (p == 0) then ! 2D - if (support(ai) < 5) then ! Planar - mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(dir(ai)) - mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(dir(ai)) - else - mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(source_spatials(ai)%angle(i)) - mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(source_spatials(ai)%angle(i)) - end if - - else ! 3D - if (support(ai) < 5) then ! Planar - mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(dir(ai)) - mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(dir(ai)) - else - mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(1, i) - mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(2, i) - mom_src(3, j, k, l) = mom_src(3, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(3, i) - end if - end if - - ! Update mass source term - if (support(ai) < 5) then ! Planar - mass_src_diff = mom_src_diff/c - else ! Spherical or cylindrical support - ! Mass source term must be calculated differently using a correction term for spherical and cylindrical support - call s_source_temporal(sim_time, c, ai, mass_label, frequency_local, gauss_sigma_time_local, source_temporal, sum_BB) - mass_src_diff = source_temporal*source_spatials(ai)%val(i) - end if - mass_src(j, k, l) = mass_src(j, k, l) + mass_src_diff - - ! Update energy source term - if (model_eqns /= 4) then - E_src(j, k, l) = E_src(j, k, l) + mass_src_diff*c**2._wp/(small_gamma - 1._wp) - end if - - end do - #:endcall GPU_PARALLEL_LOOP - end do - - ! Update the rhs variables - #:call GPU_PARALLEL_LOOP(collapse=3) - do l = 0, p - do k = 0, n - do j = 0, m - $:GPU_LOOP(parallelism='[seq]') - do q = contxb, contxe - rhs_vf(q)%sf(j, k, l) = rhs_vf(q)%sf(j, k, l) + mass_src(j, k, l) - end do - $:GPU_LOOP(parallelism='[seq]') - do q = momxb, momxe - rhs_vf(q)%sf(j, k, l) = rhs_vf(q)%sf(j, k, l) + mom_src(q - contxe, j, k, l) - end do - rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + e_src(j, k, l) - end do - end do - end do - #:endcall GPU_PARALLEL_LOOP + if (not (sim_time < delay(ai) .and. (pulse(ai) == 1 .or. pulse(ai) == 3))) then + + ! Decide if frequency need to be converted from wavelength + freq_conv_flag = f_is_default(frequency(ai)) + gauss_conv_flag = f_is_default(gauss_sigma_time(ai)) + + num_points = source_spatials_num_points(ai) ! Use scalar to force firstprivate to prevent GPU bug + + ! Calculate the broadband source + period_BB = 0._wp + sl_BB = 0._wp + ffre_BB = 0._wp + sum_BB = 0._wp + + ! Allocate buffers for random phase shift + allocate (phi_rn(1:bb_num_freq(ai))) + + if (pulse(ai) == 4) then + call random_number(phi_rn(1:bb_num_freq(ai))) + ! Ensure all the ranks have the same random phase shift + call s_mpi_send_random_number(phi_rn, bb_num_freq(ai)) + end if + + $:GPU_LOOP(reduction='[[sum_BB]]', reductionOp='[+]') + do k = 1, bb_num_freq(ai) + ! Acoustic period of the wave at each discrete frequency + period_BB = 1._wp/(bb_lowest_freq(ai) + k*bb_bandwidth(ai)) + ! Spectral level at each frequency + sl_BB = broadband_spectral_level_constant*mag(ai) + k*mag(ai)/broadband_spectral_level_growth_rate + ! Source term corresponding to each frequencies + ffre_BB = sqrt((2._wp*sl_BB*bb_bandwidth(ai)))*cos((sim_time)*2._wp*pi/period_BB + 2._wp*pi*phi_rn(k)) + ! Sum up the source term of each frequency to obtain the total source term for broadband wave + sum_BB = sum_BB + ffre_BB + end do + + deallocate (phi_rn) + + #:call GPU_PARALLEL_LOOP(private='[myalpha,myalpha_rho]') + do i = 1, num_points + j = source_spatials(ai)%coord(1, i) + k = source_spatials(ai)%coord(2, i) + l = source_spatials(ai)%coord(3, i) + + ! Compute speed of sound + myRho = 0._wp + B_tait = 0._wp + small_gamma = 0._wp + + $:GPU_LOOP(parallelism='[seq]') + do q = 1, num_fluids + myalpha_rho(q) = q_cons_vf(q)%sf(j, k, l) + myalpha(q) = q_cons_vf(advxb + q - 1)%sf(j, k, l) + end do + + if (bubbles_euler) then + if (num_fluids > 2) then + $:GPU_LOOP(parallelism='[seq]') + do q = 1, num_fluids - 1 + myRho = myRho + myalpha_rho(q) + B_tait = B_tait + myalpha(q)*pi_infs(q) + small_gamma = small_gamma + myalpha(q)*gammas(q) + end do + else + myRho = myalpha_rho(1) + B_tait = pi_infs(1) + small_gamma = gammas(1) + end if + end if + + if ((.not. bubbles_euler) .or. (mpp_lim .and. (num_fluids > 2))) then + $:GPU_LOOP(parallelism='[seq]') + do q = 1, num_fluids + myRho = myRho + myalpha_rho(q) + B_tait = B_tait + myalpha(q)*pi_infs(q) + small_gamma = small_gamma + myalpha(q)*gammas(q) + end do + end if + + small_gamma = 1._wp/small_gamma + 1._wp + c = sqrt(small_gamma*(q_prim_vf(E_idx)%sf(j, k, l) + ((small_gamma - 1._wp)/small_gamma)*B_tait)/myRho) + + ! Wavelength to frequency conversion + if (pulse(ai) == 1 .or. pulse(ai) == 3) frequency_local = f_frequency_local(freq_conv_flag, ai, c) + if (pulse(ai) == 2) gauss_sigma_time_local = f_gauss_sigma_time_local(gauss_conv_flag, ai, c) + + ! Update momentum source term + call s_source_temporal(sim_time, c, ai, mom_label, frequency_local, gauss_sigma_time_local, source_temporal, sum_BB) + mom_src_diff = source_temporal*source_spatials(ai)%val(i) + + if (dipole(ai)) then ! Double amplitude & No momentum source term (only works for Planar) + mass_src(j, k, l) = mass_src(j, k, l) + 2._wp*mom_src_diff/c + if (model_eqns /= 4) E_src(j, k, l) = E_src(j, k, l) + 2._wp*mom_src_diff*c/(small_gamma - 1._wp) + cycle + end if + + if (n == 0) then ! 1D + mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*sign(1._wp, dir(ai)) ! Left or right-going wave + + elseif (p == 0) then ! 2D + if (support(ai) < 5) then ! Planar + mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(dir(ai)) + mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(dir(ai)) + else + mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(source_spatials(ai)%angle(i)) + mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(source_spatials(ai)%angle(i)) + end if + + else ! 3D + if (support(ai) < 5) then ! Planar + mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*cos(dir(ai)) + mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*sin(dir(ai)) + else + mom_src(1, j, k, l) = mom_src(1, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(1, i) + mom_src(2, j, k, l) = mom_src(2, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(2, i) + mom_src(3, j, k, l) = mom_src(3, j, k, l) + mom_src_diff*source_spatials(ai)%xyz_to_r_ratios(3, i) + end if + end if + + ! Update mass source term + if (support(ai) < 5) then ! Planar + mass_src_diff = mom_src_diff/c + else ! Spherical or cylindrical support + ! Mass source term must be calculated differently using a correction term for spherical and cylindrical support + call s_source_temporal(sim_time, c, ai, mass_label, frequency_local, gauss_sigma_time_local, source_temporal, sum_BB) + mass_src_diff = source_temporal*source_spatials(ai)%val(i) + end if + mass_src(j, k, l) = mass_src(j, k, l) + mass_src_diff + + ! Update energy source term + if (model_eqns /= 4) then + E_src(j, k, l) = E_src(j, k, l) + mass_src_diff*c**2._wp/(small_gamma - 1._wp) + end if + + end do + #:endcall GPU_PARALLEL_LOOP + end if + end do + + ! Update the rhs variables + #:call GPU_PARALLEL_LOOP(collapse=3) + do l = 0, p + do k = 0, n + do j = 0, m + $:GPU_LOOP(parallelism='[seq]') + do q = contxb, contxe + rhs_vf(q)%sf(j, k, l) = rhs_vf(q)%sf(j, k, l) + mass_src(j, k, l) + end do + $:GPU_LOOP(parallelism='[seq]') + do q = momxb, momxe + rhs_vf(q)%sf(j, k, l) = rhs_vf(q)%sf(j, k, l) + mom_src(q - contxe, j, k, l) + end do + rhs_vf(E_idx)%sf(j, k, l) = rhs_vf(E_idx)%sf(j, k, l) + e_src(j, k, l) + end do + end do + end do + #:endcall GPU_PARALLEL_LOOP end subroutine s_acoustic_src_calculations !> This subroutine gives the temporally varying amplitude of the pulse diff --git a/src/simulation/m_fftw.fpp b/src/simulation/m_fftw.fpp index 3211fce682..4ea2ac6934 100644 --- a/src/simulation/m_fftw.fpp +++ b/src/simulation/m_fftw.fpp @@ -52,7 +52,6 @@ module m_fftw complex(dp), allocatable, target :: data_cmplx_gpu(:) complex(dp), allocatable, target :: data_fltr_cmplx_gpu(:) $:GPU_DECLARE(create='[data_real_gpu,data_cmplx_gpu,data_fltr_cmplx_gpu]') - !$omp declare target (data_real_gpu,data_cmplx_gpu,data_fltr_cmplx_gpu) #if defined(__PGI) integer :: fwd_plan_gpu, bwd_plan_gpu diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp index c8a3b09d56..854e350781 100644 --- a/src/simulation/m_global_parameters.fpp +++ b/src/simulation/m_global_parameters.fpp @@ -182,7 +182,7 @@ module m_global_parameters #:endfor real(wp), dimension(3) :: accel_bf $:GPU_DECLARE(create='[accel_bf]') - $:GPU_DECLARE(create='[k_x,w_x,p_x,g_x,k_y,w_y,p_y,g_y,k_z,w_z,p_z,g_z]') + ! $:GPU_DECLARE(create='[k_x,w_x,p_x,g_x,k_y,w_y,p_y,g_y,k_z,w_z,p_z,g_z]') integer :: cpu_start, cpu_end, cpu_rate diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index 3dbf37386b..bb6ba2871e 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -830,9 +830,9 @@ contains irx%beg = 0; iry%beg = 0; irz%beg = -1 end if irx%end = m; iry%end = n; irz%end = p - $:GPU_UPDATE(host='[qL_rsx_vf,qR_rsx_vf]') - print *, "L", qL_rsx_vf(100:300, 0, 0, 1) - print *, "R", qR_rsx_vf(100:300, 0, 0, 1) + ! $:GPU_UPDATE(host='[qL_rsx_vf,qR_rsx_vf]') + ! print *, "L", qL_rsx_vf(100:300, 0, 0, 1) + ! print *, "R", qR_rsx_vf(100:300, 0, 0, 1) !Computing Riemann Solver Flux and Source Flux call nvtxStartRange("RHS-RIEMANN-SOLVER") @@ -852,8 +852,8 @@ contains flux_gsrc_n(id)%vf, & id, irx, iry, irz) call nvtxEndRange - $:GPU_UPDATE(host='[flux_n(1)%vf(1)%sf]') - print *, "FLUX", flux_n(1)%vf(1)%sf(100:300, 0, 0) + ! $:GPU_UPDATE(host='[flux_n(1)%vf(1)%sf]') + ! print *, "FLUX", flux_n(1)%vf(1)%sf(100:300, 0, 0) ! Additional physics and source terms ! RHS addition for advection source @@ -1075,8 +1075,8 @@ contains end do end do #:endcall GPU_PARALLEL_LOOP - $:GPU_UPDATE(host='[rhs_vf(1)%sf]') - print *, "RHS", rhs_vf(1)%sf(100:300, 0, 0) + ! $:GPU_UPDATE(host='[rhs_vf(1)%sf]') + ! print *, "RHS", rhs_vf(1)%sf(100:300, 0, 0) if (model_eqns == 3) then #:call GPU_PARALLEL_LOOP(collapse=4,private='[inv_ds,advected_qty_val, pressure_val,flux_face1,flux_face2]') do q_loop = 0, p diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index 0406fd99bb..039020248b 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -357,7 +357,7 @@ contains #:for NORM_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (norm_dir == ${NORM_DIR}$) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp]', extraOmpArgs='defaultmap(firstprivate:scalar) bind(teams, parallel)') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -480,8 +480,8 @@ contains ! call get_mixture_molecular_weight(Ys_L, MW_L) ! call get_mixture_molecular_weight(Ys_R, MW_R) - ! Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) - ! Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) + Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) + Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) R_gas_L = gas_constant/MW_L R_gas_R = gas_constant/MW_R @@ -496,8 +496,8 @@ contains Gamma_iL = Cp_iL/(Cp_iL - 1.0_wp) Gamma_iR = Cp_iR/(Cp_iR - 1.0_wp) - ! gamma_L = sum(Xs_L(:)/(Gamma_iL(:) - 1.0_wp)) - ! gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) + gamma_L = sum(Xs_L(:)/(Gamma_iL(:) - 1.0_wp)) + gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) else if (chem_params%gamma_method == 2) then ! gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. ! call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) @@ -524,8 +524,8 @@ contains vdotB%L = vel_L(1)*B%L(1) + vel_L(2)*B%L(2) + vel_L(3)*B%L(3) vdotB%R = vel_R(1)*B%R(1) + vel_R(2)*B%R(2) + vel_R(3)*B%R(3) - ! b4%L(1:3) = B%L(1:3)/Ga%L + Ga%L*vel_L(1:3)*vdotB%L - ! b4%R(1:3) = B%R(1:3)/Ga%R + Ga%R*vel_R(1:3)*vdotB%R + b4%L(1:3) = B%L(1:3)/Ga%L + Ga%L*vel_L(1:3)*vdotB%L + b4%R(1:3) = B%R(1:3)/Ga%R + Ga%R*vel_R(1:3)*vdotB%R B2%L = B%L(1)**2._wp + B%L(2)**2._wp + B%L(3)**2._wp B2%R = B%R(1)**2._wp + B%R(2)**2._wp + B%R(3)**2._wp @@ -536,8 +536,8 @@ contains H_L = 1._wp + (gamma_L + 1)*pres_L/rho_L H_R = 1._wp + (gamma_R + 1)*pres_R/rho_R - ! cm%L(1:3) = (rho_L*H_L*Ga%L**2 + B2%L)*vel_L(1:3) - vdotB%L*B%L(1:3) - ! cm%R(1:3) = (rho_R*H_R*Ga%R**2 + B2%R)*vel_R(1:3) - vdotB%R*B%R(1:3) + cm%L(1:3) = (rho_L*H_L*Ga%L**2 + B2%L)*vel_L(1:3) - vdotB%L*B%L(1:3) + cm%R(1:3) = (rho_R*H_R*Ga%R**2 + B2%R)*vel_R(1:3) - vdotB%R*B%R(1:3) E_L = rho_L*H_L*Ga%L**2 - pres_L + 0.5_wp*(B2%L + vel_L_rms*B2%L - vdotB%L**2._wp) - rho_L*Ga%L E_R = rho_R*H_R*Ga%R**2 - pres_R + 0.5_wp*(B2%R + vel_R_rms*B2%R - vdotB%R**2._wp) - rho_R*Ga%R From 828d9d89f54941286bf5d24362250e462ccd3a11 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Fri, 25 Jul 2025 16:25:02 -0400 Subject: [PATCH 024/199] Fixed IGR 2D, readded parallel loop in cbc, undid changes in derived types, removed rest of pure functions, fix issue with acoustic on nvfortran --- src/common/m_boundary_common.fpp | 46 ++- src/common/m_derived_types.fpp | 397 ++++++----------------- src/common/m_helper_basic.fpp | 2 +- src/post_process/m_derived_variables.fpp | 14 +- src/pre_process/m_assign_variables.fpp | 4 +- src/pre_process/m_compute_levelset.fpp | 14 +- src/pre_process/m_model.fpp | 24 +- src/pre_process/m_patches.fpp | 4 +- src/simulation/m_acoustic_src.fpp | 2 +- src/simulation/m_cbc.fpp | 4 +- 10 files changed, 147 insertions(+), 364 deletions(-) diff --git a/src/common/m_boundary_common.fpp b/src/common/m_boundary_common.fpp index 3c21279314..9c33009050 100644 --- a/src/common/m_boundary_common.fpp +++ b/src/common/m_boundary_common.fpp @@ -26,9 +26,6 @@ module m_boundary_common type(scalar_field), dimension(:, :), allocatable :: bc_buffers $:GPU_DECLARE(create='[bc_buffers]') - type(scalar_field), dimension(1) :: jac_sf - $:GPU_DECLARE(create='[jac_sf]') - #ifdef MFC_MPI integer, dimension(1:3, -1:1) :: MPI_BC_TYPE_TYPE, MPI_BC_BUFFER_TYPE #endif @@ -1475,16 +1472,13 @@ contains end subroutine s_color_function_ghost_cell_extrapolation - impure subroutine s_populate_F_igr_buffers(bc_type, jac) + impure subroutine s_populate_F_igr_buffers(bc_type, jac_sf) type(integer_field), dimension(1:num_dims, -1:1), intent(in) :: bc_type - real(wp), target, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:), intent(inout) :: jac + type(scalar_field), dimension(1:), intent(inout) :: jac_sf integer :: j, k, l - jac_sf(1)%sf => jac - $:GPU_UPDATE(device='[jac_sf(1)%sf]') - if (bc_x%beg >= 0) then call s_mpi_sendrecv_variables_buffers(jac_sf, 1, -1, 1) else @@ -1494,15 +1488,15 @@ contains select case (bc_type(1, -1)%sf(0, k, l)) case (BC_PERIODIC) do j = 1, buff_size - jac(-j, k, l) = jac(m - j + 1, k, l) + jac_sf(1)%sf(-j, k, l) = jac_sf(1)%sf(m - j + 1, k, l) end do case (BC_REFLECTIVE) do j = 1, buff_size - jac(-j, k, l) = jac(j - 1, k, l) + jac_sf(1)%sf(-j, k, l) = jac_sf(1)%sf(j - 1, k, l) end do case default do j = 1, buff_size - jac(-j, k, l) = jac(0, k, l) + jac_sf(1)%sf(-j, k, l) = jac_sf(1)%sf(0, k, l) end do end select end do @@ -1520,15 +1514,15 @@ contains select case (bc_type(1, 1)%sf(0, k, l)) case (BC_PERIODIC) do j = 1, buff_size - jac(m + j, k, l) = jac(j - 1, k, l) + jac_sf(1)%sf(m + j, k, l) = jac_sf(1)%sf(j - 1, k, l) end do case (BC_REFLECTIVE) do j = 1, buff_size - jac(m + j, k, l) = jac(m - (j - 1), k, l) + jac_sf(1)%sf(m + j, k, l) = jac_sf(1)%sf(m - (j - 1), k, l) end do case default do j = 1, buff_size - jac(m + j, k, l) = jac(m, k, l) + jac_sf(1)%sf(m + j, k, l) = jac_sf(1)%sf(m, k, l) end do end select end do @@ -1548,15 +1542,15 @@ contains select case (bc_type(2, -1)%sf(k, 0, l)) case (BC_PERIODIC) do j = 1, buff_size - jac(k, -j, l) = jac(k, n - j + 1, l) + jac_sf(1)%sf(k, -j, l) = jac_sf(1)%sf(k, n - j + 1, l) end do case (BC_REFLECTIVE) do j = 1, buff_size - jac(k, -j, l) = jac(k, j - 1, l) + jac_sf(1)%sf(k, -j, l) = jac_sf(1)%sf(k, j - 1, l) end do case default do j = 1, buff_size - jac(k, -j, l) = jac(k, 0, l) + jac_sf(1)%sf(k, -j, l) = jac_sf(1)%sf(k, 0, l) end do end select end do @@ -1574,15 +1568,15 @@ contains select case (bc_type(2, 1)%sf(k, 0, l)) case (BC_PERIODIC) do j = 1, buff_size - jac(k, n + j, l) = jac(k, j - 1, l) + jac_sf(1)%sf(k, n + j, l) = jac_sf(1)%sf(k, j - 1, l) end do case (BC_REFLECTIVE) do j = 1, buff_size - jac(k, n + j, l) = jac(k, n - (j - 1), l) + jac_sf(1)%sf(k, n + j, l) = jac_sf(1)%sf(k, n - (j - 1), l) end do case default do j = 1, buff_size - jac(k, n + j, l) = jac(k, n, l) + jac_sf(1)%sf(k, n + j, l) = jac_sf(1)%sf(k, n, l) end do end select end do @@ -1601,15 +1595,15 @@ contains select case (bc_type(3, -1)%sf(k, l, 0)) case (BC_PERIODIC) do j = 1, buff_size - jac(k, l, -j) = jac(k, l, p - j + 1) + jac_sf(1)%sf(k, l, -j) = jac_sf(1)%sf(k, l, p - j + 1) end do case (BC_REFLECTIVE) do j = 1, buff_size - jac(k, l, -j) = jac(k, l, j - 1) + jac_sf(1)%sf(k, l, -j) = jac_sf(1)%sf(k, l, j - 1) end do case default do j = 1, buff_size - jac(k, l, -j) = jac(k, l, 0) + jac_sf(1)%sf(k, l, -j) = jac_sf(1)%sf(k, l, 0) end do end select end do @@ -1626,15 +1620,15 @@ contains select case (bc_type(3, 1)%sf(k, l, 0)) case (BC_PERIODIC) do j = 1, buff_size - jac(k, l, p + j) = jac(k, l, j - 1) + jac_sf(1)%sf(k, l, p + j) = jac_sf(1)%sf(k, l, j - 1) end do case (BC_REFLECTIVE) do j = 1, buff_size - jac(k, l, p + j) = jac(k, l, p - (j - 1)) + jac_sf(1)%sf(k, l, p + j) = jac_sf(1)%sf(k, l, p - (j - 1)) end do case default do j = 1, buff_size - jac(k, l, p + j) = jac(k, l, p) + jac_sf(1)%sf(k, l, p + j) = jac_sf(1)%sf(k, l, p) end do end select end do diff --git a/src/common/m_derived_types.fpp b/src/common/m_derived_types.fpp index e069567bfd..23fcc87c13 100644 --- a/src/common/m_derived_types.fpp +++ b/src/common/m_derived_types.fpp @@ -1,101 +1,75 @@ !> !! @file m_derived_types.f90 !! @brief Contains module m_derived_types -! New line at end of file is required for FYPP# 2 "/storage/home/hcoda1/5/tprathi3/OSPO/MFC-prathi.git/openmp/src/common/include/parallel_macros.fpp" 2 -! New line at end of file is required for FYPP# 2 "/storage/home/hcoda1/5/tprathi3/OSPO/MFC-prathi.git/openmp/src/common/include/omp_macros.fpp" 2 -! New line at end of file is required for FYPP# 3 "/storage/home/hcoda1/5/tprathi3/OSPO/MFC-prathi.git/openmp/src/common/include/parallel_macros.fpp" 2 -! New line at end of file is required for FYPP# 2 "/storage/home/hcoda1/5/tprathi3/OSPO/MFC-prathi.git/openmp/src/common/include/acc_macros.fpp" 2 -! New line at end of file is required for FYPP# 4 "/storage/home/hcoda1/5/tprathi3/OSPO/MFC-prathi.git/openmp/src/common/include/parallel_macros.fpp" 2 -! New line at end of file is required for FYPP -! New line at end of file is required for FYPP + +#:include "macros.fpp" + !> @brief This file contains the definitions of all of the custom-defined !! types used in the pre-process code. module m_derived_types + use m_constants !< Constants + use m_precision_select use m_thermochem, only: num_species + implicit none + !> Derived type adding the field position (fp) as an attribute type field_position real(wp), allocatable, dimension(:, :, :) :: fp !< Field position end type field_position -!$omp declare mapper (field_position::x) map ( & -!$omp x%fp & -!$omp ) + !> Derived type annexing a scalar field (SF) type scalar_field real(wp), pointer, dimension(:, :, :) :: sf => null() end type scalar_field -!$omp declare mapper (scalar_field::x) map ( & -!$omp x%sf & -!$omp ) + !> Derived type for bubble variables pb and mv at quadrature nodes (qbmm) type pres_field real(wp), pointer, dimension(:, :, :, :, :) :: sf => null() end type pres_field -!$omp declare mapper (pres_field::x) map ( & -!$omp x%sf & -!$omp ) + !> Derived type annexing an integer scalar field (SF) type integer_field integer, pointer, dimension(:, :, :) :: sf => null() end type integer_field -!$omp declare mapper (integer_field::x) map ( & -!$omp x%sf & -!$omp ) + !> Derived type for levelset type levelset_field real(wp), pointer, dimension(:, :, :, :) :: sf => null() end type levelset_field -!$omp declare mapper (levelset_field::x) map ( & -!$omp x%sf & -!$omp ) + !> Derived type for levelset norm type levelset_norm_field real(wp), pointer, dimension(:, :, :, :, :) :: sf => null() end type levelset_norm_field -!$omp declare mapper (levelset_norm_field::x) map ( & -!$omp x%sf & -!$omp ) + type mpi_io_var integer, allocatable, dimension(:) :: view type(scalar_field), allocatable, dimension(:) :: var end type mpi_io_var -!$omp declare mapper (mpi_io_var::x) map ( & -!$omp x%view & -!$omp , x%var & -!$omp ) + type mpi_io_ib_var integer :: view type(integer_field) :: var end type mpi_io_ib_var -!$omp declare mapper (mpi_io_ib_var::x) map ( & -!$omp x%view & -!$omp , x%var & -!$omp ) + type mpi_io_levelset_var integer :: view type(levelset_field) :: var end type mpi_io_levelset_var -!$omp declare mapper (mpi_io_levelset_var::x) map ( & -!$omp x%view & -!$omp , x%var & -!$omp ) + type mpi_io_levelset_norm_var integer :: view type(levelset_norm_field) :: var end type mpi_io_levelset_norm_var -!$omp declare mapper (mpi_io_levelset_norm_var::x) map ( & -!$omp x%view & -!$omp , x%var & -!$omp ) + !> Derived type annexing a vector field (VF) type vector_field type(scalar_field), allocatable, dimension(:) :: vf !< Vector field end type vector_field -!$omp declare mapper (vector_field::x) map ( & -!$omp x%vf & -!$omp ) + !> Generic 3-component vector (e.g., spatial coordinates or field components) !! Named _dt (derived types: x,y,z) to differentiate from t_vec3 (3-component vector) type vec3_dt ! dt for derived types @@ -103,33 +77,24 @@ module m_derived_types real(wp) :: y real(wp) :: z end type vec3_dt -!$omp declare mapper (vec3_dt::x) map ( & -!$omp x%x & -!$omp , x%y & -!$omp , x%z & -!$omp ) + !> Left and right Riemann states type riemann_states real(wp) :: L real(wp) :: R end type riemann_states -!$omp declare mapper (riemann_states::x) map ( & -!$omp x%L & -!$omp , x%R & -!$omp ) + !> Left and right Riemann states for 3-component vectors type riemann_states_vec3 real(wp) :: L(3) real(wp) :: R(3) end type riemann_states_vec3 -!$omp declare mapper (riemann_states_vec3::x) map ( & -!$omp x%L(3) & -!$omp , x%R(3) & -!$omp ) + !> Integer bounds for variables type int_bounds_info integer :: beg integer :: end + real(wp) :: vb1 real(wp) :: vb2 real(wp) :: vb3 @@ -140,26 +105,9 @@ module m_derived_types real(wp), dimension(3) :: vel_in, vel_out real(wp), dimension(num_fluids_max) :: alpha_rho_in, alpha_in logical :: grcbc_in, grcbc_out, grcbc_vel_out + end type int_bounds_info -!$omp declare mapper (int_bounds_info::x) map ( & -!$omp x%beg & -!$omp , x%end & -!$omp , x%vb1 & -!$omp , x%vb2 & -!$omp , x%vb3 & -!$omp , x%ve1 & -!$omp , x%ve2 & -!$omp , x%ve3 & -!$omp , x%pres_in & -!$omp , x%pres_out & -!$omp , x%vel_in & -!$omp , x%vel_out & -!$omp , x%alpha_rho_in & -!$omp , x%alpha_in & -!$omp , x%grcbc_in & -!$omp , x%grcbc_out & -!$omp , x%grcbc_vel_out & -!$omp ) + type bc_patch_parameters integer :: geometry integer :: type @@ -169,24 +117,13 @@ module m_derived_types real(wp), dimension(3) :: length real(wp) :: radius end type bc_patch_parameters -!$omp declare mapper (bc_patch_parameters::x) map ( & -!$omp x%geometry & -!$omp , x%type & -!$omp , x%dir & -!$omp , x%loc & -!$omp , x%centroid & -!$omp , x%length & -!$omp , x%radius & -!$omp ) + !> Derived type adding beginning (beg) and end bounds info as attributes type bounds_info real(wp) :: beg real(wp) :: end end type bounds_info -!$omp declare mapper (bounds_info::x) map ( & -!$omp x%beg & -!$omp , x%end & -!$omp ) + !> bounds for the bubble dynamic variables type bub_bounds_info integer :: beg @@ -198,108 +135,99 @@ module m_derived_types integer, dimension(:, :), allocatable :: moms !< Moment indices for qbmm integer, dimension(:, :, :), allocatable :: fullmom !< Moment indices for qbmm end type bub_bounds_info -!$omp declare mapper (bub_bounds_info::x) map ( & -!$omp x%beg & -!$omp , x%end & -!$omp , x%rs & -!$omp , x%vs & -!$omp , x%ps & -!$omp , x%ms & -!$omp , x%moms & -!$omp , x%fullmom & -!$omp ) + !> Defines parameters for a Model Patch type ic_model_parameters character(LEN=pathlen_max) :: filepath !< !! Path the STL file relative to case_dir. + real(wp), dimension(1:3) :: translate !< !! Translation of the STL object. + real(wp), dimension(1:3) :: scale !< !! Scale factor for the STL object. + real(wp), dimension(1:3) :: rotate !< !! Angle to rotate the STL object along each cartesian coordinate axis, !! in radians. + integer :: spc !< !! Number of samples per cell to use when discretizing the STL object. + real(wp) :: threshold !< !! Threshold to turn on smoothen STL patch. end type ic_model_parameters -!$omp declare mapper (ic_model_parameters::x) map ( & -!$omp x%filepath & -!$omp , x%translate & -!$omp , x%scale & -!$omp , x%rotate & -!$omp , x%spc & -!$omp , x%threshold & -!$omp ) + type :: t_triangle real(wp), dimension(1:3, 1:3) :: v ! Vertices of the triangle real(wp), dimension(1:3) :: n ! Normal vector end type t_triangle -!$omp declare mapper (t_triangle::x) map ( & -!$omp x%v & -!$omp , x%n & -!$omp ) + type :: t_ray real(wp), dimension(1:3) :: o ! Origin real(wp), dimension(1:3) :: d ! Direction end type t_ray -!$omp declare mapper (t_ray::x) map ( & -!$omp x%o & -!$omp , x%d & -!$omp ) + type :: t_bbox real(wp), dimension(1:3) :: min ! Minimum coordinates real(wp), dimension(1:3) :: max ! Maximum coordinates end type t_bbox -!$omp declare mapper (t_bbox::x) map ( & -!$omp x%min & -!$omp , x%max & -!$omp ) + type :: t_model integer :: ntrs ! Number of triangles type(t_triangle), allocatable :: trs(:) ! Triangles end type t_model -!$omp declare mapper (t_model::x) map ( & -!$omp x%ntrs & -!$omp , x%trs(:) & -!$omp ) + !> Derived type adding initial condition (ic) patch parameters as attributes !! NOTE: The requirements for the specification of the above parameters !! are strongly dependent on both the choice of the multicomponent flow !! model as well as the choice of the patch geometry. type ic_patch_parameters + integer :: geometry !< Type of geometry for the patch + real(wp) :: x_centroid, y_centroid, z_centroid !< !! Location of the geometric center, i.e. the centroid, of the patch. It !! is specified through its x-, y- and z-coordinates, respectively. + real(wp) :: length_x, length_y, length_z !< Dimensions of the patch. x,y,z Lengths. real(wp) :: radius !< Dimensions of the patch. radius. + real(wp), dimension(3) :: radii !< !! Vector indicating the various radii for the elliptical and ellipsoidal !! patch geometries. It is specified through its x-, y-, and z-components !! respectively. + real(wp) :: epsilon, beta !< !! The isentropic vortex parameters for the amplitude of the disturbance and !! domain of influence. + real(wp), dimension(2:9) :: a !< !! The parameters needed for the spherical harmonic patch + logical :: non_axis_sym + real(wp), dimension(3) :: normal !< !! Normal vector indicating the orientation of the patch. It is specified !! through its x-, y- and z-components, respectively. + logical, dimension(0:num_patches_max - 1) :: alter_patch !< + !! List of permissions that indicate to the current patch which preceding !! patches it is allowed to overwrite when it is in process of being laid !! out in the domain + logical :: smoothen !< !! Permission indicating to the current patch whether its boundaries will !! be smoothed out across a few cells or whether they are to remain sharp + integer :: smooth_patch_id !< !! Identity (id) of the patch with which current patch is to get smoothed + real(wp) :: smooth_coeff !< !! Smoothing coefficient (coeff) for the size of the stencil of !! cells across which boundaries of the current patch will be smeared out + real(wp), dimension(num_fluids_max) :: alpha_rho real(wp) :: rho real(wp), dimension(3) :: vel @@ -310,130 +238,88 @@ module m_derived_types real(wp) :: cv !< real(wp) :: qv !< real(wp) :: qvp !< + !! Primitive variables associated with the patch. In order, these include !! the partial densities, density, velocity, pressure, volume fractions, !! specific heat ratio function and the liquid stiffness function. + real(wp) :: Bx, By, Bz !< !! Magnetic field components; B%x is not used for 1D + real(wp), dimension(6) :: tau_e !< !! Elastic stresses added to primitive variables if hypoelasticity = True + real(wp) :: R0 !< Bubble size real(wp) :: V0 !< Bubble velocity + real(wp) :: p0 !< Bubble size real(wp) :: m0 !< Bubble velocity + integer :: hcid !! id for hard coded initial condition + real(wp) :: cf_val !! color function value real(wp) :: Y(1:num_species) + !! STL or OBJ model input parameter character(LEN=pathlen_max) :: model_filepath !< !! Path the STL file relative to case_dir. + real(wp), dimension(1:3) :: model_translate !< !! Translation of the STL object. + real(wp), dimension(1:3) :: model_scale !< !! Scale factor for the STL object. + real(wp), dimension(1:3) :: model_rotate !< !! Angle to rotate the STL object along each cartesian coordinate axis, !! in radians. + integer :: model_spc !< !! Number of samples per cell to use when discretizing the STL object. + real(wp) :: model_threshold !< !! Threshold to turn on smoothen STL patch. + end type ic_patch_parameters -!$omp declare mapper (ic_patch_parameters::x) map ( & -!$omp x%geometry & -!$omp , x%x_centroid & -!$omp , x%y_centroid & -!$omp , x%z_centroid & -!$omp , x%length_x & -!$omp , x%length_y & -!$omp , x%length_z & -!$omp , x%radius & -!$omp , x%radii & -!$omp , x%epsilon & -!$omp , x%beta & -!$omp , x%a & -!$omp , x%non_axis_sym & -!$omp , x%normal & -!$omp , x%alter_patch & -!$omp , x%smoothen & -!$omp , x%smooth_patch_id & -!$omp , x%smooth_coeff & -!$omp , x%alpha_rho & -!$omp , x%rho & -!$omp , x%vel & -!$omp , x%pres & -!$omp , x%alpha & -!$omp , x%gamma & -!$omp , x%pi_inf & -!$omp , x%cv & -!$omp , x%qv & -!$omp , x%qvp & -!$omp , x%Bx & -!$omp , x%By & -!$omp , x%Bz & -!$omp , x%tau_e & -!$omp , x%R0 & -!$omp , x%V0 & -!$omp , x%p0 & -!$omp , x%m0 & -!$omp , x%hcid & -!$omp , x%cf_val & -!$omp , x%Y(1:num_species) & -!$omp , x%model_filepath & -!$omp , x%model_translate & -!$omp , x%model_scale & -!$omp , x%model_rotate & -!$omp , x%model_spc & -!$omp , x%model_threshold & -!$omp ) + type ib_patch_parameters + integer :: geometry !< Type of geometry for the patch + real(wp) :: x_centroid, y_centroid, z_centroid !< !! Location of the geometric center, i.e. the centroid, of the patch. It !! is specified through its x-, y- and z-coordinates, respectively. + real(wp) :: c, p, t, m + real(wp) :: length_x, length_y, length_z !< Dimensions of the patch. x,y,z Lengths. real(wp) :: radius !< Dimensions of the patch. radius. real(wp) :: theta + logical :: slip + !! STL or OBJ model input parameter character(LEN=pathlen_max) :: model_filepath !< !! Path the STL file relative to case_dir. + real(wp), dimension(1:3) :: model_translate !< !! Translation of the STL object. + real(wp), dimension(1:3) :: model_scale !< !! Scale factor for the STL object. + real(wp), dimension(1:3) :: model_rotate !< !! Angle to rotate the STL object along each cartesian coordinate axis, !! in radians. + integer :: model_spc !< !! Number of samples per cell to use when discretizing the STL object. + real(wp) :: model_threshold !< !! Threshold to turn on smoothen STL patch. end type ib_patch_parameters -!$omp declare mapper (ib_patch_parameters::x) map ( & -!$omp x%geometry & -!$omp , x%x_centroid & -!$omp , x%y_centroid & -!$omp , x%z_centroid & -!$omp , x%c & -!$omp , x%p & -!$omp , x%t & -!$omp , x%m & -!$omp , x%length_x & -!$omp , x%length_y & -!$omp , x%length_z & -!$omp , x%radius & -!$omp , x%theta & -!$omp , x%slip & -!$omp , x%model_filepath & -!$omp , x%model_translate & -!$omp , x%model_scale & -!$omp , x%model_rotate & -!$omp , x%model_spc & -!$omp , x%model_threshold & -!$omp ) + !> Derived type annexing the physical parameters (PP) of the fluids. These !! include the specific heat ratio function and liquid stiffness function. type physical_parameters @@ -453,31 +339,12 @@ module m_derived_types real(wp) :: cp_v real(wp) :: G end type physical_parameters -!$omp declare mapper (physical_parameters::x) map ( & -!$omp x%gamma & -!$omp , x%pi_inf & -!$omp , x%Re & -!$omp , x%cv & -!$omp , x%qv & -!$omp , x%qvp & -!$omp , x%mul0 & -!$omp , x%ss & -!$omp , x%pv & -!$omp , x%gamma_v & -!$omp , x%M_v & -!$omp , x%mu_v & -!$omp , x%k_v & -!$omp , x%cp_v & -!$omp , x%G & -!$omp ) + type mpi_io_airfoil_ib_var integer, dimension(2) :: view type(vec3_dt), allocatable, dimension(:) :: var end type mpi_io_airfoil_ib_var -!$omp declare mapper (mpi_io_airfoil_ib_var::x) map ( & -!$omp x%view & -!$omp , x%var & -!$omp ) + !> Derived type annexing integral regions type integral_parameters real(wp) :: xmin !< Min. boundary first coordinate direction @@ -487,14 +354,7 @@ module m_derived_types real(wp) :: zmin !< Min. boundary third coordinate direction real(wp) :: zmax !< Max. boundary third coordinate direction end type integral_parameters -!$omp declare mapper (integral_parameters::x) map ( & -!$omp x%xmin & -!$omp , x%xmax & -!$omp , x%ymin & -!$omp , x%ymax & -!$omp , x%zmin & -!$omp , x%zmax & -!$omp ) + !> Acoustic source parameters type acoustic_parameters integer :: pulse !< Type of pulse @@ -522,32 +382,7 @@ module m_derived_types integer :: element_on !< Element in the acoustic array to turn on integer :: bb_num_freq !< Number of frequencies in the broadband wave end type acoustic_parameters -!$omp declare mapper (acoustic_parameters::x) map ( & -!$omp x%pulse & -!$omp , x%support & -!$omp , x%dipole & -!$omp , x%loc & -!$omp , x%mag & -!$omp , x%length & -!$omp , x%height & -!$omp , x%wavelength & -!$omp , x%frequency & -!$omp , x%gauss_sigma_dist & -!$omp , x%gauss_sigma_time & -!$omp , x%npulse & -!$omp , x%dir & -!$omp , x%delay & -!$omp , x%foc_length & -!$omp , x%aperture & -!$omp , x%element_spacing_angle & -!$omp , x%element_polygon_ratio & -!$omp , x%rotate_angle & -!$omp , x%bb_bandwidth & -!$omp , x%bb_lowest_freq & -!$omp , x%num_elements & -!$omp , x%element_on & -!$omp , x%bb_num_freq & -!$omp ) + !> Acoustic source source_spatial pre-calculated values type source_spatial_type integer, dimension(:, :), allocatable :: coord !< List of grid points indices with non-zero source_spatial values @@ -555,12 +390,7 @@ module m_derived_types real(wp), dimension(:), allocatable :: angle !< List of angles with x-axis for mom source term vector real(wp), dimension(:, :), allocatable :: xyz_to_r_ratios !< List of [xyz]/r for mom source term vector end type source_spatial_type -!$omp declare mapper (source_spatial_type::x) map ( & -!$omp x%coord & -!$omp , x%val & -!$omp , x%angle & -!$omp , x%xyz_to_r_ratios & -!$omp ) + !> Ghost Point for Immersed Boundaries type ghost_point integer, dimension(3) :: loc !< Physical location of the ghost point @@ -571,40 +401,28 @@ module m_derived_types logical :: slip integer, dimension(3) :: DB end type ghost_point -!$omp declare mapper (ghost_point::x) map ( & -!$omp x%loc & -!$omp , x%ip_loc & -!$omp , x%ip_grid & -!$omp , x%interp_coeffs & -!$omp , x%ib_patch_id & -!$omp , x%slip & -!$omp , x%DB & -!$omp ) + !> Species parameters type species_parameters character(LEN=name_len) :: name !< Name of species end type species_parameters -!$omp declare mapper (species_parameters::x) map ( & -!$omp x%name & -!$omp ) + !> Chemistry parameters type chemistry_parameters character(LEN=name_len) :: cantera_file !< Path to Cantera file + logical :: diffusion logical :: reactions + !> Method of determining gamma. !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. !> gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. integer :: gamma_method end type chemistry_parameters -!$omp declare mapper (chemistry_parameters::x) map ( & -!$omp x%cantera_file & -!$omp , x%diffusion & -!$omp , x%reactions & -!$omp , x%gamma_method & -!$omp ) + !> Lagrangian bubble parameters type bubbles_lagrange_parameters + integer :: solver_approach !< 1: One-way coupling, 2: two-way coupling integer :: cluster_type !< Cluster model to find p_inf logical :: pressure_corrector !< Cell pressure correction term @@ -622,42 +440,13 @@ module m_derived_types real(wp) :: T0, Thost !< Reference temperature and host temperature real(wp) :: x0 !< Reference length real(wp) :: diffcoefvap !< Vapor diffusivity in the gas + end type bubbles_lagrange_parameters -!$omp declare mapper (bubbles_lagrange_parameters::x) map ( & -!$omp x%solver_approach & -!$omp , x%cluster_type & -!$omp , x%pressure_corrector & -!$omp , x%smooth_type & -!$omp , x%heatTransfer_model & -!$omp , x%massTransfer_model & -!$omp , x%write_bubbles & -!$omp , x%write_bubbles_stats & -!$omp , x%nBubs_glb & -!$omp , x%epsilonb & -!$omp , x%charwidth & -!$omp , x%valmaxvoid & -!$omp , x%c0 & -!$omp , x%rho0 & -!$omp , x%T0 & -!$omp , x%Thost & -!$omp , x%x0 & -!$omp , x%diffcoefvap & -!$omp ) + !> Max and min number of cells in a direction of each combination of x-,y-, and z- type cell_num_bounds integer :: mn_max, np_max, mp_max, mnp_max integer :: mn_min, np_min, mp_min, mnp_min end type cell_num_bounds -!$omp declare mapper (cell_num_bounds::x) map ( & -!$omp x%mn_max & -!$omp , x%np_max & -!$omp , x%mp_max & -!$omp , x%mnp_max & -!$omp , x%mn_min & -!$omp , x%np_min & -!$omp , x%mp_min & -!$omp , x%mnp_min & -!$omp ) -end module m_derived_types - -! Code was translated using: /media/shared/Documents/GitHub/OSPO/intel-application-migration-tool-for-openacc-to-openmp/simulation/src/intel-application-migration-tool-for-openacc-to-openmp -keep-binding-clauses=all simulation/p_main.fpp.f90 + +end module m_derived_types \ No newline at end of file diff --git a/src/common/m_helper_basic.fpp b/src/common/m_helper_basic.fpp index 91eebe1992..e2dc0e8b14 100644 --- a/src/common/m_helper_basic.fpp +++ b/src/common/m_helper_basic.fpp @@ -161,7 +161,7 @@ contains !! @param m Number of cells in x-axis !! @param n Number of cells in y-axis !! @param p Number of cells in z-axis - pure elemental subroutine s_update_cell_bounds(bounds, m, n, p) + elemental subroutine s_update_cell_bounds(bounds, m, n, p) type(cell_num_bounds), intent(out) :: bounds integer, intent(in) :: m, n, p diff --git a/src/post_process/m_derived_variables.fpp b/src/post_process/m_derived_variables.fpp index d3f27f6e81..ce5e4bc07b 100644 --- a/src/post_process/m_derived_variables.fpp +++ b/src/post_process/m_derived_variables.fpp @@ -117,7 +117,7 @@ contains !! ratio. The latter is stored in the derived flow quantity !! storage variable, q_sf. !! @param q_sf Specific heat ratio - pure subroutine s_derive_specific_heat_ratio(q_sf) + subroutine s_derive_specific_heat_ratio(q_sf) real(wp), & dimension(-offset_x%beg:m + offset_x%end, & @@ -144,7 +144,7 @@ contains !! values of the liquid stiffness, which are stored in the !! derived flow quantity storage variable, q_sf. !! @param q_sf Liquid stiffness - pure subroutine s_derive_liquid_stiffness(q_sf) + subroutine s_derive_liquid_stiffness(q_sf) real(wp), & dimension(-offset_x%beg:m + offset_x%end, & @@ -173,7 +173,7 @@ contains !! derived flow quantity storage variable, q_sf. !! @param q_prim_vf Primitive variables !! @param q_sf Speed of sound - pure subroutine s_derive_sound_speed(q_prim_vf, q_sf) + subroutine s_derive_sound_speed(q_prim_vf, q_sf) type(scalar_field), & dimension(sys_size), & @@ -230,7 +230,7 @@ contains !! @param i Component indicator !! @param q_prim_vf Primitive variables !! @param q_sf Flux limiter - pure subroutine s_derive_flux_limiter(i, q_prim_vf, q_sf) + subroutine s_derive_flux_limiter(i, q_prim_vf, q_sf) integer, intent(in) :: i @@ -324,7 +324,7 @@ contains !! @param b right-hane-side !! @param sol Solution !! @param ndim Problem size - pure subroutine s_solve_linear_system(A, b, sol, ndim) + subroutine s_solve_linear_system(A, b, sol, ndim) integer, intent(in) :: ndim real(wp), dimension(ndim, ndim), intent(inout) :: A @@ -374,7 +374,7 @@ contains !! @param i Vorticity component indicator !! @param q_prim_vf Primitive variables !! @param q_sf Vorticity component - pure subroutine s_derive_vorticity_component(i, q_prim_vf, q_sf) + subroutine s_derive_vorticity_component(i, q_prim_vf, q_sf) integer, intent(in) :: i @@ -476,7 +476,7 @@ contains !! quantity storage variable, q_sf. !! @param q_prim_vf Primitive variables !! @param q_sf Q_M - pure subroutine s_derive_qm(q_prim_vf, q_sf) + subroutine s_derive_qm(q_prim_vf, q_sf) type(scalar_field), & dimension(sys_size), & intent(in) :: q_prim_vf diff --git a/src/pre_process/m_assign_variables.fpp b/src/pre_process/m_assign_variables.fpp index f1bfe06fa3..a4407266b3 100644 --- a/src/pre_process/m_assign_variables.fpp +++ b/src/pre_process/m_assign_variables.fpp @@ -102,7 +102,7 @@ contains !! @param eta pseudo volume fraction !! @param q_prim_vf Primitive variables !! @param patch_id_fp Array to track patch ids - pure subroutine s_assign_patch_mixture_primitive_variables(patch_id, j, k, l, & + subroutine s_assign_patch_mixture_primitive_variables(patch_id, j, k, l, & eta, q_prim_vf, patch_id_fp) $:GPU_ROUTINE(parallelism='[seq]') @@ -191,7 +191,7 @@ contains !! @param k the y-dir node index !! @param l the z-dir node index !! @param q_prim_vf Primitive variables - pure subroutine s_perturb_primitive(j, k, l, q_prim_vf) + subroutine s_perturb_primitive(j, k, l, q_prim_vf) integer, intent(in) :: j, k, l type(scalar_field), dimension(1:sys_size), intent(inout) :: q_prim_vf diff --git a/src/pre_process/m_compute_levelset.fpp b/src/pre_process/m_compute_levelset.fpp index 17f66f8d68..673a2aff5b 100644 --- a/src/pre_process/m_compute_levelset.fpp +++ b/src/pre_process/m_compute_levelset.fpp @@ -27,7 +27,7 @@ module m_compute_levelset contains - pure subroutine s_circle_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_circle_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -63,7 +63,7 @@ contains end subroutine s_circle_levelset - pure subroutine s_airfoil_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_airfoil_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -146,7 +146,7 @@ contains end subroutine s_airfoil_levelset - pure subroutine s_3D_airfoil_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_3D_airfoil_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -250,7 +250,7 @@ contains end subroutine s_3D_airfoil_levelset !> Initialize IBM module - pure subroutine s_rectangle_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_rectangle_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -347,7 +347,7 @@ contains end subroutine s_rectangle_levelset - pure subroutine s_cuboid_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_cuboid_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -464,7 +464,7 @@ contains end subroutine s_cuboid_levelset - pure subroutine s_sphere_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_sphere_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -501,7 +501,7 @@ contains end subroutine s_sphere_levelset - pure subroutine s_cylinder_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_cylinder_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm diff --git a/src/pre_process/m_model.fpp b/src/pre_process/m_model.fpp index 734e83f4af..03225a4b76 100644 --- a/src/pre_process/m_model.fpp +++ b/src/pre_process/m_model.fpp @@ -424,7 +424,7 @@ contains end subroutine s_model_write !> This procedure frees the memory allocated for an STL mesh. - pure subroutine s_model_free(model) + subroutine s_model_free(model) type(t_model), intent(inout) :: model @@ -532,7 +532,7 @@ contains !! @param ray Ray. !! @param triangle Triangle. !! @return True if the ray intersects the triangle, false otherwise. - pure elemental function f_intersects_triangle(ray, triangle) result(intersects) + elemental function f_intersects_triangle(ray, triangle) result(intersects) type(t_ray), intent(in) :: ray type(t_triangle), intent(in) :: triangle @@ -592,7 +592,7 @@ contains !! @param boundary_v Output boundary vertices/normals. !! @param boundary_vertex_count Output total boundary vertex count !! @param boundary_edge_count Output total boundary edge counts - pure subroutine f_check_boundary(model, boundary_v, boundary_vertex_count, boundary_edge_count) + subroutine f_check_boundary(model, boundary_v, boundary_vertex_count, boundary_edge_count) type(t_model), intent(in) :: model real(wp), allocatable, intent(out), dimension(:, :, :) :: boundary_v !< Output boundary vertices/normals integer, intent(out) :: boundary_vertex_count, boundary_edge_count !< Output boundary vertex/edge count @@ -705,7 +705,7 @@ contains !! @param edge Edges end points to be registered !! @param edge_index Edge index iterator !! @param edge_count Total number of edges - pure subroutine f_register_edge(temp_boundary_v, edge, edge_index, edge_count) + subroutine f_register_edge(temp_boundary_v, edge, edge_index, edge_count) integer, intent(inout) :: edge_index !< Edge index iterator integer, intent(inout) :: edge_count !< Total number of edges real(wp), intent(in), dimension(1:2, 1:2) :: edge !< Edges end points to be registered @@ -723,7 +723,7 @@ contains !! @param boundary_edge_count Output total number of boundary edges !! @param spacing Dimensions of the current levelset cell !! @param interpolate Logical output - pure subroutine f_check_interpolation_2D(boundary_v, boundary_edge_count, spacing, interpolate) + subroutine f_check_interpolation_2D(boundary_v, boundary_edge_count, spacing, interpolate) logical, intent(inout) :: interpolate !< Logical indicator of interpolation integer, intent(in) :: boundary_edge_count !< Number of boundary edges real(wp), intent(in), dimension(1:boundary_edge_count, 1:3, 1:2) :: boundary_v @@ -753,7 +753,7 @@ contains !! @param model Model to search in. !! @param spacing Dimensions of the current levelset cell !! @param interpolate Logical output - pure subroutine f_check_interpolation_3D(model, spacing, interpolate) + subroutine f_check_interpolation_3D(model, spacing, interpolate) logical, intent(inout) :: interpolate type(t_model), intent(in) :: model real(wp), dimension(1:3), intent(in) :: spacing @@ -799,7 +799,7 @@ contains !! @param spacing Dimensions of the current levelset cell !! @param interpolated_boundary_v Output all the boundary vertices of the interpolated 2D model !! @param total_vertices Total number of vertices after interpolation - pure subroutine f_interpolate_2D(boundary_v, boundary_edge_count, spacing, interpolated_boundary_v, total_vertices) + subroutine f_interpolate_2D(boundary_v, boundary_edge_count, spacing, interpolated_boundary_v, total_vertices) real(wp), intent(in), dimension(:, :, :) :: boundary_v real(wp), dimension(1:3), intent(in) :: spacing real(wp), allocatable, intent(inout), dimension(:, :) :: interpolated_boundary_v @@ -1042,7 +1042,7 @@ contains !! @param point The cell centers of the current level cell !! @param normals The output levelset normals !! @param distance The output levelset distance - pure subroutine f_distance_normals_3D(model, point, normals, distance) + subroutine f_distance_normals_3D(model, point, normals, distance) type(t_model), intent(IN) :: model real(wp), dimension(1:3), intent(in) :: point real(wp), dimension(1:3), intent(out) :: normals @@ -1104,7 +1104,7 @@ contains !! @param point The cell centers of the current levelset cell !! @param spacing Dimensions of the current levelset cell !! @return Distance which the levelset distance without interpolation - pure function f_distance(boundary_v, boundary_edge_count, point) result(distance) + function f_distance(boundary_v, boundary_edge_count, point) result(distance) integer, intent(in) :: boundary_edge_count real(wp), intent(in), dimension(1:boundary_edge_count, 1:3, 1:2) :: boundary_v real(wp), dimension(1:3), intent(in) :: point @@ -1134,7 +1134,7 @@ contains !! @param boundary_edge_count Output the total number of boundary edges !! @param point The cell centers of the current levelset cell !! @param normals Output levelset normals without interpolation - pure subroutine f_normals(boundary_v, boundary_edge_count, point, normals) + subroutine f_normals(boundary_v, boundary_edge_count, point, normals) integer, intent(in) :: boundary_edge_count real(wp), intent(in), dimension(1:boundary_edge_count, 1:3, 1:2) :: boundary_v real(wp), dimension(1:3), intent(in) :: point @@ -1169,7 +1169,7 @@ contains end subroutine f_normals !> This procedure calculates the barycentric facet area - pure subroutine f_tri_area(tri, tri_area) + subroutine f_tri_area(tri, tri_area) real(wp), dimension(1:3, 1:3), intent(in) :: tri real(wp), intent(out) :: tri_area real(wp), dimension(1:3) :: AB, AC, cross @@ -1192,7 +1192,7 @@ contains !! @param total_vertices Total number of vertices after interpolation !! @param point The cell centers of the current levelset cell !! @return Distance which the levelset distance without interpolation - pure function f_interpolated_distance(interpolated_boundary_v, total_vertices, point) result(distance) + function f_interpolated_distance(interpolated_boundary_v, total_vertices, point) result(distance) integer, intent(in) :: total_vertices real(wp), intent(in), dimension(1:total_vertices, 1:3) :: interpolated_boundary_v real(wp), dimension(1:3), intent(in) :: point diff --git a/src/pre_process/m_patches.fpp b/src/pre_process/m_patches.fpp index db09af9d1f..f1427a255f 100644 --- a/src/pre_process/m_patches.fpp +++ b/src/pre_process/m_patches.fpp @@ -2266,7 +2266,7 @@ contains end subroutine s_convert_cylindrical_to_cartesian_coord - pure function f_convert_cyl_to_cart(cyl) result(cart) + function f_convert_cyl_to_cart(cyl) result(cart) $:GPU_ROUTINE(parallelism='[seq]') @@ -2292,7 +2292,7 @@ contains !! @param myth Angle !! @param offset Thickness !! @param a Starting position - pure elemental function f_r(myth, offset, a) + elemental function f_r(myth, offset, a) $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: myth, offset, a real(wp) :: b diff --git a/src/simulation/m_acoustic_src.fpp b/src/simulation/m_acoustic_src.fpp index 39f671ba7f..e75b6629e0 100644 --- a/src/simulation/m_acoustic_src.fpp +++ b/src/simulation/m_acoustic_src.fpp @@ -183,7 +183,7 @@ contains ! Keep outer loop sequel because different sources can have very different number of points do ai = 1, num_source ! Skip if the pulse has not started yet for sine and square waves - if (not (sim_time < delay(ai) .and. (pulse(ai) == 1 .or. pulse(ai) == 3))) then + if (.not. (sim_time < delay(ai) .and. (pulse(ai) == 1 .or. pulse(ai) == 3))) then ! Decide if frequency need to be converted from wavelength freq_conv_flag = f_is_default(frequency(ai)) diff --git a/src/simulation/m_cbc.fpp b/src/simulation/m_cbc.fpp index 020833d6c2..e99f073205 100644 --- a/src/simulation/m_cbc.fpp +++ b/src/simulation/m_cbc.fpp @@ -773,7 +773,7 @@ contains end if ! FD2 or FD4 of RHS at j = 0 - ! #:call GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, dYs_ds, h_k, Cp_i, Gamma_i, Xs]') + #:call GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, dYs_ds, h_k, Cp_i, Gamma_i, Xs]') do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1104,7 +1104,7 @@ contains end do end do - ! #:endcall GPU_PARALLEL_LOOP + #:endcall GPU_PARALLEL_LOOP end if #:endfor From cb025117812e2baab8207955a2e72b63a219a452 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Fri, 25 Jul 2025 16:29:59 -0400 Subject: [PATCH 025/199] Forgot to add something for IGR and add back parallel loop for data output --- src/simulation/m_data_output.fpp | 4 ++-- src/simulation/m_igr.fpp | 12 ++++++++++-- src/simulation/m_start_up.fpp | 5 ++++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/simulation/m_data_output.fpp b/src/simulation/m_data_output.fpp index f39bdfc940..9f80df014e 100644 --- a/src/simulation/m_data_output.fpp +++ b/src/simulation/m_data_output.fpp @@ -279,7 +279,7 @@ contains integer :: j, k, l ! Computing Stability Criteria at Current Time-step - ! #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') do l = 0, p do k = 0, n do j = 0, m @@ -296,7 +296,7 @@ contains end do end do end do - ! #:endcall GPU_PARALLEL_LOOP + #:endcall GPU_PARALLEL_LOOP ! end: Computing Stability Criteria at Current Time-step diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index 59684c9e05..0bf904b220 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -23,10 +23,14 @@ module m_igr s_igr_sigma_x, & s_igr_flux_add, & s_finalize_igr_module + real(wp), allocatable, target, dimension(:, :, :) :: jac - real(wp), allocatable, dimension(:, :, :) :: jac, jac_rhs, jac_old + real(wp), allocatable, dimension(:, :, :) :: jac_rhs, jac_old $:GPU_DECLARE(create='[jac, jac_rhs, jac_old]') + type(scalar_field), dimension(1) :: jac_sf + $:GPU_DECLARE(create='[jac_sf]') + real(wp), allocatable, dimension(:, :) :: Res $:GPU_DECLARE(create='[Res]') @@ -161,6 +165,10 @@ contains end if #:endif + jac_sf(1)%sf => jac + $:GPU_ENTER_DATA(copyin='[jac_sf(1)%sf]') + $:GPU_ENTER_DATA(attach='[jac_sf(1)%sf]') + end subroutine s_initialize_igr_module subroutine s_igr_iterative_solve(q_cons_vf, bc_type, t_step) @@ -247,7 +255,7 @@ contains end do #:endcall GPU_PARALLEL_LOOP - call s_populate_F_igr_buffers(bc_type, jac) + call s_populate_F_igr_buffers(bc_type, jac_sf) if (igr_iter_solver == 1) then ! Jacobi iteration #:call GPU_PARALLEL_LOOP(collapse=3) diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index b425a3a5cd..8f950c6b50 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -1430,7 +1430,7 @@ contains $:GPU_UPDATE(device='[sigma, surface_tension]') $:GPU_UPDATE(device='[dx,dy,dz,x_cb,x_cc,y_cb,y_cc,z_cb,z_cc]') - +! #if defined(MFC_OpenACC) $:GPU_UPDATE(device='[bc_x%vb1,bc_x%vb2,bc_x%vb3,bc_x%ve1,bc_x%ve2,bc_x%ve3]') $:GPU_UPDATE(device='[bc_y%vb1,bc_y%vb2,bc_y%vb3,bc_y%ve1,bc_y%ve2,bc_y%ve3]') $:GPU_UPDATE(device='[bc_z%vb1,bc_z%vb2,bc_z%vb3,bc_z%ve1,bc_z%ve2,bc_z%ve3]') @@ -1438,6 +1438,9 @@ contains $:GPU_UPDATE(device='[bc_x%grcbc_in,bc_x%grcbc_out,bc_x%grcbc_vel_out]') $:GPU_UPDATE(device='[bc_y%grcbc_in,bc_y%grcbc_out,bc_y%grcbc_vel_out]') $:GPU_UPDATE(device='[bc_z%grcbc_in,bc_z%grcbc_out,bc_z%grcbc_vel_out]') +! #elif defined(MFC_OpenMP) +! $:GPU_UPDATE(device='[bc_x,bc_y,bc_z]') +! #endif $:GPU_UPDATE(device='[relax, relax_model]') if (relax) then From 69b579247eac95799a3e25b222e0976107d047d6 Mon Sep 17 00:00:00 2001 From: Anand Radhakrishnan Date: Mon, 28 Jul 2025 10:01:01 -0400 Subject: [PATCH 026/199] change binding + test suite works --- src/common/include/omp_macros.fpp | 4 ++-- src/simulation/m_ibm.fpp | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 00735eae2c..3ae7927943 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -160,7 +160,7 @@ & no_create_val.strip('\n') + present_val.strip('\n') + & & deviceptr_val.strip('\n') + attach_val.strip('\n') #! Hardcoding the parallelism for now - #:set omp_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams)' + & + #:set omp_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel)' + & & clause_val + extraOmpArgs_val.strip('\n') #:set omp_end_directive = '!$omp end target teams loop' $:omp_directive @@ -295,4 +295,4 @@ #:set omp_directive = '!$omp barrier ' + clause_val + extraOmpArgs_val.strip('\n') $:omp_directive #:enddef -! New line at end of file is required for FYPP \ No newline at end of file +! New line at end of file is required for FYPP diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index 668a15d41e..d7972188d7 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -175,9 +175,9 @@ contains gp = ghost_points(i) j = gp%loc(1) k = gp%loc(2) - l = gp%loc(3) - patch_id = ghost_points(i)%ib_patch_id - + l = gp%loc(3) + patch_id = ghost_points(i)%ib_patch_id + ! Calculate physical location of GP if (p > 0) then physical_loc = [x_cc(j), y_cc(k), z_cc(l)] @@ -202,7 +202,6 @@ contains call s_interpolate_image_point(q_prim_vf, gp, & alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP) end if - dyn_pres = 0._wp ! Set q_prim_vf params at GP so that mixture vars calculated properly @@ -214,8 +213,7 @@ contains if (surface_tension) then q_prim_vf(c_idx)%sf(j, k, l) = c_IP - end if - + end if if (model_eqns /= 4) then ! If in simulation, use acc mixture subroutines if (elasticity) then @@ -259,7 +257,7 @@ contains ! Set color function if (surface_tension) then q_cons_vf(c_idx)%sf(j, k, l) = c_IP - end if + end if ! Set Energy if (bubbles_euler) then @@ -267,10 +265,10 @@ contains else q_cons_vf(E_idx)%sf(j, k, l) = gamma*pres_IP + pi_inf + dyn_pres end if - ! Set bubble vars if (bubbles_euler .and. .not. qbmm) then call s_comp_n_from_prim(alpha_IP(1), r_IP, nbub, weight) + $:GPU_LOOP(parallelism='[seq]') do q = 1, nb q_cons_vf(bubxb + (q - 1)*2)%sf(j, k, l) = nbub*r_IP(q) q_cons_vf(bubxb + (q - 1)*2 + 1)%sf(j, k, l) = nbub*v_IP(q) @@ -286,15 +284,20 @@ contains if (qbmm) then nbub = nmom_IP(1) + $:GPU_LOOP(parallelism='[seq]') do q = 1, nb*nmom q_cons_vf(bubxb + q - 1)%sf(j, k, l) = nbub*nmom_IP(q) end do + + $:GPU_LOOP(parallelism='[seq]') do q = 1, nb q_cons_vf(bubxb + (q - 1)*nmom)%sf(j, k, l) = nbub end do if (.not. polytropic) then + $:GPU_LOOP(parallelism='[seq]') do q = 1, nb + $:GPU_LOOP(parallelism='[seq]') do r = 1, nnode pb_in(j, k, l, r, q) = presb_IP((q - 1)*nnode + r) mv_in(j, k, l, r, q) = massv_IP((q - 1)*nnode + r) From a01f2627580ef4d4b31c758f9016101ab3819189 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Mon, 28 Jul 2025 15:11:06 -0400 Subject: [PATCH 027/199] Added missing space --- src/common/include/omp_macros.fpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 3ae7927943..bf71a73914 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -160,7 +160,7 @@ & no_create_val.strip('\n') + present_val.strip('\n') + & & deviceptr_val.strip('\n') + attach_val.strip('\n') #! Hardcoding the parallelism for now - #:set omp_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel)' + & + #:set omp_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel) ' + & & clause_val + extraOmpArgs_val.strip('\n') #:set omp_end_directive = '!$omp end target teams loop' $:omp_directive From d7fbcab573c8d80f83b0d4851918f6ec3fcd13ee Mon Sep 17 00:00:00 2001 From: Ben Wilfong Date: Mon, 28 Jul 2025 22:19:43 -0400 Subject: [PATCH 028/199] Chemistry works with OpenACC and almost works with OpenMP --- src/common/m_chemistry.fpp | 2 +- src/common/m_variables_conversion.fpp | 12 +++---- src/simulation/include/inline_riemann.fpp | 8 ++--- src/simulation/m_cbc.fpp | 14 ++++---- src/simulation/m_compute_cbc.fpp | 4 +++ src/simulation/m_riemann_solvers.fpp | 40 +++++++++++------------ src/simulation/m_start_up.fpp | 6 ++-- toolchain/mfc/run/input.py | 8 ++++- toolchain/pyproject.toml | 3 +- 9 files changed, 54 insertions(+), 43 deletions(-) diff --git a/src/common/m_chemistry.fpp b/src/common/m_chemistry.fpp index 97dbcf2632..e9e5bc5ee8 100644 --- a/src/common/m_chemistry.fpp +++ b/src/common/m_chemistry.fpp @@ -112,7 +112,7 @@ contains rho = q_cons_qp(contxe)%sf(x, y, z) T = q_T_sf%sf(x, y, z) - ! call get_net_production_rates(rho, T, Ys, omega) + call get_net_production_rates(rho, T, Ys, omega) $:GPU_LOOP(parallelism='[seq]') do eqn = chemxb, chemxe diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index e68097df7b..0bffeee879 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -181,8 +181,8 @@ contains T_guess = T - ! call get_temperature(e_Per_Kg - Pdyn_Per_Kg, T_guess, Y_rs, .true., T) - ! call get_pressure(rho, T, Y_rs, pres) + call get_temperature(e_Per_Kg - Pdyn_Per_Kg, T_guess, Y_rs, .true., T) + call get_pressure(rho, T, Y_rs, pres) #:endif @@ -1306,9 +1306,9 @@ contains q_cons_vf(i)%sf(j, k, l) = rho*q_prim_vf(i)%sf(j, k, l) end do - ! call get_mixture_molecular_weight(Ys, mix_mol_weight) + call get_mixture_molecular_weight(Ys, mix_mol_weight) T = q_prim_vf(E_idx)%sf(j, k, l)*mix_mol_weight/(gas_constant*rho) - ! call get_mixture_energy_mass(T, Ys, e_mix) + call get_mixture_energy_mass(T, Ys, e_mix) q_cons_vf(E_idx)%sf(j, k, l) = & dyn_pres + rho*e_mix @@ -1534,10 +1534,10 @@ contains Y_K(i - chemxb + 1) = qK_prim_vf(j, k, l, i) end do !Computing the energy from the internal energy of the mixture - ! call get_mixture_molecular_weight(Y_k, mix_mol_weight) + call get_mixture_molecular_weight(Y_k, mix_mol_weight) R_gas = gas_constant/mix_mol_weight T_K = pres_K/rho_K/R_gas - ! call get_mixture_energy_mass(T_K, Y_K, E_K) + call get_mixture_energy_mass(T_K, Y_K, E_K) E_K = rho_K*E_K + 5.e-1_wp*rho_K*vel_K_sum else ! Computing the energy from the pressure diff --git a/src/simulation/include/inline_riemann.fpp b/src/simulation/include/inline_riemann.fpp index 69b79abba5..9972799b02 100644 --- a/src/simulation/include/inline_riemann.fpp +++ b/src/simulation/include/inline_riemann.fpp @@ -34,13 +34,13 @@ if (chemistry) then eps = 0.001_wp - ! call get_species_enthalpies_rt(T_L, h_iL) - ! call get_species_enthalpies_rt(T_R, h_iR) + call get_species_enthalpies_rt(T_L, h_iL) + call get_species_enthalpies_rt(T_R, h_iR) h_iL = h_iL*gas_constant/molecular_weights*T_L h_iR = h_iR*gas_constant/molecular_weights*T_R - ! call get_species_specific_heats_r(T_L, Cp_iL) - ! call get_species_specific_heats_r(T_R, Cp_iR) + call get_species_specific_heats_r(T_L, Cp_iL) + call get_species_specific_heats_r(T_R, Cp_iR) h_avg_2 = (sqrt(rho_L)*h_iL + sqrt(rho_R)*h_iR)/(sqrt(rho_L) + sqrt(rho_R)) Yi_avg = (sqrt(rho_L)*Ys_L + sqrt(rho_R)*Ys_R)/(sqrt(rho_L) + sqrt(rho_R)) diff --git a/src/simulation/m_cbc.fpp b/src/simulation/m_cbc.fpp index e99f073205..14d81fdf31 100644 --- a/src/simulation/m_cbc.fpp +++ b/src/simulation/m_cbc.fpp @@ -818,21 +818,21 @@ contains Ys(i - chemxb + 1) = q_prim_rs${XYZ}$_vf(0, k, r, i) end do - ! call get_mixture_molecular_weight(Ys, Mw) + call get_mixture_molecular_weight(Ys, Mw) R_gas = gas_constant/Mw T = pres/rho/R_gas - ! call get_mixture_specific_heat_cp_mass(T, Ys, Cp) - ! call get_mixture_energy_mass(T, Ys, e_mix) + call get_mixture_specific_heat_cp_mass(T, Ys, Cp) + call get_mixture_energy_mass(T, Ys, e_mix) E = rho*e_mix + 5.e-1_wp*rho*vel_K_sum if (chem_params%gamma_method == 1) then !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. - ! call get_mole_fractions(Mw, Ys, Xs) - ! call get_species_specific_heats_r(T, Cp_i) + call get_mole_fractions(Mw, Ys, Xs) + call get_species_specific_heats_r(T, Cp_i) Gamma_i = Cp_i/(Cp_i - 1.0_wp) gamma = sum(Xs(:)/(Gamma_i(:) - 1.0_wp)) else if (chem_params%gamma_method == 2) then !> gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. - ! call get_mixture_specific_heat_cv_mass(T, Ys, Cv) + call get_mixture_specific_heat_cv_mass(T, Ys, Cv) gamma = 1.0_wp/(Cp/Cv - 1.0_wp) end if else @@ -1045,7 +1045,7 @@ contains if (chemistry) then ! Evolution of LODI equation of energy for real gases adjusted to perfect gas, doi:10.1006/jcph.2002.6990 - ! call get_species_enthalpies_rt(T, h_k) + call get_species_enthalpies_rt(T, h_k) sum_Enthalpies = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_species diff --git a/src/simulation/m_compute_cbc.fpp b/src/simulation/m_compute_cbc.fpp index a6e19c0ed4..5f361ee61b 100644 --- a/src/simulation/m_compute_cbc.fpp +++ b/src/simulation/m_compute_cbc.fpp @@ -37,6 +37,7 @@ contains real(wp), intent(in) :: dpres_ds integer :: i + $:GPU_LOOP(parallelism='[seq]') do i = 2, momxb L(i) = lambda_factor*lambda2*(c*c*dalpha_rho_ds(i - 1) - mf(i - 1)*dpres_ds) end do @@ -50,6 +51,7 @@ contains real(wp), dimension(num_dims), intent(in) :: dvel_ds integer :: i + $:GPU_LOOP(parallelism='[seq]') do i = momxb + 1, momxe L(i) = lambda_factor*lambda2*dvel_ds(dir_idx(i - contxe)) end do @@ -63,6 +65,7 @@ contains real(wp), dimension(num_fluids), intent(in) :: dadv_ds integer :: i + $:GPU_LOOP(parallelism='[seq]') do i = E_idx, advxe - 1 L(i) = lambda_factor*lambda2*dadv_ds(i - momxe) end do @@ -78,6 +81,7 @@ contains if (.not. chemistry) return + $:GPU_LOOP(parallelism='[seq]') do i = chemxb, chemxe L(i) = lambda_factor*lambda2*dYs_ds(i - chemxb + 1) end do diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index 039020248b..03b9f683d2 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -477,8 +477,8 @@ contains Ys_R(i - chemxb + 1) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) end do - ! call get_mixture_molecular_weight(Ys_L, MW_L) - ! call get_mixture_molecular_weight(Ys_R, MW_R) + call get_mixture_molecular_weight(Ys_L, MW_L) + call get_mixture_molecular_weight(Ys_R, MW_R) Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) @@ -488,8 +488,8 @@ contains T_L = pres_L/rho_L/R_gas_L T_R = pres_R/rho_R/R_gas_R - ! call get_species_specific_heats_r(T_L, Cp_iL) - ! call get_species_specific_heats_r(T_R, Cp_iR) + call get_species_specific_heats_r(T_L, Cp_iL) + call get_species_specific_heats_r(T_R, Cp_iR) if (chem_params%gamma_method == 1) then ! gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. @@ -500,10 +500,10 @@ contains gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) else if (chem_params%gamma_method == 2) then ! gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. - ! call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) - ! call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) - ! call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) - ! call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) + call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) + call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) + call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) + call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) Gamm_L = Cp_L/Cv_L gamma_L = 1.0_wp/(Gamm_L - 1.0_wp) @@ -511,8 +511,8 @@ contains gamma_R = 1.0_wp/(Gamm_R - 1.0_wp) end if - ! call get_mixture_energy_mass(T_L, Ys_L, E_L) - ! call get_mixture_energy_mass(T_R, Ys_R, E_R) + call get_mixture_energy_mass(T_L, Ys_L, E_L) + call get_mixture_energy_mass(T_R, Ys_R, E_R) E_L = rho_L*E_L + 5.e-1*rho_L*vel_L_rms E_R = rho_R*E_R + 5.e-1*rho_R*vel_R_rms @@ -2446,8 +2446,8 @@ contains Ys_R(i - chemxb + 1) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i) end do - ! call get_mixture_molecular_weight(Ys_L, MW_L) - ! call get_mixture_molecular_weight(Ys_R, MW_R) + call get_mixture_molecular_weight(Ys_L, MW_L) + call get_mixture_molecular_weight(Ys_R, MW_R) Xs_L(:) = Ys_L(:)*MW_L/molecular_weights(:) Xs_R(:) = Ys_R(:)*MW_R/molecular_weights(:) @@ -2458,8 +2458,8 @@ contains T_L = pres_L/rho_L/R_gas_L T_R = pres_R/rho_R/R_gas_R - ! call get_species_specific_heats_r(T_L, Cp_iL) - ! call get_species_specific_heats_r(T_R, Cp_iR) + call get_species_specific_heats_r(T_L, Cp_iL) + call get_species_specific_heats_r(T_R, Cp_iR) if (chem_params%gamma_method == 1) then !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. @@ -2470,10 +2470,10 @@ contains gamma_R = sum(Xs_R(:)/(Gamma_iR(:) - 1.0_wp)) else if (chem_params%gamma_method == 2) then !> gamma_method = 2: c_p / c_v where c_p, c_v are specific heats. - ! call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) - ! call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) - ! call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) - ! call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) + call get_mixture_specific_heat_cp_mass(T_L, Ys_L, Cp_L) + call get_mixture_specific_heat_cp_mass(T_R, Ys_R, Cp_R) + call get_mixture_specific_heat_cv_mass(T_L, Ys_L, Cv_L) + call get_mixture_specific_heat_cv_mass(T_R, Ys_R, Cv_R) Gamm_L = Cp_L/Cv_L gamma_L = 1.0_wp/(Gamm_L - 1.0_wp) @@ -2481,8 +2481,8 @@ contains gamma_R = 1.0_wp/(Gamm_R - 1.0_wp) end if - ! call get_mixture_energy_mass(T_L, Ys_L, E_L) - ! call get_mixture_energy_mass(T_R, Ys_R, E_R) + call get_mixture_energy_mass(T_L, Ys_L, E_L) + call get_mixture_energy_mass(T_R, Ys_R, E_R) E_L = rho_L*E_L + 5.e-1*rho_L*vel_L_rms E_R = rho_R*E_R + 5.e-1*rho_R*vel_R_rms diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index 8f950c6b50..f6a955ad38 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -1383,10 +1383,10 @@ contains "case-optimized", & #:endif m, n, p, num_procs, & -#ifdef MFC_OpenACC -!&< +#if defined(MFC_OpenACC) "with OpenACC offloading" -!&> +#elif defined(MFC_OpenMP) + "with OpenMP offloading" #else "on CPUs" #endif diff --git a/toolchain/mfc/run/input.py b/toolchain/mfc/run/input.py index 1b4ea004d9..a220ca635d 100644 --- a/toolchain/mfc/run/input.py +++ b/toolchain/mfc/run/input.py @@ -73,13 +73,19 @@ def generate_fpp(self, target) -> None: # Determine the real type based on the single precision flag real_type = 'real(sp)' if ARG('single') else 'real(dp)' + gpu_type = None + if (ARG("gpu") == "mp"): + directive_str = 'mp' + elif (ARG("gpu") == "acc"): + directive_str = 'acc' + # Write the generated Fortran code to the m_thermochem.f90 file with the chosen precision common.file_write( os.path.join(modules_dir, "m_thermochem.f90"), pyro.FortranCodeGenerator().generate( "m_thermochem", self.get_cantera_solution(), - pyro.CodeGenerationOptions(scalar_type = real_type) + pyro.CodeGenerationOptions(scalar_type = real_type, directive_offload = directive_str) ), True ) diff --git a/toolchain/pyproject.toml b/toolchain/pyproject.toml index cb1bc8fa07..927b8277bd 100644 --- a/toolchain/pyproject.toml +++ b/toolchain/pyproject.toml @@ -39,7 +39,8 @@ dependencies = [ # Chemistry "cantera==3.1.0", - "pyrometheus == 1.0.3", + #"pyrometheus == 1.0.4", + "pyrometheus @ git+https://github.com/wilfonba/pyrometheus-wilfong.git@OpenMPTest", # Frontier Profiling "astunparse==1.6.2", From b3c1ad16d49509ddbb0d2c5cee3d19a92776526d Mon Sep 17 00:00:00 2001 From: Daniel Vickers Date: Tue, 29 Jul 2025 11:41:18 -0400 Subject: [PATCH 029/199] Added a half-precision data type --- src/common/m_precision_select.f90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/m_precision_select.f90 b/src/common/m_precision_select.f90 index 3d3fa03838..2246c9a47a 100644 --- a/src/common/m_precision_select.f90 +++ b/src/common/m_precision_select.f90 @@ -13,9 +13,11 @@ module m_precision_select implicit none ! Define the available precision types + integer, parameter :: half_precision = selected_real_kind(3, 4) ! TODO :: Computed by hand. Double check these later. integer, parameter :: single_precision = selected_real_kind(6, 37) integer, parameter :: double_precision = selected_real_kind(15, 307) + integer, parameter :: hp = half_precision integer, parameter :: sp = single_precision integer, parameter :: dp = double_precision From 0d550aaff6082f3c82a840e15933ac0b5ab91c3f Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Tue, 29 Jul 2025 11:44:35 -0400 Subject: [PATCH 030/199] Readd LTO to cmake --- CMakeLists.txt | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af2941b7ae..304fce3725 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,7 +194,7 @@ elseif ((CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") OR (CMAKE_Fortran_COMPILER_ add_compile_options( $<$:-Mfreeform> $<$:-cpp> - $<$:-Minfo=inline> + $<$:-Minfo=inline> $<$:-Minfo=accel> ) @@ -234,14 +234,14 @@ if (CMAKE_BUILD_TYPE STREQUAL "Release") elseif(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS "23.11") message(STATUS "LTO/IPO is not supported in NVHPC Version < 23.11. Use a newer version of NVHPC for best performance.") else() - # message(STATUS "Performing IPO using -Mextract followed by -Minline") - # set(NVHPC_USE_TWO_PASS_IPO TRUE) + message(STATUS "Performing IPO using -Mextract followed by -Minline") + set(NVHPC_USE_TWO_PASS_IPO TRUE) endif() else() CHECK_IPO_SUPPORTED(RESULT SUPPORTS_IPO OUTPUT IPO_ERROR) if (SUPPORTS_IPO) message(STATUS "Enabled IPO / LTO") - # set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) else() message(STATUS "IPO / LTO is NOT available") endif() @@ -401,14 +401,14 @@ function(MFC_SETUP_TARGET) # Here we need to split into "library" and "executable" to perform IPO on the NVIDIA compiler. # A little hacky, but it *is* an edge-case for *one* compiler. if (NVHPC_USE_TWO_PASS_IPO) - # add_library(${ARGS_TARGET}_lib OBJECT ${ARGS_SOURCES}) - # target_compile_options(${ARGS_TARGET}_lib PRIVATE - # $<$:-Mextract=lib:${ARGS_TARGET}_lib> - # $<$:-Minline> - # ) - # add_dependencies(${ARGS_TARGET} ${ARGS_TARGET}_lib) - # target_compile_options(${ARGS_TARGET} PRIVATE -Minline=lib:${ARGS_TARGET}_lib) - # list(PREPEND IPO_TARGETS ${ARGS_TARGET}_lib) + add_library(${ARGS_TARGET}_lib OBJECT ${ARGS_SOURCES}) + target_compile_options(${ARGS_TARGET}_lib PRIVATE + $<$:-Mextract=lib:${ARGS_TARGET}_lib> + $<$:-Minline> + ) + add_dependencies(${ARGS_TARGET} ${ARGS_TARGET}_lib) + target_compile_options(${ARGS_TARGET} PRIVATE -Minline=lib:${ARGS_TARGET}_lib) + list(PREPEND IPO_TARGETS ${ARGS_TARGET}_lib) endif() foreach (a_target ${IPO_TARGETS}) @@ -511,7 +511,7 @@ function(MFC_SETUP_TARGET) endforeach() target_compile_options(${a_target} - PRIVATE -gpu=lineinfo + PRIVATE -gpu=keep,ptxinfo,lineinfo ) # GH-200 Unified Memory Support @@ -527,7 +527,7 @@ function(MFC_SETUP_TARGET) if (CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_options(${a_target} - PRIVATE -gpu=debug + PRIVATE -gpu=autocompare,debug ) endif() elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") From bac089d35dfe519c828323babc32962f0d6b2f54 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Tue, 29 Jul 2025 11:58:38 -0400 Subject: [PATCH 031/199] Update toolchain to support swapping between OpenACC and OpenMP --- toolchain/mfc/args.py | 2 +- toolchain/mfc/state.py | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/toolchain/mfc/args.py b/toolchain/mfc/args.py index b73bf93763..3e39750d88 100644 --- a/toolchain/mfc/args.py +++ b/toolchain/mfc/args.py @@ -59,7 +59,7 @@ def add_common_arguments(p: argparse.ArgumentParser, mask = None): if "m" not in mask: for f in dataclasses.fields(config): if f.name == 'gpu': - p.add_argument(f"--{f.name}", action="store", nargs='?', default=gpuConfigOptions.ACC.value, choices=[e.value for e in gpuConfigOptions]) + p.add_argument(f"--{f.name}", action="store", nargs='?', default=gpuConfigOptions.ACC.value, dest=f.name, choices=[e.value for e in gpuConfigOptions], help=f"Turn the {f.name} option to OpenACC or OpenMP.") p.add_argument(f"--no-{f.name}", action="store_const", const = gpuConfigOptions.NONE.value, dest=f.name, help=f"Turn the {f.name} option OFF.") continue p.add_argument( f"--{f.name}", action="store_true", help=f"Turn the {f.name} option ON.") diff --git a/toolchain/mfc/state.py b/toolchain/mfc/state.py index 383a458ec9..d801cb7654 100644 --- a/toolchain/mfc/state.py +++ b/toolchain/mfc/state.py @@ -35,12 +35,24 @@ def items(self) -> typing.Iterable[typing.Tuple[str, typing.Any]]: def make_options(self) -> typing.List[str]: """ Returns a list of options that could be passed to mfc.sh again. Example: --no-debug --mpi --no-gpu --no-gcov --no-unified""" - return [ f"--{'no-' if not v else ''}{k}" for k, v in self.items() ] + options = [] + for k, v in self.items(): + if (k == 'gpu'): + options.append(f"--{v}-{k}") + else: + options.append(f"--{'no-' if not v else ''}{k}") + return options def make_slug(self) -> str: """ Sort the items by key, then join them with underscores. This uniquely identifies the configuration. Example: no-debug_no-gpu_no_mpi_no-gcov """ - return '_'.join([ f"{'no-' if not v else ''}{k}" for k, v in sorted(self.items(), key=lambda x: x[0]) ]) + options = [] + for k, v in sorted(self.items(), key=lambda x: x[0]): + if (k == 'gpu'): + options.append(f"--{v}-{k}") + else: + options.append(f"--{'no-' if not v else ''}{k}") + return '_'.join(options) def __eq__(self, other) -> bool: """ Check if two MFCConfig objects are equal, field by field. """ From 555cf062a17e411426489a9a335770904c1080a9 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Tue, 29 Jul 2025 11:59:18 -0400 Subject: [PATCH 032/199] Add themochem build for CPU --- toolchain/mfc/run/input.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/toolchain/mfc/run/input.py b/toolchain/mfc/run/input.py index a220ca635d..dac7072afe 100644 --- a/toolchain/mfc/run/input.py +++ b/toolchain/mfc/run/input.py @@ -5,7 +5,7 @@ from ..printer import cons from .. import common, build -from ..state import ARGS, ARG +from ..state import ARGS, ARG, gpuConfigOptions from ..case import Case @dataclasses.dataclass(init=False) @@ -73,10 +73,10 @@ def generate_fpp(self, target) -> None: # Determine the real type based on the single precision flag real_type = 'real(sp)' if ARG('single') else 'real(dp)' - gpu_type = None - if (ARG("gpu") == "mp"): + directive_str = None + if (ARG("gpu") == gpuConfigOptions.MP.value): directive_str = 'mp' - elif (ARG("gpu") == "acc"): + elif (ARG("gpu") == gpuConfigOptions.ACC.value): directive_str = 'acc' # Write the generated Fortran code to the m_thermochem.f90 file with the chosen precision From 16c9ce3ea7fe2d1317c1cbaf0f94c37b84506489 Mon Sep 17 00:00:00 2001 From: Ben Wilfong Date: Tue, 29 Jul 2025 12:33:29 -0400 Subject: [PATCH 033/199] pyro updates --- toolchain/mfc/run/input.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/toolchain/mfc/run/input.py b/toolchain/mfc/run/input.py index dac7072afe..7f14441fd6 100644 --- a/toolchain/mfc/run/input.py +++ b/toolchain/mfc/run/input.py @@ -73,11 +73,12 @@ def generate_fpp(self, target) -> None: # Determine the real type based on the single precision flag real_type = 'real(sp)' if ARG('single') else 'real(dp)' - directive_str = None if (ARG("gpu") == gpuConfigOptions.MP.value): directive_str = 'mp' elif (ARG("gpu") == gpuConfigOptions.ACC.value): directive_str = 'acc' + else: + directive_str = None # Write the generated Fortran code to the m_thermochem.f90 file with the chosen precision common.file_write( From 6abe1468b7659fa9d067e5abe5841f79046fa543 Mon Sep 17 00:00:00 2001 From: Daniel Vickers Date: Tue, 29 Jul 2025 13:40:19 -0400 Subject: [PATCH 034/199] Added CMAKE defintion flags that should set the precision types --- src/common/m_precision_select.f90 | 7 +++++++ toolchain/mfc/build.py | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/common/m_precision_select.f90 b/src/common/m_precision_select.f90 index 2246c9a47a..2addfbc537 100644 --- a/src/common/m_precision_select.f90 +++ b/src/common/m_precision_select.f90 @@ -28,6 +28,13 @@ module m_precision_select integer, parameter :: wp = double_precision #endif + ! Set the storage preceision (stp) to half if mixed precision is requested +#ifdef MFC_MIXED_PRECISION + integer, parameter :: stp = half_precision +#else + integer, parameter :: stp = wp +#endif + #ifdef MFC_MPI ! Set mpi_p based on wp using the merge intrinsic function integer, parameter :: mpi_p = merge(MPI_DOUBLE_PRECISION, MPI_REAL, wp == double_precision) diff --git a/toolchain/mfc/build.py b/toolchain/mfc/build.py index 2de738986d..27913a10c8 100644 --- a/toolchain/mfc/build.py +++ b/toolchain/mfc/build.py @@ -133,7 +133,8 @@ def configure(self, case: Case): # Location prefix to install bin/, lib/, include/, etc. # See: https://cmake.org/cmake/help/latest/command/install.html. f"-DCMAKE_INSTALL_PREFIX={install_dirpath}", - f"-DMFC_SINGLE_PRECISION={'ON' if ARG('single') else 'OFF'}" + f"-DMFC_SINGLE_PRECISION={'ON' if (ARG('single') or ARG('half')) else 'OFF'}" + f"-DMFC_MIXED_PRECISION={'ON' if ARG('half') else 'OFF'}" ] if ARG("verbose"): From d7dfc0d4677ce0edc3083d4353fb27ed2f27cfee Mon Sep 17 00:00:00 2001 From: wilfonba Date: Wed, 30 Jul 2025 08:18:08 -0400 Subject: [PATCH 035/199] compiles and runs with OpenMP on CCE but fails all tests --- CMakeLists.txt | 4 +- src/common/include/omp_macros.fpp | 9 +- src/common/m_derived_types.fpp | 3 +- src/common/m_helper.fpp | 22 +- src/common/m_helper_basic.fpp | 7 +- src/common/m_phase_change.fpp | 2 +- src/common/m_variables_conversion.fpp | 50 ++--- src/pre_process/m_assign_variables.fpp | 4 +- src/pre_process/m_compute_levelset.fpp | 14 +- src/pre_process/m_model.fpp | 34 +-- src/pre_process/m_patches.fpp | 5 +- src/simulation/m_fftw.fpp | 2 + src/simulation/m_global_parameters.fpp | 2 - src/simulation/m_hyperelastic.fpp | 62 +++--- src/simulation/m_hypoelastic.fpp | 250 +++++++++++------------ src/simulation/m_igr.fpp | 40 ++-- src/simulation/m_mhd.fpp | 20 +- src/simulation/m_pressure_relaxation.fpp | 14 +- src/simulation/m_qbmm.fpp | 10 +- src/simulation/m_rhs.fpp | 5 +- src/simulation/m_riemann_solvers.fpp | 66 +++--- 21 files changed, 319 insertions(+), 306 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 304fce3725..0a005beb16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -492,8 +492,8 @@ function(MFC_SETUP_TARGET) target_compile_options(${a_target} PRIVATE -fopenmp -fopenmp-targets=spir64) target_link_options(${a_target} PRIVATE -fopenmp -fopenmp-targets=spir64) elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") - target_compile_options(${a_target} PRIVATE -fopenmp -fopenmp-targets=spir64 ) - target_link_options(${a_target} PRIVATE -fopenmp -fopenmp-targets=spir64) + target_compile_options(${a_target} PRIVATE -fopenmp) + target_link_options(${a_target} PRIVATE -fopenmp) endif() endif() diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index bf71a73914..bcc9b5533e 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -160,9 +160,12 @@ & no_create_val.strip('\n') + present_val.strip('\n') + & & deviceptr_val.strip('\n') + attach_val.strip('\n') #! Hardcoding the parallelism for now - #:set omp_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel) ' + & + !#:set omp_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel) ' + & + !& clause_val + extraOmpArgs_val.strip('\n') + !#:set omp_end_directive = '!$omp end target teams loop' + #:set omp_directive = '!$omp target teams distribute parallel do simd defaultmap(firstprivate:scalar) ' + & & clause_val + extraOmpArgs_val.strip('\n') - #:set omp_end_directive = '!$omp end target teams loop' + #:set omp_end_directive = '!$omp end target teams distribute parallel do simd' $:omp_directive $:code $:omp_end_directive @@ -201,7 +204,7 @@ #! Not implemented yet #:def OMP_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraOmpArgs=None) #! loop is going to be ignored since all loops right now are seq - #:set temp = '!$omp loop bind(thread)' + #:set temp = '' $:temp #:enddef diff --git a/src/common/m_derived_types.fpp b/src/common/m_derived_types.fpp index 23fcc87c13..0d3cfebee8 100644 --- a/src/common/m_derived_types.fpp +++ b/src/common/m_derived_types.fpp @@ -449,4 +449,5 @@ module m_derived_types integer :: mn_min, np_min, mp_min, mnp_min end type cell_num_bounds -end module m_derived_types \ No newline at end of file +end module m_derived_types + diff --git a/src/common/m_helper.fpp b/src/common/m_helper.fpp index c8a17a1875..68c75b1388 100644 --- a/src/common/m_helper.fpp +++ b/src/common/m_helper.fpp @@ -14,7 +14,7 @@ module m_helper implicit none - private; + private; public :: s_comp_n_from_prim, & s_comp_n_from_cons, & s_initialize_nonpoly, & @@ -292,7 +292,7 @@ contains !! @param a First vector. !! @param b Second vector. !! @return The cross product of the two vectors. - function f_cross(a, b) result(c) + pure function f_cross(a, b) result(c) real(wp), dimension(3), intent(in) :: a, b real(wp), dimension(3) :: c @@ -513,11 +513,11 @@ contains real(wp) :: Y, prefactor, local_pi local_pi = acos(-1._wp) - prefactor = sqrt((2*l + 1)/(4*local_pi)*factorial(l - m_order)/factorial(l + m_order)); + prefactor = sqrt((2*l + 1)/(4*local_pi)*factorial(l - m_order)/factorial(l + m_order)); if (m_order == 0) then - Y = prefactor*associated_legendre(x, l, m_order); + Y = prefactor*associated_legendre(x, l, m_order); elseif (m_order > 0) then - Y = (-1._wp)**m_order*sqrt(2._wp)*prefactor*associated_legendre(x, l, m_order)*cos(m_order*phi); + Y = (-1._wp)**m_order*sqrt(2._wp)*prefactor*associated_legendre(x, l, m_order)*cos(m_order*phi); end if end function spherical_harmonic_func @@ -535,17 +535,17 @@ contains real(wp) :: result_P if (m_order <= 0 .and. l <= 0) then - result_P = 1; + result_P = 1; elseif (l == 1 .and. m_order <= 0) then - result_P = x; + result_P = x; elseif (l == 1 .and. m_order == 1) then - result_P = -(1 - x**2)**(1._wp/2._wp); + result_P = -(1 - x**2)**(1._wp/2._wp); elseif (m_order == l) then - result_P = (-1)**l*double_factorial(2*l - 1)*(1 - x**2)**(l/2); + result_P = (-1)**l*double_factorial(2*l - 1)*(1 - x**2)**(l/2); elseif (m_order == l - 1) then - result_P = x*(2*l - 1)*associated_legendre(x, l - 1, l - 1); + result_P = x*(2*l - 1)*associated_legendre(x, l - 1, l - 1); else - result_P = ((2*l - 1)*x*associated_legendre(x, l - 1, m_order) - (l + m_order - 1)*associated_legendre(x, l - 2, m_order))/(l - m_order); + result_P = ((2*l - 1)*x*associated_legendre(x, l - 1, m_order) - (l + m_order - 1)*associated_legendre(x, l - 2, m_order))/(l - m_order); end if end function associated_legendre diff --git a/src/common/m_helper_basic.fpp b/src/common/m_helper_basic.fpp index e2dc0e8b14..9606140c76 100644 --- a/src/common/m_helper_basic.fpp +++ b/src/common/m_helper_basic.fpp @@ -89,11 +89,12 @@ contains !! @param var_array Array to check. logical function f_all_default(var_array) result(res) real(wp), intent(in) :: var_array(:) - ! logical :: res_array(size(var_array)) - ! integer :: i res = all(f_is_default(var_array)) + !logical :: res_array(size(var_array)) + !integer :: i + ! do i = 1, size(var_array) ! res_array(i) = f_is_default(var_array(i)) ! end do @@ -161,7 +162,7 @@ contains !! @param m Number of cells in x-axis !! @param n Number of cells in y-axis !! @param p Number of cells in z-axis - elemental subroutine s_update_cell_bounds(bounds, m, n, p) + elemental subroutine s_update_cell_bounds(bounds, m, n, p) type(cell_num_bounds), intent(out) :: bounds integer, intent(in) :: m, n, p diff --git a/src/common/m_phase_change.fpp b/src/common/m_phase_change.fpp index c36cff840d..a395b5c553 100644 --- a/src/common/m_phase_change.fpp +++ b/src/common/m_phase_change.fpp @@ -42,7 +42,7 @@ module m_phase_change real(wp) :: A, B, C, D !> @} - $:GPU_DECLARE(create='[max_iter,pCr,TCr,mixM,lp,vp,A,B,C,D]') + $:GPU_DECLARE(create='[A,B,C,D]') contains diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index 0bffeee879..bcccd47e73 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -53,10 +53,10 @@ module m_variables_conversion $:GPU_DECLARE(create='[gammas,gs_min,pi_infs,ps_inf,cvs,qvs,qvps]') #endif - real(wp), allocatable, dimension(:) :: Gs - integer, allocatable, dimension(:) :: bubrs - real(wp), allocatable, dimension(:, :) :: Res - $:GPU_DECLARE(create='[bubrs,Gs,Res]') + real(wp), allocatable, dimension(:) :: Gs_vc + integer, allocatable, dimension(:) :: bubrs_vc + real(wp), allocatable, dimension(:, :) :: Res_vc + $:GPU_DECLARE(create='[bubrs_vc,Gs_vc,Res_vc]') integer :: is1b, is2b, is3b, is1e, is2e, is3e $:GPU_DECLARE(create='[is1b,is2b,is3b,is1e,is2e,is3e]') @@ -516,7 +516,7 @@ contains if (present(G_K)) then G_K = 0._wp do i = 1, num_fluids - !TODO: change to use Gs directly here? + !TODO: change to use Gs_vc directly here? !TODO: Make this changes as well for GPUs G_K = G_K + alpha_K(i)*G(i) end do @@ -531,7 +531,7 @@ contains if (Re_size(i) > 0) Re_K(i) = 0._wp do j = 1, Re_size(i) - Re_K(i) = alpha_K(Re_idx(i, j))/Res(i, j) & + Re_K(i) = alpha_K(Re_idx(i, j))/Res_vc(i, j) & + Re_K(i) end do @@ -594,7 +594,7 @@ contains if (Re_size(i) > 0) Re_K(i) = 0._wp do j = 1, Re_size(i) - Re_K(i) = (1._wp - alpha_K(Re_idx(i, j)))/Res(i, j) & + Re_K(i) = (1._wp - alpha_K(Re_idx(i, j)))/Res_vc(i, j) & + Re_K(i) end do @@ -624,7 +624,7 @@ contains @:ALLOCATE(cvs (1:num_fluids)) @:ALLOCATE(qvs (1:num_fluids)) @:ALLOCATE(qvps (1:num_fluids)) - @:ALLOCATE(Gs (1:num_fluids)) + @:ALLOCATE(Gs_vc (1:num_fluids)) #else @:ALLOCATE(gammas (1:num_fluids)) @:ALLOCATE(gs_min (1:num_fluids)) @@ -633,46 +633,46 @@ contains @:ALLOCATE(cvs (1:num_fluids)) @:ALLOCATE(qvs (1:num_fluids)) @:ALLOCATE(qvps (1:num_fluids)) - @:ALLOCATE(Gs (1:num_fluids)) + @:ALLOCATE(Gs_vc (1:num_fluids)) #endif do i = 1, num_fluids gammas(i) = fluid_pp(i)%gamma gs_min(i) = 1.0_wp/gammas(i) + 1.0_wp pi_infs(i) = fluid_pp(i)%pi_inf - Gs(i) = fluid_pp(i)%G + Gs_vc(i) = fluid_pp(i)%G ps_inf(i) = pi_infs(i)/(1.0_wp + gammas(i)) cvs(i) = fluid_pp(i)%cv qvs(i) = fluid_pp(i)%qv qvps(i) = fluid_pp(i)%qvp end do - $:GPU_UPDATE(device='[gammas,gs_min,pi_infs,ps_inf,cvs,qvs,qvps,Gs]') + $:GPU_UPDATE(device='[gammas,gs_min,pi_infs,ps_inf,cvs,qvs,qvps,Gs_vc]') #ifdef MFC_SIMULATION if (viscous) then - @:ALLOCATE(Res(1:2, 1:Re_size_max)) + @:ALLOCATE(Res_vc(1:2, 1:Re_size_max)) do i = 1, 2 do j = 1, Re_size(i) - Res(i, j) = fluid_pp(Re_idx(i, j))%Re(i) + Res_vc(i, j) = fluid_pp(Re_idx(i, j))%Re(i) end do end do - $:GPU_UPDATE(device='[Res,Re_idx,Re_size]') + $:GPU_UPDATE(device='[Res_vc,Re_idx,Re_size]') end if #endif if (bubbles_euler) then #ifdef MFC_SIMULATION - @:ALLOCATE(bubrs(1:nb)) + @:ALLOCATE(bubrs_vc(1:nb)) #else - @:ALLOCATE(bubrs(1:nb)) + @:ALLOCATE(bubrs_vc(1:nb)) #endif do i = 1, nb - bubrs(i) = bub_idx%rs(i) + bubrs_vc(i) = bub_idx%rs(i) end do - $:GPU_UPDATE(device='[bubrs]') + $:GPU_UPDATE(device='[bubrs_vc]') end if #ifdef MFC_POST_PROCESS @@ -906,7 +906,7 @@ contains ! If in simulation, use acc mixture subroutines if (elasticity) then call s_convert_species_to_mixture_variables_acc(rho_K, gamma_K, pi_inf_K, qv_K, alpha_K, & - alpha_rho_K, Re_K, G_K, Gs) + alpha_rho_K, Re_K, G_K, Gs_vc) else if (bubbles_euler) then call s_convert_species_to_mixture_variables_bubbles_acc(rho_K, gamma_K, pi_inf_K, qv_K, & alpha_K, alpha_rho_K, Re_K) @@ -1073,7 +1073,7 @@ contains if (bubbles_euler) then $:GPU_LOOP(parallelism='[seq]') do i = 1, nb - nRtmp(i) = qK_cons_vf(bubrs(i))%sf(j, k, l) + nRtmp(i) = qK_cons_vf(bubrs_vc(i))%sf(j, k, l) end do vftmp = qK_cons_vf(alf_idx)%sf(j, k, l) @@ -1517,7 +1517,7 @@ contains if (elasticity) then call s_convert_species_to_mixture_variables_acc(rho_K, gamma_K, pi_inf_K, qv_K, & alpha_K, alpha_rho_K, Re_K, & - G_K, Gs) + G_K, Gs_vc) else if (bubbles_euler) then call s_convert_species_to_mixture_variables_bubbles_acc(rho_K, gamma_K, & pi_inf_K, qv_K, alpha_K, alpha_rho_K, Re_K) @@ -1607,14 +1607,14 @@ contains #endif #ifdef MFC_SIMULATION - @:DEALLOCATE(gammas, gs_min, pi_infs, ps_inf, cvs, qvs, qvps, Gs) + @:DEALLOCATE(gammas, gs_min, pi_infs, ps_inf, cvs, qvs, qvps, Gs_vc) if (bubbles_euler) then - @:DEALLOCATE(bubrs) + @:DEALLOCATE(bubrs_vc) end if #else - @:DEALLOCATE(gammas, gs_min, pi_infs, ps_inf, cvs, qvs, qvps, Gs) + @:DEALLOCATE(gammas, gs_min, pi_infs, ps_inf, cvs, qvs, qvps, Gs_vc) if (bubbles_euler) then - @:DEALLOCATE(bubrs) + @:DEALLOCATE(bubrs_vc) end if #endif diff --git a/src/pre_process/m_assign_variables.fpp b/src/pre_process/m_assign_variables.fpp index a4407266b3..a6b65e1ebc 100644 --- a/src/pre_process/m_assign_variables.fpp +++ b/src/pre_process/m_assign_variables.fpp @@ -102,7 +102,7 @@ contains !! @param eta pseudo volume fraction !! @param q_prim_vf Primitive variables !! @param patch_id_fp Array to track patch ids - subroutine s_assign_patch_mixture_primitive_variables(patch_id, j, k, l, & + subroutine s_assign_patch_mixture_primitive_variables(patch_id, j, k, l, & eta, q_prim_vf, patch_id_fp) $:GPU_ROUTINE(parallelism='[seq]') @@ -191,7 +191,7 @@ contains !! @param k the y-dir node index !! @param l the z-dir node index !! @param q_prim_vf Primitive variables - subroutine s_perturb_primitive(j, k, l, q_prim_vf) + subroutine s_perturb_primitive(j, k, l, q_prim_vf) integer, intent(in) :: j, k, l type(scalar_field), dimension(1:sys_size), intent(inout) :: q_prim_vf diff --git a/src/pre_process/m_compute_levelset.fpp b/src/pre_process/m_compute_levelset.fpp index 673a2aff5b..483045c553 100644 --- a/src/pre_process/m_compute_levelset.fpp +++ b/src/pre_process/m_compute_levelset.fpp @@ -27,7 +27,7 @@ module m_compute_levelset contains - subroutine s_circle_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_circle_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -63,7 +63,7 @@ contains end subroutine s_circle_levelset - subroutine s_airfoil_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_airfoil_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -146,7 +146,7 @@ contains end subroutine s_airfoil_levelset - subroutine s_3D_airfoil_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_3D_airfoil_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -250,7 +250,7 @@ contains end subroutine s_3D_airfoil_levelset !> Initialize IBM module - subroutine s_rectangle_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_rectangle_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -347,7 +347,7 @@ contains end subroutine s_rectangle_levelset - subroutine s_cuboid_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_cuboid_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -464,7 +464,7 @@ contains end subroutine s_cuboid_levelset - subroutine s_sphere_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_sphere_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm @@ -501,7 +501,7 @@ contains end subroutine s_sphere_levelset - subroutine s_cylinder_levelset(levelset, levelset_norm, ib_patch_id) + subroutine s_cylinder_levelset(levelset, levelset_norm, ib_patch_id) type(levelset_field), intent(INOUT) :: levelset type(levelset_norm_field), intent(INOUT) :: levelset_norm diff --git a/src/pre_process/m_model.fpp b/src/pre_process/m_model.fpp index 03225a4b76..0ae508a172 100644 --- a/src/pre_process/m_model.fpp +++ b/src/pre_process/m_model.fpp @@ -424,7 +424,7 @@ contains end subroutine s_model_write !> This procedure frees the memory allocated for an STL mesh. - subroutine s_model_free(model) + subroutine s_model_free(model) type(t_model), intent(inout) :: model @@ -532,7 +532,7 @@ contains !! @param ray Ray. !! @param triangle Triangle. !! @return True if the ray intersects the triangle, false otherwise. - elemental function f_intersects_triangle(ray, triangle) result(intersects) + elemental function f_intersects_triangle(ray, triangle) result(intersects) type(t_ray), intent(in) :: ray type(t_triangle), intent(in) :: triangle @@ -592,7 +592,8 @@ contains !! @param boundary_v Output boundary vertices/normals. !! @param boundary_vertex_count Output total boundary vertex count !! @param boundary_edge_count Output total boundary edge counts - subroutine f_check_boundary(model, boundary_v, boundary_vertex_count, boundary_edge_count) + subroutine f_check_boundary(model, boundary_v, boundary_vertex_count, boundary_edge_count) + type(t_model), intent(in) :: model real(wp), allocatable, intent(out), dimension(:, :, :) :: boundary_v !< Output boundary vertices/normals integer, intent(out) :: boundary_vertex_count, boundary_edge_count !< Output boundary vertex/edge count @@ -705,7 +706,8 @@ contains !! @param edge Edges end points to be registered !! @param edge_index Edge index iterator !! @param edge_count Total number of edges - subroutine f_register_edge(temp_boundary_v, edge, edge_index, edge_count) + subroutine f_register_edge(temp_boundary_v, edge, edge_index, edge_count) + integer, intent(inout) :: edge_index !< Edge index iterator integer, intent(inout) :: edge_count !< Total number of edges real(wp), intent(in), dimension(1:2, 1:2) :: edge !< Edges end points to be registered @@ -723,7 +725,8 @@ contains !! @param boundary_edge_count Output total number of boundary edges !! @param spacing Dimensions of the current levelset cell !! @param interpolate Logical output - subroutine f_check_interpolation_2D(boundary_v, boundary_edge_count, spacing, interpolate) + subroutine f_check_interpolation_2D(boundary_v, boundary_edge_count, spacing, interpolate) + logical, intent(inout) :: interpolate !< Logical indicator of interpolation integer, intent(in) :: boundary_edge_count !< Number of boundary edges real(wp), intent(in), dimension(1:boundary_edge_count, 1:3, 1:2) :: boundary_v @@ -753,7 +756,8 @@ contains !! @param model Model to search in. !! @param spacing Dimensions of the current levelset cell !! @param interpolate Logical output - subroutine f_check_interpolation_3D(model, spacing, interpolate) + subroutine f_check_interpolation_3D(model, spacing, interpolate) + logical, intent(inout) :: interpolate type(t_model), intent(in) :: model real(wp), dimension(1:3), intent(in) :: spacing @@ -799,7 +803,8 @@ contains !! @param spacing Dimensions of the current levelset cell !! @param interpolated_boundary_v Output all the boundary vertices of the interpolated 2D model !! @param total_vertices Total number of vertices after interpolation - subroutine f_interpolate_2D(boundary_v, boundary_edge_count, spacing, interpolated_boundary_v, total_vertices) + subroutine f_interpolate_2D(boundary_v, boundary_edge_count, spacing, interpolated_boundary_v, total_vertices) + real(wp), intent(in), dimension(:, :, :) :: boundary_v real(wp), dimension(1:3), intent(in) :: spacing real(wp), allocatable, intent(inout), dimension(:, :) :: interpolated_boundary_v @@ -1042,7 +1047,8 @@ contains !! @param point The cell centers of the current level cell !! @param normals The output levelset normals !! @param distance The output levelset distance - subroutine f_distance_normals_3D(model, point, normals, distance) + subroutine f_distance_normals_3D(model, point, normals, distance) + type(t_model), intent(IN) :: model real(wp), dimension(1:3), intent(in) :: point real(wp), dimension(1:3), intent(out) :: normals @@ -1104,7 +1110,8 @@ contains !! @param point The cell centers of the current levelset cell !! @param spacing Dimensions of the current levelset cell !! @return Distance which the levelset distance without interpolation - function f_distance(boundary_v, boundary_edge_count, point) result(distance) + function f_distance(boundary_v, boundary_edge_count, point) result(distance) + integer, intent(in) :: boundary_edge_count real(wp), intent(in), dimension(1:boundary_edge_count, 1:3, 1:2) :: boundary_v real(wp), dimension(1:3), intent(in) :: point @@ -1134,7 +1141,8 @@ contains !! @param boundary_edge_count Output the total number of boundary edges !! @param point The cell centers of the current levelset cell !! @param normals Output levelset normals without interpolation - subroutine f_normals(boundary_v, boundary_edge_count, point, normals) + subroutine f_normals(boundary_v, boundary_edge_count, point, normals) + integer, intent(in) :: boundary_edge_count real(wp), intent(in), dimension(1:boundary_edge_count, 1:3, 1:2) :: boundary_v real(wp), dimension(1:3), intent(in) :: point @@ -1169,7 +1177,8 @@ contains end subroutine f_normals !> This procedure calculates the barycentric facet area - subroutine f_tri_area(tri, tri_area) + subroutine f_tri_area(tri, tri_area) + real(wp), dimension(1:3, 1:3), intent(in) :: tri real(wp), intent(out) :: tri_area real(wp), dimension(1:3) :: AB, AC, cross @@ -1192,7 +1201,8 @@ contains !! @param total_vertices Total number of vertices after interpolation !! @param point The cell centers of the current levelset cell !! @return Distance which the levelset distance without interpolation - function f_interpolated_distance(interpolated_boundary_v, total_vertices, point) result(distance) + function f_interpolated_distance(interpolated_boundary_v, total_vertices, point) result(distance) + integer, intent(in) :: total_vertices real(wp), intent(in), dimension(1:total_vertices, 1:3) :: interpolated_boundary_v real(wp), dimension(1:3), intent(in) :: point diff --git a/src/pre_process/m_patches.fpp b/src/pre_process/m_patches.fpp index f1427a255f..3a25346eab 100644 --- a/src/pre_process/m_patches.fpp +++ b/src/pre_process/m_patches.fpp @@ -2266,7 +2266,7 @@ contains end subroutine s_convert_cylindrical_to_cartesian_coord - function f_convert_cyl_to_cart(cyl) result(cart) + function f_convert_cyl_to_cart(cyl) result(cart) $:GPU_ROUTINE(parallelism='[seq]') @@ -2292,7 +2292,8 @@ contains !! @param myth Angle !! @param offset Thickness !! @param a Starting position - elemental function f_r(myth, offset, a) + elemental function f_r(myth, offset, a) + $:GPU_ROUTINE(parallelism='[seq]') real(wp), intent(in) :: myth, offset, a real(wp) :: b diff --git a/src/simulation/m_fftw.fpp b/src/simulation/m_fftw.fpp index 4ea2ac6934..fa29f5bac3 100644 --- a/src/simulation/m_fftw.fpp +++ b/src/simulation/m_fftw.fpp @@ -136,6 +136,7 @@ contains integer :: i, j, k, l !< Generic loop iterators integer :: ierr !< Generic flag used to identify and report GPU errors +#if 0 ! Restrict filter to processors that have cells adjacent to axis if (bc_y%beg >= 0) return #if defined(MFC_GPU) @@ -302,6 +303,7 @@ contains end do end do end do +#endif #endif end subroutine s_apply_fourier_filter diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp index 854e350781..36d78bd379 100644 --- a/src/simulation/m_global_parameters.fpp +++ b/src/simulation/m_global_parameters.fpp @@ -170,8 +170,6 @@ module m_global_parameters integer :: num_igr_warm_start_iters !< number of warm start iterations for elliptic solve real(wp) :: alf_factor !< alpha factor for IGR - $:GPU_DECLARE(create='[chemistry]') - logical :: bodyForces logical :: bf_x, bf_y, bf_z !< body force toggle in three directions !< amplitude, frequency, and phase shift sinusoid in each direction diff --git a/src/simulation/m_hyperelastic.fpp b/src/simulation/m_hyperelastic.fpp index bd79e0f7fb..2b171016cb 100644 --- a/src/simulation/m_hyperelastic.fpp +++ b/src/simulation/m_hyperelastic.fpp @@ -28,12 +28,12 @@ module m_hyperelastic type(vector_field) :: btensor !< $:GPU_DECLARE(create='[btensor]') - real(wp), allocatable, dimension(:, :) :: fd_coeff_x - real(wp), allocatable, dimension(:, :) :: fd_coeff_y - real(wp), allocatable, dimension(:, :) :: fd_coeff_z - $:GPU_DECLARE(create='[fd_coeff_x,fd_coeff_y, fd_coeff_z]') - real(wp), allocatable, dimension(:) :: Gs - $:GPU_DECLARE(create='[Gs]') + real(wp), allocatable, dimension(:, :) :: fd_coeff_x_hyper + real(wp), allocatable, dimension(:, :) :: fd_coeff_y_hyper + real(wp), allocatable, dimension(:, :) :: fd_coeff_z_hyper + $:GPU_DECLARE(create='[fd_coeff_x_hyper,fd_coeff_y_hyper, fd_coeff_z_hyper]') + real(wp), allocatable, dimension(:) :: Gs_hyper + $:GPU_DECLARE(create='[Gs_hyper]') contains @@ -54,34 +54,34 @@ contains end do @:ACC_SETUP_VFs(btensor) - @:ALLOCATE(Gs(1:num_fluids)) + @:ALLOCATE(Gs_hyper(1:num_fluids)) $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - Gs(i) = fluid_pp(i)%G + Gs_hyper(i) = fluid_pp(i)%G end do - $:GPU_UPDATE(device='[Gs]') + $:GPU_UPDATE(device='[Gs_hyper]') - @:ALLOCATE(fd_coeff_x(-fd_number:fd_number, 0:m)) + @:ALLOCATE(fd_coeff_x_hyper(-fd_number:fd_number, 0:m)) if (n > 0) then - @:ALLOCATE(fd_coeff_y(-fd_number:fd_number, 0:n)) + @:ALLOCATE(fd_coeff_y_hyper(-fd_number:fd_number, 0:n)) end if if (p > 0) then - @:ALLOCATE(fd_coeff_z(-fd_number:fd_number, 0:p)) + @:ALLOCATE(fd_coeff_z_hyper(-fd_number:fd_number, 0:p)) end if ! Computing centered finite difference coefficients - call s_compute_finite_difference_coefficients(m, x_cc, fd_coeff_x, buff_size, & + call s_compute_finite_difference_coefficients(m, x_cc, fd_coeff_x_hyper, buff_size, & fd_number, fd_order) - $:GPU_UPDATE(device='[fd_coeff_x]') + $:GPU_UPDATE(device='[fd_coeff_x_hyper]') if (n > 0) then - call s_compute_finite_difference_coefficients(n, y_cc, fd_coeff_y, buff_size, & + call s_compute_finite_difference_coefficients(n, y_cc, fd_coeff_y_hyper, buff_size, & fd_number, fd_order) - $:GPU_UPDATE(device='[fd_coeff_y]') + $:GPU_UPDATE(device='[fd_coeff_y_hyper]') end if if (p > 0) then - call s_compute_finite_difference_coefficients(p, z_cc, fd_coeff_z, buff_size, & + call s_compute_finite_difference_coefficients(p, z_cc, fd_coeff_z_hyper, buff_size, & fd_number, fd_order) - $:GPU_UPDATE(device='[fd_coeff_z]') + $:GPU_UPDATE(device='[fd_coeff_z_hyper]') end if end subroutine s_initialize_hyperelastic_module @@ -117,7 +117,7 @@ contains end do ! If in simulation, use acc mixture subroutines call s_convert_species_to_mixture_variables_acc(rho, gamma, pi_inf, qv, alpha_k, & - alpha_rho_k, Re, G_local, Gs) + alpha_rho_k, Re, G_local, Gs_hyper) rho = max(rho, sgm_eps) G_local = max(G_local, sgm_eps) !if ( G_local <= verysmall ) G_K = 0._wp @@ -135,17 +135,17 @@ contains $:GPU_LOOP(parallelism='[seq]') do r = -fd_number, fd_number ! derivatives in the x-direction - tensora(1) = tensora(1) + q_prim_vf(xibeg)%sf(j + r, k, l)*fd_coeff_x(r, j) - tensora(2) = tensora(2) + q_prim_vf(xibeg + 1)%sf(j + r, k, l)*fd_coeff_x(r, j) - tensora(3) = tensora(3) + q_prim_vf(xiend)%sf(j + r, k, l)*fd_coeff_x(r, j) + tensora(1) = tensora(1) + q_prim_vf(xibeg)%sf(j + r, k, l)*fd_coeff_x_hyper(r, j) + tensora(2) = tensora(2) + q_prim_vf(xibeg + 1)%sf(j + r, k, l)*fd_coeff_x_hyper(r, j) + tensora(3) = tensora(3) + q_prim_vf(xiend)%sf(j + r, k, l)*fd_coeff_x_hyper(r, j) ! derivatives in the y-direction - tensora(4) = tensora(4) + q_prim_vf(xibeg)%sf(j, k + r, l)*fd_coeff_y(r, k) - tensora(5) = tensora(5) + q_prim_vf(xibeg + 1)%sf(j, k + r, l)*fd_coeff_y(r, k) - tensora(6) = tensora(6) + q_prim_vf(xiend)%sf(j, k + r, l)*fd_coeff_y(r, k) + tensora(4) = tensora(4) + q_prim_vf(xibeg)%sf(j, k + r, l)*fd_coeff_y_hyper(r, k) + tensora(5) = tensora(5) + q_prim_vf(xibeg + 1)%sf(j, k + r, l)*fd_coeff_y_hyper(r, k) + tensora(6) = tensora(6) + q_prim_vf(xiend)%sf(j, k + r, l)*fd_coeff_y_hyper(r, k) ! derivatives in the z-direction - tensora(7) = tensora(7) + q_prim_vf(xibeg)%sf(j, k, l + r)*fd_coeff_z(r, l) - tensora(8) = tensora(8) + q_prim_vf(xibeg + 1)%sf(j, k, l + r)*fd_coeff_z(r, l) - tensora(9) = tensora(9) + q_prim_vf(xiend)%sf(j, k, l + r)*fd_coeff_z(r, l) + tensora(7) = tensora(7) + q_prim_vf(xibeg)%sf(j, k, l + r)*fd_coeff_z_hyper(r, l) + tensora(8) = tensora(8) + q_prim_vf(xibeg + 1)%sf(j, k, l + r)*fd_coeff_z_hyper(r, l) + tensora(9) = tensora(9) + q_prim_vf(xiend)%sf(j, k, l + r)*fd_coeff_z_hyper(r, l) end do ! STEP 2a: computing the adjoint of the grad_xi tensor for the inverse tensorb(1) = tensora(5)*tensora(9) - tensora(6)*tensora(8) @@ -298,11 +298,11 @@ contains do i = 1, b_size @:DEALLOCATE(btensor%vf(i)%sf) end do - @:DEALLOCATE(fd_coeff_x) + @:DEALLOCATE(fd_coeff_x_hyper) if (n > 0) then - @:DEALLOCATE(fd_coeff_y) + @:DEALLOCATE(fd_coeff_y_hyper) if (p > 0) then - @:DEALLOCATE(fd_coeff_z) + @:DEALLOCATE(fd_coeff_z_hyper) end if end if diff --git a/src/simulation/m_hypoelastic.fpp b/src/simulation/m_hypoelastic.fpp index e4c781ebe9..8748478c85 100644 --- a/src/simulation/m_hypoelastic.fpp +++ b/src/simulation/m_hypoelastic.fpp @@ -19,21 +19,21 @@ module m_hypoelastic s_compute_hypoelastic_rhs, & s_compute_damage_state - real(wp), allocatable, dimension(:) :: Gs - $:GPU_DECLARE(create='[Gs]') + real(wp), allocatable, dimension(:) :: Gs_hypo + $:GPU_DECLARE(create='[Gs_hypo]') - real(wp), allocatable, dimension(:, :, :) :: du_dx, du_dy, du_dz - real(wp), allocatable, dimension(:, :, :) :: dv_dx, dv_dy, dv_dz - real(wp), allocatable, dimension(:, :, :) :: dw_dx, dw_dy, dw_dz - $:GPU_DECLARE(create='[du_dx,du_dy,du_dz,dv_dx,dv_dy,dv_dz,dw_dx,dw_dy,dw_dz]') + real(wp), allocatable, dimension(:, :, :) :: du_dx_hypo, du_dy_hypo, du_dz_hypo + real(wp), allocatable, dimension(:, :, :) :: dv_dx_hypo, dv_dy_hypo, dv_dz_hypo + real(wp), allocatable, dimension(:, :, :) :: dw_dx_hypo, dw_dy_hypo, dw_dz_hypo + $:GPU_DECLARE(create='[du_dx_hypo,du_dy_hypo,du_dz_hypo,dv_dx_hypo,dv_dy_hypo,dv_dz_hypo,dw_dx_hypo,dw_dy_hypo,dw_dz_hypo]') real(wp), allocatable, dimension(:, :, :) :: rho_K_field, G_K_field $:GPU_DECLARE(create='[rho_K_field,G_K_field]') - real(wp), allocatable, dimension(:, :) :: fd_coeff_x_h - real(wp), allocatable, dimension(:, :) :: fd_coeff_y_h - real(wp), allocatable, dimension(:, :) :: fd_coeff_z_h - $:GPU_DECLARE(create='[fd_coeff_x_h,fd_coeff_y_h,fd_coeff_z_h]') + real(wp), allocatable, dimension(:, :) :: fd_coeff_x_hypo + real(wp), allocatable, dimension(:, :) :: fd_coeff_y_hypo + real(wp), allocatable, dimension(:, :) :: fd_coeff_z_hypo + $:GPU_DECLARE(create='[fd_coeff_x_hypo,fd_coeff_y_hypo,fd_coeff_z_hypo]') contains @@ -41,43 +41,43 @@ contains integer :: i - @:ALLOCATE(Gs(1:num_fluids)) + @:ALLOCATE(Gs_hypo(1:num_fluids)) @:ALLOCATE(rho_K_field(0:m,0:n,0:p), G_K_field(0:m,0:n,0:p)) - @:ALLOCATE(du_dx(0:m,0:n,0:p)) + @:ALLOCATE(du_dx_hypo(0:m,0:n,0:p)) if (n > 0) then - @:ALLOCATE(du_dy(0:m,0:n,0:p), dv_dx(0:m,0:n,0:p), dv_dy(0:m,0:n,0:p)) + @:ALLOCATE(du_dy_hypo(0:m,0:n,0:p), dv_dx_hypo(0:m,0:n,0:p), dv_dy_hypo(0:m,0:n,0:p)) if (p > 0) then - @:ALLOCATE(du_dz(0:m,0:n,0:p), dv_dz(0:m,0:n,0:p)) - @:ALLOCATE(dw_dx(0:m,0:n,0:p), dw_dy(0:m,0:n,0:p), dw_dz(0:m,0:n,0:p)) + @:ALLOCATE(du_dz_hypo(0:m,0:n,0:p), dv_dz_hypo(0:m,0:n,0:p)) + @:ALLOCATE(dw_dx_hypo(0:m,0:n,0:p), dw_dy_hypo(0:m,0:n,0:p), dw_dz_hypo(0:m,0:n,0:p)) end if end if do i = 1, num_fluids - Gs(i) = fluid_pp(i)%G + Gs_hypo(i) = fluid_pp(i)%G end do - $:GPU_UPDATE(device='[Gs]') + $:GPU_UPDATE(device='[Gs_hypo]') - @:ALLOCATE(fd_coeff_x_h(-fd_number:fd_number, 0:m)) + @:ALLOCATE(fd_coeff_x_hypo(-fd_number:fd_number, 0:m)) if (n > 0) then - @:ALLOCATE(fd_coeff_y_h(-fd_number:fd_number, 0:n)) + @:ALLOCATE(fd_coeff_y_hypo(-fd_number:fd_number, 0:n)) end if if (p > 0) then - @:ALLOCATE(fd_coeff_z_h(-fd_number:fd_number, 0:p)) + @:ALLOCATE(fd_coeff_z_hypo(-fd_number:fd_number, 0:p)) end if ! Computing centered finite difference coefficients - call s_compute_finite_difference_coefficients(m, x_cc, fd_coeff_x_h, buff_size, & + call s_compute_finite_difference_coefficients(m, x_cc, fd_coeff_x_hypo, buff_size, & fd_number, fd_order) - $:GPU_UPDATE(device='[fd_coeff_x_h]') + $:GPU_UPDATE(device='[fd_coeff_x_hypo]') if (n > 0) then - call s_compute_finite_difference_coefficients(n, y_cc, fd_coeff_y_h, buff_size, & + call s_compute_finite_difference_coefficients(n, y_cc, fd_coeff_y_hypo, buff_size, & fd_number, fd_order) - $:GPU_UPDATE(device='[fd_coeff_y_h]') + $:GPU_UPDATE(device='[fd_coeff_y_hypo]') end if if (p > 0) then - call s_compute_finite_difference_coefficients(p, z_cc, fd_coeff_z_h, buff_size, & + call s_compute_finite_difference_coefficients(p, z_cc, fd_coeff_z_hypo, buff_size, & fd_number, fd_order) - $:GPU_UPDATE(device='[fd_coeff_z_h]') + $:GPU_UPDATE(device='[fd_coeff_z_hypo]') end if end subroutine s_initialize_hypoelastic_module @@ -108,7 +108,7 @@ contains do q = 0, p do l = 0, n do k = 0, m - du_dx(k, l, q) = 0._wp + du_dx_hypo(k, l, q) = 0._wp end do end do end do @@ -120,8 +120,8 @@ contains do k = 0, m $:GPU_LOOP(parallelism='[seq]') do r = -fd_number, fd_number - du_dx(k, l, q) = du_dx(k, l, q) & - + q_prim_vf(momxb)%sf(k + r, l, q)*fd_coeff_x_h(r, k) + du_dx_hypo(k, l, q) = du_dx_hypo(k, l, q) & + + q_prim_vf(momxb)%sf(k + r, l, q)*fd_coeff_x_hypo(r, k) end do end do @@ -134,7 +134,7 @@ contains do q = 0, p do l = 0, n do k = 0, m - du_dy(k, l, q) = 0._wp; dv_dx(k, l, q) = 0._wp; dv_dy(k, l, q) = 0._wp + du_dy_hypo(k, l, q) = 0._wp; dv_dx_hypo(k, l, q) = 0._wp; dv_dy_hypo(k, l, q) = 0._wp end do end do end do @@ -146,12 +146,12 @@ contains do k = 0, m $:GPU_LOOP(parallelism='[seq]') do r = -fd_number, fd_number - du_dy(k, l, q) = du_dy(k, l, q) & - + q_prim_vf(momxb)%sf(k, l + r, q)*fd_coeff_y_h(r, l) - dv_dx(k, l, q) = dv_dx(k, l, q) & - + q_prim_vf(momxb + 1)%sf(k + r, l, q)*fd_coeff_x_h(r, k) - dv_dy(k, l, q) = dv_dy(k, l, q) & - + q_prim_vf(momxb + 1)%sf(k, l + r, q)*fd_coeff_y_h(r, l) + du_dy_hypo(k, l, q) = du_dy_hypo(k, l, q) & + + q_prim_vf(momxb)%sf(k, l + r, q)*fd_coeff_y_hypo(r, l) + dv_dx_hypo(k, l, q) = dv_dx_hypo(k, l, q) & + + q_prim_vf(momxb + 1)%sf(k + r, l, q)*fd_coeff_x_hypo(r, k) + dv_dy_hypo(k, l, q) = dv_dy_hypo(k, l, q) & + + q_prim_vf(momxb + 1)%sf(k, l + r, q)*fd_coeff_y_hypo(r, l) end do end do end do @@ -165,8 +165,8 @@ contains do q = 0, p do l = 0, n do k = 0, m - du_dz(k, l, q) = 0._wp; dv_dz(k, l, q) = 0._wp; dw_dx(k, l, q) = 0._wp; - dw_dy(k, l, q) = 0._wp; dw_dz(k, l, q) = 0._wp; + du_dz_hypo(k, l, q) = 0._wp; dv_dz_hypo(k, l, q) = 0._wp; dw_dx_hypo(k, l, q) = 0._wp; + dw_dy_hypo(k, l, q) = 0._wp; dw_dz_hypo(k, l, q) = 0._wp; end do end do end do @@ -178,16 +178,16 @@ contains do k = 0, m $:GPU_LOOP(parallelism='[seq]') do r = -fd_number, fd_number - du_dz(k, l, q) = du_dz(k, l, q) & - + q_prim_vf(momxb)%sf(k, l, q + r)*fd_coeff_z_h(r, q) - dv_dz(k, l, q) = dv_dz(k, l, q) & - + q_prim_vf(momxb + 1)%sf(k, l, q + r)*fd_coeff_z_h(r, q) - dw_dx(k, l, q) = dw_dx(k, l, q) & - + q_prim_vf(momxe)%sf(k + r, l, q)*fd_coeff_x_h(r, k) - dw_dy(k, l, q) = dw_dy(k, l, q) & - + q_prim_vf(momxe)%sf(k, l + r, q)*fd_coeff_y_h(r, l) - dw_dz(k, l, q) = dw_dz(k, l, q) & - + q_prim_vf(momxe)%sf(k, l, q + r)*fd_coeff_z_h(r, q) + du_dz_hypo(k, l, q) = du_dz_hypo(k, l, q) & + + q_prim_vf(momxb)%sf(k, l, q + r)*fd_coeff_z_hypo(r, q) + dv_dz_hypo(k, l, q) = dv_dz_hypo(k, l, q) & + + q_prim_vf(momxb + 1)%sf(k, l, q + r)*fd_coeff_z_hypo(r, q) + dw_dx_hypo(k, l, q) = dw_dx_hypo(k, l, q) & + + q_prim_vf(momxe)%sf(k + r, l, q)*fd_coeff_x_hypo(r, k) + dw_dy_hypo(k, l, q) = dw_dy_hypo(k, l, q) & + + q_prim_vf(momxe)%sf(k, l + r, q)*fd_coeff_y_hypo(r, l) + dw_dz_hypo(k, l, q) = dw_dz_hypo(k, l, q) & + + q_prim_vf(momxe)%sf(k, l, q + r)*fd_coeff_z_hypo(r, q) end do end do end do @@ -203,7 +203,7 @@ contains rho_K = 0._wp; G_K = 0._wp do i = 1, num_fluids rho_K = rho_K + q_prim_vf(i)%sf(k, l, q) !alpha_rho_K(1) - G_K = G_K + q_prim_vf(advxb - 1 + i)%sf(k, l, q)*Gs(i) !alpha_K(1) * Gs(1) + G_K = G_K + q_prim_vf(advxb - 1 + i)%sf(k, l, q)*Gs_hypo(i) !alpha_K(1) * Gs_hypo(1) end do if (cont_damage) G_K = G_K*max((1._wp - q_prim_vf(damage_idx)%sf(k, l, q)), 0._wp) @@ -229,7 +229,7 @@ contains rhs_vf(strxb)%sf(k, l, q) + rho_K_field(k, l, q)* & ((4._wp*G_K_field(k, l, q)/3._wp) + & q_prim_vf(strxb)%sf(k, l, q))* & - du_dx(k, l, q) + du_dx_hypo(k, l, q) end do end do end do @@ -241,31 +241,31 @@ contains do l = 0, n do k = 0, m rhs_vf(strxb)%sf(k, l, q) = rhs_vf(strxb)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 1)%sf(k, l, q)*du_dy(k, l, q) + & - q_prim_vf(strxb + 1)%sf(k, l, q)*du_dy(k, l, q) - & - q_prim_vf(strxb)%sf(k, l, q)*dv_dy(k, l, q) - & - 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dv_dy(k, l, q)) + (q_prim_vf(strxb + 1)%sf(k, l, q)*du_dy_hypo(k, l, q) + & + q_prim_vf(strxb + 1)%sf(k, l, q)*du_dy_hypo(k, l, q) - & + q_prim_vf(strxb)%sf(k, l, q)*dv_dy_hypo(k, l, q) - & + 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dv_dy_hypo(k, l, q)) rhs_vf(strxb + 1)%sf(k, l, q) = rhs_vf(strxb + 1)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 1)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb)%sf(k, l, q)*dv_dx(k, l, q) - & - q_prim_vf(strxb + 1)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb + 2)%sf(k, l, q)*du_dy(k, l, q) + & - q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dy(k, l, q) - & - q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dy(k, l, q) + & - 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(du_dy(k, l, q) + & - dv_dx(k, l, q))) + (q_prim_vf(strxb + 1)%sf(k, l, q)*du_dx_hypo(k, l, q) + & + q_prim_vf(strxb)%sf(k, l, q)*dv_dx_hypo(k, l, q) - & + q_prim_vf(strxb + 1)%sf(k, l, q)*du_dx_hypo(k, l, q) + & + q_prim_vf(strxb + 2)%sf(k, l, q)*du_dy_hypo(k, l, q) + & + q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dy_hypo(k, l, q) - & + q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dy_hypo(k, l, q) + & + 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(du_dy_hypo(k, l, q) + & + dv_dx_hypo(k, l, q))) rhs_vf(strxb + 2)%sf(k, l, q) = rhs_vf(strxb + 2)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dx(k, l, q) + & - q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dx(k, l, q) - & - q_prim_vf(strxb + 2)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy(k, l, q) + & - q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy(k, l, q) - & - q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy(k, l, q) + & - 2._wp*G_K_field(k, l, q)*(dv_dy(k, l, q) - (1._wp/3._wp)* & - (du_dx(k, l, q) + & - dv_dy(k, l, q)))) + (q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dx_hypo(k, l, q) + & + q_prim_vf(strxb + 1)%sf(k, l, q)*dv_dx_hypo(k, l, q) - & + q_prim_vf(strxb + 2)%sf(k, l, q)*du_dx_hypo(k, l, q) + & + q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy_hypo(k, l, q) + & + q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy_hypo(k, l, q) - & + q_prim_vf(strxb + 2)%sf(k, l, q)*dv_dy_hypo(k, l, q) + & + 2._wp*G_K_field(k, l, q)*(dv_dy_hypo(k, l, q) - (1._wp/3._wp)* & + (du_dx_hypo(k, l, q) + & + dv_dy_hypo(k, l, q)))) end do end do end do @@ -277,62 +277,62 @@ contains do l = 0, n do k = 0, m rhs_vf(strxb)%sf(k, l, q) = rhs_vf(strxb)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 3)%sf(k, l, q)*du_dz(k, l, q) + & - q_prim_vf(strxb + 3)%sf(k, l, q)*du_dz(k, l, q) - & - q_prim_vf(strxb)%sf(k, l, q)*dw_dz(k, l, q) - & - 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dw_dz(k, l, q)) + (q_prim_vf(strxb + 3)%sf(k, l, q)*du_dz_hypo(k, l, q) + & + q_prim_vf(strxb + 3)%sf(k, l, q)*du_dz_hypo(k, l, q) - & + q_prim_vf(strxb)%sf(k, l, q)*dw_dz_hypo(k, l, q) - & + 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dw_dz_hypo(k, l, q)) rhs_vf(strxb + 1)%sf(k, l, q) = rhs_vf(strxb + 1)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 4)%sf(k, l, q)*du_dz(k, l, q) + & - q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dz(k, l, q) - & - q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dz(k, l, q)) + (q_prim_vf(strxb + 4)%sf(k, l, q)*du_dz_hypo(k, l, q) + & + q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dz_hypo(k, l, q) - & + q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dz_hypo(k, l, q)) rhs_vf(strxb + 2)%sf(k, l, q) = rhs_vf(strxb + 2)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dz(k, l, q) + & - q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dz(k, l, q) - & - q_prim_vf(strxb + 2)%sf(k, l, q)*dw_dz(k, l, q) - & - 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dw_dz(k, l, q)) + (q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dz_hypo(k, l, q) + & + q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dz_hypo(k, l, q) - & + q_prim_vf(strxb + 2)%sf(k, l, q)*dw_dz_hypo(k, l, q) - & + 2._wp*G_K_field(k, l, q)*(1._wp/3._wp)*dw_dz_hypo(k, l, q)) rhs_vf(strxb + 3)%sf(k, l, q) = rhs_vf(strxb + 3)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 3)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb)%sf(k, l, q)*dw_dx(k, l, q) - & - q_prim_vf(strxb + 3)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb + 4)%sf(k, l, q)*du_dy(k, l, q) + & - q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dy(k, l, q) - & - q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dy(k, l, q) + & - q_prim_vf(strxb + 5)%sf(k, l, q)*du_dz(k, l, q) + & - q_prim_vf(strxb + 3)%sf(k, l, q)*dw_dz(k, l, q) - & - q_prim_vf(strxb + 3)%sf(k, l, q)*dw_dz(k, l, q) + & - 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(du_dz(k, l, q) + & - dw_dx(k, l, q))) + (q_prim_vf(strxb + 3)%sf(k, l, q)*du_dx_hypo(k, l, q) + & + q_prim_vf(strxb)%sf(k, l, q)*dw_dx_hypo(k, l, q) - & + q_prim_vf(strxb + 3)%sf(k, l, q)*du_dx_hypo(k, l, q) + & + q_prim_vf(strxb + 4)%sf(k, l, q)*du_dy_hypo(k, l, q) + & + q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dy_hypo(k, l, q) - & + q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dy_hypo(k, l, q) + & + q_prim_vf(strxb + 5)%sf(k, l, q)*du_dz_hypo(k, l, q) + & + q_prim_vf(strxb + 3)%sf(k, l, q)*dw_dz_hypo(k, l, q) - & + q_prim_vf(strxb + 3)%sf(k, l, q)*dw_dz_hypo(k, l, q) + & + 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(du_dz_hypo(k, l, q) + & + dw_dx_hypo(k, l, q))) rhs_vf(strxb + 4)%sf(k, l, q) = rhs_vf(strxb + 4)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dx(k, l, q) + & - q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dx(k, l, q) - & - q_prim_vf(strxb + 4)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dy(k, l, q) + & - q_prim_vf(strxb + 2)%sf(k, l, q)*dw_dy(k, l, q) - & - q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dy(k, l, q) + & - q_prim_vf(strxb + 5)%sf(k, l, q)*dv_dz(k, l, q) + & - q_prim_vf(strxb + 4)%sf(k, l, q)*dw_dz(k, l, q) - & - q_prim_vf(strxb + 4)%sf(k, l, q)*dw_dz(k, l, q) + & - 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(dv_dz(k, l, q) + & - dw_dy(k, l, q))) + (q_prim_vf(strxb + 3)%sf(k, l, q)*dv_dx_hypo(k, l, q) + & + q_prim_vf(strxb + 1)%sf(k, l, q)*dw_dx_hypo(k, l, q) - & + q_prim_vf(strxb + 4)%sf(k, l, q)*du_dx_hypo(k, l, q) + & + q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dy_hypo(k, l, q) + & + q_prim_vf(strxb + 2)%sf(k, l, q)*dw_dy_hypo(k, l, q) - & + q_prim_vf(strxb + 4)%sf(k, l, q)*dv_dy_hypo(k, l, q) + & + q_prim_vf(strxb + 5)%sf(k, l, q)*dv_dz_hypo(k, l, q) + & + q_prim_vf(strxb + 4)%sf(k, l, q)*dw_dz_hypo(k, l, q) - & + q_prim_vf(strxb + 4)%sf(k, l, q)*dw_dz_hypo(k, l, q) + & + 2._wp*G_K_field(k, l, q)*(1._wp/2._wp)*(dv_dz_hypo(k, l, q) + & + dw_dy_hypo(k, l, q))) rhs_vf(strxe)%sf(k, l, q) = rhs_vf(strxe)%sf(k, l, q) + rho_K_field(k, l, q)* & - (q_prim_vf(strxe - 2)%sf(k, l, q)*dw_dx(k, l, q) + & - q_prim_vf(strxe - 2)%sf(k, l, q)*dw_dx(k, l, q) - & - q_prim_vf(strxe)%sf(k, l, q)*du_dx(k, l, q) + & - q_prim_vf(strxe - 1)%sf(k, l, q)*dw_dy(k, l, q) + & - q_prim_vf(strxe - 1)%sf(k, l, q)*dw_dy(k, l, q) - & - q_prim_vf(strxe)%sf(k, l, q)*dv_dy(k, l, q) + & - q_prim_vf(strxe)%sf(k, l, q)*dw_dz(k, l, q) + & - q_prim_vf(strxe)%sf(k, l, q)*dw_dz(k, l, q) - & - q_prim_vf(strxe)%sf(k, l, q)*dw_dz(k, l, q) + & - 2._wp*G_K_field(k, l, q)*(dw_dz(k, l, q) - (1._wp/3._wp)* & - (du_dx(k, l, q) + & - dv_dy(k, l, q) + & - dw_dz(k, l, q)))) + (q_prim_vf(strxe - 2)%sf(k, l, q)*dw_dx_hypo(k, l, q) + & + q_prim_vf(strxe - 2)%sf(k, l, q)*dw_dx_hypo(k, l, q) - & + q_prim_vf(strxe)%sf(k, l, q)*du_dx_hypo(k, l, q) + & + q_prim_vf(strxe - 1)%sf(k, l, q)*dw_dy_hypo(k, l, q) + & + q_prim_vf(strxe - 1)%sf(k, l, q)*dw_dy_hypo(k, l, q) - & + q_prim_vf(strxe)%sf(k, l, q)*dv_dy_hypo(k, l, q) + & + q_prim_vf(strxe)%sf(k, l, q)*dw_dz_hypo(k, l, q) + & + q_prim_vf(strxe)%sf(k, l, q)*dw_dz_hypo(k, l, q) - & + q_prim_vf(strxe)%sf(k, l, q)*dw_dz_hypo(k, l, q) + & + 2._wp*G_K_field(k, l, q)*(dw_dz_hypo(k, l, q) - (1._wp/3._wp)* & + (du_dx_hypo(k, l, q) + & + dv_dy_hypo(k, l, q) + & + dw_dz_hypo(k, l, q)))) end do end do end do @@ -364,7 +364,7 @@ contains rhs_vf(strxb + 3)%sf(k, l, q) = rhs_vf(strxb + 3)%sf(k, l, q) + & rho_K_field(k, l, q)*( & -(q_prim_vf(strxb + 3)%sf(k, l, q) + (2._wp/3._wp)*G_K_field(k, l, q))* & - (du_dx(k, l, q) + dv_dy(k, l, q) + q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)) & + (du_dx_hypo(k, l, q) + dv_dy_hypo(k, l, q) + q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)) & + 2._wp*(q_prim_vf(strxb + 3)%sf(k, l, q) + G_K_field(k, l, q))*q_prim_vf(momxb + 1)%sf(k, l, q)/y_cc(l)) end do end do @@ -377,16 +377,16 @@ contains impure subroutine s_finalize_hypoelastic_module() - @:DEALLOCATE(Gs) + @:DEALLOCATE(Gs_hypo) @:DEALLOCATE(rho_K_field, G_K_field) - @:DEALLOCATE(du_dx) - @:DEALLOCATE(fd_coeff_x_h) + @:DEALLOCATE(du_dx_hypo) + @:DEALLOCATE(fd_coeff_x_hypo) if (n > 0) then - @:DEALLOCATE(du_dy,dv_dx,dv_dy) - @:DEALLOCATE(fd_coeff_y_h) + @:DEALLOCATE(du_dy_hypo,dv_dx_hypo,dv_dy_hypo) + @:DEALLOCATE(fd_coeff_y_hypo) if (p > 0) then - @:DEALLOCATE(du_dz, dv_dz, dw_dx, dw_dy, dw_dz) - @:DEALLOCATE(fd_coeff_z_h) + @:DEALLOCATE(du_dz_hypo, dv_dz_hypo, dw_dx_hypo, dw_dy_hypo, dw_dz_hypo) + @:DEALLOCATE(fd_coeff_z_hypo) end if end if diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index 0bf904b220..e868b2f0a7 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -23,16 +23,16 @@ module m_igr s_igr_sigma_x, & s_igr_flux_add, & s_finalize_igr_module - real(wp), allocatable, target, dimension(:, :, :) :: jac + real(wp), allocatable, target, dimension(: ,:, :) :: jac real(wp), allocatable, dimension(:, :, :) :: jac_rhs, jac_old $:GPU_DECLARE(create='[jac, jac_rhs, jac_old]') type(scalar_field), dimension(1) :: jac_sf $:GPU_DECLARE(create='[jac_sf]') - real(wp), allocatable, dimension(:, :) :: Res - $:GPU_DECLARE(create='[Res]') + real(wp), allocatable, dimension(:, :) :: Res_igr + $:GPU_DECLARE(create='[Res_igr]') real(wp) :: alf_igr $:GPU_DECLARE(create='[alf_igr]') @@ -88,13 +88,13 @@ contains subroutine s_initialize_igr_module() if (viscous) then - @:ALLOCATE(Res(1:2, 1:maxval(Re_size))) + @:ALLOCATE(Res_igr(1:2, 1:maxval(Re_size))) do i = 1, 2 do j = 1, Re_size(i) - Res(i, j) = fluid_pp(Re_idx(i, j))%Re(i) + Res_igr(i, j) = fluid_pp(Re_idx(i, j))%Re(i) end do end do - $:GPU_UPDATE(device='[Res, Re_idx, Re_size]') + $:GPU_UPDATE(device='[Res_igr, Re_idx, Re_size]') end if @:ALLOCATE(jac(idwbuff(1)%beg:idwbuff(1)%end, & @@ -128,7 +128,7 @@ contains #:if not MFC_CASE_OPTIMIZATION if (igr_order == 3) then - vidxb = -1; vidxe = 2; + vidxb = -1; vidxe = 2; $:GPU_UPDATE(device='[vidxb, vidxe]') @:ALLOCATE(coeff_L(0:2)) @@ -144,7 +144,7 @@ contains $:GPU_UPDATE(device='[coeff_R]') elseif (igr_order == 5) then - vidxb = -2; vidxe = 3; + vidxb = -2; vidxe = 3; $:GPU_UPDATE(device='[vidxb, vidxe]') @:ALLOCATE(coeff_L(-1:3)) @@ -516,8 +516,8 @@ contains mu_L = 0._wp; mu_R = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - mu_L = alpha_L(i)/Res(1, i) + mu_L - mu_R = alpha_R(i)/Res(1, i) + mu_R + mu_L = alpha_L(i)/Res_igr(1, i) + mu_L + mu_R = alpha_R(i)/Res_igr(1, i) + mu_R end do $:GPU_ATOMIC(atomic='update') @@ -938,8 +938,8 @@ contains mu_R = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - mu_L = alpha_L(i)/Res(1, i) + mu_L - mu_R = alpha_R(i)/Res(1, i) + mu_R + mu_L = alpha_L(i)/Res_igr(1, i) + mu_L + mu_R = alpha_R(i)/Res_igr(1, i) + mu_R end do $:GPU_ATOMIC(atomic='update') @@ -1362,8 +1362,8 @@ contains mu_R = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - mu_L = alpha_L(i)/Res(1, i) + mu_L - mu_R = alpha_R(i)/Res(1, i) + mu_R + mu_L = alpha_L(i)/Res_igr(1, i) + mu_L + mu_R = alpha_R(i)/Res_igr(1, i) + mu_R end do $:GPU_ATOMIC(atomic='update') @@ -1762,8 +1762,8 @@ contains mu_R = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - mu_L = alpha_L(i)/Res(1, i) + mu_L - mu_R = alpha_R(i)/Res(1, i) + mu_R + mu_L = alpha_L(i)/Res_igr(1, i) + mu_L + mu_R = alpha_R(i)/Res_igr(1, i) + mu_R end do $:GPU_ATOMIC(atomic='update') @@ -2218,8 +2218,8 @@ contains mu_R = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - mu_L = alpha_L(i)/Res(1, i) + mu_L - mu_R = alpha_R(i)/Res(1, i) + mu_R + mu_L = alpha_L(i)/Res_igr(1, i) + mu_L + mu_R = alpha_R(i)/Res_igr(1, i) + mu_R end do $:GPU_ATOMIC(atomic='update') @@ -2502,7 +2502,7 @@ contains end subroutine s_igr_riemann_solver - pure subroutine s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & + subroutine s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & E_R, gamma_R, pi_inf_R, rho_R, vel_R, & pres_L, pres_R, cfl) $:GPU_ROUTINE(parallelism='[seq]') @@ -2607,7 +2607,7 @@ contains subroutine s_finalize_igr_module() if (viscous) then - @:DEALLOCATE(Res) + @:DEALLOCATE(Res_igr) end if @:DEALLOCATE(jac, jac_rhs) diff --git a/src/simulation/m_mhd.fpp b/src/simulation/m_mhd.fpp index 1680efdb6f..12ba72809c 100644 --- a/src/simulation/m_mhd.fpp +++ b/src/simulation/m_mhd.fpp @@ -21,10 +21,10 @@ module m_mhd s_finalize_mhd_powell_module, & s_compute_mhd_powell_rhs - real(wp), allocatable, dimension(:, :, :) :: du_dx, du_dy, du_dz - real(wp), allocatable, dimension(:, :, :) :: dv_dx, dv_dy, dv_dz - real(wp), allocatable, dimension(:, :, :) :: dw_dx, dw_dy, dw_dz - $:GPU_DECLARE(create='[du_dx,du_dy,du_dz,dv_dx,dv_dy,dv_dz,dw_dx,dw_dy,dw_dz]') + real(wp), allocatable, dimension(:, :, :) :: du_dx_mhd, du_dy_mhd, du_dz_mhd + real(wp), allocatable, dimension(:, :, :) :: dv_dx_mhd, dv_dy_mhd, dv_dz_mhd + real(wp), allocatable, dimension(:, :, :) :: dw_dx_mhd, dw_dy_mhd, dw_dz_mhd + $:GPU_DECLARE(create='[du_dx_mhd,du_dy_mhd,du_dz_mhd,dv_dx_mhd,dv_dy_mhd,dv_dz_mhd,dw_dx_mhd,dw_dy_mhd,dw_dz_mhd]') real(wp), allocatable, dimension(:, :) :: fd_coeff_x_h real(wp), allocatable, dimension(:, :) :: fd_coeff_y_h @@ -38,10 +38,10 @@ contains ! Additional safety check beyond m_checker if (n == 0) call s_mpi_abort('Fatal Error: Powell correction is not applicable for 1D') - @:ALLOCATE(du_dx(0:m,0:n,0:p), dv_dx(0:m,0:n,0:p), dw_dx(0:m,0:n,0:p)) - @:ALLOCATE(du_dy(0:m,0:n,0:p), dv_dy(0:m,0:n,0:p), dw_dy(0:m,0:n,0:p)) + @:ALLOCATE(du_dx_mhd(0:m,0:n,0:p), dv_dx_mhd(0:m,0:n,0:p), dw_dx_mhd(0:m,0:n,0:p)) + @:ALLOCATE(du_dy_mhd(0:m,0:n,0:p), dv_dy_mhd(0:m,0:n,0:p), dw_dy_mhd(0:m,0:n,0:p)) if (p > 0) then - @:ALLOCATE(dw_dx(0:m,0:n,0:p), dw_dy(0:m,0:n,0:p), dw_dz(0:m,0:n,0:p)) + @:ALLOCATE(dw_dx_mhd(0:m,0:n,0:p), dw_dy_mhd(0:m,0:n,0:p), dw_dz_mhd(0:m,0:n,0:p)) end if @:ALLOCATE(fd_coeff_x_h(-fd_number:fd_number, 0:m)) @@ -135,12 +135,12 @@ contains impure subroutine s_finalize_mhd_powell_module - @:DEALLOCATE(du_dx, dv_dx, dw_dx) + @:DEALLOCATE(du_dx_mhd, dv_dx_mhd, dw_dx_mhd) @:DEALLOCATE(fd_coeff_x_h) - @:DEALLOCATE(du_dy, dv_dy, dw_dy) + @:DEALLOCATE(du_dy_mhd, dv_dy_mhd, dw_dy_mhd) @:DEALLOCATE(fd_coeff_y_h) if (p > 0) then - @:DEALLOCATE(dw_dx, dw_dy, dw_dz) + @:DEALLOCATE(dw_dx_mhd, dw_dy_mhd, dw_dz_mhd) @:DEALLOCATE(fd_coeff_z_h) end if diff --git a/src/simulation/m_pressure_relaxation.fpp b/src/simulation/m_pressure_relaxation.fpp index 52340ccbb2..407c01ff10 100644 --- a/src/simulation/m_pressure_relaxation.fpp +++ b/src/simulation/m_pressure_relaxation.fpp @@ -23,8 +23,8 @@ module m_pressure_relaxation real(wp), allocatable, dimension(:) :: gamma_min, pres_inf $:GPU_DECLARE(create='[gamma_min, pres_inf]') - real(wp), allocatable, dimension(:, :) :: Res - $:GPU_DECLARE(create='[Res]') + real(wp), allocatable, dimension(:, :) :: Res_pr + $:GPU_DECLARE(create='[Res_pr]') contains @@ -42,13 +42,13 @@ contains $:GPU_UPDATE(device='[gamma_min, pres_inf]') if (viscous) then - @:ALLOCATE(Res(1:2, 1:Re_size_max)) + @:ALLOCATE(Res_pr(1:2, 1:Re_size_max)) do i = 1, 2 do j = 1, Re_size(i) - Res(i, j) = fluid_pp(Re_idx(i, j))%Re(i) + Res_pr(i, j) = fluid_pp(Re_idx(i, j))%Re(i) end do end do - $:GPU_UPDATE(device='[Res, Re_idx, Re_size]') + $:GPU_UPDATE(device='[Res_pr, Re_idx, Re_size]') end if end subroutine s_initialize_pressure_relaxation_module @@ -58,7 +58,7 @@ contains @:DEALLOCATE(gamma_min, pres_inf) if (viscous) then - @:DEALLOCATE(Res) + @:DEALLOCATE(Res_pr) end if end subroutine s_finalize_pressure_relaxation_module @@ -288,7 +288,7 @@ contains if (Re_size(i) > 0) Re(i) = 0._wp $:GPU_LOOP(parallelism='[seq]') do q = 1, Re_size(i) - Re(i) = alpha(Re_idx(i, q))/Res(i, q) + Re(i) + Re(i) = alpha(Re_idx(i, q))/Res_pr(i, q) + Re(i) end do Re(i) = 1._wp/max(Re(i), sgm_eps) end do diff --git a/src/simulation/m_qbmm.fpp b/src/simulation/m_qbmm.fpp index 6ce6005e87..2da72f2c53 100644 --- a/src/simulation/m_qbmm.fpp +++ b/src/simulation/m_qbmm.fpp @@ -37,9 +37,9 @@ module m_qbmm type(int_bounds_info) :: is1_qbmm, is2_qbmm, is3_qbmm $:GPU_DECLARE(create='[is1_qbmm,is2_qbmm,is3_qbmm]') - integer, allocatable, dimension(:) :: bubrs + integer, allocatable, dimension(:) :: bubrs_qbmm integer, allocatable, dimension(:, :) :: bubmoms - $:GPU_DECLARE(create='[bubrs,bubmoms]') + $:GPU_DECLARE(create='[bubrs_qbmm,bubmoms]') contains @@ -394,13 +394,13 @@ contains $:GPU_UPDATE(device='[momrhs]') - @:ALLOCATE(bubrs(1:nb)) + @:ALLOCATE(bubrs_qbmm(1:nb)) @:ALLOCATE(bubmoms(1:nb, 1:nmom)) do i = 1, nb - bubrs(i) = bub_idx%rs(i) + bubrs_qbmm(i) = bub_idx%rs(i) end do - $:GPU_UPDATE(device='[bubrs]') + $:GPU_UPDATE(device='[bubrs_qbmm]') do j = 1, nmom do i = 1, nb diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index bb6ba2871e..ac36e2bff2 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -852,8 +852,9 @@ contains flux_gsrc_n(id)%vf, & id, irx, iry, irz) call nvtxEndRange - ! $:GPU_UPDATE(host='[flux_n(1)%vf(1)%sf]') - ! print *, "FLUX", flux_n(1)%vf(1)%sf(100:300, 0, 0) + + !$:GPU_UPDATE(host='[flux_n(1)%vf(1)%sf]') + !print *, "FLUX", flux_n(1)%vf(1)%sf(100:300, 0, 0) ! Additional physics and source terms ! RHS addition for advection source diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index 03b9f683d2..41001dbe3c 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -107,11 +107,11 @@ module m_riemann_solvers $:GPU_DECLARE(create='[is1,is2,is3,isx,isy,isz]') - real(wp), allocatable, dimension(:) :: Gs - $:GPU_DECLARE(create='[Gs]') + real(wp), allocatable, dimension(:) :: Gs_rs + $:GPU_DECLARE(create='[Gs_rs]') - real(wp), allocatable, dimension(:, :) :: Res - $:GPU_DECLARE(create='[Res]') + real(wp), allocatable, dimension(:, :) :: Res_gs + $:GPU_DECLARE(create='[Res_gs]') contains @@ -357,7 +357,7 @@ contains #:for NORM_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (norm_dir == ${NORM_DIR}$) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -459,9 +459,9 @@ contains $:GPU_LOOP(parallelism='[seq]') do q = 1, Re_size(i) - Re_L(i) = alpha_L(Re_idx(i, q))/Res(i, q) & + Re_L(i) = alpha_L(Re_idx(i, q))/Res_gs(i, q) & + Re_L(i) - Re_R(i) = alpha_R(Re_idx(i, q))/Res(i, q) & + Re_R(i) = alpha_R(Re_idx(i, q))/Res_gs(i, q) & + Re_R(i) end do @@ -561,8 +561,8 @@ contains $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - G_L = G_L + alpha_L(i)*Gs(i) - G_R = G_R + alpha_R(i)*Gs(i) + G_L = G_L + alpha_L(i)*Gs_rs(i) + G_R = G_R + alpha_R(i)*Gs_rs(i) end do if (cont_damage) then @@ -595,8 +595,8 @@ contains ! ! $:GPU_LOOP(parallelism='[seq]') ! do i = 1, num_fluids - ! G_L = G_L + alpha_L(i)*Gs(i) - ! G_R = G_R + alpha_R(i)*Gs(i) + ! G_L = G_L + alpha_L(i)*Gs_rs(i) + ! G_R = G_R + alpha_R(i)*Gs_rs(i) ! end do ! ! Elastic contribution to energy if G large enough ! if ((G_L > 1.e-3_wp) .and. (G_R > 1.e-3_wp)) then @@ -1267,7 +1267,7 @@ contains $:GPU_LOOP(parallelism='[seq]') do q = 1, Re_size(i) - Re_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q))/Res(i, q) & + Re_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q))/Res_gs(i, q) & + Re_L(i) end do @@ -1283,7 +1283,7 @@ contains $:GPU_LOOP(parallelism='[seq]') do q = 1, Re_size(i) - Re_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q))/Res(i, q) & + Re_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q))/Res_gs(i, q) & + Re_R(i) end do @@ -1305,8 +1305,8 @@ contains G_L = 0._wp; G_R = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - G_L = G_L + alpha_L(i)*Gs(i) - G_R = G_R + alpha_R(i)*Gs(i) + G_L = G_L + alpha_L(i)*Gs_rs(i) + G_R = G_R + alpha_R(i)*Gs_rs(i) end do $:GPU_LOOP(parallelism='[seq]') do i = 1, strxe - strxb + 1 @@ -1334,8 +1334,8 @@ contains $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids ! Mixture left and right shear modulus - G_L = G_L + alpha_L(i)*Gs(i) - G_R = G_R + alpha_R(i)*Gs(i) + G_L = G_L + alpha_L(i)*Gs_rs(i) + G_R = G_R + alpha_R(i)*Gs_rs(i) end do ! Elastic contribution to energy if G large enough if (G_L > verysmall .and. G_R > verysmall) then @@ -1951,7 +1951,7 @@ contains $:GPU_LOOP(parallelism='[seq]') do q = 1, Re_size(i) - Re_L(i) = (1._wp - qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q)))/Res(i, q) & + Re_L(i) = (1._wp - qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q)))/Res_gs(i, q) & + Re_L(i) end do @@ -1967,7 +1967,7 @@ contains $:GPU_LOOP(parallelism='[seq]') do q = 1, Re_size(i) - Re_R(i) = (1._wp - qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q)))/Res(i, q) & + Re_R(i) = (1._wp - qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q)))/Res_gs(i, q) & + Re_R(i) end do @@ -2414,7 +2414,7 @@ contains $:GPU_LOOP(parallelism='[seq]') do q = 1, Re_size(i) - Re_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q))/Res(i, q) & + Re_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, E_idx + Re_idx(i, q))/Res_gs(i, q) & + Re_L(i) end do @@ -2430,7 +2430,7 @@ contains $:GPU_LOOP(parallelism='[seq]') do q = 1, Re_size(i) - Re_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q))/Res(i, q) & + Re_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, E_idx + Re_idx(i, q))/Res_gs(i, q) & + Re_R(i) end do @@ -2508,8 +2508,8 @@ contains G_R = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - G_L = G_L + alpha_L(i)*Gs(i) - G_R = G_R + alpha_R(i)*Gs(i) + G_L = G_L + alpha_L(i)*Gs_rs(i) + G_R = G_R + alpha_R(i)*Gs_rs(i) end do $:GPU_LOOP(parallelism='[seq]') do i = 1, strxe - strxb + 1 @@ -2538,8 +2538,8 @@ contains $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids ! Mixture left and right shear modulus - G_L = G_L + alpha_L(i)*Gs(i) - G_R = G_R + alpha_R(i)*Gs(i) + G_L = G_L + alpha_L(i)*Gs_rs(i) + G_R = G_R + alpha_R(i)*Gs_rs(i) end do ! Elastic contribution to energy if G large enough if (G_L > verysmall .and. G_R > verysmall) then @@ -3133,24 +3133,24 @@ contains ! the Riemann problem solution integer :: i, j - @:ALLOCATE(Gs(1:num_fluids)) + @:ALLOCATE(Gs_rs(1:num_fluids)) do i = 1, num_fluids - Gs(i) = fluid_pp(i)%G + Gs_rs(i) = fluid_pp(i)%G end do - $:GPU_UPDATE(device='[Gs]') + $:GPU_UPDATE(device='[Gs_rs]') if (viscous) then - @:ALLOCATE(Res(1:2, 1:Re_size_max)) + @:ALLOCATE(Res_gs(1:2, 1:Re_size_max)) end if if (viscous) then do i = 1, 2 do j = 1, Re_size(i) - Res(i, j) = fluid_pp(Re_idx(i, j))%Re(i) + Res_gs(i, j) = fluid_pp(Re_idx(i, j))%Re(i) end do end do - $:GPU_UPDATE(device='[Res,Re_idx,Re_size]') + $:GPU_UPDATE(device='[Res_gs,Re_idx,Re_size]') end if $:GPU_ENTER_DATA(copyin='[is1,is2,is3,isx,isy,isz]') @@ -4084,8 +4084,6 @@ contains subroutine s_calculate_shear_stress_tensor(vel_grad_avg, Re_shear, divergence_v, tau_shear_out) $:GPU_ROUTINE(parallelism='[seq]') - implicit none - ! Arguments real(wp), dimension(num_dims, num_dims), intent(in) :: vel_grad_avg real(wp), intent(in) :: Re_shear @@ -4118,8 +4116,6 @@ contains subroutine s_calculate_bulk_stress_tensor(Re_bulk, divergence_v, tau_bulk_out) $:GPU_ROUTINE(parallelism='[seq]') - implicit none - ! Arguments real(wp), intent(in) :: Re_bulk real(wp), intent(in) :: divergence_v From d52abd2bf20213100da5a53b735525bdcb416fdb Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Thu, 31 Jul 2025 12:31:18 -0400 Subject: [PATCH 036/199] Add AMD compiler support, different macro expansions based on compiler --- CMakeLists.txt | 6 +++ src/common/include/omp_macros.fpp | 78 +++++++++++++++++++++++----- src/common/m_chemistry.fpp | 2 + src/simulation/m_cbc.fpp | 2 + src/simulation/m_fftw.fpp | 5 +- src/simulation/m_riemann_solvers.fpp | 2 + 6 files changed, 80 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a005beb16..92f26ac417 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -494,6 +494,9 @@ function(MFC_SETUP_TARGET) elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") target_compile_options(${a_target} PRIVATE -fopenmp) target_link_options(${a_target} PRIVATE -fopenmp) + elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang") + target_compile_options(${a_target} PRIVATE -fopenmp --offload-arch=gfx90a) + target_link_options(${a_target} PRIVATE -fopenmp --offload-arch=gfx90a) endif() endif() @@ -533,6 +536,9 @@ function(MFC_SETUP_TARGET) elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") find_package(hipfort COMPONENTS hip CONFIG REQUIRED) target_link_libraries(${a_target} PRIVATE hipfort::hip hipfort::hipfort-amdgcn) + elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang") + find_package(hipfort COMPONENTS hip CONFIG REQUIRED) + target_link_libraries(${a_target} PRIVATE hipfort::hip hipfort::hipfort-amdgcn flang_rt.hostdevice) endif() elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") target_compile_options(${a_target} PRIVATE "SHELL:-h noacc" "SHELL:-x acc") diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index bcc9b5533e..f595546a5d 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -1,5 +1,11 @@ #:include 'shared_parallel_macros.fpp' +#:set NVIDIA_COMPILER_ID="NVHPC" +#:set PGI_COMPILER_ID="PGI" +#:set INTEL_COMPILER_ID="Intel" +#:set CCE_COMPILER_ID="Cray" +#:set AMD_COMPILER_ID="LLVMFlang" + #:def OMP_MAP_STR(map_type, var_list) #:assert map_type is not None #:assert isinstance(map_type, str) @@ -17,8 +23,15 @@ #:assert isinstance(default, str) #:assert (default == 'present' or default == 'none') #:if default == 'present' - #! #:set default_val = 'defaultmap(present:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer) ' - #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(tofrom:allocatable) defaultmap(tofrom:pointer) ' + #:if MFC_COMPILER == NVIDIA_COMPILER_ID or MFC_COMPILER == PGI_COMPILER_ID + #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(tofrom:allocatable) defaultmap(tofrom:pointer) ' + #:elif MFC_COMPILER == CCE_COMPILER_ID + #:set default_val = 'defaultmap(present:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer) ' + #:elif MFC_COMPILER == AMD_COMPILER_ID + #:set default_val = '' + #:else + #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(tofrom:allocatable) defaultmap(tofrom:pointer) ' + #:endif #:elif default == 'none' #:stop 'Not Supported Yet' #:endif @@ -160,12 +173,22 @@ & no_create_val.strip('\n') + present_val.strip('\n') + & & deviceptr_val.strip('\n') + attach_val.strip('\n') #! Hardcoding the parallelism for now - !#:set omp_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel) ' + & - !& clause_val + extraOmpArgs_val.strip('\n') - !#:set omp_end_directive = '!$omp end target teams loop' - #:set omp_directive = '!$omp target teams distribute parallel do simd defaultmap(firstprivate:scalar) ' + & - & clause_val + extraOmpArgs_val.strip('\n') - #:set omp_end_directive = '!$omp end target teams distribute parallel do simd' + + #:if MFC_COMPILER == NVIDIA_COMPILER_ID or MFC_COMPILER == PGI_COMPILER_ID + #:set omp_start_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel) ' + #:set omp_end_directive = '!$omp end target teams loop' + #:elif MFC_COMPILER == CCE_COMPILER_ID + #:set omp_start_directive = '!$omp target teams distribute parallel do simd defaultmap(firstprivate:scalar) ' + #:set omp_end_directive = '!$omp end target teams distribute parallel do simd' + #:elif MFC_COMPILER == AMD_COMPILER_ID + #:set omp_start_directive = '!$omp target teams distribute parallel do ' + #:set omp_end_directive = '!$omp end target teams distribute parallel do' + #:else + #:set omp_start_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel) ' + #:set omp_end_directive = '!$omp end target teams loop' + #:endif + + #:set omp_directive = omp_start_directive + clause_val + extraOmpArgs_val.strip('\n') $:omp_directive $:code $:omp_end_directive @@ -184,7 +207,13 @@ #:else #:set function_name_val = '' #:endif - #:set clause_val = nohost_val.strip('\n') + + #:if MFC_COMPILER == AMD_COMPILER_ID + #:set clause_val = '' + #:else + #:set clause_val = nohost_val.strip('\n') + #:endif + #:set omp_directive = '!$omp declare target ' + & & clause_val + extraOmpArgs_val.strip('\n') $:omp_directive @@ -201,11 +230,16 @@ $:omp_directive #:enddef -#! Not implemented yet +#! Not fully implemented yet (ignores most args right now) #:def OMP_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraOmpArgs=None) - #! loop is going to be ignored since all loops right now are seq - #:set temp = '' - $:temp + #:if MFC_COMPILER == NVIDIA_COMPILER_ID or MFC_COMPILER == PGI_COMPILER_ID + #:set omp_directive = '!$omp loop bind(thread)' + #:elif MFC_COMPILER == CRAY_COMPILER_ID or MFC_COMPILER == AMD_COMPILER_ID + #:set omp_directive = '' + #:else + #:set omp_directive = '' + #:endif + $:omp_directive #:enddef #:def OMP_DATA(code, copy=None, copyin=None, copyinReadOnly=None, copyout=None, create=None, no_create=None, present=None, deviceptr=None, attach=None, default=None, extraOmpArgs=None) @@ -298,4 +332,22 @@ #:set omp_directive = '!$omp barrier ' + clause_val + extraOmpArgs_val.strip('\n') $:omp_directive #:enddef + +#:def UNDEF_AMD(code) + #:if MFC_COMPILER != AMD_COMPILER_ID + $:code + #:endif +#:enddef + +#:def UNDEF_CCE(code) + #:if MFC_COMPILER != CCE_COMPILER_ID + $:code + #:endif +#:enddef + +#:def UNDEF_NVIDIA(code) + #:if MFC_COMPILER != NVIDIA_COMPILER_ID and MFC_COMPILER != PGI_COMPILER_ID + $:code + #:endif +#:enddef ! New line at end of file is required for FYPP diff --git a/src/common/m_chemistry.fpp b/src/common/m_chemistry.fpp index e9e5bc5ee8..cd1cfc984e 100644 --- a/src/common/m_chemistry.fpp +++ b/src/common/m_chemistry.fpp @@ -99,6 +99,7 @@ contains real(wp), dimension(num_species) :: Ys real(wp), dimension(num_species) :: omega + #:block UNDEF_AMD #:call GPU_PARALLEL_LOOP(collapse=3, private='[Ys, omega]') do z = bounds(3)%beg, bounds(3)%end do y = bounds(2)%beg, bounds(2)%end @@ -127,6 +128,7 @@ contains end do end do #:endcall GPU_PARALLEL_LOOP + #:endblock UNDEF_AMD end subroutine s_compute_chemistry_reaction_flux diff --git a/src/simulation/m_cbc.fpp b/src/simulation/m_cbc.fpp index 14d81fdf31..ac7829eb0a 100644 --- a/src/simulation/m_cbc.fpp +++ b/src/simulation/m_cbc.fpp @@ -773,6 +773,7 @@ contains end if ! FD2 or FD4 of RHS at j = 0 + #:block UNDEF_AMD #:call GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, dYs_ds, h_k, Cp_i, Gamma_i, Xs]') do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1105,6 +1106,7 @@ contains end do end do #:endcall GPU_PARALLEL_LOOP + #:endblock UNDEF_AMD end if #:endfor diff --git a/src/simulation/m_fftw.fpp b/src/simulation/m_fftw.fpp index fa29f5bac3..8e81af6fa6 100644 --- a/src/simulation/m_fftw.fpp +++ b/src/simulation/m_fftw.fpp @@ -136,7 +136,7 @@ contains integer :: i, j, k, l !< Generic loop iterators integer :: ierr !< Generic flag used to identify and report GPU errors -#if 0 +#:block UNDEF_CCE ! Restrict filter to processors that have cells adjacent to axis if (bc_y%beg >= 0) return #if defined(MFC_GPU) @@ -304,7 +304,8 @@ contains end do end do #endif -#endif +#:endblock UNDEF_CCE + end subroutine s_apply_fourier_filter !> The purpose of this subroutine is to destroy the fftw plan diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index 41001dbe3c..436a8e8029 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -2943,6 +2943,7 @@ contains #:for NORM_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (norm_dir == ${NORM_DIR}$) then + #:block UNDEF_AMD #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel, alpha_L, alpha_R, rho, pres,E, H_no_mag, gamma, pi_inf, qv, vel_rms, B, c, c_fast, pres_mag, U_L, U_R, U_starL, U_starR, U_doubleL, U_doubleR, F_L, F_R, F_starL, F_starR, F_hlld]') do l = is3%beg, is3%end do k = is2%beg, is2%end @@ -3116,6 +3117,7 @@ contains end do end do #:endcall GPU_PARALLEL_LOOP + #:endblock UNDEF_AMD end if #:endfor From ddf8755fea0e8c23f28581ebe925ab775e2574e2 Mon Sep 17 00:00:00 2001 From: "Daniel J. Vickers" Date: Thu, 31 Jul 2025 17:02:28 -0400 Subject: [PATCH 037/199] Passed with --mixed into python builder and changed some variables --- src/common/m_derived_types.fpp | 10 +++++----- toolchain/main.py | 1 + toolchain/mfc/build.py | 4 ++-- toolchain/mfc/state.py | 3 ++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/common/m_derived_types.fpp b/src/common/m_derived_types.fpp index 38674af615..acb02e66ce 100644 --- a/src/common/m_derived_types.fpp +++ b/src/common/m_derived_types.fpp @@ -17,17 +17,17 @@ module m_derived_types !> Derived type adding the field position (fp) as an attribute type field_position - real(wp), allocatable, dimension(:, :, :) :: fp !< Field position + real(stp), allocatable, dimension(:, :, :) :: fp !< Field position end type field_position !> Derived type annexing a scalar field (SF) type scalar_field - real(wp), pointer, dimension(:, :, :) :: sf => null() + real(stp), pointer, dimension(:, :, :) :: sf => null() end type scalar_field !> Derived type for bubble variables pb and mv at quadrature nodes (qbmm) type pres_field - real(wp), pointer, dimension(:, :, :, :, :) :: sf => null() + real(stp), pointer, dimension(:, :, :, :, :) :: sf => null() end type pres_field !> Derived type annexing an integer scalar field (SF) @@ -37,12 +37,12 @@ module m_derived_types !> Derived type for levelset type levelset_field - real(wp), pointer, dimension(:, :, :, :) :: sf => null() + real(stp), pointer, dimension(:, :, :, :) :: sf => null() end type levelset_field !> Derived type for levelset norm type levelset_norm_field - real(wp), pointer, dimension(:, :, :, :, :) :: sf => null() + real(stp), pointer, dimension(:, :, :, :, :) :: sf => null() end type levelset_norm_field type mpi_io_var diff --git a/toolchain/main.py b/toolchain/main.py index 4afc10cf3c..b971f9da91 100644 --- a/toolchain/main.py +++ b/toolchain/main.py @@ -58,6 +58,7 @@ def __run(): try: lock.init() state.gARG = args.parse(state.gCFG) + print(state.gARG) lock.switch(state.MFCConfig.from_dict(state.gARG)) diff --git a/toolchain/mfc/build.py b/toolchain/mfc/build.py index 27913a10c8..58d8a341a6 100644 --- a/toolchain/mfc/build.py +++ b/toolchain/mfc/build.py @@ -133,8 +133,8 @@ def configure(self, case: Case): # Location prefix to install bin/, lib/, include/, etc. # See: https://cmake.org/cmake/help/latest/command/install.html. f"-DCMAKE_INSTALL_PREFIX={install_dirpath}", - f"-DMFC_SINGLE_PRECISION={'ON' if (ARG('single') or ARG('half')) else 'OFF'}" - f"-DMFC_MIXED_PRECISION={'ON' if ARG('half') else 'OFF'}" + f"-DMFC_SINGLE_PRECISION={'ON' if (ARG('single') or ARG('mixed')) else 'OFF'}" + f"-DMFC_MIXED_PRECISION={'ON' if ARG('mixed') else 'OFF'}" ] if ARG("verbose"): diff --git a/toolchain/mfc/state.py b/toolchain/mfc/state.py index fa7d438e77..2e5901e550 100644 --- a/toolchain/mfc/state.py +++ b/toolchain/mfc/state.py @@ -8,7 +8,8 @@ class MFCConfig: debug: bool = False gcov: bool = False unified: bool = False - single: bool = False + single: bool = False + mixed: bool = False @staticmethod def from_dict(d: dict): From 04fa590b0667f99cfcc71725e8ef1ed8b81a68d8 Mon Sep 17 00:00:00 2001 From: "Daniel J. Vickers" Date: Thu, 31 Jul 2025 17:28:55 -0400 Subject: [PATCH 038/199] Everything up to post-processing works --- toolchain/mfc/run/input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/mfc/run/input.py b/toolchain/mfc/run/input.py index 1b4ea004d9..ac8eb97516 100644 --- a/toolchain/mfc/run/input.py +++ b/toolchain/mfc/run/input.py @@ -71,7 +71,7 @@ def generate_fpp(self, target) -> None: common.create_directory(modules_dir) # Determine the real type based on the single precision flag - real_type = 'real(sp)' if ARG('single') else 'real(dp)' + real_type = 'real(sp)' if (ARG('single') or ARG('mixed')) else 'real(dp)' # Write the generated Fortran code to the m_thermochem.f90 file with the chosen precision common.file_write( From cc8cd816423e2e4c4b42c81c7a2d130b2c9f327c Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Thu, 31 Jul 2025 19:08:24 -0400 Subject: [PATCH 039/199] Remove autocompare as failing debug cases, fix COMPILER_ID bug --- CMakeLists.txt | 2 +- src/common/include/omp_macros.fpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 92f26ac417..e51c33e481 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -530,7 +530,7 @@ function(MFC_SETUP_TARGET) if (CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_options(${a_target} - PRIVATE -gpu=autocompare,debug + PRIVATE -gpu=debug ) endif() elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index f595546a5d..61e45056bc 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -234,7 +234,7 @@ #:def OMP_LOOP(collapse=None, parallelism=None, data_dependency=None, reduction=None, reductionOp=None, private=None, extraOmpArgs=None) #:if MFC_COMPILER == NVIDIA_COMPILER_ID or MFC_COMPILER == PGI_COMPILER_ID #:set omp_directive = '!$omp loop bind(thread)' - #:elif MFC_COMPILER == CRAY_COMPILER_ID or MFC_COMPILER == AMD_COMPILER_ID + #:elif MFC_COMPILER == CCE_COMPILER_ID or MFC_COMPILER == AMD_COMPILER_ID #:set omp_directive = '' #:else #:set omp_directive = '' From f834b9ae8d31b8014eb4c37ae27be6cb68735b5c Mon Sep 17 00:00:00 2001 From: "Daniel J. Vickers" Date: Fri, 1 Aug 2025 11:04:32 -0400 Subject: [PATCH 040/199] Intermediate commit with print statements --- src/common/m_precision_select.f90 | 2 +- src/simulation/m_time_steppers.fpp | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/common/m_precision_select.f90 b/src/common/m_precision_select.f90 index 2addfbc537..eb81ea652d 100644 --- a/src/common/m_precision_select.f90 +++ b/src/common/m_precision_select.f90 @@ -13,7 +13,7 @@ module m_precision_select implicit none ! Define the available precision types - integer, parameter :: half_precision = selected_real_kind(3, 4) ! TODO :: Computed by hand. Double check these later. + integer, parameter :: half_precision = selected_real_kind(3, 4) integer, parameter :: single_precision = selected_real_kind(6, 37) integer, parameter :: double_precision = selected_real_kind(15, 307) diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index d040650bfa..f5b4af2880 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -346,6 +346,13 @@ contains end do end do + print *, "This is the size of one of the elements in a vector field: ", SIZEOF(q_cons_ts(2)%vf(1)%sf(1, 1, 1)) ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of an half precision value: ", hp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of an single precision value: ", sp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of an double precision value: ", dp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of wp precision value: ", wp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of stp double precision value: ", stp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + end subroutine s_initialize_time_steppers_module !> 1st order TVD RK time-stepping algorithm @@ -653,6 +660,8 @@ contains real(wp) :: start, finish + print *, "This is the size of one of the elements in a vector field: ", SIZEOF(q_cons_ts(2)%vf(1)%sf(1, 1, 1)) ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + ! Stage 1 of 3 if (.not. adap_dt) then From 2358d298f81336a0a26ea068b698305e8157d2fa Mon Sep 17 00:00:00 2001 From: Nikolaos Tselepidis Date: Fri, 1 Aug 2025 18:04:49 +0200 Subject: [PATCH 041/199] Add scripts for santis/alps, example case, and captures for UVM comms via RDMA --- CMakeLists.txt | 6 +- .../3D_IGR_TaylorGreenVortex_nvidia/case.py | 101 ++++++++++++++++++ misc/nvidia_uvm/bind.sh | 24 +++++ misc/nvidia_uvm/nsys.sh | 24 +++++ src/common/m_mpi_common.fpp | 8 ++ toolchain/mfc/build.py | 3 + toolchain/modules | 3 + toolchain/templates/santis.mako | 86 +++++++++++++++ 8 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 examples/3D_IGR_TaylorGreenVortex_nvidia/case.py create mode 100755 misc/nvidia_uvm/bind.sh create mode 100755 misc/nvidia_uvm/nsys.sh create mode 100644 toolchain/templates/santis.mako diff --git a/CMakeLists.txt b/CMakeLists.txt index 8269c1cb48..c0acb3dbe3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -486,17 +486,17 @@ function(MFC_SETUP_TARGET) endforeach() target_compile_options(${a_target} - PRIVATE -gpu=keep,ptxinfo,lineinfo + PRIVATE -gpu=keep,ptxinfo,lineinfo,fastmath ) # GH-200 Unified Memory Support if (MFC_Unified) target_compile_options(${ARGS_TARGET} - PRIVATE -gpu=unified + PRIVATE -gpu=mem:unified -cuda ) # "This option must appear in both the compile and link lines" -- NVHPC Docs target_link_options(${ARGS_TARGET} - PRIVATE -gpu=unified + PRIVATE -gpu=mem:unified -cuda ) endif() diff --git a/examples/3D_IGR_TaylorGreenVortex_nvidia/case.py b/examples/3D_IGR_TaylorGreenVortex_nvidia/case.py new file mode 100644 index 0000000000..74faa7aa22 --- /dev/null +++ b/examples/3D_IGR_TaylorGreenVortex_nvidia/case.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +import math +import json + +N = 799 +Nx = N +Ny = 2*(N+1)-1 +Nz = 2*(N+1)-1 + +Re = 1600 +L = 1 +P0 = 101325 +rho0 = 1 +C0 = math.sqrt(1.4 * P0) +V0 = 0.1 * C0 +mu = V0 * L / Re + +cfl = 0.5 +dx = 2 * math.pi * L / (Ny + 1) + +dt = cfl * dx / (C0) + +tC = L / V0 +tEnd = 20 * tC + +Nt = int(tEnd / dt) +Nt = 10 + + +# Configuring case dictionary +print( + json.dumps( + { + "rdma_mpi": "T", + # Logistics + "run_time_info": "F", + # Computational Domain Parameters + "x_domain%beg": -math.pi * L, + "x_domain%end": math.pi * L, + "y_domain%beg": -math.pi * L, + "y_domain%end": math.pi * L, + "z_domain%beg": -math.pi * L, + "z_domain%end": math.pi * L, + "m": Nx, + "n": Ny, + "p": Nz, + "cyl_coord": "F", + "dt": dt, + "t_step_start": 0, + "t_step_stop": Nt, + "t_step_save": int(Nt / 100), + # Simulation Algorithm Parameters + "num_patches": 1, + "model_eqns": 2, + "num_fluids": 1, + "time_stepper": 3, + "bc_x%beg": -1, + "bc_x%end": -1, + "bc_y%beg": -1, + "bc_y%end": -1, + "bc_z%beg": -1, + "bc_z%end": -1, + "igr": "T", + "igr_order": 5, + "igr_iter_solver": 1, + "num_igr_iters": 3, + "num_igr_warm_start_iters": 3, + "alf_factor": 10, + "viscous": "T", + # Formatted Database Files Structure Parameters + "format": 1, + "precision": 2, + "prim_vars_wrt": "T", + "omega_wrt(1)": "T", + "omega_wrt(2)": "T", + "omega_wrt(3)": "T", + "qm_wrt": "T", + "fd_order": 4, + "parallel_io": "T", + # Patch 1: Background (AIR - 2) + "patch_icpp(1)%geometry": 9, + "patch_icpp(1)%x_centroid": 0, + "patch_icpp(1)%y_centroid": 0, + "patch_icpp(1)%z_centroid": 0, + "patch_icpp(1)%length_x": 2 * math.pi * L, + "patch_icpp(1)%length_y": 2 * math.pi * L, + "patch_icpp(1)%length_z": 2 * math.pi * L, + "patch_icpp(1)%vel(1)": 0.0, + "patch_icpp(1)%vel(2)": 0.0, + "patch_icpp(1)%vel(3)": 0, + "patch_icpp(1)%pres": 0.0, + "patch_icpp(1)%hcid": 380, + "patch_icpp(1)%alpha_rho(1)": 1, + "patch_icpp(1)%alpha(1)": 1, + # Fluids Physical Parameters + "fluid_pp(1)%gamma": 1.0e00 / (1.4 - 1), + "fluid_pp(1)%pi_inf": 0, + "fluid_pp(1)%Re(1)": 1 / mu, + } + ) +) diff --git a/misc/nvidia_uvm/bind.sh b/misc/nvidia_uvm/bind.sh new file mode 100755 index 0000000000..0b7bf91e96 --- /dev/null +++ b/misc/nvidia_uvm/bind.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +# -------------------------------- # +# Binding for a single Santis node # +# -------------------------------- # + +# Local rank +export local_rank="${OMPI_COMM_WORLD_LOCAL_RANK:-$SLURM_LOCALID}" + +# Bind to GPU +export CUDA_VISIBLE_DEVICES="$local_rank" + +# Binding to NIC +export MPICH_OFI_NIC_POLICY=USER +export MPICH_OFI_NIC_MAPPING="0:0; 1:1; 2:2; 3:3" + +# Bind to cores ( first core per socket ) +physcores=(0 72 144 216) + +#echo hostname: $(hostname), rank: $local_rank, cores: ${physcores[$local_rank]}, GPU: $CUDA_VISIBLE_DEVICES, NIC mapping: $MPICH_OFI_NIC_POLICY + +#set -x +numactl -l --all --physcpubind=${physcores[$local_rank]} "$@" +#set +x diff --git a/misc/nvidia_uvm/nsys.sh b/misc/nvidia_uvm/nsys.sh new file mode 100755 index 0000000000..172bcb2f69 --- /dev/null +++ b/misc/nvidia_uvm/nsys.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +#set -x +set -euo pipefail + +rank="${OMPI_COMM_WORLD_RANK:-$SLURM_PROCID}" + +[[ -z "${NSYS_FILE+x}" ]] && NSYS_FILE=report.qdrep +[[ -z "${NSYS+x}" ]] && NSYS=0 + +if [[ "$NSYS" -ne 0 && "$rank" -eq 0 ]]; then + exec nsys profile \ + --cpuctxsw=none -b none -s none \ + --event-sample=system-wide \ + --cpu-socket-events=61,71,265,273 \ + --cpu-socket-metrics=103,104 \ + --event-sampling-interval=10 \ + --trace=nvtx,openacc \ + --force-overwrite=true \ + -e NSYS_MPI_STORE_TEAMS_PER_RANK=1 \ + -o "$NSYS_FILE" "$@" +else + exec "$@" +fi diff --git a/src/common/m_mpi_common.fpp b/src/common/m_mpi_common.fpp index 100c055d8d..2bdd241344 100644 --- a/src/common/m_mpi_common.fpp +++ b/src/common/m_mpi_common.fpp @@ -38,7 +38,9 @@ module m_mpi_common !! average primitive variables, for a single computational domain boundary !! at the time, from the relevant neighboring processor. +#ifndef __NVCOMPILER_GPU_UNIFIED_MEM $:GPU_DECLARE(create='[buff_send, buff_recv]') +#endif integer :: halo_size $:GPU_DECLARE(create='[halo_size]') @@ -78,7 +80,13 @@ contains $:GPU_UPDATE(device='[halo_size, v_size]') +#ifndef __NVCOMPILER_GPU_UNIFIED_MEM @:ALLOCATE(buff_send(0:halo_size), buff_recv(0:halo_size)) +#else + ALLOCATE(buff_send(0:halo_size), buff_recv(0:halo_size)) + !$acc enter data create(capture:buff_send) + !$acc enter data create(capture:buff_recv) +#endif #endif end subroutine s_initialize_mpi_common_module diff --git a/toolchain/mfc/build.py b/toolchain/mfc/build.py index 2de738986d..750c9b294c 100644 --- a/toolchain/mfc/build.py +++ b/toolchain/mfc/build.py @@ -64,6 +64,9 @@ def get_install_dirpath(self, case: Case ) -> str: # The install directory is located /build/install/ return os.sep.join([os.getcwd(), "build", "install", self.get_slug(case)]) + def get_home_dirpath(self, case: Case) -> str: + return os.sep.join([os.getcwd()]) + def get_install_binpath(self, case: Case ) -> str: # /install//bin/ return os.sep.join([self.get_install_dirpath(case), "bin", self.name]) diff --git a/toolchain/modules b/toolchain/modules index 1e7ebe97f3..19e4e4d8df 100644 --- a/toolchain/modules +++ b/toolchain/modules @@ -85,3 +85,6 @@ n-cpu penguin/openmpi/4.1.5/gcc-8.5.0 n-gpu penguin/openmpi/4.1.5/nvhpc-22.3 nvidia/nvhpc/22.3 cuda/cuda-11.6 n-gpu CC=nvc CXX=nvc++ FC=nvfortran +san CSCS Santis +san-all cmake python +san-gpu nvhpc cuda cray-mpich diff --git a/toolchain/templates/santis.mako b/toolchain/templates/santis.mako new file mode 100644 index 0000000000..926c682039 --- /dev/null +++ b/toolchain/templates/santis.mako @@ -0,0 +1,86 @@ +#!/usr/bin/env bash + +<%namespace name="helpers" file="helpers.mako"/> + +% if engine == 'batch': +#SBATCH --uenv=icon/25.2:v1 +#SBATCH --nodes=${nodes} +#SBATCH --reservation=g183 +#SBATCH --ntasks-per-node=${tasks_per_node} +#SBATCH --job-name="${name}" +#SBATCH --output="${name}.out" +#SBATCH --error="${name}.err" +#SBATCH --time=${walltime} +% if account: +#SBATCH --account=${account} +% endif +% if partition: +#SBATCH --partition=${partition} +% endif +% if quality_of_service: +#SBATCH --qos=${quality_of_service} +% endif +% if email: +#SBATCH --mail-user=${email} +#SBATCH --mail-type="BEGIN, END, FAIL" +% endif +% endif + +# NVHPC and CUDA env vars +export NV_ACC_USE_MALLOC=0 # use cudaMallocManaged instead of malloc ( compiled using -gpu=mem:unified ) +export NVCOMPILER_ACC_NO_MEMHINTS=1 # disable implicit compiler hints +#export CUDA_BUFFER_PAGE_IN_THRESHOLD_MS=0.001 # workaround for copying to/from unpopulated buffers on GH + +# Cray MPICH +export MPICH_GPU_SUPPORT_ENABLED=1 +export FI_CXI_RX_MATCH_MODE=software +export FI_MR_CACHE_MONITOR=disabled +export MPICH_NO_BUFFER_ALIAS_CHECK=1 + +# CUSTOM env vars to MFC +export NVIDIA_ALLOC_MODE=0 # do nothing +export NVIDIA_MANUAL_GPU_HINTS=1 # prefloc GPU on some +export NVIDIA_IGR_TEMPS_ON_GPU=3 # jac, jac_rhs, and jac_old on GPU +export NVIDIA_VARS_ON_GPU=7 # q_cons_ts(1)%vf%sf for j=1-7 on GPU + +# NSYS +export NSYS=1 # enable nsys profiling +export NSYS_FILE=myreport.qdrep + +${helpers.template_prologue()} + +ok ":) Loading modules:\n" +cd "${MFC_ROOT_DIR}" +% if engine == 'batch': +. ./mfc.sh load -c san -m ${'g' if gpu else 'c'} +% endif +cd - > /dev/null +echo + +% for target in targets: + ${helpers.run_prologue(target)} + + % if not mpi: + (set -x; ${profiler} "${target.get_install_binpath(case)}") + % else: + (set -x; srun --unbuffered \ + --ntasks=${nodes*tasks_per_node} \ + --cpus-per-task 1 \ + --cpu-bind=none \ + % if gpu: + --gpus-per-task 1 \ + % endif + --wait 200 --bcast=/tmp/${target.name} \ + "${target.get_home_dirpath(case)}/misc/nvidia_uvm/bind.sh" \ + % if target.name == 'simulation': + "${target.get_home_dirpath(case)}/misc/nvidia_uvm/nsys.sh" \ + % endif + "${target.get_install_binpath(case)}") + % endif + + ${helpers.run_epilogue(target)} + + echo +% endfor + +${helpers.template_epilogue()} From 347fe84aa7cfd4583b412a945221a49aa0efa013 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Fri, 1 Aug 2025 14:24:39 -0400 Subject: [PATCH 042/199] I am dumb. Nothing to see here. Carry on. --- toolchain/mfc/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/mfc/build.py b/toolchain/mfc/build.py index 58d8a341a6..a80fd62754 100644 --- a/toolchain/mfc/build.py +++ b/toolchain/mfc/build.py @@ -133,7 +133,7 @@ def configure(self, case: Case): # Location prefix to install bin/, lib/, include/, etc. # See: https://cmake.org/cmake/help/latest/command/install.html. f"-DCMAKE_INSTALL_PREFIX={install_dirpath}", - f"-DMFC_SINGLE_PRECISION={'ON' if (ARG('single') or ARG('mixed')) else 'OFF'}" + f"-DMFC_SINGLE_PRECISION={'ON' if (ARG('single') or ARG('mixed')) else 'OFF'}", f"-DMFC_MIXED_PRECISION={'ON' if ARG('mixed') else 'OFF'}" ] From 37d393b02f5a5d01a27a1ffeca10d96231600d22 Mon Sep 17 00:00:00 2001 From: Nikolaos Tselepidis Date: Fri, 1 Aug 2025 20:34:32 +0200 Subject: [PATCH 043/199] Add PREFER_GPU and rearrange update for out-of-core computation --- src/common/include/macros.fpp | 41 ++++++++++++++++ src/simulation/m_global_parameters.fpp | 9 ++++ src/simulation/m_igr.fpp | 6 +++ src/simulation/m_time_steppers.fpp | 65 +++++++++++++++++++++++++- 4 files changed, 119 insertions(+), 2 deletions(-) diff --git a/src/common/include/macros.fpp b/src/common/include/macros.fpp index c1652388c3..b0d87d31b0 100644 --- a/src/common/include/macros.fpp +++ b/src/common/include/macros.fpp @@ -12,6 +12,47 @@ #endif #:enddef +#:def PREFER_GPU(*args) +#ifdef MFC_SIMULATION +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + block + use cudafor, gpu_sum => sum, gpu_maxval => maxval, gpu_minval => minval + integer :: istat + integer :: prefer_gpu_mode + character(len=10) :: prefer_gpu_mode_str + + ! environment variable + call get_environment_variable("NVIDIA_MANUAL_GPU_HINTS", prefer_gpu_mode_str) + if (trim(prefer_gpu_mode_str) == "0") then ! OFF + prefer_gpu_mode = 0 + elseif (trim(prefer_gpu_mode_str) == "1") then ! ON + prefer_gpu_mode = 1 + else ! default + prefer_gpu_mode = 0 + endif + + if (prefer_gpu_mode .eq. 1) then + #:for arg in args + !print*, "Moving ${arg}$ to GPU => ", SHAPE(${arg}$) + ! unset + istat = cudaMemAdvise( c_devloc(${arg}$), SIZEOF(${arg}$), cudaMemAdviseUnSetPreferredLocation, cudaCpuDeviceId ) + if (istat /= cudaSuccess) then + write(*,"('Error code: ',I0, ': ')") istat + write(*,*) cudaGetErrorString(istat) + endif + ! set + istat = cudaMemAdvise( c_devloc(${arg}$), SIZEOF(${arg}$), cudaMemAdviseSetPreferredLocation, 0 ) + if (istat /= cudaSuccess) then + write(*,"('Error code: ',I0, ': ')") istat + write(*,*) cudaGetErrorString(istat) + endif + #:endfor + end if + end block +#endif +#endif +#:enddef + #:def ALLOCATE(*args) @:LOG({'@:ALLOCATE(${re.sub(' +', ' ', ', '.join(args))}$)'}) #:set allocated_variables = ', '.join(args) diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp index 5be11129a2..2c2d0af646 100644 --- a/src/simulation/m_global_parameters.fpp +++ b/src/simulation/m_global_parameters.fpp @@ -1308,16 +1308,25 @@ contains @:ALLOCATE(x_cb(-1 - buff_size:m + buff_size)) @:ALLOCATE(x_cc(-buff_size:m + buff_size)) @:ALLOCATE(dx(-buff_size:m + buff_size)) + @:PREFER_GPU(x_cb) + @:PREFER_GPU(x_cc) + @:PREFER_GPU(dx) if (n == 0) return; @:ALLOCATE(y_cb(-1 - buff_size:n + buff_size)) @:ALLOCATE(y_cc(-buff_size:n + buff_size)) @:ALLOCATE(dy(-buff_size:n + buff_size)) + @:PREFER_GPU(y_cb) + @:PREFER_GPU(y_cc) + @:PREFER_GPU(dy) if (p == 0) return; @:ALLOCATE(z_cb(-1 - buff_size:p + buff_size)) @:ALLOCATE(z_cc(-buff_size:p + buff_size)) @:ALLOCATE(dz(-buff_size:p + buff_size)) + @:PREFER_GPU(z_cb) + @:PREFER_GPU(z_cc) + @:PREFER_GPU(dz) end subroutine s_initialize_global_parameters_module diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index db80bb8346..76069928f2 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -91,17 +91,23 @@ contains end do end do $:GPU_UPDATE(device='[Res, Re_idx, Re_size]') + @:PREFER_GPU(Res) + @:PREFER_GPU(Re_idx) end if @:ALLOCATE(jac(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) + @:PREFER_GPU(jac) + @:ALLOCATE(jac_rhs(-1:m,-1:n,-1:p)) + @:PREFER_GPU(jac_rhs) if (igr_iter_solver == 1) then ! Jacobi iteration @:ALLOCATE(jac_old(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) + @:PREFER_GPU(jac_old) end if $:GPU_PARALLEL_LOOP(collapse=3) diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index d040650bfa..c87bcad464 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -95,9 +95,11 @@ contains ! Allocating the cell-average conservative variables @:ALLOCATE(q_cons_ts(1:num_ts)) + @:PREFER_GPU(q_cons_ts) do i = 1, num_ts @:ALLOCATE(q_cons_ts(i)%vf(1:sys_size)) + @:PREFER_GPU(q_cons_ts(i)%vf) end do do i = 1, num_ts @@ -105,6 +107,7 @@ contains @:ALLOCATE(q_cons_ts(i)%vf(j)%sf(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) + @:PREFER_GPU(q_cons_ts(i)%vf(j)%sf) end do @:ACC_SETUP_VFs(q_cons_ts(i)) end do @@ -304,11 +307,13 @@ contains ! Allocating the cell-average RHS variables @:ALLOCATE(rhs_vf(1:sys_size)) + @:PREFER_GPU(rhs_vf) if (igr) then do i = 1, sys_size @:ALLOCATE(rhs_vf(i)%sf(-1:m+1,-1:n+1,-1:p+1)) @:ACC_SETUP_SFs(rhs_vf(i)) + @:PREFER_GPU(rhs_vf(i)%sf) end do else do i = 1, sys_size @@ -650,6 +655,7 @@ contains real(wp), intent(INOUT) :: time_avg integer :: i, j, k, l, q !< Generic loop iterator + integer :: dest real(wp) :: start, finish @@ -682,6 +688,7 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) +#if !defined(__NVCOMPILER_GPU_UNIFIED_MEM) $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p @@ -694,6 +701,24 @@ contains end do end do end do + dest = 2 ! result in q_cons_ts(2)%vf +#else + $:GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(2)%vf(i)%sf(j, k, l) = & + q_cons_ts(1)%vf(i)%sf(j, k, l) + q_cons_ts(1)%vf(i)%sf(j, k, l) = & + q_cons_ts(1)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l) + end do + end do + end do + end do + dest = 1 ! result in q_cons_ts(1)%vf +#endif !Evolve pb and mv for non-polytropic qbmm if (qbmm .and. (.not. polytropic)) then @@ -750,10 +775,11 @@ contains ! Stage 2 of 3 - call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) + call s_compute_rhs(q_cons_ts(dest)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) +#if !defined(__NVCOMPILER_GPU_UNIFIED_MEM) $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p @@ -767,6 +793,23 @@ contains end do end do end do + dest = 2 ! result in q_cons_ts(2)%vf +#else + $:GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(1)%vf(i)%sf(j, k, l) = & + (3._wp*q_cons_ts(2)%vf(i)%sf(j, k, l) & + + q_cons_ts(1)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l))/4._wp + end do + end do + end do + end do + dest = 1 ! result in q_cons_ts(1)%vf +#endif if (qbmm .and. (.not. polytropic)) then $:GPU_PARALLEL_LOOP(collapse=5) @@ -823,10 +866,11 @@ contains end if ! Stage 3 of 3 - call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 3) + call s_compute_rhs(q_cons_ts(dest)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 3) if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=3) +#if !defined(__NVCOMPILER_GPU_UNIFIED_MEM) $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p @@ -840,6 +884,23 @@ contains end do end do end do + dest = 1 ! result in q_cons_ts(1)%vf +#else + $:GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(1)%vf(i)%sf(j, k, l) = & + (q_cons_ts(2)%vf(i)%sf(j, k, l) & + + 2._wp*q_cons_ts(1)%vf(i)%sf(j, k, l) & + + 2._wp*dt*rhs_vf(i)%sf(j, k, l))/3._wp + end do + end do + end do + end do + dest = 1 ! result in q_cons_ts(1)%vf +#endif if (qbmm .and. (.not. polytropic)) then $:GPU_PARALLEL_LOOP(collapse=5) From 693c7f46e562d5039fe30d23ccfcca3753721ff6 Mon Sep 17 00:00:00 2001 From: Nikolaos Tselepidis Date: Fri, 1 Aug 2025 20:35:21 +0200 Subject: [PATCH 044/199] Allow keeping q_cons_ts(2) on CPU using pinned allocations --- src/simulation/m_time_steppers.fpp | 68 +++++++++++++++++++++++++++--- toolchain/templates/santis.mako | 3 +- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index c87bcad464..0d9ddfd885 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -75,8 +75,14 @@ module m_time_steppers integer, private :: num_ts !< !! Number of time stages in the time-stepping scheme + integer, private :: out_of_core + $:GPU_DECLARE(create='[q_cons_ts,q_prim_vf,q_T_sf,rhs_vf,q_prim_ts,rhs_mv,rhs_pb,max_dt]') +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + real(wp), allocatable, dimension(:, :, :, :), pinned, target :: q_cons_ts_pool_host +#endif + contains !> The computation of parameters, the allocation of memory, @@ -86,6 +92,21 @@ contains integer :: i, j !< Generic loop iterators + character(len=10) :: out_of_core_str + out_of_core = 0 + +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + call get_environment_variable("MFC_OUT_OF_CORE", out_of_core_str) + + if (trim(out_of_core_str) == "0") then + out_of_core = 0 + elseif (trim(out_of_core_str) == "1") then + out_of_core = 1 + else ! default + out_of_core = 0 + endif +#endif + ! Setting number of time-stages for selected time-stepping scheme if (time_stepper == 1) then num_ts = 1 @@ -102,12 +123,33 @@ contains @:PREFER_GPU(q_cons_ts(i)%vf) end do +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + if ( out_of_core == 1 ) then + allocate(q_cons_ts_pool_host(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end, & + 1:sys_size)) + end if +#endif + do i = 1, num_ts do j = 1, sys_size - @:ALLOCATE(q_cons_ts(i)%vf(j)%sf(idwbuff(1)%beg:idwbuff(1)%end, & - idwbuff(2)%beg:idwbuff(2)%end, & - idwbuff(3)%beg:idwbuff(3)%end)) - @:PREFER_GPU(q_cons_ts(i)%vf(j)%sf) +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + if ( i <= (num_ts - out_of_core) ) then + !print*, "q_cons_ts", i, j, "on GPU" +#endif + @:ALLOCATE(q_cons_ts(i)%vf(j)%sf(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end)) + @:PREFER_GPU(q_cons_ts(i)%vf(j)%sf) +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + else + !print*, "q_cons_ts", i, j, "on CPU" + q_cons_ts(i)%vf(j)%sf(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end) => q_cons_ts_pool_host(:,:,:,j) + end if +#endif end do @:ACC_SETUP_VFs(q_cons_ts(i)) end do @@ -1205,7 +1247,17 @@ contains ! Deallocating the cell-average conservative variables do i = 1, num_ts do j = 1, sys_size - @:DEALLOCATE(q_cons_ts(i)%vf(j)%sf) +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + if ( i <= (num_ts - out_of_core) ) then + !print*, "q_cons_ts", i, j, "dealloc" +#endif + @:DEALLOCATE(q_cons_ts(i)%vf(j)%sf) +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + else + !print*, "q_cons_ts", i, j, "nullify" + nullify(q_cons_ts(i)%vf(j)%sf) + end if +#endif end do @:DEALLOCATE(q_cons_ts(i)%vf) @@ -1213,6 +1265,12 @@ contains @:DEALLOCATE(q_cons_ts) +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + if ( out_of_core == 1 ) then + deallocate(q_cons_ts_pool_host) + end if +#endif + ! Deallocating the cell-average primitive ts variables if (probe_wrt) then do i = 0, 3 diff --git a/toolchain/templates/santis.mako b/toolchain/templates/santis.mako index 926c682039..27b4d6b425 100644 --- a/toolchain/templates/santis.mako +++ b/toolchain/templates/santis.mako @@ -38,10 +38,9 @@ export FI_MR_CACHE_MONITOR=disabled export MPICH_NO_BUFFER_ALIAS_CHECK=1 # CUSTOM env vars to MFC -export NVIDIA_ALLOC_MODE=0 # do nothing +export MFC_OUT_OF_CORE=1 # out of core export NVIDIA_MANUAL_GPU_HINTS=1 # prefloc GPU on some export NVIDIA_IGR_TEMPS_ON_GPU=3 # jac, jac_rhs, and jac_old on GPU -export NVIDIA_VARS_ON_GPU=7 # q_cons_ts(1)%vf%sf for j=1-7 on GPU # NSYS export NSYS=1 # enable nsys profiling From 7054b7b666226cbe91d5a078353ae0389eefad43 Mon Sep 17 00:00:00 2001 From: Nikolaos Tselepidis Date: Fri, 1 Aug 2025 21:06:39 +0200 Subject: [PATCH 045/199] Modify PREFER_GPU macro --- src/common/include/macros.fpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/common/include/macros.fpp b/src/common/include/macros.fpp index b0d87d31b0..0ffad2e06b 100644 --- a/src/common/include/macros.fpp +++ b/src/common/include/macros.fpp @@ -34,14 +34,20 @@ if (prefer_gpu_mode .eq. 1) then #:for arg in args !print*, "Moving ${arg}$ to GPU => ", SHAPE(${arg}$) - ! unset - istat = cudaMemAdvise( c_devloc(${arg}$), SIZEOF(${arg}$), cudaMemAdviseUnSetPreferredLocation, cudaCpuDeviceId ) + ! set preferred location GPU + istat = cudaMemAdvise( c_devloc(${arg}$), SIZEOF(${arg}$), cudaMemAdviseSetPreferredLocation, 0 ) if (istat /= cudaSuccess) then write(*,"('Error code: ',I0, ': ')") istat write(*,*) cudaGetErrorString(istat) endif - ! set - istat = cudaMemAdvise( c_devloc(${arg}$), SIZEOF(${arg}$), cudaMemAdviseSetPreferredLocation, 0 ) + ! set accessed by CPU + istat = cudaMemAdvise( c_devloc(${arg}$), SIZEOF(${arg}$), cudaMemAdviseSetAccessedBy, cudaCpuDeviceId ) + if (istat /= cudaSuccess) then + write(*,"('Error code: ',I0, ': ')") istat + write(*,*) cudaGetErrorString(istat) + endif + ! prefetch to GPU - physically populate memory pages + istat = cudaMemPrefetchAsync( c_devloc(${arg}$), SIZEOF(${arg}$), 0, 0 ) if (istat /= cudaSuccess) then write(*,"('Error code: ',I0, ': ')") istat write(*,*) cudaGetErrorString(istat) From dcd616acd49c3a5aebfb5cf2b9ce96e4389e1eae Mon Sep 17 00:00:00 2001 From: danieljvickers Date: Fri, 1 Aug 2025 16:01:19 -0400 Subject: [PATCH 046/199] Updated CMAKE to actually take half precision flag --- CMakeLists.txt | 6 +++++- src/common/m_precision_select.f90 | 2 +- src/simulation/m_time_steppers.fpp | 14 ++++++-------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8269c1cb48..905b01b960 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,10 @@ else() add_compile_definitions(MFC_DOUBLE_PRECISION) endif() +if (MFC_MIXED_PRECISION) + add_compile_definitions(MFC_MIXED_PRECISION) +endif() + # CMake Library Imports @@ -234,7 +238,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Release") message(STATUS "LTO/IPO is not supported in NVHPC Version < 23.11. Use a newer version of NVHPC for best performance.") else() message(STATUS "Performing IPO using -Mextract followed by -Minline") - set(NVHPC_USE_TWO_PASS_IPO TRUE) + set(NVHPC_USE_TWO_PASS_IPO FALSE) endif() else() CHECK_IPO_SUPPORTED(RESULT SUPPORTS_IPO OUTPUT IPO_ERROR) diff --git a/src/common/m_precision_select.f90 b/src/common/m_precision_select.f90 index eb81ea652d..536363c242 100644 --- a/src/common/m_precision_select.f90 +++ b/src/common/m_precision_select.f90 @@ -13,7 +13,7 @@ module m_precision_select implicit none ! Define the available precision types - integer, parameter :: half_precision = selected_real_kind(3, 4) + integer, parameter :: half_precision = real(kind=2) ! selected_real_kind(3, 4) integer, parameter :: single_precision = selected_real_kind(6, 37) integer, parameter :: double_precision = selected_real_kind(15, 307) diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index f5b4af2880..5f516bd96c 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -346,12 +346,12 @@ contains end do end do - print *, "This is the size of one of the elements in a vector field: ", SIZEOF(q_cons_ts(2)%vf(1)%sf(1, 1, 1)) ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - print *, "This is the size of an half precision value: ", hp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - print *, "This is the size of an single precision value: ", sp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - print *, "This is the size of an double precision value: ", dp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - print *, "This is the size of wp precision value: ", wp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - print *, "This is the size of stp double precision value: ", stp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of a vector field element: ", SIZEOF(q_cons_ts(2)%vf(1)%sf(1, 1, 1)) ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of hp precision: ", hp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of sp precision: ", sp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of dp precision: ", dp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of wp precision: ", wp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + print *, "This is the size of stp precision: ", stp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH end subroutine s_initialize_time_steppers_module @@ -660,8 +660,6 @@ contains real(wp) :: start, finish - print *, "This is the size of one of the elements in a vector field: ", SIZEOF(q_cons_ts(2)%vf(1)%sf(1, 1, 1)) ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - ! Stage 1 of 3 if (.not. adap_dt) then From e28423a47e4eafdd2956b7e361c3816d6b31078a Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Fri, 1 Aug 2025 16:09:41 -0400 Subject: [PATCH 047/199] made nonparameterized molecular_weights to compile few AMD kernels, make attach an always map --- src/common/include/omp_macros.fpp | 38 +++++++++++++++++++++---------- src/common/m_chemistry.fpp | 16 +++++++++---- src/simulation/m_cbc.fpp | 12 ++++++++-- src/simulation/m_start_up.fpp | 9 ++++++++ 4 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 61e45056bc..522bb62167 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -84,13 +84,15 @@ $:deviceptr_val #:enddef -#:def OMP_ATTACH_STR(attach) - #! #:if attach is not None - #! #:stop 'attach is not supported yet' - #! #:endif - #:set attach_val = '' - $:attach_val -#:enddef +#! #:def OMP_ATTACH_STR(attach) + #! #:set attach_val = OMP_MAP_STR('always,to', attach) + #! $:attach_val +#! #:enddef + +#! #:def OMP_DETACH_STR(detach) + #! #:set detach_val = OMP_MAP_STR('always,from', detach) + #! $:detach_val +#! #:enddef #:def OMP_TO_STR(to) #:set to_val = GEN_PARENTHESES_CLAUSE('to', to) @@ -130,7 +132,7 @@ #:set no_create_val = OMP_NOCREATE_STR(no_create) #:set present_val = OMP_PRESENT_STR(present) #:set deviceptr_val = OMP_DEVICEPTR_STR(deviceptr) - #:set attach_val = OMP_MAP_STR('tofrom', attach) + #:set attach_val = OMP_MAP_STR('always,tofrom', attach) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set omp_clause_val = default_val.strip('\n') + private_val.strip('\n') + reduction_val.strip('\n') + & & copy_val.strip('\n') + copyin_val.strip('\n') + & @@ -164,7 +166,7 @@ #:set no_create_val = OMP_NOCREATE_STR(no_create) #:set present_val = OMP_PRESENT_STR(present) #:set deviceptr_val = OMP_DEVICEPTR_STR(deviceptr) - #:set attach_val = OMP_MAP_STR('tofrom', attach) + #:set attach_val = OMP_MAP_STR('always,tofrom', attach) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set clause_val = collapse_val.strip('\n') + parallelism_val.strip('\n') + & & default_val.strip('\n') + private_val.strip('\n') + reduction_val.strip('\n') + & @@ -255,7 +257,7 @@ #:set no_create_val = OMP_NOCREATE_STR(no_create) #:set present_val = OMP_PRESENT_STR(present) #:set deviceptr_val = OMP_DEVICEPTR_STR(deviceptr) - #:set attach_val = OMP_MAP_STR('tofrom', attach) + #:set attach_val = OMP_MAP_STR('always,tofrom', attach) #:set default_val = OMP_DEFAULT_STR(default) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set clause_val = copy_val.strip('\n') + copyin_val.strip('\n') + & @@ -273,7 +275,7 @@ #:def OMP_ENTER_DATA(copyin=None, copyinReadOnly=None, create=None, attach=None, extraOmpArgs=None) #:set copyin_val = OMP_COPYIN_STR(copyin).strip('\n') + OMP_COPYIN_STR(copyinReadOnly).strip('\n') #:set create_val = OMP_CREATE_STR(create) - #:set attach_val = OMP_MAP_STR('to', attach) + #:set attach_val = OMP_MAP_STR('always,to', attach) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set omp_clause_val = copyin_val.strip('\n') + create_val.strip('\n') + attach_val.strip('\n') #:set omp_directive = '!$omp target enter data ' + omp_clause_val + extraOmpArgs_val.strip('\n') @@ -283,7 +285,7 @@ #:def OMP_EXIT_DATA(copyout=None, delete=None, detach=None, extraOmpArgs=None) #:set copyout_val = OMP_COPYOUT_STR(copyout) #:set delete_val = OMP_DELETE_STR(delete) - #:set detach_val = OMP_MAP_STR('from', detach) + #:set detach_val = OMP_MAP_STR('always,from', detach) #:set extraOmpArgs_val = GEN_EXTRA_ARGS_STR(extraOmpArgs) #:set clause_val = copyout_val.strip('\n') + delete_val.strip('\n') + detach_val.strip('\n') #:set omp_directive = '!$omp target exit data ' + clause_val + extraOmpArgs_val.strip('\n') @@ -339,12 +341,24 @@ #:endif #:enddef +#:def DEF_AMD(code) + #:if MFC_COMPILER == AMD_COMPILER_ID + $:code + #:endif +#:enddef + #:def UNDEF_CCE(code) #:if MFC_COMPILER != CCE_COMPILER_ID $:code #:endif #:enddef +#:def DEF_CCE(code) + #:if MFC_COMPILER == CCE_COMPILER_ID + $:code + #:endif +#:enddef + #:def UNDEF_NVIDIA(code) #:if MFC_COMPILER != NVIDIA_COMPILER_ID and MFC_COMPILER != PGI_COMPILER_ID $:code diff --git a/src/common/m_chemistry.fpp b/src/common/m_chemistry.fpp index cd1cfc984e..2e5b13ac43 100644 --- a/src/common/m_chemistry.fpp +++ b/src/common/m_chemistry.fpp @@ -15,6 +15,13 @@ module m_chemistry use m_global_parameters implicit none + + #:block DEF_AMD + real(dp) :: molecular_weights_nonparameter(10) = & + (/ 2.016d0, 1.008d0, 15.999d0, 31.998d0, 17.007d0, 18.015d0, 33.006d0, & + 34.014d0, 39.95d0, 28.014d0 /) + $:GPU_DECLARE(create='[molecular_weights_nonparameter]') + #:endblock DEF_AMD contains @@ -99,7 +106,6 @@ contains real(wp), dimension(num_species) :: Ys real(wp), dimension(num_species) :: omega - #:block UNDEF_AMD #:call GPU_PARALLEL_LOOP(collapse=3, private='[Ys, omega]') do z = bounds(3)%beg, bounds(3)%end do y = bounds(2)%beg, bounds(2)%end @@ -117,9 +123,12 @@ contains $:GPU_LOOP(parallelism='[seq]') do eqn = chemxb, chemxe - + #:block UNDEF_AMD omega_m = molecular_weights(eqn - chemxb + 1)*omega(eqn - chemxb + 1) - + #:endblock UNDEF_AMD + #:block DEF_AMD + omega_m = molecular_weights_nonparameter(eqn - chemxb + 1)*omega(eqn - chemxb + 1) + #:endblock DEF_AMD rhs_vf(eqn)%sf(x, y, z) = rhs_vf(eqn)%sf(x, y, z) + omega_m end do @@ -128,7 +137,6 @@ contains end do end do #:endcall GPU_PARALLEL_LOOP - #:endblock UNDEF_AMD end subroutine s_compute_chemistry_reaction_flux diff --git a/src/simulation/m_cbc.fpp b/src/simulation/m_cbc.fpp index ac7829eb0a..1d3b84229a 100644 --- a/src/simulation/m_cbc.fpp +++ b/src/simulation/m_cbc.fpp @@ -37,6 +37,9 @@ module m_cbc molecular_weights, get_species_specific_heats_r, & get_mole_fractions, get_species_specific_heats_r + #:block DEF_AMD + use m_chemistry, only: molecular_weights_nonparameter + #:endblock DEF_AMD implicit none private; public :: s_initialize_cbc_module, s_cbc, s_finalize_cbc_module @@ -773,7 +776,6 @@ contains end if ! FD2 or FD4 of RHS at j = 0 - #:block UNDEF_AMD #:call GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, dYs_ds, h_k, Cp_i, Gamma_i, Xs]') do r = is3%beg, is3%end do k = is2%beg, is2%end @@ -1050,8 +1052,15 @@ contains sum_Enthalpies = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_species + #:block UNDEF_AMD h_k(i) = h_k(i)*gas_constant/molecular_weights(i)*T sum_Enthalpies = sum_Enthalpies + (rho*h_k(i) - pres*Mw/molecular_weights(i)*Cp/R_gas)*dYs_dt(i) + #:endblock UNDEF_AMD + + #:block DEF_AMD + h_k(i) = h_k(i)*gas_constant/molecular_weights_nonparameter(i)*T + sum_Enthalpies = sum_Enthalpies + (rho*h_k(i) - pres*Mw/molecular_weights_nonparameter(i)*Cp/R_gas)*dYs_dt(i) + #:endblock DEF_AMD end do flux_rs${XYZ}$_vf_l(-1, k, r, E_idx) = flux_rs${XYZ}$_vf_l(0, k, r, E_idx) & + ds(0)*((E/rho + pres/rho)*drho_dt + rho*vel_dv_dt_sum + Cp*T*L(2)/(c*c) + sum_Enthalpies) @@ -1106,7 +1115,6 @@ contains end do end do #:endcall GPU_PARALLEL_LOOP - #:endblock UNDEF_AMD end if #:endfor diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index f6a955ad38..85c7d727ea 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -1453,6 +1453,15 @@ contains $:GPU_UPDATE(device='[igr, igr_order]') + #:block DEF_AMD + block + use m_thermochem, only: molecular_weights + use m_chemistry, only: molecular_weights_nonparameter + molecular_weights_nonparameter(:) = molecular_weights(:) + $:GPU_UPDATE(device='[molecular_weights_nonparameter]') + end block + #:endblock + end subroutine s_initialize_gpu_vars impure subroutine s_finalize_modules From 616a37d6be2e22acc23b884a4a58afe3da481439 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Fri, 1 Aug 2025 16:55:12 -0400 Subject: [PATCH 048/199] Fixed one error and defined how to convert. Moving work from wingtip --- CMakeLists.txt | 3 +- src/common/m_precision_select.f90 | 2 +- src/common/m_variables_conversion.fpp | 2 +- temp.txt | 275 ++++++++++++++++++++++++++ 4 files changed, 279 insertions(+), 3 deletions(-) create mode 100644 temp.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 905b01b960..c8e3760999 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ cmake_minimum_required(VERSION 3.20) # We include C as a language because - for some reason - # FIND_LIBRARY_USE_LIB64_PATHS is otherwise ignored. -project(MFC LANGUAGES C CXX Fortran) +project(MFC LANGUAGES C CUDA CXX Fortran) # Build options exposed to users and their default values. @@ -27,6 +27,7 @@ option(MFC_SYSCHECK "Build syscheck" OFF option(MFC_DOCUMENTATION "Build documentation" OFF) option(MFC_ALL "Build everything" OFF) option(MFC_SINGLE_PRECISION "Build single precision" OFF) +option(MFC_MIXED_PRECISION "Build mixed precision" OFF) if (MFC_ALL) set(MFC_PRE_PROCESS ON FORCE) diff --git a/src/common/m_precision_select.f90 b/src/common/m_precision_select.f90 index 536363c242..3c6f1a87d1 100644 --- a/src/common/m_precision_select.f90 +++ b/src/common/m_precision_select.f90 @@ -13,7 +13,7 @@ module m_precision_select implicit none ! Define the available precision types - integer, parameter :: half_precision = real(kind=2) ! selected_real_kind(3, 4) + integer, parameter :: half_precision = 2 ! selected_real_kind(3, 4) integer, parameter :: single_precision = selected_real_kind(6, 37) integer, parameter :: double_precision = selected_real_kind(15, 307) diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index b9ef279f9e..a426ddbd36 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -119,7 +119,7 @@ contains $:GPU_ROUTINE(function_name='s_compute_pressure',parallelism='[seq]', & & cray_inline=True) - real(wp), intent(in) :: energy, alf + real(stp), intent(in) :: energy, alf real(wp), intent(in) :: dyn_p real(wp), intent(in) :: pi_inf, gamma, rho, qv real(wp), intent(out) :: pres diff --git a/temp.txt b/temp.txt new file mode 100644 index 0000000000..464a2171e7 --- /dev/null +++ b/temp.txt @@ -0,0 +1,275 @@ +mfc: Found CMake: /nethome/dvickers6/repos/MFC-Dan/build/cmake/bin/cmake. +mfc: OK > (venv) Entered the Python 3.10.16 virtual environment (>= 3.9). + +{'command': 'run', 'targets': ['pre_process', 'simulation', 'post_process'], 'mpi': True, 'gpu': False, 'debug': False, 'gcov': False, 'unified': False, 'single': False, 'mixed': True, 'jobs': 1, 'verbose': False, 'gpus': None, 'input': '/nethome/dvickers6/cases/half_p/case.py', 'engine': 'interactive', 'partition': '', 'quality_of_service': '', 'nodes': 1, 'tasks_per_node': 1, 'walltime': '01:00:00', 'account': '', 'email': '', 'name': 'MFC', 'scratch': False, 'binary': None, 'dry_run': False, 'case_optimization': False, 'no_build': False, 'wait': False, 'computer': 'default', 'output_summary': None, 'clean': False, 'ncu': None, 'nsys': None, 'rcu': None, 'rsys': None, '--': [], 'list': False, 'from': 'EA8FA07E', 'to': 'F8ADA51B', 'only': [], 'test_all': False, 'percent': 100, 'max_attempts': 1, 'no_examples': False, 'generate': False, 'add_new_variables': False, 'remove_old_tests': False} + .=++*: -+*+=. | dvickers6@wingtip-gpu3 [Linux] + :+ -*- == =* . | ------------------------------ + :*+ == ++ .+- | + :*##-.....:*+ .#%+++=--+=:::. | --jobs 1 + -=-++-======#=--**+++==+*++=::-:. | --mpi --no-gpu --no-debug --no-gcov --no-unified --no-single --mixed + .:++=----------====+*= ==..:%..... | --targets pre_process, simulation, and post_process + .:-=++++===--==+=-+= +. := | + +#=::::::::=%=. -+: =+ *: | ---------------------------------------------------------- + .*=-=*=.. :=+*+: -...-- | $ ./mfc.sh (build, run, test, clean, count, packer) --help + + Acquiring /nethome/dvickers6/cases/half_p/case.py... + Acquiring /nethome/dvickers6/cases/half_p/case.py... + Build | syscheck, syscheck, pre_process, simulation, and post_process + + Generating case.fpp. + Writing a (new) custom case.fpp file. + $ cmake --build /nethome/dvickers6/repos/MFC-Dan/build/staging/b21a1f4975 --target syscheck --parallel 1 --config Release + +[ 16%] Building Fortran object CMakeFiles/syscheck_lib.dir/modules/syscheck/m_thermochem.f90.o +[ 33%] Building Fortran object CMakeFiles/syscheck_lib.dir/fypp/syscheck/syscheck.fpp.f90.o +[ 50%] Built target syscheck_lib +[100%] Built target syscheck + + $ cmake --install /nethome/dvickers6/repos/MFC-Dan/build/staging/b21a1f4975 + +-- Install configuration: "Release" +-- Installing: /nethome/dvickers6/repos/MFC-Dan/build/install/b21a1f4975/bin/syscheck +-- Set runtime path of "/nethome/dvickers6/repos/MFC-Dan/build/install/b21a1f4975/bin/syscheck" to "" + + Generating case.fpp. + Writing a (new) custom case.fpp file. + $ cmake --build /nethome/dvickers6/repos/MFC-Dan/build/staging/7b8ccae857 --target pre_process --parallel 1 --config Release + +[ 1%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/common/m_precision_select.f90.o +[ 2%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_constants.fpp.f90.o +[ 3%] Building Fortran object CMakeFiles/pre_process_lib.dir/modules/pre_process/m_thermochem.f90.o +[ 4%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_derived_types.fpp.f90.o +[ 5%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_helper_basic.fpp.f90.o +[ 6%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_global_parameters.fpp.f90.o +[ 7%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_helper.fpp.f90.o +[ 8%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/common/m_nvtx.f90.o +[ 9%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_mpi_common.fpp.f90.o +[ 10%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_mpi_proxy.fpp.f90.o +[ 11%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_variables_conversion.fpp.f90.o +[ 13%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_assign_variables.fpp.f90.o +[ 14%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/common/m_compile_specific.f90.o +[ 15%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/common/m_delay_file_access.f90.o +[ 16%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_boundary_common.fpp.f90.o +[ 17%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_boundary_conditions.fpp.f90.o +[ 18%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_data_output.fpp.f90.o +[ 19%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_check_ib_patches.fpp.f90.o +[ 20%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_check_patches.fpp.f90.o +[ 21%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_checker.fpp.f90.o +[ 22%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_checker_common.fpp.f90.o +[ 23%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_chemistry.fpp.f90.o +[ 25%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_compute_levelset.fpp.f90.o +[ 26%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_finite_differences.fpp.f90.o +[ 27%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_model.fpp.f90.o +[ 28%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_patches.fpp.f90.o +[ 29%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_perturbation.fpp.f90.o +[ 30%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_initial_condition.fpp.f90.o +[ 31%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_phase_change.fpp.f90.o +[ 32%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/pre_process/m_grid.f90.o +[ 33%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_start_up.fpp.f90.o +[ 34%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/common/m_eigen_solver.f90.o +[ 35%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/pre_process/p_main.f90.o +[ 63%] Built target pre_process_lib +[100%] Built target pre_process + + $ cmake --install /nethome/dvickers6/repos/MFC-Dan/build/staging/7b8ccae857 + +-- Install configuration: "Release" +-- Installing: /nethome/dvickers6/repos/MFC-Dan/build/install/7b8ccae857/bin/pre_process +-- Set runtime path of "/nethome/dvickers6/repos/MFC-Dan/build/install/7b8ccae857/bin/pre_process" to "" + + Generating case.fpp. + Writing a (new) custom case.fpp file. + $ cmake --build /nethome/dvickers6/repos/MFC-Dan/build/staging/35b0985e3e --target simulation --parallel 1 --config Release + +[ 0%] Building Fortran object CMakeFiles/simulation_lib.dir/src/common/m_precision_select.f90.o +[ 0%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_constants.fpp.f90.o +[ 1%] Building Fortran object CMakeFiles/simulation_lib.dir/modules/simulation/m_thermochem.f90.o +[ 2%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_derived_types.fpp.f90.o +[ 2%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_helper_basic.fpp.f90.o +[ 3%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_global_parameters.fpp.f90.o +[ 4%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_helper.fpp.f90.o +[ 5%] Building Fortran object CMakeFiles/simulation_lib.dir/src/common/m_nvtx.f90.o +[ 6%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_mpi_common.fpp.f90.o +[ 6%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_mpi_proxy.fpp.f90.o +[ 7%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_variables_conversion.fpp.f90.o +[ 8%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_bubbles.fpp.f90.o +[ 9%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_acoustic_src.fpp.f90.o +[ 10%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_body_forces.fpp.f90.o +[ 10%] Building Fortran object CMakeFiles/simulation_lib.dir/src/common/m_compile_specific.f90.o +[ 11%] Building Fortran object CMakeFiles/simulation_lib.dir/src/common/m_delay_file_access.f90.o +[ 12%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_boundary_common.fpp.f90.o +[ 12%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_bubbles_EE.fpp.f90.o +[ 13%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_bubbles_EL_kernels.fpp.f90.o +[ 14%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_sim_helpers.fpp.f90.o +[ 15%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_bubbles_EL.fpp.f90.o +[ 16%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_compute_cbc.fpp.f90.o +[ 17%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_cbc.fpp.f90.o +[ 17%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_checker.fpp.f90.o +[ 18%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_checker_common.fpp.f90.o +[ 19%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_chemistry.fpp.f90.o +[ 20%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_ibm.fpp.f90.o +[ 21%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_data_output.fpp.f90.o +[ 22%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_finite_differences.fpp.f90.o +[ 23%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_fftw.fpp.f90.o +[ 24%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_hyperelastic.fpp.f90.o +[ 25%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_pressure_relaxation.fpp.f90.o +[ 25%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_hypoelastic.fpp.f90.o +[ 26%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_igr.fpp.f90.o +[ 27%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_mhd.fpp.f90.o +[ 28%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_qbmm.fpp.f90.o +[ 29%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_weno.fpp.f90.o +[ 29%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_surface_tension.fpp.f90.o +[ 29%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_riemann_solvers.fpp.f90.o +[ 30%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_viscous.fpp.f90.o +[ 31%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_rhs.fpp.f90.o +[ 32%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_time_steppers.fpp.f90.o +[ 32%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_derived_variables.fpp.f90.o +[ 33%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_phase_change.fpp.f90.o +[ 34%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_start_up.fpp.f90.o +[ 35%] Building Fortran object CMakeFiles/simulation_lib.dir/src/common/m_eigen_solver.f90.o +[ 35%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/p_main.fpp.f90.o +[ 65%] Built target simulation_lib +[100%] Built target simulation + + $ cmake --install /nethome/dvickers6/repos/MFC-Dan/build/staging/35b0985e3e + +-- Install configuration: "Release" +-- Installing: /nethome/dvickers6/repos/MFC-Dan/build/install/35b0985e3e/bin/simulation +-- Set runtime path of "/nethome/dvickers6/repos/MFC-Dan/build/install/35b0985e3e/bin/simulation" to "" + + Generating case.fpp. + Writing a (new) custom case.fpp file. + $ cmake --build /nethome/dvickers6/repos/MFC-Dan/build/staging/5c53382570 --target post_process --parallel 1 --config Release + +[ 1%] Building Fortran object CMakeFiles/post_process_lib.dir/src/common/m_precision_select.f90.o +[ 2%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_constants.fpp.f90.o +[ 4%] Building Fortran object CMakeFiles/post_process_lib.dir/modules/post_process/m_thermochem.f90.o +[ 5%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_derived_types.fpp.f90.o +[ 7%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_helper_basic.fpp.f90.o +[ 8%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_global_parameters.fpp.f90.o +[ 10%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_helper.fpp.f90.o +[ 11%] Building Fortran object CMakeFiles/post_process_lib.dir/src/common/m_nvtx.f90.o +[ 13%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_mpi_common.fpp.f90.o +[ 14%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_mpi_proxy.fpp.f90.o +[ 16%] Building Fortran object CMakeFiles/post_process_lib.dir/src/common/m_compile_specific.f90.o +[ 17%] Building Fortran object CMakeFiles/post_process_lib.dir/src/common/m_delay_file_access.f90.o +[ 19%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_boundary_common.fpp.f90.o +[ 20%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_checker.fpp.f90.o +[ 22%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_checker_common.fpp.f90.o +[ 23%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_chemistry.fpp.f90.o +[ 25%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_variables_conversion.fpp.f90.o +[ 26%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_derived_variables.fpp.f90.o +[ 27%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_data_output.fpp.f90.o +[ 29%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_finite_differences.fpp.f90.o +[ 30%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_phase_change.fpp.f90.o +[ 32%] Building Fortran object CMakeFiles/post_process_lib.dir/src/common/m_eigen_solver.f90.o +[ 33%] Building Fortran object CMakeFiles/post_process_lib.dir/src/post_process/m_data_input.f90.o +[ 35%] Building Fortran object CMakeFiles/post_process_lib.dir/src/post_process/m_start_up.f90.o +[ 36%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/p_main.fpp.f90.o +[ 61%] Built target post_process_lib +[100%] Built target post_process + + $ cmake --install /nethome/dvickers6/repos/MFC-Dan/build/staging/5c53382570 + +-- Install configuration: "Release" +-- Installing: /nethome/dvickers6/repos/MFC-Dan/build/install/5c53382570/bin/post_process +-- Set runtime path of "/nethome/dvickers6/repos/MFC-Dan/build/install/5c53382570/bin/post_process" to "" + + Run + Using queue system Interactive. + Using baked-in template for default. + Generating input files for syscheck... + + Generating syscheck.inp: + INFO: Forwarded 0/58 parameters. + + Generating input files for pre_process... + + Generating pre_process.inp: + INFO: Forwarded 37/58 parameters. + + Generating input files for simulation... + + Generating simulation.inp: + INFO: Forwarded 43/58 parameters. + + Generating input files for post_process... + + Generating post_process.inp: + INFO: Forwarded 26/58 parameters. + + $ /bin/bash /nethome/dvickers6/cases/half_p/MFC.sh + ++-----------------------------------------------------------------------------------------------------------+ +| MFC case # MFC @ /nethome/dvickers6/cases/half_p/case.py: | ++-----------------------------------------------------------------------------------------------------------+ +| * Start-time 15:17:23 * Start-date 15:17:23 | +| * Partition N/A * Walltime 01:00:00 | +| * Account N/A * Nodes 1 | +| * Job Name MFC * Engine interactive | +| * QoS N/A * Binary N/A | +| * Queue System Interactive * Email N/A | ++-----------------------------------------------------------------------------------------------------------+ + +mfc: WARNING > This is the default template. +mfc: WARNING > It is not intended to support all systems and execution engines. +mfc: WARNING > Consider using a different template via the --computer option if you encounter problems. +mfc: OK > :) Selected MPI launcher mpirun. Use --binary to override. +mfc: OK > :) Running syscheck: + + [TEST] MPI: call mpi_init(ierr) + [TEST] MPI: call mpi_comm_rank(MPI_COMM_WORLD, rank, ierr) + [TEST] MPI: call mpi_barrier(MPI_COMM_WORLD, ierr) + [TEST] MPI: call assert(rank >= 0) + [TEST] MPI: call mpi_comm_size(MPI_COMM_WORLD, nRanks, ierr) + [TEST] MPI: call assert(nRanks > 0 .and. rank < nRanks) + [SKIP] ACC: devtype = acc_get_device_type() + [SKIP] ACC: num_devices = acc_get_num_devices(devtype) + [SKIP] ACC: call assert(num_devices > 0) + [SKIP] ACC: call acc_set_device_num(mod(rank, nRanks), devtype) + [SKIP] ACC: allocate(arr(1:N)) + [SKIP] ACC: !$acc enter data create(arr(1:N)) + [SKIP] ACC: !$acc parallel loop + [SKIP] ACC: !$acc update host(arr(1:N)) + [SKIP] ACC: !$acc exit data delete(arr) + [TEST] MPI: call mpi_barrier(MPI_COMM_WORLD, ierr) + [TEST] MPI: call mpi_finalize(ierr) + + Syscheck: PASSED. + +mfc: OK > :) Running pre_process: + + Pre-processing a 41x41x0 case on 1 rank(s) + Processing patch 1 + Elapsed Time 1.7494917E-02 + +mfc: OK > :) Running simulation: + + Simulating a regular 41x41x0 case on 1 rank(s) on CPUs. + This is the size of one of the elements in a vector field: + 4 + This is the size of half precision: 2 + This is the size of single precision: 4 + This is the size of double precision value: 8 + This is the size of wp precision value: 4 + This is the size of stp precision value: 4 + [ 0%] Time step 1 of 6 @ t_step = 0 + [ 17%] Time step 2 of 6 @ t_step = 1 + [ 34%] Time step 3 of 6 @ t_step = 2 + [ 50%] Time step 4 of 6 @ t_step = 3 + [ 67%] Time step 5 of 6 @ t_step = 4 + Performance: 933.0239 ns/gp/eq/rhs + +mfc: OK > :) Running post_process: + + Post-processing a 41x41x0 case on 1 rank(s) + [ 0%] Saving 1 of 2 @ t_step = 0 + [ 84%] Saving 2 of 2 @ t_step = 5 + ++-----------------------------------------------------------------------------------------------------------+ +| Finished MFC: | +| * Total-time: 5s * Exit Code: 0 | +| * End-time: 15:17:28 * End-date: 15:17:28 | ++-----------------------------------------------------------------------------------------------------------+ + +mfc: (venv) Exiting the Python virtual environment. From ee1277d8dae3a02e9e66377f9ce2b28c977bf70f Mon Sep 17 00:00:00 2001 From: Nikolaos Tselepidis Date: Sat, 2 Aug 2025 00:53:53 +0200 Subject: [PATCH 049/199] Allow control in placement of IGR temps --- src/simulation/m_igr.fpp | 124 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index 76069928f2..94fb6cd857 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -24,8 +24,16 @@ module m_igr s_igr_flux_add, & s_finalize_igr_module +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + integer, dimension(3) :: temp_on_gpu + real(wp), pointer, contiguous, dimension(:, :, :) :: jac,jac_rhs,jac_old + real(wp), allocatable, dimension(:, :, :), pinned, target :: pool_host1 + real(wp), allocatable, dimension(:, :, :), pinned, target :: pool_host2 + real(wp), allocatable, dimension(:, :, :), pinned, target :: pool_host3 +#else real(wp), allocatable, dimension(:, :, :) :: jac, jac_rhs, jac_old $:GPU_DECLARE(create='[jac, jac_rhs, jac_old]') +#endif real(wp), allocatable, dimension(:, :) :: Res $:GPU_DECLARE(create='[Res]') @@ -82,6 +90,47 @@ module m_igr contains subroutine s_initialize_igr_module() +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + integer :: igr_temps_total + integer :: igr_temps_on_gpu + integer :: igr_temps_on_cpu + character(len=10) :: igr_temps_on_gpu_str + + ! initialize + if (igr_iter_solver == 1) then ! Jacobi iteration + igr_temps_total = 3 + else + igr_temps_total = 2 + end if + igr_temps_on_gpu = igr_temps_total + igr_temps_on_cpu = 0 + + call get_environment_variable("NVIDIA_IGR_TEMPS_ON_GPU", igr_temps_on_gpu_str) + + if (trim(igr_temps_on_gpu_str) == "0") then + igr_temps_on_gpu = 0 ! jac, jac_rhs and jac_old on CPU + else if (trim(igr_temps_on_gpu_str) == "1") then + igr_temps_on_gpu = 1 ! jac on GPU, jac_rhs on CPU, jac_old on CPU + else if (trim(igr_temps_on_gpu_str) == "2") then + igr_temps_on_gpu = 2 ! jac and jac_rhs on GPU, jac_old on CPU + else if (trim(igr_temps_on_gpu_str) == "3") then + igr_temps_on_gpu = 3 ! jac, jac_rhs and jac_old on GPU + else ! default on GPU + igr_temps_on_gpu = 3 + end if + + ! trim if needed + if ( igr_temps_on_gpu > igr_temps_total ) then + igr_temps_on_gpu = igr_temps_total + end if + igr_temps_on_cpu = igr_temps_total - igr_temps_on_gpu + + ! create map + temp_on_gpu(1:3) = -1 + temp_on_gpu(1:igr_temps_total) = 0 + temp_on_gpu(1:igr_temps_on_gpu) = 1 + print*, temp_on_gpu(1:3) +#endif if (viscous) then @:ALLOCATE(Res(1:2, 1:maxval(Re_size))) @@ -95,6 +144,7 @@ contains @:PREFER_GPU(Re_idx) end if +#ifndef __NVCOMPILER_GPU_UNIFIED_MEM @:ALLOCATE(jac(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) @@ -109,6 +159,55 @@ contains idwbuff(3)%beg:idwbuff(3)%end)) @:PREFER_GPU(jac_old) end if +#else + + if ( temp_on_gpu(1) == 1 ) then + @:ALLOCATE(jac(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end)) + @:PREFER_GPU(jac) + else + print*, 'jac on CPU' + + allocate(pool_host1(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end)) + + jac(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end) => pool_host1(:,:,:) + end if + + if ( temp_on_gpu(2) == 1 ) then + @:ALLOCATE(jac_rhs(-1:m,-1:n,-1:p)) + @:PREFER_GPU(jac_rhs) + else + print*, 'jac_rhs on CPU' + + allocate(pool_host2(-1:m,-1:n,-1:p)) + + jac_rhs(-1:m,-1:n,-1:p) => pool_host2(:,:,:) + end if + + if (igr_iter_solver == 1) then ! Jacobi iteration + if ( temp_on_gpu(3) == 1 ) then + @:ALLOCATE(jac_old(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end)) + @:PREFER_GPU(jac_old) + else + print*, 'jac_old on CPU' + + allocate(pool_host3(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end)) + + jac_old(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end) => pool_host3(:,:,:) + end if + end if +#endif $:GPU_PARALLEL_LOOP(collapse=3) do l = idwbuff(3)%beg, idwbuff(3)%end @@ -2618,11 +2717,36 @@ contains @:DEALLOCATE(Res) end if +#ifndef __NVCOMPILER_GPU_UNIFIED_MEM @:DEALLOCATE(jac, jac_rhs) if (igr_iter_solver == 1) then ! Jacobi iteration @:DEALLOCATE(jac_old) end if +#else + if (temp_on_gpu(1) == 1) then + @:DEALLOCATE(jac) + else + nullify(jac) + deallocate(pool_host1) + end if + + if (temp_on_gpu(2) == 1) then + @:DEALLOCATE(jac_rhs) + else + nullify(jac_rhs) + deallocate(pool_host2) + end if + + if (igr_iter_solver == 1) then ! Jacobi iteration + if (temp_on_gpu(3) == 1) then + @:DEALLOCATE(jac_old) + else + nullify(jac_old) + deallocate(pool_host3) + end if + end if +#endif #:if not MFC_CASE_OPTIMIZATION @:DEALLOCATE(coeff_L, coeff_R) From aaa0ddfd2d44be6671529e2897e57493646b86ff Mon Sep 17 00:00:00 2001 From: Anand Radhakrishnan Date: Fri, 1 Aug 2025 19:22:36 -0400 Subject: [PATCH 050/199] Test suite passes fully on Phoenix (NVHPC + OPENMP), Fixes failing chemistry cases --- src/common/m_constants.fpp | 1 + src/common/m_variables_conversion.fpp | 3 +-- src/simulation/m_riemann_solvers.fpp | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/common/m_constants.fpp b/src/common/m_constants.fpp index 3682bbcf56..16570aff0f 100644 --- a/src/common/m_constants.fpp +++ b/src/common/m_constants.fpp @@ -10,6 +10,7 @@ module m_constants real(wp), parameter :: dflt_real = -1.e6_wp !< Default real value real(wp), parameter :: sgm_eps = 1.e-16_wp !< Segmentation tolerance + real(wp), parameter :: Chem_Tolerance = 1.e-16_wp !< Speed of Sound Tolerance in Chemistry real(wp), parameter :: small_alf = 1.e-11_wp !< Small alf tolerance real(wp), parameter :: pi = 3.141592653589793_wp !< Pi real(wp), parameter :: verysmall = 1.e-12_wp !< Very small number diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index bcccd47e73..36a0562d0e 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -1634,12 +1634,11 @@ contains real(wp), intent(out) :: c real(wp) :: blkmod1, blkmod2 - real(wp) :: Tolerance integer :: q if (chemistry) then - if (avg_state == 1 .and. abs(c_c) > Tolerance) then + if (avg_state == 1 .and. abs(c_c) > Chem_Tolerance) then c = sqrt(c_c - (gamma - 1.0_wp)*(vel_sum - H)) else c = sqrt((1.0_wp + 1.0_wp/gamma)*pres/rho) diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index 436a8e8029..d2258a1dec 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -2326,12 +2326,12 @@ contains #:endcall GPU_PARALLEL_LOOP else ! 5-EQUATION MODEL WITH HLLC - #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel_L, vel_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, alpha_L, alpha_R, s_L, s_R, s_S, vel_avg_rms, pcorr, zcoef, vel_L_tmp, vel_R_tmp, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, tau_e_L, tau_e_R, xi_field_L, xi_field_R, Yi_avg,Phi_avg, h_iL, h_iR, h_avg_2]', copyin='[is1, is2, is3]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[T_L, T_R, vel_L, vel_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, alpha_L, alpha_R, s_L, s_R, s_S, vel_avg_rms, pcorr, zcoef, vel_L_tmp, vel_R_tmp, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, tau_e_L, tau_e_R, xi_field_L, xi_field_R, Yi_avg,Phi_avg, h_iL, h_iR, h_avg_2]', copyin='[is1, is2, is3]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end - !idx1 = 1; if (dir_idx(1) == 2) idx1 = 2; if (dir_idx(1) == 3) idx1 = 3 + idx1 = 1; if (dir_idx(1) == 2) idx1 = 2; if (dir_idx(1) == 3) idx1 = 3 $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids @@ -2459,7 +2459,7 @@ contains T_R = pres_R/rho_R/R_gas_R call get_species_specific_heats_r(T_L, Cp_iL) - call get_species_specific_heats_r(T_R, Cp_iR) + call get_species_specific_heats_r(T_R, Cp_iR) if (chem_params%gamma_method == 1) then !> gamma_method = 1: Ref. Section 2.3.1 Formulation of doi:10.7907/ZKW8-ES97. @@ -2554,20 +2554,20 @@ contains end if H_L = (E_L + pres_L)/rho_L - H_R = (E_R + pres_R)/rho_R + H_R = (E_R + pres_R)/rho_R @:compute_average_state() call s_compute_speed_of_sound(pres_L, rho_L, gamma_L, pi_inf_L, H_L, alpha_L, & - vel_L_rms, 0._wp, c_L) + vel_L_rms, 0._wp, c_L) call s_compute_speed_of_sound(pres_R, rho_R, gamma_R, pi_inf_R, H_R, alpha_R, & - vel_R_rms, 0._wp, c_R) + vel_R_rms, 0._wp, c_R) !> The computation of c_avg does not require all the variables, and therefore the non '_avg' - ! variables are placeholders to call the subroutine. + ! variables are placeholders to call the subroutine. call s_compute_speed_of_sound(pres_R, rho_avg, gamma_avg, pi_inf_R, H_avg, alpha_R, & - vel_avg_rms, c_sum_Yi_Phi, c_avg) + vel_avg_rms, c_sum_Yi_Phi, c_avg) if (viscous) then $:GPU_LOOP(parallelism='[seq]') From 389e5379f37f4286cd82fd57096d44de84bedae2 Mon Sep 17 00:00:00 2001 From: Tanush Prathi Date: Fri, 1 Aug 2025 21:00:36 -0400 Subject: [PATCH 051/199] Make --gpu default to OpenACC if no extra arg given --- toolchain/mfc/args.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/mfc/args.py b/toolchain/mfc/args.py index 3e39750d88..f915e4cbcd 100644 --- a/toolchain/mfc/args.py +++ b/toolchain/mfc/args.py @@ -59,7 +59,7 @@ def add_common_arguments(p: argparse.ArgumentParser, mask = None): if "m" not in mask: for f in dataclasses.fields(config): if f.name == 'gpu': - p.add_argument(f"--{f.name}", action="store", nargs='?', default=gpuConfigOptions.ACC.value, dest=f.name, choices=[e.value for e in gpuConfigOptions], help=f"Turn the {f.name} option to OpenACC or OpenMP.") + p.add_argument(f"--{f.name}", action="store", nargs='?', const= gpuConfigOptions.ACC.value,default=gpuConfigOptions.ACC.value, dest=f.name, choices=[e.value for e in gpuConfigOptions], help=f"Turn the {f.name} option to OpenACC or OpenMP.") p.add_argument(f"--no-{f.name}", action="store_const", const = gpuConfigOptions.NONE.value, dest=f.name, help=f"Turn the {f.name} option OFF.") continue p.add_argument( f"--{f.name}", action="store_true", help=f"Turn the {f.name} option ON.") From 4065c024734978f95498f1be2504781c86da434b Mon Sep 17 00:00:00 2001 From: Nikolaos Tselepidis Date: Sat, 2 Aug 2025 09:26:23 +0200 Subject: [PATCH 052/199] Do some clean up --- src/simulation/m_igr.fpp | 37 +++++------------------------- src/simulation/m_time_steppers.fpp | 5 ++-- 2 files changed, 8 insertions(+), 34 deletions(-) diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index 94fb6cd857..9be4b514c3 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -91,20 +91,9 @@ contains subroutine s_initialize_igr_module() #ifdef __NVCOMPILER_GPU_UNIFIED_MEM - integer :: igr_temps_total - integer :: igr_temps_on_gpu - integer :: igr_temps_on_cpu + integer :: igr_temps_on_gpu = 3 character(len=10) :: igr_temps_on_gpu_str - ! initialize - if (igr_iter_solver == 1) then ! Jacobi iteration - igr_temps_total = 3 - else - igr_temps_total = 2 - end if - igr_temps_on_gpu = igr_temps_total - igr_temps_on_cpu = 0 - call get_environment_variable("NVIDIA_IGR_TEMPS_ON_GPU", igr_temps_on_gpu_str) if (trim(igr_temps_on_gpu_str) == "0") then @@ -119,17 +108,10 @@ contains igr_temps_on_gpu = 3 end if - ! trim if needed - if ( igr_temps_on_gpu > igr_temps_total ) then - igr_temps_on_gpu = igr_temps_total - end if - igr_temps_on_cpu = igr_temps_total - igr_temps_on_gpu - ! create map - temp_on_gpu(1:3) = -1 - temp_on_gpu(1:igr_temps_total) = 0 + temp_on_gpu(1:3) = 0 temp_on_gpu(1:igr_temps_on_gpu) = 1 - print*, temp_on_gpu(1:3) + !print*, temp_on_gpu(1:3) #endif if (viscous) then @@ -148,16 +130,12 @@ contains @:ALLOCATE(jac(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) - @:PREFER_GPU(jac) - @:ALLOCATE(jac_rhs(-1:m,-1:n,-1:p)) - @:PREFER_GPU(jac_rhs) if (igr_iter_solver == 1) then ! Jacobi iteration @:ALLOCATE(jac_old(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) - @:PREFER_GPU(jac_old) end if #else @@ -167,8 +145,7 @@ contains idwbuff(3)%beg:idwbuff(3)%end)) @:PREFER_GPU(jac) else - print*, 'jac on CPU' - + !print*, 'jac on CPU' allocate(pool_host1(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) @@ -182,8 +159,7 @@ contains @:ALLOCATE(jac_rhs(-1:m,-1:n,-1:p)) @:PREFER_GPU(jac_rhs) else - print*, 'jac_rhs on CPU' - + !print*, 'jac_rhs on CPU' allocate(pool_host2(-1:m,-1:n,-1:p)) jac_rhs(-1:m,-1:n,-1:p) => pool_host2(:,:,:) @@ -196,8 +172,7 @@ contains idwbuff(3)%beg:idwbuff(3)%end)) @:PREFER_GPU(jac_old) else - print*, 'jac_old on CPU' - + !print*, 'jac_old on CPU' allocate(pool_host3(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index 0d9ddfd885..8f86202bbe 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -75,12 +75,11 @@ module m_time_steppers integer, private :: num_ts !< !! Number of time stages in the time-stepping scheme - integer, private :: out_of_core - $:GPU_DECLARE(create='[q_cons_ts,q_prim_vf,q_T_sf,rhs_vf,q_prim_ts,rhs_mv,rhs_pb,max_dt]') #ifdef __NVCOMPILER_GPU_UNIFIED_MEM real(wp), allocatable, dimension(:, :, :, :), pinned, target :: q_cons_ts_pool_host + integer, private :: out_of_core #endif contains @@ -92,10 +91,10 @@ contains integer :: i, j !< Generic loop iterators +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM character(len=10) :: out_of_core_str out_of_core = 0 -#ifdef __NVCOMPILER_GPU_UNIFIED_MEM call get_environment_variable("MFC_OUT_OF_CORE", out_of_core_str) if (trim(out_of_core_str) == "0") then From a64686a71f66314a42b0106ff61ce2a1f26e562a Mon Sep 17 00:00:00 2001 From: danieljvickers Date: Sat, 2 Aug 2025 14:26:01 -0400 Subject: [PATCH 053/199] I did not intend to commit the temp file --- temp.txt | 275 ------------------------------------------------------- 1 file changed, 275 deletions(-) delete mode 100644 temp.txt diff --git a/temp.txt b/temp.txt deleted file mode 100644 index 464a2171e7..0000000000 --- a/temp.txt +++ /dev/null @@ -1,275 +0,0 @@ -mfc: Found CMake: /nethome/dvickers6/repos/MFC-Dan/build/cmake/bin/cmake. -mfc: OK > (venv) Entered the Python 3.10.16 virtual environment (>= 3.9). - -{'command': 'run', 'targets': ['pre_process', 'simulation', 'post_process'], 'mpi': True, 'gpu': False, 'debug': False, 'gcov': False, 'unified': False, 'single': False, 'mixed': True, 'jobs': 1, 'verbose': False, 'gpus': None, 'input': '/nethome/dvickers6/cases/half_p/case.py', 'engine': 'interactive', 'partition': '', 'quality_of_service': '', 'nodes': 1, 'tasks_per_node': 1, 'walltime': '01:00:00', 'account': '', 'email': '', 'name': 'MFC', 'scratch': False, 'binary': None, 'dry_run': False, 'case_optimization': False, 'no_build': False, 'wait': False, 'computer': 'default', 'output_summary': None, 'clean': False, 'ncu': None, 'nsys': None, 'rcu': None, 'rsys': None, '--': [], 'list': False, 'from': 'EA8FA07E', 'to': 'F8ADA51B', 'only': [], 'test_all': False, 'percent': 100, 'max_attempts': 1, 'no_examples': False, 'generate': False, 'add_new_variables': False, 'remove_old_tests': False} - .=++*: -+*+=. | dvickers6@wingtip-gpu3 [Linux] - :+ -*- == =* . | ------------------------------ - :*+ == ++ .+- | - :*##-.....:*+ .#%+++=--+=:::. | --jobs 1 - -=-++-======#=--**+++==+*++=::-:. | --mpi --no-gpu --no-debug --no-gcov --no-unified --no-single --mixed - .:++=----------====+*= ==..:%..... | --targets pre_process, simulation, and post_process - .:-=++++===--==+=-+= +. := | - +#=::::::::=%=. -+: =+ *: | ---------------------------------------------------------- - .*=-=*=.. :=+*+: -...-- | $ ./mfc.sh (build, run, test, clean, count, packer) --help - - Acquiring /nethome/dvickers6/cases/half_p/case.py... - Acquiring /nethome/dvickers6/cases/half_p/case.py... - Build | syscheck, syscheck, pre_process, simulation, and post_process - - Generating case.fpp. - Writing a (new) custom case.fpp file. - $ cmake --build /nethome/dvickers6/repos/MFC-Dan/build/staging/b21a1f4975 --target syscheck --parallel 1 --config Release - -[ 16%] Building Fortran object CMakeFiles/syscheck_lib.dir/modules/syscheck/m_thermochem.f90.o -[ 33%] Building Fortran object CMakeFiles/syscheck_lib.dir/fypp/syscheck/syscheck.fpp.f90.o -[ 50%] Built target syscheck_lib -[100%] Built target syscheck - - $ cmake --install /nethome/dvickers6/repos/MFC-Dan/build/staging/b21a1f4975 - --- Install configuration: "Release" --- Installing: /nethome/dvickers6/repos/MFC-Dan/build/install/b21a1f4975/bin/syscheck --- Set runtime path of "/nethome/dvickers6/repos/MFC-Dan/build/install/b21a1f4975/bin/syscheck" to "" - - Generating case.fpp. - Writing a (new) custom case.fpp file. - $ cmake --build /nethome/dvickers6/repos/MFC-Dan/build/staging/7b8ccae857 --target pre_process --parallel 1 --config Release - -[ 1%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/common/m_precision_select.f90.o -[ 2%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_constants.fpp.f90.o -[ 3%] Building Fortran object CMakeFiles/pre_process_lib.dir/modules/pre_process/m_thermochem.f90.o -[ 4%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_derived_types.fpp.f90.o -[ 5%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_helper_basic.fpp.f90.o -[ 6%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_global_parameters.fpp.f90.o -[ 7%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_helper.fpp.f90.o -[ 8%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/common/m_nvtx.f90.o -[ 9%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_mpi_common.fpp.f90.o -[ 10%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_mpi_proxy.fpp.f90.o -[ 11%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_variables_conversion.fpp.f90.o -[ 13%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_assign_variables.fpp.f90.o -[ 14%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/common/m_compile_specific.f90.o -[ 15%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/common/m_delay_file_access.f90.o -[ 16%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_boundary_common.fpp.f90.o -[ 17%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_boundary_conditions.fpp.f90.o -[ 18%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_data_output.fpp.f90.o -[ 19%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_check_ib_patches.fpp.f90.o -[ 20%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_check_patches.fpp.f90.o -[ 21%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_checker.fpp.f90.o -[ 22%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_checker_common.fpp.f90.o -[ 23%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_chemistry.fpp.f90.o -[ 25%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_compute_levelset.fpp.f90.o -[ 26%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_finite_differences.fpp.f90.o -[ 27%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_model.fpp.f90.o -[ 28%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_patches.fpp.f90.o -[ 29%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_perturbation.fpp.f90.o -[ 30%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_initial_condition.fpp.f90.o -[ 31%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_phase_change.fpp.f90.o -[ 32%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/pre_process/m_grid.f90.o -[ 33%] Building Fortran object CMakeFiles/pre_process_lib.dir/fypp/pre_process/m_start_up.fpp.f90.o -[ 34%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/common/m_eigen_solver.f90.o -[ 35%] Building Fortran object CMakeFiles/pre_process_lib.dir/src/pre_process/p_main.f90.o -[ 63%] Built target pre_process_lib -[100%] Built target pre_process - - $ cmake --install /nethome/dvickers6/repos/MFC-Dan/build/staging/7b8ccae857 - --- Install configuration: "Release" --- Installing: /nethome/dvickers6/repos/MFC-Dan/build/install/7b8ccae857/bin/pre_process --- Set runtime path of "/nethome/dvickers6/repos/MFC-Dan/build/install/7b8ccae857/bin/pre_process" to "" - - Generating case.fpp. - Writing a (new) custom case.fpp file. - $ cmake --build /nethome/dvickers6/repos/MFC-Dan/build/staging/35b0985e3e --target simulation --parallel 1 --config Release - -[ 0%] Building Fortran object CMakeFiles/simulation_lib.dir/src/common/m_precision_select.f90.o -[ 0%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_constants.fpp.f90.o -[ 1%] Building Fortran object CMakeFiles/simulation_lib.dir/modules/simulation/m_thermochem.f90.o -[ 2%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_derived_types.fpp.f90.o -[ 2%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_helper_basic.fpp.f90.o -[ 3%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_global_parameters.fpp.f90.o -[ 4%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_helper.fpp.f90.o -[ 5%] Building Fortran object CMakeFiles/simulation_lib.dir/src/common/m_nvtx.f90.o -[ 6%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_mpi_common.fpp.f90.o -[ 6%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_mpi_proxy.fpp.f90.o -[ 7%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_variables_conversion.fpp.f90.o -[ 8%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_bubbles.fpp.f90.o -[ 9%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_acoustic_src.fpp.f90.o -[ 10%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_body_forces.fpp.f90.o -[ 10%] Building Fortran object CMakeFiles/simulation_lib.dir/src/common/m_compile_specific.f90.o -[ 11%] Building Fortran object CMakeFiles/simulation_lib.dir/src/common/m_delay_file_access.f90.o -[ 12%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_boundary_common.fpp.f90.o -[ 12%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_bubbles_EE.fpp.f90.o -[ 13%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_bubbles_EL_kernels.fpp.f90.o -[ 14%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_sim_helpers.fpp.f90.o -[ 15%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_bubbles_EL.fpp.f90.o -[ 16%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_compute_cbc.fpp.f90.o -[ 17%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_cbc.fpp.f90.o -[ 17%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_checker.fpp.f90.o -[ 18%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_checker_common.fpp.f90.o -[ 19%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_chemistry.fpp.f90.o -[ 20%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_ibm.fpp.f90.o -[ 21%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_data_output.fpp.f90.o -[ 22%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_finite_differences.fpp.f90.o -[ 23%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_fftw.fpp.f90.o -[ 24%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_hyperelastic.fpp.f90.o -[ 25%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_pressure_relaxation.fpp.f90.o -[ 25%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_hypoelastic.fpp.f90.o -[ 26%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_igr.fpp.f90.o -[ 27%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_mhd.fpp.f90.o -[ 28%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_qbmm.fpp.f90.o -[ 29%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_weno.fpp.f90.o -[ 29%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_surface_tension.fpp.f90.o -[ 29%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_riemann_solvers.fpp.f90.o -[ 30%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_viscous.fpp.f90.o -[ 31%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_rhs.fpp.f90.o -[ 32%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_time_steppers.fpp.f90.o -[ 32%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_derived_variables.fpp.f90.o -[ 33%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_phase_change.fpp.f90.o -[ 34%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/m_start_up.fpp.f90.o -[ 35%] Building Fortran object CMakeFiles/simulation_lib.dir/src/common/m_eigen_solver.f90.o -[ 35%] Building Fortran object CMakeFiles/simulation_lib.dir/fypp/simulation/p_main.fpp.f90.o -[ 65%] Built target simulation_lib -[100%] Built target simulation - - $ cmake --install /nethome/dvickers6/repos/MFC-Dan/build/staging/35b0985e3e - --- Install configuration: "Release" --- Installing: /nethome/dvickers6/repos/MFC-Dan/build/install/35b0985e3e/bin/simulation --- Set runtime path of "/nethome/dvickers6/repos/MFC-Dan/build/install/35b0985e3e/bin/simulation" to "" - - Generating case.fpp. - Writing a (new) custom case.fpp file. - $ cmake --build /nethome/dvickers6/repos/MFC-Dan/build/staging/5c53382570 --target post_process --parallel 1 --config Release - -[ 1%] Building Fortran object CMakeFiles/post_process_lib.dir/src/common/m_precision_select.f90.o -[ 2%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_constants.fpp.f90.o -[ 4%] Building Fortran object CMakeFiles/post_process_lib.dir/modules/post_process/m_thermochem.f90.o -[ 5%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_derived_types.fpp.f90.o -[ 7%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_helper_basic.fpp.f90.o -[ 8%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_global_parameters.fpp.f90.o -[ 10%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_helper.fpp.f90.o -[ 11%] Building Fortran object CMakeFiles/post_process_lib.dir/src/common/m_nvtx.f90.o -[ 13%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_mpi_common.fpp.f90.o -[ 14%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_mpi_proxy.fpp.f90.o -[ 16%] Building Fortran object CMakeFiles/post_process_lib.dir/src/common/m_compile_specific.f90.o -[ 17%] Building Fortran object CMakeFiles/post_process_lib.dir/src/common/m_delay_file_access.f90.o -[ 19%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_boundary_common.fpp.f90.o -[ 20%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_checker.fpp.f90.o -[ 22%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_checker_common.fpp.f90.o -[ 23%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_chemistry.fpp.f90.o -[ 25%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_variables_conversion.fpp.f90.o -[ 26%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_derived_variables.fpp.f90.o -[ 27%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_data_output.fpp.f90.o -[ 29%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_finite_differences.fpp.f90.o -[ 30%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/m_phase_change.fpp.f90.o -[ 32%] Building Fortran object CMakeFiles/post_process_lib.dir/src/common/m_eigen_solver.f90.o -[ 33%] Building Fortran object CMakeFiles/post_process_lib.dir/src/post_process/m_data_input.f90.o -[ 35%] Building Fortran object CMakeFiles/post_process_lib.dir/src/post_process/m_start_up.f90.o -[ 36%] Building Fortran object CMakeFiles/post_process_lib.dir/fypp/post_process/p_main.fpp.f90.o -[ 61%] Built target post_process_lib -[100%] Built target post_process - - $ cmake --install /nethome/dvickers6/repos/MFC-Dan/build/staging/5c53382570 - --- Install configuration: "Release" --- Installing: /nethome/dvickers6/repos/MFC-Dan/build/install/5c53382570/bin/post_process --- Set runtime path of "/nethome/dvickers6/repos/MFC-Dan/build/install/5c53382570/bin/post_process" to "" - - Run - Using queue system Interactive. - Using baked-in template for default. - Generating input files for syscheck... - - Generating syscheck.inp: - INFO: Forwarded 0/58 parameters. - - Generating input files for pre_process... - - Generating pre_process.inp: - INFO: Forwarded 37/58 parameters. - - Generating input files for simulation... - - Generating simulation.inp: - INFO: Forwarded 43/58 parameters. - - Generating input files for post_process... - - Generating post_process.inp: - INFO: Forwarded 26/58 parameters. - - $ /bin/bash /nethome/dvickers6/cases/half_p/MFC.sh - -+-----------------------------------------------------------------------------------------------------------+ -| MFC case # MFC @ /nethome/dvickers6/cases/half_p/case.py: | -+-----------------------------------------------------------------------------------------------------------+ -| * Start-time 15:17:23 * Start-date 15:17:23 | -| * Partition N/A * Walltime 01:00:00 | -| * Account N/A * Nodes 1 | -| * Job Name MFC * Engine interactive | -| * QoS N/A * Binary N/A | -| * Queue System Interactive * Email N/A | -+-----------------------------------------------------------------------------------------------------------+ - -mfc: WARNING > This is the default template. -mfc: WARNING > It is not intended to support all systems and execution engines. -mfc: WARNING > Consider using a different template via the --computer option if you encounter problems. -mfc: OK > :) Selected MPI launcher mpirun. Use --binary to override. -mfc: OK > :) Running syscheck: - - [TEST] MPI: call mpi_init(ierr) - [TEST] MPI: call mpi_comm_rank(MPI_COMM_WORLD, rank, ierr) - [TEST] MPI: call mpi_barrier(MPI_COMM_WORLD, ierr) - [TEST] MPI: call assert(rank >= 0) - [TEST] MPI: call mpi_comm_size(MPI_COMM_WORLD, nRanks, ierr) - [TEST] MPI: call assert(nRanks > 0 .and. rank < nRanks) - [SKIP] ACC: devtype = acc_get_device_type() - [SKIP] ACC: num_devices = acc_get_num_devices(devtype) - [SKIP] ACC: call assert(num_devices > 0) - [SKIP] ACC: call acc_set_device_num(mod(rank, nRanks), devtype) - [SKIP] ACC: allocate(arr(1:N)) - [SKIP] ACC: !$acc enter data create(arr(1:N)) - [SKIP] ACC: !$acc parallel loop - [SKIP] ACC: !$acc update host(arr(1:N)) - [SKIP] ACC: !$acc exit data delete(arr) - [TEST] MPI: call mpi_barrier(MPI_COMM_WORLD, ierr) - [TEST] MPI: call mpi_finalize(ierr) - - Syscheck: PASSED. - -mfc: OK > :) Running pre_process: - - Pre-processing a 41x41x0 case on 1 rank(s) - Processing patch 1 - Elapsed Time 1.7494917E-02 - -mfc: OK > :) Running simulation: - - Simulating a regular 41x41x0 case on 1 rank(s) on CPUs. - This is the size of one of the elements in a vector field: - 4 - This is the size of half precision: 2 - This is the size of single precision: 4 - This is the size of double precision value: 8 - This is the size of wp precision value: 4 - This is the size of stp precision value: 4 - [ 0%] Time step 1 of 6 @ t_step = 0 - [ 17%] Time step 2 of 6 @ t_step = 1 - [ 34%] Time step 3 of 6 @ t_step = 2 - [ 50%] Time step 4 of 6 @ t_step = 3 - [ 67%] Time step 5 of 6 @ t_step = 4 - Performance: 933.0239 ns/gp/eq/rhs - -mfc: OK > :) Running post_process: - - Post-processing a 41x41x0 case on 1 rank(s) - [ 0%] Saving 1 of 2 @ t_step = 0 - [ 84%] Saving 2 of 2 @ t_step = 5 - -+-----------------------------------------------------------------------------------------------------------+ -| Finished MFC: | -| * Total-time: 5s * Exit Code: 0 | -| * End-time: 15:17:28 * End-date: 15:17:28 | -+-----------------------------------------------------------------------------------------------------------+ - -mfc: (venv) Exiting the Python virtual environment. From de78aeedca52c4407bf0b4549c961c8653e21053 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Sat, 2 Aug 2025 15:56:37 -0400 Subject: [PATCH 054/199] Made it 11% through pre_process --- src/common/m_boundary_common.fpp | 2 +- src/common/m_variables_conversion.fpp | 2 +- src/pre_process/m_assign_variables.fpp | 4 ++-- src/pre_process/m_data_output.fpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common/m_boundary_common.fpp b/src/common/m_boundary_common.fpp index 3dc4da2c2e..3e4a94049a 100644 --- a/src/common/m_boundary_common.fpp +++ b/src/common/m_boundary_common.fpp @@ -1466,7 +1466,7 @@ contains impure subroutine s_populate_F_igr_buffers(bc_type, jac) type(integer_field), dimension(1:num_dims, -1:1), intent(in) :: bc_type - real(wp), target, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:), intent(inout) :: jac + real(stp), target, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:), intent(inout) :: jac integer :: j, k, l diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index a426ddbd36..05c89a1b29 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -1363,7 +1363,7 @@ contains q_cons_vf(n_idx)%sf(j, k, l) = q_prim_vf(n_idx)%sf(j, k, l) nbub = q_prim_vf(n_idx)%sf(j, k, l) else - call s_comp_n_from_prim(q_prim_vf(alf_idx)%sf(j, k, l), Rtmp, nbub, weight) + call s_comp_n_from_prim(real(q_prim_vf(alf_idx)%sf(j, k, l), kind=wp), Rtmp, nbub, weight) end if else !Initialize R3 averaging over R0 and R directions diff --git a/src/pre_process/m_assign_variables.fpp b/src/pre_process/m_assign_variables.fpp index e40ebffeff..4d2b6aceb9 100644 --- a/src/pre_process/m_assign_variables.fpp +++ b/src/pre_process/m_assign_variables.fpp @@ -666,11 +666,11 @@ contains if (bubbles_euler .and. (.not. polytropic) .and. (.not. qbmm)) then do i = 1, nb - if (f_is_default(q_prim_vf(bub_idx%ps(i))%sf(j, k, l))) then + if (f_is_default(real(q_prim_vf(bub_idx%ps(i))%sf(j, k, l), kind=wp))) then q_prim_vf(bub_idx%ps(i))%sf(j, k, l) = pb0(i) ! print *, 'setting to pb0' end if - if (f_is_default(q_prim_vf(bub_idx%ms(i))%sf(j, k, l))) then + if (f_is_default(real(q_prim_vf(bub_idx%ms(i))%sf(j, k, l), kind=wp))) then q_prim_vf(bub_idx%ms(i))%sf(j, k, l) = mass_v0(i) end if end do diff --git a/src/pre_process/m_data_output.fpp b/src/pre_process/m_data_output.fpp index 5465af4229..5d070e2aa4 100644 --- a/src/pre_process/m_data_output.fpp +++ b/src/pre_process/m_data_output.fpp @@ -353,7 +353,7 @@ contains nRtmp(k) = q_cons_vf(bub_idx%rs(k))%sf(j, 0, 0) end do - call s_comp_n_from_cons(q_cons_vf(alf_idx)%sf(j, 0, 0), nRtmp, nbub, weight) + call s_comp_n_from_cons(real(q_cons_vf(alf_idx)%sf(j, 0, 0), kind=wp), nRtmp, nbub, weight) end if end if write (2, FMT) x_cb(j), q_cons_vf(i)%sf(j, 0, 0)/nbub From d9eb6e08b7c91e014366ee3e2b39468038ea52dc Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Sat, 2 Aug 2025 16:12:13 -0400 Subject: [PATCH 055/199] Made it through 86% of pre_process --- src/common/m_chemistry.fpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/m_chemistry.fpp b/src/common/m_chemistry.fpp index 71aa890e87..d5e42cdc08 100644 --- a/src/common/m_chemistry.fpp +++ b/src/common/m_chemistry.fpp @@ -52,7 +52,7 @@ contains 0.5_wp*(q_cons_vf(eqn)%sf(x, y, z)/q_cons_vf(contxb)%sf(x, y, z))**2._wp end do - call get_temperature(energy, dflt_T_guess, Ys, .true., q_T_sf%sf(x, y, z)) + call get_temperature(energy, dflt_T_guess, Ys, .true., real(q_T_sf%sf(x, y, z), kind=wp)) end do end do end do From 78d9490a407c69de4ff9b4a58aaeea542601c674 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Sat, 2 Aug 2025 16:36:44 -0400 Subject: [PATCH 056/199] Made it through 66% of simulation --- src/common/m_variables_conversion.fpp | 6 +++--- src/pre_process/m_patches.fpp | 4 ++-- src/pre_process/m_perturbation.fpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index 05c89a1b29..6f8d894ec2 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -741,7 +741,7 @@ contains type(scalar_field), dimension(sys_size), intent(in) :: qK_cons_vf - real(wp), dimension(idwint(1)%beg:, idwint(2)%beg:, idwint(3)%beg:, 1:, 1:), intent(inout) :: mv + real(stp), dimension(idwint(1)%beg:, idwint(2)%beg:, idwint(3)%beg:, 1:, 1:), intent(inout) :: mv integer :: i, j, k, l real(wp) :: mu, sig, nbub_sc @@ -773,8 +773,8 @@ contains pure subroutine s_initialize_pb(qK_cons_vf, mv, pb) type(scalar_field), dimension(sys_size), intent(in) :: qK_cons_vf - real(wp), dimension(idwint(1)%beg:, idwint(2)%beg:, idwint(3)%beg:, 1:, 1:), intent(in) :: mv - real(wp), dimension(idwint(1)%beg:, idwint(2)%beg:, idwint(3)%beg:, 1:, 1:), intent(inout) :: pb + real(stp), dimension(idwint(1)%beg:, idwint(2)%beg:, idwint(3)%beg:, 1:, 1:), intent(in) :: mv + real(stp), dimension(idwint(1)%beg:, idwint(2)%beg:, idwint(3)%beg:, 1:, 1:), intent(inout) :: pb integer :: i, j, k, l real(wp) :: mu, sig, nbub_sc diff --git a/src/pre_process/m_patches.fpp b/src/pre_process/m_patches.fpp index db09af9d1f..f8cc7484cc 100644 --- a/src/pre_process/m_patches.fpp +++ b/src/pre_process/m_patches.fpp @@ -2182,7 +2182,7 @@ contains ! Correct the sign of the levelset if (patch_id_fp(i, j, k) > 0) then - STL_levelset%sf(i, j, k, patch_id) = -abs(STL_levelset%sf(i, j, k, patch_id)) + STL_levelset%sf(i, j, k, patch_id) = -real(abs(real(STL_levelset%sf(i, j, k, patch_id), kind=wp)), kind=stp) ! TODO :: Make sure this isn't slow. It feels bad. end if ! Correct the sign of the levelset_norm @@ -2208,7 +2208,7 @@ contains ! Correct the sign of the levelset if (patch_id_fp(i, j, k) > 0) then - STL_levelset%sf(i, j, 0, patch_id) = -abs(STL_levelset%sf(i, j, 0, patch_id)) + STL_levelset%sf(i, j, 0, patch_id) = -real(abs(real(STL_levelset%sf(i, j, 0, patch_id), kind=wp)), kind=stp) end if ! Get the boundary normals diff --git a/src/pre_process/m_perturbation.fpp b/src/pre_process/m_perturbation.fpp index 32b3eaa2b7..e8a178c9b5 100644 --- a/src/pre_process/m_perturbation.fpp +++ b/src/pre_process/m_perturbation.fpp @@ -98,7 +98,7 @@ contains do q = 1, elliptic_smoothing_iters ! Communication of buffer regions and apply boundary conditions - call s_populate_variables_buffers(bc_type, q_prim_vf, pb%sf, mv%sf) + call s_populate_variables_buffers(bc_type, q_prim_vf, real(pb%sf, kind=wp), real(mv%sf, kind=wp)) ! Perform smoothing and store in temp array if (n == 0) then From 4ade3006b00408e04544da305a5cc558f3a326a9 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Sat, 2 Aug 2025 21:05:18 -0400 Subject: [PATCH 057/199] Made it through even more of simulation --- src/common/m_variables_conversion.fpp | 3 ++- src/simulation/m_bubbles_EE.fpp | 4 ++-- src/simulation/m_ibm.fpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index 6f8d894ec2..74170c48c2 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -124,7 +124,8 @@ contains real(wp), intent(in) :: pi_inf, gamma, rho, qv real(wp), intent(out) :: pres real(wp), intent(inout) :: T - real(wp), intent(in), optional :: stress, mom, G, pres_mag + real(stp), intent(in), optional :: stress, mom + real(wp), intent(in), optional :: G, pres_mag ! Chemistry real(wp), dimension(1:num_species), intent(in) :: rhoYks diff --git a/src/simulation/m_bubbles_EE.fpp b/src/simulation/m_bubbles_EE.fpp index b43a89e2e5..2e1abac51a 100644 --- a/src/simulation/m_bubbles_EE.fpp +++ b/src/simulation/m_bubbles_EE.fpp @@ -290,7 +290,7 @@ contains call s_advance_step(myRho, myP, myR, myV, R0(q), & pb_local, pbdot, alf, n_tait, B_tait, & - bub_adv_src(j, k, l), divu_in%sf(j, k, l), & + bub_adv_src(j, k, l), real(divu_in%sf(j, k, l), kind=wp), & dmBub_id, dmMass_v, dmMass_n, dmBeta_c, & dmBeta_t, dmCson, adap_dt_stop) @@ -300,7 +300,7 @@ contains else rddot = f_rddot(myRho, myP, myR, myV, R0(q), & pb_local, pbdot, alf, n_tait, B_tait, & - bub_adv_src(j, k, l), divu_in%sf(j, k, l), & + bub_adv_src(j, k, l), real(divu_in%sf(j, k, l), kind=wp), & dmCson) bub_v_src(j, k, l, q) = nbub*rddot bub_r_src(j, k, l, q) = q_cons_vf(vs(q))%sf(j, k, l) diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index 9b18f5b5fc..a7e439fca9 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -371,7 +371,7 @@ contains ! Calculate and store the precise location of the image point patch_id = gp%ib_patch_id - dist = abs(levelset_in%sf(i, j, k, patch_id)) + dist = abs(real(levelset_in%sf(i, j, k, patch_id), kind=wp)) norm(:) = levelset_norm_in%sf(i, j, k, patch_id, :) ghost_points_in(q)%ip_loc(:) = physical_loc(:) + 2*dist*norm(:) From 2feca3b4c897ec65e5c461bdf983b02a7654d1ce Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Sat, 2 Aug 2025 21:32:11 -0400 Subject: [PATCH 058/199] Made it through the time stepper compiling --- src/common/m_boundary_common.fpp | 10 +++++----- src/common/m_mpi_common.fpp | 2 +- src/pre_process/m_perturbation.fpp | 2 +- src/simulation/m_hypoelastic.fpp | 2 +- src/simulation/m_igr.fpp | 4 ++-- src/simulation/m_rhs.fpp | 6 ++++-- src/simulation/m_surface_tension.fpp | 2 +- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/common/m_boundary_common.fpp b/src/common/m_boundary_common.fpp index 3e4a94049a..d60edb8fb6 100644 --- a/src/common/m_boundary_common.fpp +++ b/src/common/m_boundary_common.fpp @@ -82,7 +82,7 @@ contains impure subroutine s_populate_variables_buffers(bc_type, q_prim_vf, pb_in, mv_in) type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf - real(wp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in + real(stp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in type(integer_field), dimension(1:num_dims, -1:1), intent(in) :: bc_type integer :: k, l @@ -340,7 +340,7 @@ contains pure subroutine s_symmetry(q_prim_vf, bc_dir, bc_loc, k, l, pb_in, mv_in) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf - real(wp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in + real(stp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in integer, intent(in) :: bc_dir, bc_loc integer, intent(in) :: k, l @@ -600,7 +600,7 @@ contains pure subroutine s_periodic(q_prim_vf, bc_dir, bc_loc, k, l, pb_in, mv_in) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf - real(wp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in + real(stp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in integer, intent(in) :: bc_dir, bc_loc integer, intent(in) :: k, l @@ -739,7 +739,7 @@ contains pure subroutine s_axis(q_prim_vf, pb_in, mv_in, k, l) $:GPU_ROUTINE(parallelism='[seq]') type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in + real(stp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in integer, intent(in) :: k, l integer :: j, q, i @@ -1081,7 +1081,7 @@ contains pure subroutine s_qbmm_extrapolation(bc_dir, bc_loc, k, l, pb_in, mv_in) $:GPU_ROUTINE(parallelism='[seq]') - real(wp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in + real(stp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in integer, intent(in) :: bc_dir, bc_loc integer, intent(in) :: k, l diff --git a/src/common/m_mpi_common.fpp b/src/common/m_mpi_common.fpp index da485fa3ac..6a35dba19b 100644 --- a/src/common/m_mpi_common.fpp +++ b/src/common/m_mpi_common.fpp @@ -612,7 +612,7 @@ contains pb_in, mv_in) type(scalar_field), dimension(1:), intent(inout) :: q_comm - real(wp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in + real(stp), optional, dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, mv_in integer, intent(in) :: mpi_dir, pbc_loc, nVar integer :: i, j, k, l, r, q !< Generic loop iterators diff --git a/src/pre_process/m_perturbation.fpp b/src/pre_process/m_perturbation.fpp index e8a178c9b5..32b3eaa2b7 100644 --- a/src/pre_process/m_perturbation.fpp +++ b/src/pre_process/m_perturbation.fpp @@ -98,7 +98,7 @@ contains do q = 1, elliptic_smoothing_iters ! Communication of buffer regions and apply boundary conditions - call s_populate_variables_buffers(bc_type, q_prim_vf, real(pb%sf, kind=wp), real(mv%sf, kind=wp)) + call s_populate_variables_buffers(bc_type, q_prim_vf, pb%sf, mv%sf) ! Perform smoothing and store in temp array if (n == 0) then diff --git a/src/simulation/m_hypoelastic.fpp b/src/simulation/m_hypoelastic.fpp index 3f736b0b0b..883b270e73 100644 --- a/src/simulation/m_hypoelastic.fpp +++ b/src/simulation/m_hypoelastic.fpp @@ -395,7 +395,7 @@ contains l = 0; q = 0 $:GPU_PARALLEL_LOOP() do k = 0, m - rhs_vf(damage_idx)%sf(k, l, q) = (alpha_bar*max(abs(q_cons_vf(stress_idx%beg)%sf(k, l, q)) - tau_star, 0._wp))**cont_damage_s + rhs_vf(damage_idx)%sf(k, l, q) = (alpha_bar*max(abs(real(q_cons_vf(stress_idx%beg)%sf(k, l, q), kind=wp)) - tau_star, 0._wp))**cont_damage_s end do elseif (p == 0) then q = 0 diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index db80bb8346..bccab025c4 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -24,10 +24,10 @@ module m_igr s_igr_flux_add, & s_finalize_igr_module - real(wp), allocatable, dimension(:, :, :) :: jac, jac_rhs, jac_old + real(stp), allocatable, dimension(:, :, :) :: jac, jac_rhs, jac_old $:GPU_DECLARE(create='[jac, jac_rhs, jac_old]') - real(wp), allocatable, dimension(:, :) :: Res + real(stp), allocatable, dimension(:, :) :: Res $:GPU_DECLARE(create='[Res]') real(wp) :: alf_igr diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index ae66f00011..0f1711c1b4 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -621,8 +621,10 @@ contains type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf type(integer_field), dimension(1:num_dims, -1:1), intent(in) :: bc_type type(scalar_field), dimension(sys_size), intent(inout) :: rhs_vf - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in, rhs_pb - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: mv_in, rhs_mv + real(stp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: rhs_pb + real(stp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: mv_in + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: rhs_mv integer, intent(in) :: t_step real(wp), intent(inout) :: time_avg integer, intent(in) :: stage diff --git a/src/simulation/m_surface_tension.fpp b/src/simulation/m_surface_tension.fpp index 5d23d8e4c3..71a30ff3f7 100644 --- a/src/simulation/m_surface_tension.fpp +++ b/src/simulation/m_surface_tension.fpp @@ -287,7 +287,7 @@ contains c_divs(i)%sf(j, k, l)**2._wp end do c_divs(num_dims + 1)%sf(j, k, l) = & - sqrt(c_divs(num_dims + 1)%sf(j, k, l)) + sqrt(real(c_divs(num_dims + 1)%sf(j, k, l), kind=wp)) end do end do end do From fdfa9f096feb3bb784f03e012fcc24b06afe3e4d Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Sat, 2 Aug 2025 21:43:31 -0400 Subject: [PATCH 059/199] Fixed rhs calculations. --- src/simulation/m_qbmm.fpp | 9 ++++++--- src/simulation/m_rhs.fpp | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/simulation/m_qbmm.fpp b/src/simulation/m_qbmm.fpp index 027c47a567..67d9d4ab9f 100644 --- a/src/simulation/m_qbmm.fpp +++ b/src/simulation/m_qbmm.fpp @@ -417,7 +417,8 @@ contains type(scalar_field), dimension(sys_size), intent(in) :: q_cons_vf, q_prim_vf type(scalar_field), dimension(sys_size), intent(inout) :: rhs_vf type(scalar_field), dimension(sys_size), intent(in) :: flux_n_vf - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb, rhs_pb + real(stp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: rhs_pb ! TODO :: I think that this should be stp as well. integer :: i, j, k, l, q real(wp) :: nb_q, nb_dot, R, R2, nR, nR2, nR_dot, nR2_dot, var, AX @@ -698,8 +699,10 @@ contains type(scalar_field), dimension(:), intent(inout) :: q_cons_vf, q_prim_vf type(scalar_field), dimension(:), intent(inout) :: momsp type(scalar_field), dimension(0:, 0:, :), intent(inout) :: moms3d - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb, rhs_pb - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: mv, rhs_mv + real(stp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: rhs_pb + real(stp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: mv + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: rhs_mv type(int_bounds_info), intent(in) :: ix, iy, iz real(wp), dimension(nmom) :: moms, msum diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index 0f1711c1b4..9bb60c4b45 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -622,7 +622,7 @@ contains type(integer_field), dimension(1:num_dims, -1:1), intent(in) :: bc_type type(scalar_field), dimension(sys_size), intent(inout) :: rhs_vf real(stp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: pb_in - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: rhs_pb + real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: rhs_pb ! TODO :: I think these other two variables need to be stp as well, but it doesn't compile like that right now real(stp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: mv_in real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), intent(inout) :: rhs_mv integer, intent(in) :: t_step From cfb792c991710dd45f64d415215b34ba23b01cec Mon Sep 17 00:00:00 2001 From: Benjamin Wilfong Date: Sun, 3 Aug 2025 06:10:07 +0200 Subject: [PATCH 060/199] ENV Vars to case file options and code structure changes --- CMakeLists.txt | 2 +- .../3D_IGR_TaylorGreenVortex_nvidia/case.py | 7 +- src/common/include/macros.fpp | 16 +- src/simulation/m_checker.fpp | 10 + src/simulation/m_global_parameters.fpp | 13 + src/simulation/m_igr.fpp | 73 ++--- src/simulation/m_mpi_proxy.fpp | 4 + src/simulation/m_start_up.fpp | 7 +- src/simulation/m_time_steppers.fpp | 251 ++++++++++-------- toolchain/mfc/run/case_dicts.py | 2 + toolchain/mfc/test/cases.py | 21 +- toolchain/templates/santis.mako | 7 +- 12 files changed, 215 insertions(+), 198 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c0acb3dbe3..8901ec0b16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,7 +234,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Release") message(STATUS "LTO/IPO is not supported in NVHPC Version < 23.11. Use a newer version of NVHPC for best performance.") else() message(STATUS "Performing IPO using -Mextract followed by -Minline") - set(NVHPC_USE_TWO_PASS_IPO TRUE) + set(NVHPC_USE_TWO_PASS_IPO FALSE) endif() else() CHECK_IPO_SUPPORTED(RESULT SUPPORTS_IPO OUTPUT IPO_ERROR) diff --git a/examples/3D_IGR_TaylorGreenVortex_nvidia/case.py b/examples/3D_IGR_TaylorGreenVortex_nvidia/case.py index 74faa7aa22..17ad1ceb43 100644 --- a/examples/3D_IGR_TaylorGreenVortex_nvidia/case.py +++ b/examples/3D_IGR_TaylorGreenVortex_nvidia/case.py @@ -47,8 +47,8 @@ "cyl_coord": "F", "dt": dt, "t_step_start": 0, - "t_step_stop": Nt, - "t_step_save": int(Nt / 100), + "t_step_stop": 10, #Nt, + "t_step_save": 10, #int(Nt / 100), # Simulation Algorithm Parameters "num_patches": 1, "model_eqns": 2, @@ -96,6 +96,9 @@ "fluid_pp(1)%gamma": 1.0e00 / (1.4 - 1), "fluid_pp(1)%pi_inf": 0, "fluid_pp(1)%Re(1)": 1 / mu, + # NVIDIA UVM Options + "nv_uvm_igr_temps_on_gpu": 3, + "nv_uvm_pref_gpu": "T", } ) ) diff --git a/src/common/include/macros.fpp b/src/common/include/macros.fpp index 0ffad2e06b..7177efa32d 100644 --- a/src/common/include/macros.fpp +++ b/src/common/include/macros.fpp @@ -18,20 +18,8 @@ block use cudafor, gpu_sum => sum, gpu_maxval => maxval, gpu_minval => minval integer :: istat - integer :: prefer_gpu_mode - character(len=10) :: prefer_gpu_mode_str - - ! environment variable - call get_environment_variable("NVIDIA_MANUAL_GPU_HINTS", prefer_gpu_mode_str) - if (trim(prefer_gpu_mode_str) == "0") then ! OFF - prefer_gpu_mode = 0 - elseif (trim(prefer_gpu_mode_str) == "1") then ! ON - prefer_gpu_mode = 1 - else ! default - prefer_gpu_mode = 0 - endif - - if (prefer_gpu_mode .eq. 1) then + + if (nv_uvm_pref_gpu) then #:for arg in args !print*, "Moving ${arg}$ to GPU => ", SHAPE(${arg}$) ! set preferred location GPU diff --git a/src/simulation/m_checker.fpp b/src/simulation/m_checker.fpp index f0196af0e2..8917b0be46 100644 --- a/src/simulation/m_checker.fpp +++ b/src/simulation/m_checker.fpp @@ -30,6 +30,7 @@ contains if (igr) then call s_check_inputs_igr + call s_check_inputs_nvidia_uvm else if (recon_type == WENO_TYPE) then call s_check_inputs_weno @@ -411,4 +412,13 @@ contains @:PROHIBIT(powell .and. fd_order == dflt_int, "fd_order must be set if Powell's method is enabled") end subroutine s_check_inputs_mhd + impure subroutine s_check_inputs_nvidia_uvm +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + @:PROHIBIT(nv_uvm_igr_temps_on_gpu > 3 .or. nv_uvm_igr_temps_on_gpu < 0, & + "nv_uvm_igr_temps_on_gpu must be in the range [0, 3]") + @:PROHIBIT(nv_uvm_igr_temps_on_gpu == 3 .and. igr_iter_solver == 2, & + "nv_uvm_igr_temps_on_gpu must be in the range [0, 2] for igr_iter_solver == 2") +#endif + end subroutine s_check_inputs_nvidia_uvm + end module m_checker diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp index 2c2d0af646..401fa5412d 100644 --- a/src/simulation/m_global_parameters.fpp +++ b/src/simulation/m_global_parameters.fpp @@ -156,6 +156,15 @@ module m_global_parameters logical :: viscous !< Viscous effects #:endif + !> @name Variables for our of core IGR computation on NVIDIA + !> @{ + integer :: nv_uvm_igr_temps_on_gpu ! 0 => jac, jac_rhs, and jac_old on CPU + ! 1 => jac on GPU, jac_rhs and jac_old on CPU + ! 2 => jac and jac_rhs on GPU, jac_old on CPU + ! 4 => jac, jac_rhs, and jac_old on GPU (default) + logical :: nv_uvm_pref_gpu ! Enable pinned gpu memory (default TRUE) + !> @} + real(wp) :: weno_eps !< Binding for the WENO nonlinear weights real(wp) :: teno_CT !< Smoothness threshold for TENO logical :: mp_weno !< Monotonicity preserving (MP) WENO @@ -570,6 +579,10 @@ contains t_stop = dflt_real t_save = dflt_real + ! NVIDIA UVM options + nv_uvm_igr_temps_on_gpu = 3 ! => jac, jac_rhs, and jac_old on GPU (default) + nv_uvm_pref_gpu = .true. + ! Simulation algorithm parameters model_eqns = dflt_int mpp_lim = .false. diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index 9be4b514c3..0d1edad478 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -25,11 +25,11 @@ module m_igr s_finalize_igr_module #ifdef __NVCOMPILER_GPU_UNIFIED_MEM - integer, dimension(3) :: temp_on_gpu + integer, dimension(3) :: nv_uvm_temp_on_gpu real(wp), pointer, contiguous, dimension(:, :, :) :: jac,jac_rhs,jac_old - real(wp), allocatable, dimension(:, :, :), pinned, target :: pool_host1 - real(wp), allocatable, dimension(:, :, :), pinned, target :: pool_host2 - real(wp), allocatable, dimension(:, :, :), pinned, target :: pool_host3 + real(wp), allocatable, dimension(:, :, :), pinned, target :: jac_host_pool + real(wp), allocatable, dimension(:, :, :), pinned, target :: jac_rhs_host_pool + real(wp), allocatable, dimension(:, :, :), pinned, target :: jac_old_host_pool #else real(wp), allocatable, dimension(:, :, :) :: jac, jac_rhs, jac_old $:GPU_DECLARE(create='[jac, jac_rhs, jac_old]') @@ -81,7 +81,6 @@ module m_igr 5._wp/6._wp, & ! Index 0 2._wp/6._wp & ! Index 1 ] - #:endif #:endif @@ -90,29 +89,6 @@ module m_igr contains subroutine s_initialize_igr_module() -#ifdef __NVCOMPILER_GPU_UNIFIED_MEM - integer :: igr_temps_on_gpu = 3 - character(len=10) :: igr_temps_on_gpu_str - - call get_environment_variable("NVIDIA_IGR_TEMPS_ON_GPU", igr_temps_on_gpu_str) - - if (trim(igr_temps_on_gpu_str) == "0") then - igr_temps_on_gpu = 0 ! jac, jac_rhs and jac_old on CPU - else if (trim(igr_temps_on_gpu_str) == "1") then - igr_temps_on_gpu = 1 ! jac on GPU, jac_rhs on CPU, jac_old on CPU - else if (trim(igr_temps_on_gpu_str) == "2") then - igr_temps_on_gpu = 2 ! jac and jac_rhs on GPU, jac_old on CPU - else if (trim(igr_temps_on_gpu_str) == "3") then - igr_temps_on_gpu = 3 ! jac, jac_rhs and jac_old on GPU - else ! default on GPU - igr_temps_on_gpu = 3 - end if - - ! create map - temp_on_gpu(1:3) = 0 - temp_on_gpu(1:igr_temps_on_gpu) = 1 - !print*, temp_on_gpu(1:3) -#endif if (viscous) then @:ALLOCATE(Res(1:2, 1:maxval(Re_size))) @@ -138,48 +114,47 @@ contains idwbuff(3)%beg:idwbuff(3)%end)) end if #else + ! create map + nv_uvm_temp_on_gpu(1:3) = 0 + nv_uvm_temp_on_gpu(1:nv_uvm_igr_temps_on_gpu) = 1 - if ( temp_on_gpu(1) == 1 ) then + if (nv_uvm_temp_on_gpu(1) == 1) then @:ALLOCATE(jac(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) @:PREFER_GPU(jac) else - !print*, 'jac on CPU' - allocate(pool_host1(idwbuff(1)%beg:idwbuff(1)%end, & + allocate(jac_host_pool(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) jac(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & - idwbuff(3)%beg:idwbuff(3)%end) => pool_host1(:,:,:) + idwbuff(3)%beg:idwbuff(3)%end) => jac_host_pool(:,:,:) end if - if ( temp_on_gpu(2) == 1 ) then + if (nv_uvm_temp_on_gpu(2) == 1) then @:ALLOCATE(jac_rhs(-1:m,-1:n,-1:p)) @:PREFER_GPU(jac_rhs) else - !print*, 'jac_rhs on CPU' - allocate(pool_host2(-1:m,-1:n,-1:p)) - - jac_rhs(-1:m,-1:n,-1:p) => pool_host2(:,:,:) + allocate(jac_rhs_host_pool(-1:m,-1:n,-1:p)) + jac_rhs(-1:m,-1:n,-1:p) => jac_rhs_host_pool(:,:,:) end if if (igr_iter_solver == 1) then ! Jacobi iteration - if ( temp_on_gpu(3) == 1 ) then + if (nv_uvm_temp_on_gpu(3) == 1) then @:ALLOCATE(jac_old(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) @:PREFER_GPU(jac_old) else - !print*, 'jac_old on CPU' - allocate(pool_host3(idwbuff(1)%beg:idwbuff(1)%end, & + allocate(jac_old_host_pool(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & idwbuff(3)%beg:idwbuff(3)%end)) jac_old(idwbuff(1)%beg:idwbuff(1)%end, & idwbuff(2)%beg:idwbuff(2)%end, & - idwbuff(3)%beg:idwbuff(3)%end) => pool_host3(:,:,:) + idwbuff(3)%beg:idwbuff(3)%end) => jac_old_host_pool(:,:,:) end if end if #endif @@ -203,7 +178,7 @@ contains #:if not MFC_CASE_OPTIMIZATION if (igr_order == 3) then - vidxb = -1; vidxe = 2; + vidxb = -1; vidxe = 2; $:GPU_UPDATE(device='[vidxb, vidxe]') @:ALLOCATE(coeff_L(0:2)) @@ -219,7 +194,7 @@ contains $:GPU_UPDATE(device='[coeff_R]') elseif (igr_order == 5) then - vidxb = -2; vidxe = 3; + vidxb = -2; vidxe = 3; $:GPU_UPDATE(device='[vidxb, vidxe]') @:ALLOCATE(coeff_L(-1:3)) @@ -2699,26 +2674,26 @@ contains @:DEALLOCATE(jac_old) end if #else - if (temp_on_gpu(1) == 1) then + if (nv_uvm_temp_on_gpu(1) == 1) then @:DEALLOCATE(jac) else nullify(jac) - deallocate(pool_host1) + deallocate(jac_host_pool) end if - if (temp_on_gpu(2) == 1) then + if (nv_uvm_temp_on_gpu(2) == 1) then @:DEALLOCATE(jac_rhs) else nullify(jac_rhs) - deallocate(pool_host2) + deallocate(jac_rhs_host_pool) end if if (igr_iter_solver == 1) then ! Jacobi iteration - if (temp_on_gpu(3) == 1) then + if (nv_uvm_temp_on_gpu(3) == 1) then @:DEALLOCATE(jac_old) else nullify(jac_old) - deallocate(pool_host3) + deallocate(jac_old_host_pool) end if end if #endif diff --git a/src/simulation/m_mpi_proxy.fpp b/src/simulation/m_mpi_proxy.fpp index f5cc89b4c5..3564c1e2e3 100644 --- a/src/simulation/m_mpi_proxy.fpp +++ b/src/simulation/m_mpi_proxy.fpp @@ -237,6 +237,10 @@ contains #:endfor end do + ! NVIDIA UVM variables + call MPI_BCAST(nv_uvm_igr_temps_on_gpu, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr) + call MPI_BCAST(nv_uvm_pref_gpu, 1, MPI_LOGICAL, 0, MPI_COMM_WORLD, ierr) + #endif end subroutine s_mpi_bcast_user_inputs diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index e004252060..2bda3c8413 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -185,9 +185,10 @@ contains surface_tension, bubbles_lagrange, lag_params, & hyperelasticity, R0ref, num_bc_patches, Bx0, powell, & cont_damage, tau_star, cont_damage_s, alpha_bar, & - alf_factor, num_igr_iters, & - num_igr_warm_start_iters, & - int_comp, ic_eps, ic_beta + alf_factor, num_igr_iters, num_igr_warm_start_iters, & + int_comp, ic_eps, ic_beta, nv_uvm_igr_temps_on_gpu, & + nv_uvm_pref_gpu + ! Checking that an input file has been provided by the user. If it ! has, then the input file is read in, otherwise, simulation exits. inquire (FILE=trim(file_path), EXIST=file_exist) diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index 8f86202bbe..540f08f547 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -79,7 +79,6 @@ module m_time_steppers #ifdef __NVCOMPILER_GPU_UNIFIED_MEM real(wp), allocatable, dimension(:, :, :, :), pinned, target :: q_cons_ts_pool_host - integer, private :: out_of_core #endif contains @@ -91,21 +90,6 @@ contains integer :: i, j !< Generic loop iterators -#ifdef __NVCOMPILER_GPU_UNIFIED_MEM - character(len=10) :: out_of_core_str - out_of_core = 0 - - call get_environment_variable("MFC_OUT_OF_CORE", out_of_core_str) - - if (trim(out_of_core_str) == "0") then - out_of_core = 0 - elseif (trim(out_of_core_str) == "1") then - out_of_core = 1 - else ! default - out_of_core = 0 - endif -#endif - ! Setting number of time-stages for selected time-stepping scheme if (time_stepper == 1) then num_ts = 1 @@ -123,35 +107,38 @@ contains end do #ifdef __NVCOMPILER_GPU_UNIFIED_MEM - if ( out_of_core == 1 ) then - allocate(q_cons_ts_pool_host(idwbuff(1)%beg:idwbuff(1)%end, & - idwbuff(2)%beg:idwbuff(2)%end, & - idwbuff(3)%beg:idwbuff(3)%end, & - 1:sys_size)) - end if -#endif + allocate(q_cons_ts_pool_host(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end, & + 1:sys_size)) + + do j = 1, sys_size + ! q_cons_ts(1) lives on the device + @:ALLOCATE(q_cons_ts(1)%vf(j)%sf(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end)) + @:PREFER_GPU(q_cons_ts(1)%vf(j)%sf) + if (num_ts == 2) then + ! q_cons_ts(2) lives on the host + q_cons_ts(2)%vf(j)%sf(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end) => q_cons_ts_pool_host(:,:,:,j) + end if + end do + do i = 1, num_ts + @:ACC_SETUP_VFs(q_cons_ts(i)) + end do +#else do i = 1, num_ts do j = 1, sys_size -#ifdef __NVCOMPILER_GPU_UNIFIED_MEM - if ( i <= (num_ts - out_of_core) ) then - !print*, "q_cons_ts", i, j, "on GPU" -#endif - @:ALLOCATE(q_cons_ts(i)%vf(j)%sf(idwbuff(1)%beg:idwbuff(1)%end, & - idwbuff(2)%beg:idwbuff(2)%end, & - idwbuff(3)%beg:idwbuff(3)%end)) - @:PREFER_GPU(q_cons_ts(i)%vf(j)%sf) -#ifdef __NVCOMPILER_GPU_UNIFIED_MEM - else - !print*, "q_cons_ts", i, j, "on CPU" - q_cons_ts(i)%vf(j)%sf(idwbuff(1)%beg:idwbuff(1)%end, & - idwbuff(2)%beg:idwbuff(2)%end, & - idwbuff(3)%beg:idwbuff(3)%end) => q_cons_ts_pool_host(:,:,:,j) - end if -#endif + @:ALLOCATE(q_cons_ts(i)%vf(j)%sf(idwbuff(1)%beg:idwbuff(1)%end, & + idwbuff(2)%beg:idwbuff(2)%end, & + idwbuff(3)%beg:idwbuff(3)%end)) end do @:ACC_SETUP_VFs(q_cons_ts(i)) end do +#endif ! Allocating the cell-average primitive ts variables if (probe_wrt) then @@ -513,6 +500,7 @@ contains integer :: i, j, k, l, q!< Generic loop iterator real(wp) :: start, finish + integer :: dest ! Stage 1 of 2 @@ -542,12 +530,15 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) +#if defined(__NVCOMPILER_GPU_UNIFIED_MEM) $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n do j = 0, m q_cons_ts(2)%vf(i)%sf(j, k, l) = & + q_cons_ts(1)%vf(i)%sf(j, k, l) + q_cons_ts(1)%vf(i)%sf(j, k, l) = & q_cons_ts(1)%vf(i)%sf(j, k, l) & + dt*rhs_vf(i)%sf(j, k, l) end do @@ -555,6 +546,24 @@ contains end do end do + dest = 1 ! Result in q_cons_ts(1)%vf +#else + $:GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(2)%vf(i)%sf(j, k, l) = & + q_cons_ts(1)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l) + end do + end do + end do + end do + + dest = 2 ! Result in q_cons_ts(2)%vf +#endif + !Evolve pb and mv for non-polytropic qbmm if (qbmm .and. (.not. polytropic)) then $:GPU_PARALLEL_LOOP(collapse=5) @@ -590,30 +599,46 @@ contains end do end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(dest)%vf, q_prim_vf, rhs_vf, dt) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(dest)%vf) if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) + call s_pressure_relaxation_procedure(q_cons_ts(dest)%vf) end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(dest)%vf) if (ib) then if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) + call s_ibm_correct_state(q_cons_ts(dest)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) else - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) + call s_ibm_correct_state(q_cons_ts(dest)%vf, q_prim_vf) end if end if ! Stage 2 of 2 - call s_compute_rhs(q_cons_ts(2)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) + call s_compute_rhs(q_cons_ts(dest)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(2)%sf, rhs_pb, mv_ts(2)%sf, rhs_mv, t_step, time_avg, 2) if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) +#if defined(__NVCOMPILER_GPU_UNIFIED_MEM) + $:GPU_PARALLEL_LOOP(collapse=4) + do i = 1, sys_size + do l = 0, p + do k = 0, n + do j = 0, m + q_cons_ts(1)%vf(i)%sf(j, k, l) = & + (q_cons_ts(2)%vf(i)%sf(j, k, l) & + + q_cons_ts(1)%vf(i)%sf(j, k, l) & + + dt*rhs_vf(i)%sf(j, k, l))/4._wp + end do + end do + end do + end do + dest = 1 ! Result in q_cons_ts(1)%vf +#else $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p @@ -628,6 +653,9 @@ contains end do end do + dest = 1 ! Result in q_cons_ts(1)%vf +#endif + if (qbmm .and. (.not. polytropic)) then $:GPU_PARALLEL_LOOP(collapse=5) do i = 1, nb @@ -664,21 +692,21 @@ contains end do end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(dest)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(1)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(dest)%vf) if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(1)%vf) + call s_pressure_relaxation_procedure(q_cons_ts(dest)%vf) end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(1)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(dest)%vf) if (ib) then if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) + call s_ibm_correct_state(q_cons_ts(dest)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) else - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) + call s_ibm_correct_state(q_cons_ts(dest)%vf, q_prim_vf) end if end if @@ -729,20 +757,23 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=1) -#if !defined(__NVCOMPILER_GPU_UNIFIED_MEM) +#if defined(__NVCOMPILER_GPU_UNIFIED_MEM) $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n do j = 0, m q_cons_ts(2)%vf(i)%sf(j, k, l) = & + q_cons_ts(1)%vf(i)%sf(j, k, l) + q_cons_ts(1)%vf(i)%sf(j, k, l) = & q_cons_ts(1)%vf(i)%sf(j, k, l) & + dt*rhs_vf(i)%sf(j, k, l) end do end do end do end do - dest = 2 ! result in q_cons_ts(2)%vf + + dest = 1 ! result in q_cons_ts(1)%vf #else $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size @@ -750,15 +781,14 @@ contains do k = 0, n do j = 0, m q_cons_ts(2)%vf(i)%sf(j, k, l) = & - q_cons_ts(1)%vf(i)%sf(j, k, l) - q_cons_ts(1)%vf(i)%sf(j, k, l) = & q_cons_ts(1)%vf(i)%sf(j, k, l) & + dt*rhs_vf(i)%sf(j, k, l) end do end do end do end do - dest = 1 ! result in q_cons_ts(1)%vf + + dest = 2 ! result in q_cons_ts(2)%vf #endif !Evolve pb and mv for non-polytropic qbmm @@ -796,21 +826,21 @@ contains end do end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(dest)%vf, q_prim_vf, rhs_vf, dt) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(dest)%vf) if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) + call s_pressure_relaxation_procedure(q_cons_ts(dest)%vf) end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(dest)%vf) if (ib) then if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) + call s_ibm_correct_state(q_cons_ts(dest)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) else - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) + call s_ibm_correct_state(q_cons_ts(dest)%vf, q_prim_vf) end if end if @@ -820,36 +850,38 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=2) -#if !defined(__NVCOMPILER_GPU_UNIFIED_MEM) - $:GPU_PARALLEL_LOOP(collapse=4) +#if defined(__NVCOMPILER_GPU_UNIFIED_MEM) + $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n do j = 0, m - q_cons_ts(2)%vf(i)%sf(j, k, l) = & - (3._wp*q_cons_ts(1)%vf(i)%sf(j, k, l) & - + q_cons_ts(2)%vf(i)%sf(j, k, l) & + q_cons_ts(1)%vf(i)%sf(j, k, l) = & + (3._wp*q_cons_ts(2)%vf(i)%sf(j, k, l) & + + q_cons_ts(1)%vf(i)%sf(j, k, l) & + dt*rhs_vf(i)%sf(j, k, l))/4._wp end do end do end do end do - dest = 2 ! result in q_cons_ts(2)%vf + + dest = 1 ! Result in q_cons_ts(1)%vf #else $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n do j = 0, m - q_cons_ts(1)%vf(i)%sf(j, k, l) = & - (3._wp*q_cons_ts(2)%vf(i)%sf(j, k, l) & - + q_cons_ts(1)%vf(i)%sf(j, k, l) & + q_cons_ts(2)%vf(i)%sf(j, k, l) = & + (3._wp*q_cons_ts(1)%vf(i)%sf(j, k, l) & + + q_cons_ts(2)%vf(i)%sf(j, k, l) & + dt*rhs_vf(i)%sf(j, k, l))/4._wp end do end do end do end do - dest = 1 ! result in q_cons_ts(1)%vf + + dest = 2 ! Result in q_cons_ts(2)%vf #endif if (qbmm .and. (.not. polytropic)) then @@ -888,21 +920,21 @@ contains end do end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(2)%vf, q_prim_vf, rhs_vf, dt/4._wp) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(dest)%vf, q_prim_vf, rhs_vf, dt/4._wp) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(2)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(dest)%vf) if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(2)%vf) + call s_pressure_relaxation_procedure(q_cons_ts(dest)%vf) end if - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(2)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(dest)%vf) if (ib) then if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) + call s_ibm_correct_state(q_cons_ts(dest)%vf, q_prim_vf, pb_ts(2)%sf, mv_ts(2)%sf) else - call s_ibm_correct_state(q_cons_ts(2)%vf, q_prim_vf) + call s_ibm_correct_state(q_cons_ts(dest)%vf, q_prim_vf) end if end if @@ -911,21 +943,22 @@ contains if (bubbles_lagrange .and. .not. adap_dt) call s_update_lagrange_tdv_rk(stage=3) -#if !defined(__NVCOMPILER_GPU_UNIFIED_MEM) +#if defined(__NVCOMPILER_GPU_UNIFIED_MEM) $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size do l = 0, p do k = 0, n do j = 0, m q_cons_ts(1)%vf(i)%sf(j, k, l) = & - (q_cons_ts(1)%vf(i)%sf(j, k, l) & - + 2._wp*q_cons_ts(2)%vf(i)%sf(j, k, l) & + (q_cons_ts(2)%vf(i)%sf(j, k, l) & + + 2._wp*q_cons_ts(1)%vf(i)%sf(j, k, l) & + 2._wp*dt*rhs_vf(i)%sf(j, k, l))/3._wp end do end do end do end do - dest = 1 ! result in q_cons_ts(1)%vf + + dest = 1 ! Result in q_cons_ts(1)%vf #else $:GPU_PARALLEL_LOOP(collapse=4) do i = 1, sys_size @@ -933,14 +966,15 @@ contains do k = 0, n do j = 0, m q_cons_ts(1)%vf(i)%sf(j, k, l) = & - (q_cons_ts(2)%vf(i)%sf(j, k, l) & - + 2._wp*q_cons_ts(1)%vf(i)%sf(j, k, l) & + (q_cons_ts(1)%vf(i)%sf(j, k, l) & + + 2._wp*q_cons_ts(2)%vf(i)%sf(j, k, l) & + 2._wp*dt*rhs_vf(i)%sf(j, k, l))/3._wp end do end do end do end do - dest = 1 ! result in q_cons_ts(1)%vf + + dest = 1 ! Result in q_cons_ts(2)%vf #endif if (qbmm .and. (.not. polytropic)) then @@ -979,25 +1013,25 @@ contains end do end if - if (bodyForces) call s_apply_bodyforces(q_cons_ts(1)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) + if (bodyForces) call s_apply_bodyforces(q_cons_ts(dest)%vf, q_prim_vf, rhs_vf, 2._wp*dt/3._wp) - if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(1)%vf) + if (grid_geometry == 3) call s_apply_fourier_filter(q_cons_ts(dest)%vf) if (model_eqns == 3 .and. (.not. relax)) then - call s_pressure_relaxation_procedure(q_cons_ts(1)%vf) + call s_pressure_relaxation_procedure(q_cons_ts(dest)%vf) end if call nvtxStartRange("RHS-ELASTIC") - if (hyperelasticity) call s_hyperelastic_rmt_stress_update(q_cons_ts(1)%vf, q_prim_vf) + if (hyperelasticity) call s_hyperelastic_rmt_stress_update(q_cons_ts(dest)%vf, q_prim_vf) call nvtxEndRange - if (adv_n) call s_comp_alpha_from_n(q_cons_ts(1)%vf) + if (adv_n) call s_comp_alpha_from_n(q_cons_ts(dest)%vf) if (ib) then if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) + call s_ibm_correct_state(q_cons_ts(dest)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) else - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) + call s_ibm_correct_state(q_cons_ts(dest)%vf, q_prim_vf) end if end if @@ -1007,6 +1041,7 @@ contains time = time + (finish - start) end if + end subroutine s_3rd_order_tvd_rk !> Strang splitting scheme with 3rd order TVD RK time-stepping algorithm for @@ -1244,30 +1279,20 @@ contains integer :: i, j !< Generic loop iterators ! Deallocating the cell-average conservative variables +#ifdef __NVCOMPILER_GPU_UNIFIED_MEM + do j = 1, sys_size + @:DEALLOCATE(q_cons_ts(1)%vf(j)%sf) + if (num_ts == 2) then + nullify(q_cons_ts(2)%vf(j)%sf) + end if + end do + deallocate(q_cons_ts_pool_host) +#else do i = 1, num_ts do j = 1, sys_size -#ifdef __NVCOMPILER_GPU_UNIFIED_MEM - if ( i <= (num_ts - out_of_core) ) then - !print*, "q_cons_ts", i, j, "dealloc" -#endif - @:DEALLOCATE(q_cons_ts(i)%vf(j)%sf) -#ifdef __NVCOMPILER_GPU_UNIFIED_MEM - else - !print*, "q_cons_ts", i, j, "nullify" - nullify(q_cons_ts(i)%vf(j)%sf) - end if -#endif + @:ALLOCATE(q_cons_ts(i)%vf(j)%sf) end do - - @:DEALLOCATE(q_cons_ts(i)%vf) end do - - @:DEALLOCATE(q_cons_ts) - -#ifdef __NVCOMPILER_GPU_UNIFIED_MEM - if ( out_of_core == 1 ) then - deallocate(q_cons_ts_pool_host) - end if #endif ! Deallocating the cell-average primitive ts variables diff --git a/toolchain/mfc/run/case_dicts.py b/toolchain/mfc/run/case_dicts.py index 6bcf0964cc..bd9dcec11a 100644 --- a/toolchain/mfc/run/case_dicts.py +++ b/toolchain/mfc/run/case_dicts.py @@ -312,6 +312,8 @@ def analytic(self): 'int_comp': ParamType.LOG, 'ic_eps': ParamType.REAL, 'ic_beta': ParamType.REAL, + 'nv_uvm_igr_temps_on_gpu': ParamType.INT, + 'nv_uvm_pref_gpu': ParamType.LOG, }) for var in [ 'heatTransfer_model', 'massTransfer_model', 'pressure_corrector', diff --git a/toolchain/mfc/test/cases.py b/toolchain/mfc/test/cases.py index fac3dc4eba..95927bb04b 100644 --- a/toolchain/mfc/test/cases.py +++ b/toolchain/mfc/test/cases.py @@ -693,17 +693,17 @@ def alter_mixlayer_perturb(dimInfo): 'patch_icpp(1)%vel(1)': 1.0, 'patch_icpp(1)%vel(2)': 0.0, 'patch_icpp(1)%vel(3)': 0.0, 'patch_icpp(1)%pres': 17.8571428571, 'patch_icpp(1)%alpha_rho(1)': 1.0, 'patch_icpp(1)%alpha(1)': 1.0, 'patch_icpp(1)%r0': -1e6, 'patch_icpp(1)%v0': -1e6, - 'patch_icpp(2)%geometry': -100, + 'patch_icpp(2)%geometry': -100, 'patch_icpp(2)%x_centroid': -1e6, 'patch_icpp(2)%length_x': -1e6, - 'patch_icpp(2)%y_centroid': -1e6, 'patch_icpp(2)%length_y': -1e6, - 'patch_icpp(2)%z_centroid': -1e6, 'patch_icpp(2)%length_z': -1e6, - 'patch_icpp(2)%vel(1)': -1e6, 'patch_icpp(2)%vel(2)': -1e6, 'patch_icpp(2)%vel(3)': -1e6, + 'patch_icpp(2)%y_centroid': -1e6, 'patch_icpp(2)%length_y': -1e6, + 'patch_icpp(2)%z_centroid': -1e6, 'patch_icpp(2)%length_z': -1e6, + 'patch_icpp(2)%vel(1)': -1e6, 'patch_icpp(2)%vel(2)': -1e6, 'patch_icpp(2)%vel(3)': -1e6, 'patch_icpp(2)%r0': -1e6, 'patch_icpp(2)%v0': -1e6, - 'patch_icpp(3)%geometry': -100, + 'patch_icpp(3)%geometry': -100, 'patch_icpp(3)%x_centroid': -1e6, 'patch_icpp(3)%length_x': -1e6, - 'patch_icpp(3)%y_centroid': -1e6, 'patch_icpp(3)%length_y': -1e6, - 'patch_icpp(3)%z_centroid': -1e6, 'patch_icpp(3)%length_z': -1e6, - 'patch_icpp(3)%vel(1)': -1e6, 'patch_icpp(3)%vel(2)': -1e6, 'patch_icpp(3)%vel(3)': -1e6, + 'patch_icpp(3)%y_centroid': -1e6, 'patch_icpp(3)%length_y': -1e6, + 'patch_icpp(3)%z_centroid': -1e6, 'patch_icpp(3)%length_z': -1e6, + 'patch_icpp(3)%vel(1)': -1e6, 'patch_icpp(3)%vel(2)': -1e6, 'patch_icpp(3)%vel(3)': -1e6, 'patch_icpp(3)%r0': -1e6, 'patch_icpp(3)%v0': -1e6 })) @@ -993,11 +993,12 @@ def foreach_example(): "2D_lagrange_bubblescreen", "3D_lagrange_bubblescreen", "2D_triple_point", "1D_shuosher_analytical", - "1D_titarevtorro_analytical", + "1D_titarevtorro_analytical", "2D_acoustic_pulse_analytical", "2D_isentropicvortex_analytical", "2D_zero_circ_vortex_analytical", - "3D_TaylorGreenVortex_analytical"] + "3D_TaylorGreenVortex_analytical", + "3D_IGR_TaylorGreenVortex_nvidia"] if path in casesToSkip: continue name = f"{path.split('_')[0]} -> Example -> {'_'.join(path.split('_')[1:])}" diff --git a/toolchain/templates/santis.mako b/toolchain/templates/santis.mako index 27b4d6b425..e798b677df 100644 --- a/toolchain/templates/santis.mako +++ b/toolchain/templates/santis.mako @@ -37,13 +37,8 @@ export FI_CXI_RX_MATCH_MODE=software export FI_MR_CACHE_MONITOR=disabled export MPICH_NO_BUFFER_ALIAS_CHECK=1 -# CUSTOM env vars to MFC -export MFC_OUT_OF_CORE=1 # out of core -export NVIDIA_MANUAL_GPU_HINTS=1 # prefloc GPU on some -export NVIDIA_IGR_TEMPS_ON_GPU=3 # jac, jac_rhs, and jac_old on GPU - # NSYS -export NSYS=1 # enable nsys profiling +export NSYS=0 # enable nsys profiling export NSYS_FILE=myreport.qdrep ${helpers.template_prologue()} From 9333105886f5a22819bd8c5b69b6eeb8648b6916 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Sun, 3 Aug 2025 01:20:54 -0400 Subject: [PATCH 061/199] It compiles! --- src/simulation/m_ibm.fpp | 4 ++-- src/simulation/m_start_up.fpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index a7e439fca9..5e50475db5 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -137,7 +137,7 @@ contains dimension(sys_size), & intent(INOUT) :: q_prim_vf !< Primitive Variables - real(wp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), optional, intent(INOUT) :: pb_in, mv_in + real(stp), dimension(idwbuff(1)%beg:, idwbuff(2)%beg:, idwbuff(3)%beg:, 1:, 1:), optional, intent(INOUT) :: pb_in, mv_in integer :: i, j, k, l, q, r!< Iterator variables integer :: patch_id !< Patch ID of ghost point @@ -198,7 +198,7 @@ contains else if (qbmm .and. .not. polytropic) then call s_interpolate_image_point(q_prim_vf, gp, & alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP, & - r_IP, v_IP, pb_IP, mv_IP, nmom_IP, pb_in, mv_in, presb_IP, massv_IP) + r_IP, v_IP, pb_IP, mv_IP, nmom_IP, real(pb_in, kind=wp), real(mv_in, kind=wp), presb_IP, massv_IP) else call s_interpolate_image_point(q_prim_vf, gp, & alpha_rho_IP, alpha_IP, pres_IP, vel_IP, c_IP) diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index 3b4e6d313d..8a854b2a9b 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -1016,7 +1016,7 @@ contains end if end if - call s_compute_pressure(v_vf(E_idx)%sf(j, k, l), 0._wp, & + call s_compute_pressure(v_vf(E_idx)%sf(j, k, l), 0._stp, & dyn_pres, pi_inf, gamma, rho, qv, rhoYks, pres, T, pres_mag = pres_mag) do i = 1, num_fluids @@ -1192,7 +1192,7 @@ contains do l = 0, p do k = 0, n do j = 0, m - if (ieee_is_nan(q_cons_ts(1)%vf(i)%sf(j, k, l))) then + if (ieee_is_nan(real(q_cons_ts(1)%vf(i)%sf(j, k, l), kind=wp))) then print *, "NaN(s) in timestep output.", j, k, l, i, proc_rank, t_step, m, n, p error stop "NaN(s) in timestep output." end if From 7499855446a14dfaf77c629efdf729f56cae3459 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Sun, 3 Aug 2025 02:29:56 -0400 Subject: [PATCH 062/199] Runs but gives errors --- src/common/m_precision_select.f90 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/common/m_precision_select.f90 b/src/common/m_precision_select.f90 index 3c6f1a87d1..ee2bbc26f2 100644 --- a/src/common/m_precision_select.f90 +++ b/src/common/m_precision_select.f90 @@ -36,9 +36,16 @@ module m_precision_select #endif #ifdef MFC_MPI + +#ifdef MFC_MIXED_PRECISION + integer, parameter :: mpi_p = MPI_SHORT + integer, parameter :: mpi_2p = MPI_FLOAT +#else ! Set mpi_p based on wp using the merge intrinsic function integer, parameter :: mpi_p = merge(MPI_DOUBLE_PRECISION, MPI_REAL, wp == double_precision) integer, parameter :: mpi_2p = merge(MPI_2DOUBLE_PRECISION, MPI_2REAL, wp == double_precision) +#endif + #else integer, parameter :: mpi_p = -100 ! Default value when MPI is not used integer, parameter :: mpi_2p = -100 From 7d8f438a0bd9dd64b82ba045d7a13060f8685525 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Sun, 3 Aug 2025 04:04:18 -0400 Subject: [PATCH 063/199] Calling it for the night. I get NaNs in the answer using --mixed, but --no-mixed works fine --- src/common/m_precision_select.f90 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/common/m_precision_select.f90 b/src/common/m_precision_select.f90 index ee2bbc26f2..21135b1be8 100644 --- a/src/common/m_precision_select.f90 +++ b/src/common/m_precision_select.f90 @@ -51,4 +51,11 @@ module m_precision_select integer, parameter :: mpi_2p = -100 #endif +use, intrinsic :: ieee_exceptions, only: ieee_set_halting_mode, ieee_invalid, ieee_divide_by_zero +logical :: status + +! Put these intrensic calls somewhere +! call ieee_set_halting_mode(ieee_invalid, .true.) ! trap invalid ops +! call ieee_set_halting_mode(ieee_divide_by_zero, .true.) ! if interested + end module m_precision_select From cacc6b041560667d319ce0f8938f694469566747 Mon Sep 17 00:00:00 2001 From: Nikolaos Tselepidis Date: Sun, 3 Aug 2025 10:53:35 +0200 Subject: [PATCH 064/199] Fix some comments --- src/simulation/m_global_parameters.fpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp index 401fa5412d..a7539327f5 100644 --- a/src/simulation/m_global_parameters.fpp +++ b/src/simulation/m_global_parameters.fpp @@ -161,8 +161,8 @@ module m_global_parameters integer :: nv_uvm_igr_temps_on_gpu ! 0 => jac, jac_rhs, and jac_old on CPU ! 1 => jac on GPU, jac_rhs and jac_old on CPU ! 2 => jac and jac_rhs on GPU, jac_old on CPU - ! 4 => jac, jac_rhs, and jac_old on GPU (default) - logical :: nv_uvm_pref_gpu ! Enable pinned gpu memory (default TRUE) + ! 3 => jac, jac_rhs, and jac_old on GPU (default) + logical :: nv_uvm_pref_gpu ! Enable explicit gpu memory hints (default TRUE) !> @} real(wp) :: weno_eps !< Binding for the WENO nonlinear weights From b3fdbff5f8df0ad7426db16195d10f9e66626533 Mon Sep 17 00:00:00 2001 From: Ben Wilfong <48168887+wilfonba@users.noreply.github.com> Date: Sun, 3 Aug 2025 14:15:05 -0400 Subject: [PATCH 065/199] test merge and add nv_uvm_out_of_core back --- src/simulation/m_global_parameters.fpp | 2 ++ src/simulation/m_mpi_proxy.fpp | 1 + src/simulation/m_time_steppers.fpp | 10 ++++++---- toolchain/mfc/run/case_dicts.py | 1 + 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp index 52ad4aec3e..24f23ed4a5 100644 --- a/src/simulation/m_global_parameters.fpp +++ b/src/simulation/m_global_parameters.fpp @@ -163,6 +163,7 @@ module m_global_parameters ! 1 => jac on GPU, jac_rhs and jac_old on CPU ! 2 => jac and jac_rhs on GPU, jac_old on CPU ! 3 => jac, jac_rhs, and jac_old on GPU (default) + logical :: nv_uvm_out_of_core ! Enable out-or-core storage of q_cons_ts(2) in timestepping logical :: nv_uvm_pref_gpu ! Enable explicit gpu memory hints (default TRUE) !> @} @@ -584,6 +585,7 @@ contains ! NVIDIA UVM options nv_uvm_igr_temps_on_gpu = 3 ! => jac, jac_rhs, and jac_old on GPU (default) + nv_uvm_out_of_core = .false. nv_uvm_pref_gpu = .true. ! Simulation algorithm parameters diff --git a/src/simulation/m_mpi_proxy.fpp b/src/simulation/m_mpi_proxy.fpp index d97fdb64c8..f2293b0ffd 100644 --- a/src/simulation/m_mpi_proxy.fpp +++ b/src/simulation/m_mpi_proxy.fpp @@ -239,6 +239,7 @@ contains ! NVIDIA UVM variables call MPI_BCAST(nv_uvm_igr_temps_on_gpu, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr) + call MPI_BCAST(nv_uvm_out_of_core, 1, MPI_LOGICAL, 0, MPI_COMM_WORLD, ierr) call MPI_BCAST(nv_uvm_pref_gpu, 1, MPI_LOGICAL, 0, MPI_COMM_WORLD, ierr) #endif diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index 9d562c6689..48fddcd8cd 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -574,7 +574,6 @@ contains real(wp), intent(inout) :: time_avg integer :: i, j, k, l, q!< Generic loop iterator - integer :: dest real(wp) :: start, finish integer :: dest @@ -810,9 +809,8 @@ contains real(wp), intent(INOUT) :: time_avg integer :: i, j, k, l, q !< Generic loop iterator - integer :: dest - real(wp) :: start, finish + integer :: dest ! Stage 1 of 3 @@ -1385,7 +1383,11 @@ contains do j = 1, sys_size @:DEALLOCATE(q_cons_ts(1)%vf(j)%sf) if (num_ts == 2) then - nullify(q_cons_ts(2)%vf(j)%sf) + if (nv_uvm_out_of_core) then + nullify(q_cons_ts(2)%vf(j)%sf) + else + @:DEALLOCATE(q_cons_ts(2)%vf(j)%sf) + end if end if end do deallocate(q_cons_ts_pool_host) diff --git a/toolchain/mfc/run/case_dicts.py b/toolchain/mfc/run/case_dicts.py index 704450a48b..54d7d00b99 100644 --- a/toolchain/mfc/run/case_dicts.py +++ b/toolchain/mfc/run/case_dicts.py @@ -314,6 +314,7 @@ def analytic(self): 'ic_eps': ParamType.REAL, 'ic_beta': ParamType.REAL, 'nv_uvm_igr_temps_on_gpu': ParamType.INT, + 'nv_uvm_igr_out_of_core': ParamType.LOG, 'nv_uvm_pref_gpu': ParamType.LOG, }) From f8f4e787895ce41bc23975de53e5dddc6044a657 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Sun, 3 Aug 2025 20:32:18 -0400 Subject: [PATCH 066/199] Added some debug statements that will fail if it ever encounters divide by zero. --- src/common/m_precision_select.f90 | 7 ------- src/simulation/m_time_steppers.fpp | 9 +-------- src/simulation/p_main.fpp | 9 +++++++++ 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/common/m_precision_select.f90 b/src/common/m_precision_select.f90 index 21135b1be8..ee2bbc26f2 100644 --- a/src/common/m_precision_select.f90 +++ b/src/common/m_precision_select.f90 @@ -51,11 +51,4 @@ module m_precision_select integer, parameter :: mpi_2p = -100 #endif -use, intrinsic :: ieee_exceptions, only: ieee_set_halting_mode, ieee_invalid, ieee_divide_by_zero -logical :: status - -! Put these intrensic calls somewhere -! call ieee_set_halting_mode(ieee_invalid, .true.) ! trap invalid ops -! call ieee_set_halting_mode(ieee_divide_by_zero, .true.) ! if interested - end module m_precision_select diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index 5f516bd96c..ea179c7545 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -346,13 +346,6 @@ contains end do end do - print *, "This is the size of a vector field element: ", SIZEOF(q_cons_ts(2)%vf(1)%sf(1, 1, 1)) ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - print *, "This is the size of hp precision: ", hp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - print *, "This is the size of sp precision: ", sp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - print *, "This is the size of dp precision: ", dp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - print *, "This is the size of wp precision: ", wp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - print *, "This is the size of stp precision: ", stp ! THIS IS WHERE IT IS AAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH - end subroutine s_initialize_time_steppers_module !> 1st order TVD RK time-stepping algorithm @@ -659,7 +652,7 @@ contains integer :: i, j, k, l, q !< Generic loop iterator real(wp) :: start, finish - + ! Stage 1 of 3 if (.not. adap_dt) then diff --git a/src/simulation/p_main.fpp b/src/simulation/p_main.fpp index 29cb3b8281..29b8f40875 100644 --- a/src/simulation/p_main.fpp +++ b/src/simulation/p_main.fpp @@ -22,6 +22,8 @@ program p_main use m_nvtx + use, intrinsic :: ieee_exceptions, only: ieee_set_halting_mode, ieee_invalid, ieee_divide_by_zero + implicit none integer :: t_step !< Iterator for the time-stepping loop @@ -33,6 +35,13 @@ program p_main real(wp) :: start, finish integer :: nt + + logical :: status + + ! call ieee_set_halting_mode(ieee_invalid, .true.) ! trap invalid ops + call ieee_set_halting_mode(ieee_divide_by_zero, .true.) ! this being true fails, incidcating the error is divide by zero + + call system_clock(COUNT=cpu_start, COUNT_RATE=cpu_rate) call nvtxStartRange("INIT") From 4914dac106c3d82d835e25bcdfa0c1963741c431 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Mon, 4 Aug 2025 14:37:28 -0400 Subject: [PATCH 067/199] Made it further and was able to remove scaler field intiial NaNs --- src/pre_process/m_assign_variables.fpp | 2 +- src/pre_process/m_initial_condition.fpp | 4 ++-- src/simulation/m_igr.fpp | 25 +++++++++++++++++++------ src/simulation/m_rhs.fpp | 10 +++++++++- src/simulation/m_start_up.fpp | 3 ++- src/simulation/m_time_steppers.fpp | 2 ++ src/simulation/p_main.fpp | 4 +++- 7 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/pre_process/m_assign_variables.fpp b/src/pre_process/m_assign_variables.fpp index 4d2b6aceb9..e87a2f2824 100644 --- a/src/pre_process/m_assign_variables.fpp +++ b/src/pre_process/m_assign_variables.fpp @@ -304,7 +304,7 @@ contains real(wp) :: Ys(1:num_species) - real(wp), dimension(sys_size) :: orig_prim_vf !< + real(stp), dimension(sys_size) :: orig_prim_vf !< !! Vector to hold original values of cell for smoothing purposes integer :: i !< Generic loop iterator diff --git a/src/pre_process/m_initial_condition.fpp b/src/pre_process/m_initial_condition.fpp index 383ff28c6c..1a60929291 100644 --- a/src/pre_process/m_initial_condition.fpp +++ b/src/pre_process/m_initial_condition.fpp @@ -113,8 +113,8 @@ contains ! up. The conservative variables do not need to be similarly treated ! since they are computed directly from the primitive variables. do i = 1, sys_size - q_cons_vf(i)%sf = dflt_real - q_prim_vf(i)%sf = dflt_real + q_cons_vf(i)%sf = -1.e-6_stp ! real(dflt_real, kind=stp) ! TODO :: remove this magic number + q_prim_vf(i)%sf = -1.e-6_stp ! real(dflt_real, kind=stp) end do ! Allocating arrays to store the bc types diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index bccab025c4..547b3bf015 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -196,16 +196,17 @@ contains $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - rho_lx = rho_lx + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j - 1, k, l))/2._wp - rho_rx = rho_rx + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j + 1, k, l))/2._wp - rho_ly = rho_ly + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k - 1, l))/2._wp - rho_ry = rho_ry + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k + 1, l))/2._wp + rho_lx = rho_lx + real(q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j - 1, k, l), kind=wp)/2._wp + rho_rx = rho_rx + real(q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j + 1, k, l), kind=wp)/2._wp + rho_ly = rho_ly + real(q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k - 1, l), kind=wp)/2._wp + rho_ry = rho_ry + real(q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k + 1, l), kind=wp)/2._wp if (p > 0) then - rho_lz = rho_lz + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k, l - 1))/2._wp - rho_rz = rho_rz + (q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k, l + 1))/2._wp + rho_lz = rho_lz + real(q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k, l - 1), kind=wp)/2._wp + rho_rz = rho_rz + real(q_cons_vf(i)%sf(j, k, l) + q_cons_vf(i)%sf(j, k, l + 1), kind=wp)/2._wp end if fd_coeff = fd_coeff + q_cons_vf(i)%sf(j, k, l) end do + print *, "After fluid loop" fd_coeff = 1._wp/fd_coeff + alf_igr* & ((1._wp/dx(j)**2._wp)*(1._wp/rho_lx + 1._wp/rho_rx) + & @@ -216,6 +217,7 @@ contains end if if (igr_iter_solver == 1) then ! Jacobi iteration + print *, "Inside jacobi iteration" if (num_dims == 3) then jac(j, k, l) = (alf_igr/fd_coeff)* & ((1._wp/dx(j)**2._wp)*(jac_old(j - 1, k, l)/rho_lx + jac_old(j + 1, k, l)/rho_rx) + & @@ -246,6 +248,7 @@ contains end do end do + print *, "populating igr buffers" call s_populate_F_igr_buffers(bc_type, jac) if (igr_iter_solver == 1) then ! Jacobi iteration @@ -363,6 +366,7 @@ contains do l = 0, p do k = 0, n do j = -1, m + print *, "(l, j, k) = ", l, j, k dvel = 0._wp vflux_L_arr = 0._wp @@ -456,6 +460,7 @@ contains if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 + print *, "q_cons_vf before ", q_cons_vf(E_idx + i)%sf(j + q, k, l) alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j + q, k, l) end do else @@ -510,6 +515,7 @@ contains mu_L = 0._wp; mu_R = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids + print *, "alpha_L/Res + mu", i, alpha_L(i)/Res(1, i) + mu_L mu_L = alpha_L(i)/Res(1, i) + mu_L mu_R = alpha_R(i)/Res(1, i) + mu_R end do @@ -582,6 +588,7 @@ contains do q = vidxb, vidxe - 1 E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j + q, k, l) end do + print *, "Before get_defived_states" call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & E_R, gamma_R, pi_inf_R, rho_R, vel_R, & @@ -675,6 +682,8 @@ contains 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dx(j))) end do + print *, "I'VE WAITED SOOOO LONG" + if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 @@ -2520,8 +2529,12 @@ contains real(wp) :: a_L, a_R if (num_dims == 2) then + ! print *, "Inside num_dims==2" + print *, "Elements", E_L, pi_inf_L, rho_L, vel_L(1), vel_L(2), gamma_L + ! print *, "Elements", E_R, pi_inf_R, rho_R, vel_R(1), vel_R(2), gamma_R pres_L = (E_L - pi_inf_L - 0.5_wp*rho_L*(vel_L(1)**2._wp + vel_L(2)**2._wp))/gamma_L pres_R = (E_R - pi_inf_R - 0.5_wp*rho_R*(vel_R(1)**2._wp + vel_R(2)**2._wp))/gamma_R + print *, "pressure", pres_L, pres_R if (igr_pres_lim) then pres_L = max(pres_L, 0._wp) diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index 9bb60c4b45..93c218c00b 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -722,6 +722,7 @@ contains call nvtxEndRange end if + print *, "Before Dimensional Splitting Loop" ! Dimensional Splitting Loop do id = 1, num_dims @@ -733,20 +734,26 @@ contains do k = -1, n + 1 do j = -1, m + 1 do i = 1, sys_size - rhs_vf(i)%sf(j, k, l) = 0._wp + rhs_vf(i)%sf(j, k, l) = 0._stp end do end do end do end do end if + + print *, "Before igr_riemann_solver" call nvtxStartRange("IGR_RIEMANN") call s_igr_riemann_solver(q_cons_vf, rhs_vf, id) call nvtxEndRange + print *, "After igr_riemann_solver" + if (id == 1) then call nvtxStartRange("IGR_Jacobi") + print *, "before iterative solve" call s_igr_iterative_solve(q_cons_vf, bc_type, t_step) + print *, "after iterative solve" call nvtxEndRange call nvtxStartRange("IGR_SIGMA") @@ -908,6 +915,7 @@ contains end if end do ! END: Dimensional Splitting Loop + print *, "Exit dimensional splitting loop" if (ib) then $:GPU_PARALLEL_LOOP(collapse=3) diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index 8a854b2a9b..91ad3b68a9 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -1093,7 +1093,6 @@ contains #ifdef DEBUG print *, 'Computed derived vars' #endif - mytime = mytime + dt ! Total-variation-diminishing (TVD) Runge-Kutta (RK) time-steppers @@ -1102,7 +1101,9 @@ contains elseif (time_stepper == 2) then call s_2nd_order_tvd_rk(t_step, time_avg) elseif (time_stepper == 3 .and. (.not. adap_dt)) then + print *, "Before s_3rd_order_tvd_rk" call s_3rd_order_tvd_rk(t_step, time_avg) + print *, "After s_3rd_order_tvd_rk" elseif (time_stepper == 3 .and. adap_dt) then call s_strang_splitting(t_step, time_avg) end if diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index ea179c7545..20e4919706 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -660,7 +660,9 @@ contains call nvtxStartRange("TIMESTEP") end if + print *, "Before s_compute_rhs" call s_compute_rhs(q_cons_ts(1)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(1)%sf, rhs_pb, mv_ts(1)%sf, rhs_mv, t_step, time_avg, 1) + print *, "After s_compute_rhs" if (run_time_info) then if (igr) then diff --git a/src/simulation/p_main.fpp b/src/simulation/p_main.fpp index 29b8f40875..e0a0e8362b 100644 --- a/src/simulation/p_main.fpp +++ b/src/simulation/p_main.fpp @@ -38,7 +38,7 @@ program p_main logical :: status - ! call ieee_set_halting_mode(ieee_invalid, .true.) ! trap invalid ops + call ieee_set_halting_mode(ieee_invalid, .true.) ! trap invalid ops call ieee_set_halting_mode(ieee_divide_by_zero, .true.) ! this being true fails, incidcating the error is divide by zero @@ -97,7 +97,9 @@ program p_main end if end if + print *, "Before s_perform_time_step" call s_perform_time_step(t_step, time_avg) + print *, "B" if (cfl_dt) then if (abs(mod(mytime, t_save)) < dt .or. mytime >= t_stop) then From 0f7ed78f7d86da4ca215d790c419087bdafd0b98 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Mon, 4 Aug 2025 15:18:22 -0400 Subject: [PATCH 068/199] Cleaned up prints --- src/simulation/m_igr.fpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index 547b3bf015..abf5fd8e47 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -225,11 +225,20 @@ contains (1._wp/dz(l)**2._wp)*(jac_old(j, k, l - 1)/rho_lz + jac_old(j, k, l + 1)/rho_rz)) + & jac_rhs(j, k, l)/fd_coeff else + print *, "Updating jac" + print *, (alf_igr/fd_coeff) + print *, (1._wp/dx(j)**2._wp) + print *, real(jac_old(j - 1, k, l), kind=wp)/rho_lx + print *, real(jac_old(j + 1, k, l), kind=wp)/rho_rx + print *, (real(jac_old(j - 1, k, l), kind=wp)/rho_lx + real(jac_old(j + 1, k, l), kind=wp)/rho_rx) + print *, (1._wp/dy(k)**2._wp)*(real(jac_old(j, k - 1, l), kind=wp)/rho_ly + real(jac_old(j, k + 1, l), kind=wp)/rho_ry) + print *, real(jac_rhs(j, k, l), kind=wp)/fd_coeff jac(j, k, l) = (alf_igr/fd_coeff)* & - ((1._wp/dx(j)**2._wp)*(jac_old(j - 1, k, l)/rho_lx + jac_old(j + 1, k, l)/rho_rx) + & - (1._wp/dy(k)**2._wp)*(jac_old(j, k - 1, l)/rho_ly + jac_old(j, k + 1, l)/rho_ry)) + & - jac_rhs(j, k, l)/fd_coeff + ((1._wp/dx(j)**2._wp)*(real(jac_old(j - 1, k, l), kind=wp)/rho_lx + real(jac_old(j + 1, k, l), kind=wp)/rho_rx) + & + (1._wp/dy(k)**2._wp)*(real(jac_old(j, k - 1, l), kind=wp)/rho_ly + real(jac_old(j, k + 1, l), kind=wp)/rho_ry)) + & + real(jac_rhs(j, k, l), kind=wp)/fd_coeff end if + print *, "Made it past to 1" else ! Gauss Seidel iteration if (num_dims == 3) then jac(j, k, l) = (alf_igr/fd_coeff)* & @@ -366,8 +375,6 @@ contains do l = 0, p do k = 0, n do j = -1, m - print *, "(l, j, k) = ", l, j, k - dvel = 0._wp vflux_L_arr = 0._wp vflux_R_arr = 0._wp @@ -460,7 +467,6 @@ contains if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - 1 - print *, "q_cons_vf before ", q_cons_vf(E_idx + i)%sf(j + q, k, l) alpha_L(i) = alpha_L(i) + coeff_L(q)*q_cons_vf(E_idx + i)%sf(j + q, k, l) end do else @@ -515,7 +521,6 @@ contains mu_L = 0._wp; mu_R = 0._wp $:GPU_LOOP(parallelism='[seq]') do i = 1, num_fluids - print *, "alpha_L/Res + mu", i, alpha_L(i)/Res(1, i) + mu_L mu_L = alpha_L(i)/Res(1, i) + mu_L mu_R = alpha_R(i)/Res(1, i) + mu_R end do @@ -588,7 +593,6 @@ contains do q = vidxb, vidxe - 1 E_R = E_R + coeff_R(q)*q_cons_vf(E_idx)%sf(j + q, k, l) end do - print *, "Before get_defived_states" call s_get_derived_states(E_L, gamma_L, pi_inf_L, rho_L, vel_L, & E_R, gamma_R, pi_inf_R, rho_R, vel_R, & @@ -682,7 +686,6 @@ contains 0.5_wp*cfl*(alpha_rho_R(i))*(1._wp/dx(j))) end do - print *, "I'VE WAITED SOOOO LONG" if (num_fluids > 1) then $:GPU_LOOP(parallelism='[seq]') @@ -2529,12 +2532,8 @@ contains real(wp) :: a_L, a_R if (num_dims == 2) then - ! print *, "Inside num_dims==2" - print *, "Elements", E_L, pi_inf_L, rho_L, vel_L(1), vel_L(2), gamma_L - ! print *, "Elements", E_R, pi_inf_R, rho_R, vel_R(1), vel_R(2), gamma_R pres_L = (E_L - pi_inf_L - 0.5_wp*rho_L*(vel_L(1)**2._wp + vel_L(2)**2._wp))/gamma_L pres_R = (E_R - pi_inf_R - 0.5_wp*rho_R*(vel_R(1)**2._wp + vel_R(2)**2._wp))/gamma_R - print *, "pressure", pres_L, pres_R if (igr_pres_lim) then pres_L = max(pres_L, 0._wp) From e090dbd9b14560a71df3cf32d232fbada86c7844 Mon Sep 17 00:00:00 2001 From: Daniel J Vickers Date: Mon, 4 Aug 2025 16:02:21 -0400 Subject: [PATCH 069/199] Working and removed print statements --- src/simulation/m_igr.fpp | 12 ------------ src/simulation/m_rhs.fpp | 6 ------ src/simulation/m_start_up.fpp | 2 -- src/simulation/m_time_steppers.fpp | 2 -- src/simulation/p_main.fpp | 6 ++---- 5 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/simulation/m_igr.fpp b/src/simulation/m_igr.fpp index abf5fd8e47..51131cc544 100644 --- a/src/simulation/m_igr.fpp +++ b/src/simulation/m_igr.fpp @@ -206,7 +206,6 @@ contains end if fd_coeff = fd_coeff + q_cons_vf(i)%sf(j, k, l) end do - print *, "After fluid loop" fd_coeff = 1._wp/fd_coeff + alf_igr* & ((1._wp/dx(j)**2._wp)*(1._wp/rho_lx + 1._wp/rho_rx) + & @@ -217,7 +216,6 @@ contains end if if (igr_iter_solver == 1) then ! Jacobi iteration - print *, "Inside jacobi iteration" if (num_dims == 3) then jac(j, k, l) = (alf_igr/fd_coeff)* & ((1._wp/dx(j)**2._wp)*(jac_old(j - 1, k, l)/rho_lx + jac_old(j + 1, k, l)/rho_rx) + & @@ -225,20 +223,11 @@ contains (1._wp/dz(l)**2._wp)*(jac_old(j, k, l - 1)/rho_lz + jac_old(j, k, l + 1)/rho_rz)) + & jac_rhs(j, k, l)/fd_coeff else - print *, "Updating jac" - print *, (alf_igr/fd_coeff) - print *, (1._wp/dx(j)**2._wp) - print *, real(jac_old(j - 1, k, l), kind=wp)/rho_lx - print *, real(jac_old(j + 1, k, l), kind=wp)/rho_rx - print *, (real(jac_old(j - 1, k, l), kind=wp)/rho_lx + real(jac_old(j + 1, k, l), kind=wp)/rho_rx) - print *, (1._wp/dy(k)**2._wp)*(real(jac_old(j, k - 1, l), kind=wp)/rho_ly + real(jac_old(j, k + 1, l), kind=wp)/rho_ry) - print *, real(jac_rhs(j, k, l), kind=wp)/fd_coeff jac(j, k, l) = (alf_igr/fd_coeff)* & ((1._wp/dx(j)**2._wp)*(real(jac_old(j - 1, k, l), kind=wp)/rho_lx + real(jac_old(j + 1, k, l), kind=wp)/rho_rx) + & (1._wp/dy(k)**2._wp)*(real(jac_old(j, k - 1, l), kind=wp)/rho_ly + real(jac_old(j, k + 1, l), kind=wp)/rho_ry)) + & real(jac_rhs(j, k, l), kind=wp)/fd_coeff end if - print *, "Made it past to 1" else ! Gauss Seidel iteration if (num_dims == 3) then jac(j, k, l) = (alf_igr/fd_coeff)* & @@ -257,7 +246,6 @@ contains end do end do - print *, "populating igr buffers" call s_populate_F_igr_buffers(bc_type, jac) if (igr_iter_solver == 1) then ! Jacobi iteration diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index 93c218c00b..d21cbdbc81 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -722,7 +722,6 @@ contains call nvtxEndRange end if - print *, "Before Dimensional Splitting Loop" ! Dimensional Splitting Loop do id = 1, num_dims @@ -742,18 +741,14 @@ contains end if - print *, "Before igr_riemann_solver" call nvtxStartRange("IGR_RIEMANN") call s_igr_riemann_solver(q_cons_vf, rhs_vf, id) call nvtxEndRange - print *, "After igr_riemann_solver" if (id == 1) then call nvtxStartRange("IGR_Jacobi") - print *, "before iterative solve" call s_igr_iterative_solve(q_cons_vf, bc_type, t_step) - print *, "after iterative solve" call nvtxEndRange call nvtxStartRange("IGR_SIGMA") @@ -915,7 +910,6 @@ contains end if end do ! END: Dimensional Splitting Loop - print *, "Exit dimensional splitting loop" if (ib) then $:GPU_PARALLEL_LOOP(collapse=3) diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index 91ad3b68a9..6f5c2ac602 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -1101,9 +1101,7 @@ contains elseif (time_stepper == 2) then call s_2nd_order_tvd_rk(t_step, time_avg) elseif (time_stepper == 3 .and. (.not. adap_dt)) then - print *, "Before s_3rd_order_tvd_rk" call s_3rd_order_tvd_rk(t_step, time_avg) - print *, "After s_3rd_order_tvd_rk" elseif (time_stepper == 3 .and. adap_dt) then call s_strang_splitting(t_step, time_avg) end if diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index 20e4919706..ea179c7545 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -660,9 +660,7 @@ contains call nvtxStartRange("TIMESTEP") end if - print *, "Before s_compute_rhs" call s_compute_rhs(q_cons_ts(1)%vf, q_T_sf, q_prim_vf, bc_type, rhs_vf, pb_ts(1)%sf, rhs_pb, mv_ts(1)%sf, rhs_mv, t_step, time_avg, 1) - print *, "After s_compute_rhs" if (run_time_info) then if (igr) then diff --git a/src/simulation/p_main.fpp b/src/simulation/p_main.fpp index e0a0e8362b..2f74fe90fc 100644 --- a/src/simulation/p_main.fpp +++ b/src/simulation/p_main.fpp @@ -38,8 +38,8 @@ program p_main logical :: status - call ieee_set_halting_mode(ieee_invalid, .true.) ! trap invalid ops - call ieee_set_halting_mode(ieee_divide_by_zero, .true.) ! this being true fails, incidcating the error is divide by zero + ! call ieee_set_halting_mode(ieee_invalid, .true.) ! trap invalid ops + ! call ieee_set_halting_mode(ieee_divide_by_zero, .true.) ! this being true fails, incidcating the error is divide by zero call system_clock(COUNT=cpu_start, COUNT_RATE=cpu_rate) @@ -97,9 +97,7 @@ program p_main end if end if - print *, "Before s_perform_time_step" call s_perform_time_step(t_step, time_avg) - print *, "B" if (cfl_dt) then if (abs(mod(mytime, t_save)) < dt .or. mytime >= t_stop) then From 590b849e9b5662e8364039bd13603f48643f1913 Mon Sep 17 00:00:00 2001 From: Anand Radhakrishnan Date: Mon, 4 Aug 2025 17:15:02 -0400 Subject: [PATCH 070/199] CCE + OpenMP works on all IGR cases + a subset of 1D/2D cases --- src/common/include/omp_macros.fpp | 2 +- src/common/m_variables_conversion.fpp | 16 +------ src/simulation/m_acoustic_src.fpp | 2 +- src/simulation/m_cbc.fpp | 2 +- src/simulation/m_data_output.fpp | 2 +- src/simulation/m_hyperelastic.fpp | 2 +- src/simulation/m_hypoelastic.fpp | 6 +-- src/simulation/m_rhs.fpp | 67 ++++++++++++++------------- src/simulation/m_riemann_solvers.fpp | 10 ++-- src/simulation/m_start_up.fpp | 2 + 10 files changed, 51 insertions(+), 60 deletions(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 522bb62167..3062f1bab3 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -26,7 +26,7 @@ #:if MFC_COMPILER == NVIDIA_COMPILER_ID or MFC_COMPILER == PGI_COMPILER_ID #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(tofrom:allocatable) defaultmap(tofrom:pointer) ' #:elif MFC_COMPILER == CCE_COMPILER_ID - #:set default_val = 'defaultmap(present:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer) ' + #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer) ' #:elif MFC_COMPILER == AMD_COMPILER_ID #:set default_val = '' #:else diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index 36a0562d0e..b105075b1b 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -824,15 +824,11 @@ contains real(wp), dimension(2) :: Re_K real(wp) :: rho_K, gamma_K, pi_inf_K, qv_K, dyn_pres_K - #:if MFC_CASE_OPTIMIZATION #ifndef MFC_SIMULATION real(wp), dimension(:), allocatable :: nRtmp #else real(wp), dimension(nb) :: nRtmp #endif - #:else - real(wp), dimension(:), allocatable :: nRtmp - #:endif real(wp) :: rhoYks(1:num_species) @@ -857,7 +853,6 @@ contains real(wp) :: f, dGa_dW, dp_dW, df_dW ! Functions within Newton-Raphson iteration integer :: iter ! Newton-Raphson iteration counter - #:if MFC_CASE_OPTIMIZATION #ifndef MFC_SIMULATION if (bubbles_euler) then allocate (nRtmp(nb)) @@ -865,15 +860,8 @@ contains allocate (nRtmp(0)) end if #endif - #:else - if (bubbles_euler) then - allocate (nRtmp(nb)) - else - allocate (nRtmp(0)) - end if - #:endif - #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_K, alpha_rho_K, Re_K, nRtmp, rho_K, gamma_K, pi_inf_K,qv_K, dyn_pres_K, rhoYks, B]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_K, alpha_rho_K, Re_K, nRtmp, rho_K, gamma_K, pi_inf_K,qv_K, dyn_pres_K, rhoYks, B, pres, vftmp, nbub_sc, G_K, T, pres_mag, Ga, B2, m2, S, W, dW, E, D, f, dGa_dW, dp_dW, df_dW, iter ]') do l = ibounds(3)%beg, ibounds(3)%end do k = ibounds(2)%beg, ibounds(2)%end do j = ibounds(1)%beg, ibounds(1)%end @@ -1488,7 +1476,7 @@ contains ! Computing the flux variables from the primitive variables, without ! accounting for the contribution of either viscosity or capillarity #ifdef MFC_SIMULATION - #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_K, vel_K, alpha_K, Re_K, Y_K]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_K, vel_K, alpha_K, Re_K, Y_K, rho_K, vel_K_sum, pres_K, E_K, gamma_K, pi_inf_K, qv_K, G_K, T_K, mix_mol_weight, R_gas]') do l = is3b, is3e do k = is2b, is2e do j = is1b, is1e diff --git a/src/simulation/m_acoustic_src.fpp b/src/simulation/m_acoustic_src.fpp index e75b6629e0..65d3ed9213 100644 --- a/src/simulation/m_acoustic_src.fpp +++ b/src/simulation/m_acoustic_src.fpp @@ -220,7 +220,7 @@ contains deallocate (phi_rn) - #:call GPU_PARALLEL_LOOP(private='[myalpha,myalpha_rho]') + #:call GPU_PARALLEL_LOOP(private='[myalpha,myalpha_rho, myRho, B_tait,sim_time, c, small_gamma, frequency_local, gauss_sigma_time_local, mass_src_diff, mom_src_diff, source_temporal, j, k, l, q ]') do i = 1, num_points j = source_spatials(ai)%coord(1, i) k = source_spatials(ai)%coord(2, i) diff --git a/src/simulation/m_cbc.fpp b/src/simulation/m_cbc.fpp index 1d3b84229a..407123b179 100644 --- a/src/simulation/m_cbc.fpp +++ b/src/simulation/m_cbc.fpp @@ -776,7 +776,7 @@ contains end if ! FD2 or FD4 of RHS at j = 0 - #:call GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, dYs_ds, h_k, Cp_i, Gamma_i, Xs]') + #:call GPU_PARALLEL_LOOP(collapse=2, private='[alpha_rho, vel, adv_local, mf, dvel_ds, dadv_ds, Re_cbc, dalpha_rho_ds,dvel_dt, dadv_dt, dalpha_rho_dt, L, lambda, Ys, dYs_dt, dYs_ds, h_k, Cp_i, Gamma_i, Xs, drho_dt, dpres_dt, dpi_inf_dt, dqv_dt, rho, pres, E, H, gamma, pi_inf, qv, c, Ma, T, sum_Enthalpies, Cv, Cp, e_mix, Mw, R_gas]') do r = is3%beg, is3%end do k = is2%beg, is2%end diff --git a/src/simulation/m_data_output.fpp b/src/simulation/m_data_output.fpp index 9f80df014e..fd555d19f0 100644 --- a/src/simulation/m_data_output.fpp +++ b/src/simulation/m_data_output.fpp @@ -279,7 +279,7 @@ contains integer :: j, k, l ! Computing Stability Criteria at Current Time-step - #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel, alpha, Re, rho, vel_sum, pres, gamma, pi_inf, c, H]') do l = 0, p do k = 0, n do j = 0, m diff --git a/src/simulation/m_hyperelastic.fpp b/src/simulation/m_hyperelastic.fpp index 2b171016cb..385cd5ca92 100644 --- a/src/simulation/m_hyperelastic.fpp +++ b/src/simulation/m_hyperelastic.fpp @@ -106,7 +106,7 @@ contains real(wp) :: G_local integer :: j, k, l, i, r - #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_K, alpha_rho_K, rho, gamma, pi_inf, qv, G_local, Re, tensora, tensorb]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_K, alpha_rho_K, rho, gamma, pi_inf, qv, G_local, Re, tensora, tensorb, rho, gamma, pi_inf, qv, G_local, i]') do l = 0, p do k = 0, n do j = 0, m diff --git a/src/simulation/m_hypoelastic.fpp b/src/simulation/m_hypoelastic.fpp index 8748478c85..3d0cece3c0 100644 --- a/src/simulation/m_hypoelastic.fpp +++ b/src/simulation/m_hypoelastic.fpp @@ -196,7 +196,7 @@ contains end if end if - #:call GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3,private='[rho_K, G_K]') do q = 0, p do l = 0, n do k = 0, m @@ -411,7 +411,7 @@ contains #:endcall GPU_PARALLEL_LOOP elseif (p == 0) then q = 0 - #:call GPU_PARALLEL_LOOP(collapse=2) + #:call GPU_PARALLEL_LOOP(collapse=2, private='[tau_p]') do l = 0, n do k = 0, m ! Maximum principal stress @@ -426,7 +426,7 @@ contains end do #:endcall GPU_PARALLEL_LOOP else - #:call GPU_PARALLEL_LOOP(collapse=3) + #:call GPU_PARALLEL_LOOP(collapse=3, private='[tau_xx, tau_xy, tau_yy, tau_xz, tau_yz, tau_zz, I1, I2, I3, temp, sqrt_term_1, sqrt_term_2, argument, phi, tau_p]') do q = 0, p do l = 0, n do k = 0, m diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index ac36e2bff2..6f8e4943e6 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -232,17 +232,16 @@ contains end if ! Allocation/Association of flux_n, flux_src_n, and flux_gsrc_n - @:ALLOCATE(flux_n(1:num_dims)) - @:ALLOCATE(flux_src_n(1:num_dims)) - @:ALLOCATE(flux_gsrc_n(1:num_dims)) - - do i = 1, num_dims + if (.not. igr) then + @:ALLOCATE(flux_n(1:num_dims)) + @:ALLOCATE(flux_src_n(1:num_dims)) + @:ALLOCATE(flux_gsrc_n(1:num_dims)) - @:ALLOCATE(flux_n(i)%vf(1:sys_size)) - @:ALLOCATE(flux_src_n(i)%vf(1:sys_size)) - @:ALLOCATE(flux_gsrc_n(i)%vf(1:sys_size)) + do i = 1, num_dims - if (.not. igr) then + @:ALLOCATE(flux_n(i)%vf(1:sys_size)) + @:ALLOCATE(flux_src_n(i)%vf(1:sys_size)) + @:ALLOCATE(flux_gsrc_n(i)%vf(1:sys_size)) if (i == 1) then do l = 1, sys_size @@ -315,28 +314,29 @@ contains $:GPU_ENTER_DATA(attach='[flux_src_n(i)%vf(l)%sf]') end do end if - end if - end do - - ! END: Allocation/Association of flux_n, flux_src_n, and flux_gsrc_n + + end do + ! END: Allocation/Association of flux_n, flux_src_n, and flux_gsrc_n + end if + - ! Allocation of dq_prim_ds_qp - @:ALLOCATE(dq_prim_dx_qp(1:1)) - @:ALLOCATE(dq_prim_dy_qp(1:1)) - @:ALLOCATE(dq_prim_dz_qp(1:1)) + if (.not. igr) then - @:ALLOCATE(qL_prim(1:num_dims)) - @:ALLOCATE(qR_prim(1:num_dims)) + ! Allocation of dq_prim_ds_qp + @:ALLOCATE(dq_prim_dx_qp(1:1)) + @:ALLOCATE(dq_prim_dy_qp(1:1)) + @:ALLOCATE(dq_prim_dz_qp(1:1)) - ! Allocation/Association of dqK_prim_ds_n - @:ALLOCATE(dqL_prim_dx_n(1:num_dims)) - @:ALLOCATE(dqL_prim_dy_n(1:num_dims)) - @:ALLOCATE(dqL_prim_dz_n(1:num_dims)) - @:ALLOCATE(dqR_prim_dx_n(1:num_dims)) - @:ALLOCATE(dqR_prim_dy_n(1:num_dims)) - @:ALLOCATE(dqR_prim_dz_n(1:num_dims)) + @:ALLOCATE(qL_prim(1:num_dims)) + @:ALLOCATE(qR_prim(1:num_dims)) - if (.not. igr) then + ! Allocation/Association of dqK_prim_ds_n + @:ALLOCATE(dqL_prim_dx_n(1:num_dims)) + @:ALLOCATE(dqL_prim_dy_n(1:num_dims)) + @:ALLOCATE(dqL_prim_dz_n(1:num_dims)) + @:ALLOCATE(dqR_prim_dx_n(1:num_dims)) + @:ALLOCATE(dqR_prim_dy_n(1:num_dims)) + @:ALLOCATE(dqR_prim_dz_n(1:num_dims)) do i = 1, num_dims @:ALLOCATE(qL_prim(i)%vf(1:sys_size)) @@ -600,8 +600,10 @@ contains ! END: Allocation/Association of qK_cons_n and qK_prim_n ! Allocation of gm_alphaK_n - @:ALLOCATE(gm_alphaL_n(1:num_dims)) - @:ALLOCATE(gm_alphaR_n(1:num_dims)) + if(.not. igr) then + @:ALLOCATE(gm_alphaL_n(1:num_dims)) + @:ALLOCATE(gm_alphaR_n(1:num_dims)) + end if if (alt_soundspeed) then @:ALLOCATE(blkmod1(0:m, 0:n, 0:p), blkmod2(0:m, 0:n, 0:p), alpha1(0:m, 0:n, 0:p), alpha2(0:m, 0:n, 0:p), Kterm(0:m, 0:n, 0:p)) @@ -1977,15 +1979,14 @@ contains @:DEALLOCATE(tau_re_vf) end if end if + @:DEALLOCATE(dqL_prim_dx_n, dqL_prim_dy_n, dqL_prim_dz_n) + @:DEALLOCATE(dqR_prim_dx_n, dqR_prim_dy_n, dqR_prim_dz_n) end if if (mpp_lim .and. bubbles_euler) then $:GPU_EXIT_DATA(delete='[alf_sum%sf]') deallocate (alf_sum%sf) - end if - - @:DEALLOCATE(dqL_prim_dx_n, dqL_prim_dy_n, dqL_prim_dz_n) - @:DEALLOCATE(dqR_prim_dx_n, dqR_prim_dy_n, dqR_prim_dz_n) + end if if (.not. igr) then do i = num_dims, 1, -1 diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index d2258a1dec..094ad4289f 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -357,7 +357,7 @@ contains #:for NORM_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (norm_dir == ${NORM_DIR}$) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp, rho_L, rho_R, pres_L, pres_R, E_L, E_R, H_L, H_R, Cp_avg, Cv_avg, T_avg, eps, c_sum_Yi_Phi, T_L, T_R, Y_L, Y_R, MW_L, MW_R, R_gas_L, R_gas_R, Cp_L, Cp_R, Cv_L, Cv_R, Gamm_L, Gamm_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, qv_L, qv_R, c_L, c_R, G_L, G_R, rho_avg, H_avg, c_avg, gamma_avg, ptilde_L, ptilde_R, vel_L_rms, vel_R_rms, vel_avg_rms, vel_L_tmp, vel_R_tmp, Ms_L, Ms_R, pres_SL, pres_SR, alpha_L_sum, alpha_R_sum]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -1183,7 +1183,7 @@ contains ! 6-EQUATION MODEL WITH HLLC if (model_eqns == 3) then !ME3 - #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel_L, vel_R, vel_K_Star, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, vel_avg_rms, alpha_L, alpha_R, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, tau_e_L, tau_e_R, G_L, G_R, flux_ene_e, xi_field_L, xi_field_R, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[vel_L, vel_R, vel_K_Star, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, vel_avg_rms, alpha_L, alpha_R, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, tau_e_L, tau_e_R, G_L, G_R, flux_ene_e, xi_field_L, xi_field_R, pcorr, zcoef, vel_L_tmp, vel_R_tmp, rho_L, rho_R, pres_L, pres_R, E_L, E_R, H_L, H_R, Cp_avg, Cv_avg, T_avg, eps, c_sum_Yi_Phi, T_L, T_R, Y_L, Y_R, MW_L, MW_R, R_gas_L, R_gas_R, Cp_L, Cp_R, Cv_L, Cv_R, Gamm_L, Gamm_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, qv_L, qv_R, c_L, c_R, G_L, G_R, rho_avg, H_avg, c_avg, gamma_avg, ptilde_L, ptilde_R, vel_L_rms, vel_R_rms, vel_avg_rms, vel_L_tmp, vel_R_tmp, Ms_L, Ms_R, pres_SL, pres_SR, alpha_L_sum, alpha_R_sum, rho_Star, E_Star, p_Star, p_K_Star, vel_K_star, s_L, s_R, s_M, s_P, s_S, xi_M, xi_P, xi_L, xi_R, xi_MP, xi_PP, idx1, idxi]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -1610,7 +1610,7 @@ contains elseif (model_eqns == 4) then !ME4 - #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, vel_avg_rms, nbub_L, nbub_R, ptilde_L, ptilde_R]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, vel_avg_rms, nbub_L, nbub_R, ptilde_L, ptilde_R, rho_L, rho_R, pres_L, pres_R, E_L, E_R, H_L, H_R, Cp_avg, Cv_avg, T_avg, eps, c_sum_Yi_Phi, T_L, T_R, Y_L, Y_R, MW_L, MW_R, R_gas_L, R_gas_R, Cp_L, Cp_R, Gamm_L, Gamm_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, qv_L, qv_R, c_L, c_R, G_L, G_R, rho_avg, H_avg, c_avg, gamma_avg, ptilde_L, ptilde_R, vel_L_rms, vel_R_rms, vel_avg_rms, vel_L_tmp, vel_R_tmp, Ms_L, Ms_R, pres_SL, pres_SR, alpha_L_sum, alpha_R_sum, rho_Star, E_Star, p_Star, p_K_Star, vel_K_star, s_L, s_R, s_M, s_P, s_S, xi_M, xi_P, xi_L, xi_R, xi_MP, xi_PP]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -1860,7 +1860,7 @@ contains #:endcall GPU_PARALLEL_LOOP elseif (model_eqns == 2 .and. bubbles_euler) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[R0_L, R0_R, V0_L, V0_R, P0_L, P0_R, pbw_L, pbw_R, vel_L, vel_R, rho_avg, alpha_L, alpha_R, h_avg, gamma_avg, s_L, s_R, s_S, nbub_L, nbub_R, ptilde_L, ptilde_R, vel_avg_rms, Re_L, Re_R, pcorr, zcoef, vel_L_tmp, vel_R_tmp]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[R0_L, R0_R, V0_L, V0_R, P0_L, P0_R, pbw_L, pbw_R, vel_L, vel_R, rho_avg, alpha_L, alpha_R, h_avg, gamma_avg, s_L, s_R, s_S, nbub_L, nbub_R, ptilde_L, ptilde_R, vel_avg_rms, Re_L, Re_R, pcorr, zcoef, rho_L, rho_R, pres_L, pres_R, E_L, E_R, H_L, H_R, Cp_avg, Cv_avg, T_avg, eps, c_sum_Yi_Phi, T_L, T_R, Y_L, Y_R, MW_L, MW_R, R_gas_L, R_gas_R, Cp_L, Cp_R, Gamm_L, Gamm_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, qv_L, qv_R, c_L, c_R, G_L, G_R, rho_avg, H_avg, c_avg, gamma_avg, ptilde_L, ptilde_R, vel_L_rms, vel_R_rms, vel_avg_rms, vel_L_tmp, vel_R_tmp, Ms_L, Ms_R, pres_SL, pres_SR, alpha_L_sum, alpha_R_sum, rho_Star, E_Star, p_Star, p_K_Star, vel_K_star, s_L, s_R, s_M, s_P, s_S, xi_M, xi_P, xi_L, xi_R, xi_MP, xi_PP, nbub_L, nbub_R, nbub_L_denom, nbub_R_denom, Pbwr3Lbar, PbwR3Rbar, R3Lbar, R3Rbar, R3V2Lbar, R3V2Rbar]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end @@ -2326,7 +2326,7 @@ contains #:endcall GPU_PARALLEL_LOOP else ! 5-EQUATION MODEL WITH HLLC - #:call GPU_PARALLEL_LOOP(collapse=3, private='[T_L, T_R, vel_L, vel_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, alpha_L, alpha_R, s_L, s_R, s_S, vel_avg_rms, pcorr, zcoef, vel_L_tmp, vel_R_tmp, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, tau_e_L, tau_e_R, xi_field_L, xi_field_R, Yi_avg,Phi_avg, h_iL, h_iR, h_avg_2]', copyin='[is1, is2, is3]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[T_L, T_R, idx1, idxi, vel_L_rms, vel_R_rms, pres_L, pres_R, rho_L, gamma_L, pi_inf_L, qv_L, rho_R, gamma_R, pi_inf_R, qv_R, alpha_L_sum, alpha_R_sum, E_L, E_R, MW_L, MW_R, R_gas_L, R_gas_R, Cp_L, Cp_R, Cv_L, Cv_R, Gamm_L, Gamm_R, Y_L, Y_R, H_L, H_R, rho_avg, gamma_avg, H_avg, c_L, c_R, c_avg, s_P, s_M, xi_P, xi_M, xi_L, xi_R, Ms_L, Ms_R, pres_SL, pres_SR, vel_L, vel_R, Re_L, Re_R, alpha_L, alpha_R, s_L, s_R, s_S, vel_avg_rms, pcorr, zcoef, vel_L_tmp, vel_R_tmp, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, tau_e_L, tau_e_R, xi_field_L, xi_field_R, Yi_avg,Phi_avg, h_iL, h_iR, h_avg_2, G_L, G_R]', copyin='[is1, is2, is3]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp index 85c7d727ea..e0d72d27b2 100644 --- a/src/simulation/m_start_up.fpp +++ b/src/simulation/m_start_up.fpp @@ -1280,6 +1280,8 @@ contains call s_initialize_rhs_module() + + if (surface_tension) call s_initialize_surface_tension_module() if (relax) call s_initialize_phasechange_module() From 0702c3cb2d1281205c82ca55cec6e674ab13c078 Mon Sep 17 00:00:00 2001 From: Anand Radhakrishnan Date: Mon, 4 Aug 2025 17:38:00 -0400 Subject: [PATCH 071/199] Hypoelasticity works --- src/simulation/m_riemann_solvers.fpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index 094ad4289f..4e75f12a7c 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -357,7 +357,7 @@ contains #:for NORM_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')] if (norm_dir == ${NORM_DIR}$) then - #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp, rho_L, rho_R, pres_L, pres_R, E_L, E_R, H_L, H_R, Cp_avg, Cv_avg, T_avg, eps, c_sum_Yi_Phi, T_L, T_R, Y_L, Y_R, MW_L, MW_R, R_gas_L, R_gas_R, Cp_L, Cp_R, Cv_L, Cv_R, Gamm_L, Gamm_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, qv_L, qv_R, c_L, c_R, G_L, G_R, rho_avg, H_avg, c_avg, gamma_avg, ptilde_L, ptilde_R, vel_L_rms, vel_R_rms, vel_avg_rms, vel_L_tmp, vel_R_tmp, Ms_L, Ms_R, pres_SL, pres_SR, alpha_L_sum, alpha_R_sum]') + #:call GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho_L, alpha_rho_R, vel_L, vel_R, alpha_L, alpha_R, tau_e_L, tau_e_R,G_L, G_R, Re_L, Re_R, rho_avg, h_avg, gamma_avg, s_L, s_R, s_S, Ys_L, Ys_R, xi_field_L, xi_field_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, c_fast, pres_mag, B, Ga, vdotB, B2, b4, cm, pcorr, zcoef, vel_L_tmp, vel_R_tmp, rho_L, rho_R, pres_L, pres_R, E_L, E_R, H_L, H_R, Cp_avg, Cv_avg, T_avg, eps, c_sum_Yi_Phi, T_L, T_R, Y_L, Y_R, MW_L, MW_R, R_gas_L, R_gas_R, Cp_L, Cp_R, Cv_L, Cv_R, Gamm_L, Gamm_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, qv_L, qv_R, c_L, c_R, G_L, G_R, rho_avg, H_avg, c_avg, gamma_avg, ptilde_L, ptilde_R, vel_L_rms, vel_R_rms, vel_avg_rms, vel_L_tmp, vel_R_tmp, Ms_L, Ms_R, pres_SL, pres_SR, alpha_L_sum, alpha_R_sum, flux_tau_L, flux_tau_R]') do l = is3%beg, is3%end do k = is2%beg, is2%end do j = is1%beg, is1%end From fb8b555caea7ee29f44cf48824a29d60f2ba6fa3 Mon Sep 17 00:00:00 2001 From: Ben Wilfong Date: Mon, 4 Aug 2025 17:39:17 -0400 Subject: [PATCH 072/199] fix prim_vars_wrt serial I/O --- src/simulation/m_data_output.fpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulation/m_data_output.fpp b/src/simulation/m_data_output.fpp index 5f5b79c481..e3621123db 100644 --- a/src/simulation/m_data_output.fpp +++ b/src/simulation/m_data_output.fpp @@ -531,7 +531,7 @@ contains if (.not. file_exist) call s_create_directory(trim(t_step_dir)) - if (prim_vars_wrt .or. (n == 0 .and. p == 0)) then + if ((prim_vars_wrt .or. (n == 0 .and. p == 0)) .and. (.not. igr)) then call s_convert_conservative_to_primitive_variables(q_cons_vf, q_T_sf, q_prim_vf, idwint) do i = 1, sys_size $:GPU_UPDATE(host='[q_prim_vf(i)%sf(:,:,:)]') From 7a88e66488f4e77e8b5135569725a82c21d56c46 Mon Sep 17 00:00:00 2001 From: Anand Radhakrishnan Date: Mon, 4 Aug 2025 17:44:23 -0400 Subject: [PATCH 073/199] IBM works --- src/simulation/m_ibm.fpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index d7972188d7..5d0a47040c 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -169,7 +169,7 @@ contains type(ghost_point) :: gp type(ghost_point) :: innerp - #:call GPU_PARALLEL_LOOP(private='[physical_loc,dyn_pres,alpha_rho_IP, alpha_IP,pres_IP,vel_IP,vel_g,vel_norm_IP,r_IP, v_IP,pb_IP,mv_IP,nmom_IP,presb_IP,massv_IP,rho, gamma,pi_inf,Re_K,G_K,Gs,gp,innerp,norm,buf, j,k,l,q]') + #:call GPU_PARALLEL_LOOP(private='[physical_loc,dyn_pres,alpha_rho_IP, alpha_IP,pres_IP,vel_IP,vel_g,vel_norm_IP,r_IP, v_IP,pb_IP,mv_IP,nmom_IP,presb_IP,massv_IP,rho, gamma,pi_inf,Re_K,G_K,Gs,gp,innerp,norm,buf, j,k,l,q,rho,gamma,pi_inf,dyn_pres,G_K,qv_K,c_IP,nbub,patch_id]') do i = 1, num_gps gp = ghost_points(i) From 31d490cf40f9bbc37df5686ae48682927266ad1d Mon Sep 17 00:00:00 2001 From: Ben Wilfong Date: Mon, 4 Aug 2025 20:08:29 -0400 Subject: [PATCH 074/199] merge upstream --- .github/workflows/bench.yml | 5 +- .github/workflows/cleanliness.yml | 4 +- .github/workflows/coverage.yml | 2 +- .github/workflows/frontier/build.sh | 3 +- .github/workflows/frontier/test.sh | 4 +- .github/workflows/test.yml | 5 +- .typos.toml | 1 + CMakeLists.txt | 18 +- README.md | 10 +- docs/documentation/case.md | 28 +- docs/documentation/getting-started.md | 13 +- docs/documentation/gpuDebugging.md | 156 ------- docs/documentation/gpuParallelization.md | 157 +++++++ docs/documentation/papers.md | 14 + docs/documentation/readme.md | 9 +- docs/documentation/references.md | 2 + docs/documentation/testing.md | 1 + examples/0D_bubblecollapse_adap/case.py | 1 + examples/1D_poly_bubscreen/case.py | 1 - examples/1D_qbmm/case.py | 1 - examples/1D_sodshocktube_muscl/case.py | 71 ++++ examples/2D_advection_muscl/case.py | 83 ++++ examples/2D_bubbly_steady_shock/case.py | 1 - examples/2D_riemann_test_muscl/case.py | 99 +++++ examples/2D_shockdroplet_muscl/case.py | 123 ++++++ examples/2D_whale_bubble_annulus/case.py | 1 - examples/3D_rayleigh_taylor_muscl/case.py | 111 +++++ examples/3D_shockdroplet_muscl/case.py | 276 +++++++++++++ examples/3D_turb_mixing/README.md | 4 + examples/3D_turb_mixing/case.py | 1 + examples/3D_turb_mixing/result.png | Bin 0 -> 2110786 bytes src/common/include/shared_parallel_macros.fpp | 4 +- src/common/m_boundary_common.fpp | 14 +- src/common/m_checker_common.fpp | 15 +- src/common/m_constants.fpp | 12 +- src/common/m_helper.fpp | 87 +++- src/common/m_helper_basic.fpp | 20 +- src/common/m_mpi_common.fpp | 64 ++- src/common/m_variables_conversion.fpp | 22 +- src/post_process/m_checker.fpp | 15 +- src/post_process/m_data_input.f90 | 79 +++- src/post_process/m_derived_variables.fpp | 136 ++++++- src/post_process/m_global_parameters.fpp | 53 ++- src/post_process/m_mpi_proxy.fpp | 9 +- src/post_process/m_start_up.f90 | 53 ++- src/pre_process/m_assign_variables.fpp | 48 +-- src/pre_process/m_checker.fpp | 11 +- src/pre_process/m_compute_levelset.fpp | 42 +- src/pre_process/m_data_output.fpp | 170 +++++--- src/pre_process/m_global_parameters.fpp | 75 ++-- src/pre_process/m_initial_condition.fpp | 23 +- src/pre_process/m_mpi_proxy.fpp | 10 +- src/pre_process/m_patches.fpp | 21 +- src/pre_process/m_start_up.fpp | 11 +- src/simulation/m_acoustic_src.fpp | 2 +- src/simulation/m_cbc.fpp | 70 ++-- src/simulation/m_checker.fpp | 22 +- src/simulation/m_data_output.fpp | 139 +++++-- src/simulation/m_global_parameters.fpp | 103 +++-- src/simulation/m_ibm.fpp | 2 +- src/simulation/m_mpi_proxy.fpp | 19 +- src/simulation/m_muscl.fpp | 382 ++++++++++++++++++ src/simulation/m_rhs.fpp | 181 +++++---- src/simulation/m_sim_helpers.fpp | 2 +- src/simulation/m_start_up.fpp | 153 +++++-- src/simulation/m_surface_tension.fpp | 120 +++--- src/simulation/m_time_steppers.fpp | 302 ++++++++++++-- src/simulation/m_viscous.fpp | 297 +++++++------- src/simulation/m_weno.fpp | 7 + tests/0045D9F8/golden-metadata.txt | 71 +--- tests/0045D9F8/golden.txt | 4 +- tests/106C0BE6/golden-metadata.txt | 77 +--- tests/106C0BE6/golden.txt | 4 +- tests/10DE58AA/golden-metadata.txt | 187 +++++++++ tests/10DE58AA/golden.txt | 18 + tests/14846B52/golden-metadata.txt | 187 +++++++++ tests/14846B52/golden.txt | 12 + tests/23573861/golden-metadata.txt | 187 +++++++++ tests/23573861/golden.txt | 16 + tests/24119641/golden-metadata.txt | 187 +++++++++ tests/24119641/golden.txt | 10 + tests/35635326/golden-metadata.txt | 187 +++++++++ tests/35635326/golden.txt | 16 + tests/37DDE283/golden-metadata.txt | 61 +-- tests/37DDE283/golden.txt | 4 +- tests/3EE4302C/golden-metadata.txt | 187 +++++++++ tests/3EE4302C/golden.txt | 16 + tests/3F0FA534/golden-metadata.txt | 187 +++++++++ tests/3F0FA534/golden.txt | 16 + tests/4440D46B/golden-metadata.txt | 71 +--- tests/4440D46B/golden.txt | 4 +- tests/550E8BF5/golden-metadata.txt | 187 +++++++++ tests/550E8BF5/golden.txt | 10 + tests/6077374F/golden-metadata.txt | 73 +--- tests/6077374F/golden.txt | 4 +- tests/6B227FF5/golden-metadata.txt | 187 +++++++++ tests/6B227FF5/golden.txt | 10 + tests/6FA80DE9/golden-metadata.txt | 187 +++++++++ tests/6FA80DE9/golden.txt | 16 + tests/743D6D71/golden-metadata.txt | 187 +++++++++ tests/743D6D71/golden.txt | 10 + tests/770BC5D4/golden-metadata.txt | 187 +++++++++ tests/770BC5D4/golden.txt | 12 + tests/82DA2499/golden-metadata.txt | 187 +++++++++ tests/82DA2499/golden.txt | 12 + tests/84A12B88/golden-metadata.txt | 187 +++++++++ tests/84A12B88/golden.txt | 10 + tests/86E9A6D4/golden-metadata.txt | 187 +++++++++ tests/86E9A6D4/golden.txt | 16 + tests/90D62933/golden-metadata.txt | 187 +++++++++ tests/90D62933/golden.txt | 12 + tests/A57E30FE/golden-metadata.txt | 53 +-- tests/A57E30FE/golden.txt | 4 +- tests/A7C19B7B/golden-metadata.txt | 187 +++++++++ tests/A7C19B7B/golden.txt | 12 + tests/AD6ED274/golden-metadata.txt | 187 +++++++++ tests/AD6ED274/golden.txt | 12 + tests/AE3FC5CB/golden-metadata.txt | 71 +--- tests/AE3FC5CB/golden.txt | 4 +- tests/AFBCBDFA/golden-metadata.txt | 65 +-- tests/AFBCBDFA/golden.txt | 4 +- tests/BAF51303/golden-metadata.txt | 187 +++++++++ tests/BAF51303/golden.txt | 10 + tests/BBFA0940/golden-metadata.txt | 187 +++++++++ tests/BBFA0940/golden.txt | 10 + tests/BDC2A773/golden-metadata.txt | 187 +++++++++ tests/BDC2A773/golden.txt | 16 + tests/BE796E10/golden-metadata.txt | 187 +++++++++ tests/BE796E10/golden.txt | 14 + tests/C4047138/golden-metadata.txt | 187 +++++++++ tests/C4047138/golden.txt | 16 + tests/C605ECCC/golden-metadata.txt | 187 +++++++++ tests/C605ECCC/golden.txt | 12 + tests/C7A6B609/golden-metadata.txt | 71 +--- tests/C7A6B609/golden.txt | 4 +- tests/CEAF553A/golden-metadata.txt | 77 +--- tests/CEAF553A/golden.txt | 4 +- tests/D78D6B12/golden-metadata.txt | 187 +++++++++ tests/D78D6B12/golden.txt | 16 + tests/E3047A62/golden-metadata.txt | 187 +++++++++ tests/E3047A62/golden.txt | 16 + tests/E49EF7B6/golden-metadata.txt | 57 +-- tests/E49EF7B6/golden.txt | 4 +- tests/E8979E4A/golden-metadata.txt | 65 +-- tests/E8979E4A/golden.txt | 4 +- tests/EAD7CADE/golden-metadata.txt | 187 +++++++++ tests/EAD7CADE/golden.txt | 10 + tests/EB58AF7F/golden-metadata.txt | 61 +-- tests/EB58AF7F/golden.txt | 4 +- tests/F1D01264/golden-metadata.txt | 187 +++++++++ tests/F1D01264/golden.txt | 12 + tests/F33CC4CA/golden-metadata.txt | 187 +++++++++ tests/F33CC4CA/golden.txt | 16 + tests/F883F4EE/golden-metadata.txt | 187 +++++++++ tests/F883F4EE/golden.txt | 10 + toolchain/cmake/regular/FindLAPACK.cmake | 61 +++ toolchain/dependencies/CMakeLists.txt | 27 ++ toolchain/mfc/args.py | 17 +- toolchain/mfc/build.py | 5 +- toolchain/mfc/case.py | 14 +- toolchain/mfc/run/case_dicts.py | 19 +- toolchain/mfc/test/case.py | 4 +- toolchain/mfc/test/cases.py | 20 +- toolchain/mfc/test/test.py | 8 +- toolchain/modules | 4 +- toolchain/templates/frontier.mako | 4 + 166 files changed, 9494 insertions(+), 1618 deletions(-) delete mode 100644 docs/documentation/gpuDebugging.md create mode 100755 examples/1D_sodshocktube_muscl/case.py create mode 100644 examples/2D_advection_muscl/case.py create mode 100644 examples/2D_riemann_test_muscl/case.py create mode 100755 examples/2D_shockdroplet_muscl/case.py create mode 100644 examples/3D_rayleigh_taylor_muscl/case.py create mode 100644 examples/3D_shockdroplet_muscl/case.py create mode 100644 examples/3D_turb_mixing/README.md create mode 100644 examples/3D_turb_mixing/result.png create mode 100644 src/simulation/m_muscl.fpp create mode 100644 tests/10DE58AA/golden-metadata.txt create mode 100644 tests/10DE58AA/golden.txt create mode 100644 tests/14846B52/golden-metadata.txt create mode 100644 tests/14846B52/golden.txt create mode 100644 tests/23573861/golden-metadata.txt create mode 100644 tests/23573861/golden.txt create mode 100644 tests/24119641/golden-metadata.txt create mode 100644 tests/24119641/golden.txt create mode 100644 tests/35635326/golden-metadata.txt create mode 100644 tests/35635326/golden.txt create mode 100644 tests/3EE4302C/golden-metadata.txt create mode 100644 tests/3EE4302C/golden.txt create mode 100644 tests/3F0FA534/golden-metadata.txt create mode 100644 tests/3F0FA534/golden.txt create mode 100644 tests/550E8BF5/golden-metadata.txt create mode 100644 tests/550E8BF5/golden.txt create mode 100644 tests/6B227FF5/golden-metadata.txt create mode 100644 tests/6B227FF5/golden.txt create mode 100644 tests/6FA80DE9/golden-metadata.txt create mode 100644 tests/6FA80DE9/golden.txt create mode 100644 tests/743D6D71/golden-metadata.txt create mode 100644 tests/743D6D71/golden.txt create mode 100644 tests/770BC5D4/golden-metadata.txt create mode 100644 tests/770BC5D4/golden.txt create mode 100644 tests/82DA2499/golden-metadata.txt create mode 100644 tests/82DA2499/golden.txt create mode 100644 tests/84A12B88/golden-metadata.txt create mode 100644 tests/84A12B88/golden.txt create mode 100644 tests/86E9A6D4/golden-metadata.txt create mode 100644 tests/86E9A6D4/golden.txt create mode 100644 tests/90D62933/golden-metadata.txt create mode 100644 tests/90D62933/golden.txt create mode 100644 tests/A7C19B7B/golden-metadata.txt create mode 100644 tests/A7C19B7B/golden.txt create mode 100644 tests/AD6ED274/golden-metadata.txt create mode 100644 tests/AD6ED274/golden.txt create mode 100644 tests/BAF51303/golden-metadata.txt create mode 100644 tests/BAF51303/golden.txt create mode 100644 tests/BBFA0940/golden-metadata.txt create mode 100644 tests/BBFA0940/golden.txt create mode 100644 tests/BDC2A773/golden-metadata.txt create mode 100644 tests/BDC2A773/golden.txt create mode 100644 tests/BE796E10/golden-metadata.txt create mode 100644 tests/BE796E10/golden.txt create mode 100644 tests/C4047138/golden-metadata.txt create mode 100644 tests/C4047138/golden.txt create mode 100644 tests/C605ECCC/golden-metadata.txt create mode 100644 tests/C605ECCC/golden.txt create mode 100644 tests/D78D6B12/golden-metadata.txt create mode 100644 tests/D78D6B12/golden.txt create mode 100644 tests/E3047A62/golden-metadata.txt create mode 100644 tests/E3047A62/golden.txt create mode 100644 tests/EAD7CADE/golden-metadata.txt create mode 100644 tests/EAD7CADE/golden.txt create mode 100644 tests/F1D01264/golden-metadata.txt create mode 100644 tests/F1D01264/golden.txt create mode 100644 tests/F33CC4CA/golden-metadata.txt create mode 100644 tests/F33CC4CA/golden.txt create mode 100644 tests/F883F4EE/golden-metadata.txt create mode 100644 tests/F883F4EE/golden.txt create mode 100644 toolchain/cmake/regular/FindLAPACK.cmake diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 63c14ad7ad..cadfe220f3 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -24,10 +24,7 @@ jobs: self: name: "${{ matrix.name }} (${{ matrix.device }})" - if: ${{ github.repository == 'MFlowCode/MFC' && needs.file-changes.outputs.checkall == 'true' && ( - (github.event_name == 'pull_request_review' && github.event.review.state == 'approved') || - (github.event_name == 'pull_request' && github.event.pull_request.user.login == 'sbryngelson') - ) }} + if: ${{ github.repository=='MFlowCode/MFC' && needs.file-changes.outputs.checkall=='true' && ((github.event_name=='pull_request_review' && github.event.review.state=='approved') || (github.event_name=='pull_request' && (github.event.pull_request.user.login=='sbryngelson' || github.event.pull_request.user.login=='wilfonba'))) }} needs: file-changes strategy: fail-fast: false diff --git a/.github/workflows/cleanliness.yml b/.github/workflows/cleanliness.yml index ec472dce98..b02df12898 100644 --- a/.github/workflows/cleanliness.yml +++ b/.github/workflows/cleanliness.yml @@ -41,8 +41,8 @@ jobs: - name: Setup Ubuntu run: | sudo apt update -y - sudo apt install -y tar wget make cmake gcc g++ python3 python3-dev "openmpi-*" libopenmpi-dev - + sudo apt install -y tar wget make cmake gcc g++ python3 python3-dev "openmpi-*" libopenmpi-dev libblas-dev liblapack-dev + - name: Build run: | (cd pr && /bin/bash mfc.sh build -j $(nproc) --debug 2> ../pr.txt) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 7487d8e550..d2c1b4ea4a 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -30,7 +30,7 @@ jobs: - name: Setup Ubuntu run: | sudo apt update -y - sudo apt install -y tar wget make cmake gcc g++ python3 python3-dev "openmpi-*" libopenmpi-dev + sudo apt install -y tar wget make cmake gcc g++ python3 python3-dev "openmpi-*" libopenmpi-dev libblas-dev liblapack-dev - name: Build run: /bin/bash mfc.sh build -j $(nproc) --gcov diff --git a/.github/workflows/frontier/build.sh b/.github/workflows/frontier/build.sh index c2e1893427..af272564e8 100644 --- a/.github/workflows/frontier/build.sh +++ b/.github/workflows/frontier/build.sh @@ -13,5 +13,6 @@ if [ "$2" == "bench" ]; then ./mfc.sh run "$dir/case.py" --case-optimization -j 8 --dry-run $build_opts done else - ./mfc.sh test --dry-run -j 8 $build_opts + ./mfc.sh test -a --dry-run --rdma-mpi --generate -j 8 $build_opts fi + diff --git a/.github/workflows/frontier/test.sh b/.github/workflows/frontier/test.sh index 57481fa949..aa977aa004 100644 --- a/.github/workflows/frontier/test.sh +++ b/.github/workflows/frontier/test.sh @@ -4,7 +4,7 @@ gpus=`rocm-smi --showid | awk '{print $1}' | grep -Eo '[0-9]+' | uniq | tr '\n' ngpus=`echo "$gpus" | tr -d '[:space:]' | wc -c` if [ "$job_device" = "gpu" ]; then - ./mfc.sh test --max-attempts 3 -j $ngpus -- -c frontier + ./mfc.sh test -a --rdma-mpi --max-attempts 3 -j $ngpus -- -c frontier else - ./mfc.sh test --max-attempts 3 -j 32 -- -c frontier + ./mfc.sh test -a --rdma-mpi --max-attempts 3 -j 32 -- -c frontier fi diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db618bea46..7eecc105c8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,7 +53,7 @@ jobs: run: | brew update brew upgrade - brew install coreutils python cmake fftw hdf5 gcc@15 boost open-mpi + brew install coreutils python cmake fftw hdf5 gcc@15 boost open-mpi lapack echo "FC=gfortran-15" >> $GITHUB_ENV echo "BOOST_INCLUDE=/opt/homebrew/include/" >> $GITHUB_ENV @@ -62,7 +62,8 @@ jobs: run: | sudo apt update -y sudo apt install -y cmake gcc g++ python3 python3-dev hdf5-tools \ - libfftw3-dev libhdf5-dev openmpi-bin libopenmpi-dev + libfftw3-dev libhdf5-dev openmpi-bin libopenmpi-dev \ + libblas-dev liblapack-dev - name: Setup Ubuntu (Intel) if: matrix.os == 'ubuntu' && matrix.intel == true diff --git a/.typos.toml b/.typos.toml index 6216993cb7..492855221f 100644 --- a/.typos.toml +++ b/.typos.toml @@ -18,6 +18,7 @@ Gam = "Gam" strang = "strang" Strang = "Strang" TKE = "TKE" +HSA = "HSA" [files] extend-exclude = ["docs/documentation/references*", "tests/", "toolchain/cce_simulation_workgroup_256.sh"] diff --git a/CMakeLists.txt b/CMakeLists.txt index e51c33e481..5b08b7d74c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,7 +194,7 @@ elseif ((CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") OR (CMAKE_Fortran_COMPILER_ add_compile_options( $<$:-Mfreeform> $<$:-cpp> - $<$:-Minfo=inline> + $<$:-Minfo=inline> $<$:-Minfo=accel> ) @@ -392,9 +392,10 @@ HANDLE_SOURCES(syscheck OFF) # * FFTW (optional) Should be linked with an FFTW-like library (fftw/cufftw), # depending on whether OpenACC is enabled and which compiler is # being used. +# * LAPACK (optional) Should be linked with LAPACK function(MFC_SETUP_TARGET) - cmake_parse_arguments(ARGS "OpenACC;MPI;SILO;HDF5;FFTW;OpenMP" "TARGET" "SOURCES" ${ARGN}) + cmake_parse_arguments(ARGS "OpenACC;OpenMP;MPI;SILO;HDF5;FFTW;LAPACK" "TARGET" "SOURCES" ${ARGN}) add_executable(${ARGS_TARGET} ${ARGS_SOURCES}) set(IPO_TARGETS ${ARGS_TARGET}) @@ -462,6 +463,11 @@ function(MFC_SETUP_TARGET) endif() endif() + if (ARGS_LAPACK) + find_package(LAPACK REQUIRED) + target_link_libraries(${a_target} PRIVATE LAPACK::LAPACK) + endif() + if ((MFC_OpenACC AND ARGS_OpenACC) OR (MFC_OpenMP AND ARGS_OpenMP)) if ((MFC_OpenACC AND ARGS_OpenACC)) find_package(OpenACC) @@ -534,6 +540,12 @@ function(MFC_SETUP_TARGET) ) endif() elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") + # Frontier Unified Memory Support + if (MFC_Unified) + target_compile_options(${ARGS_TARGET} + PRIVATE -DFRONTIER_UNIFIED) + endif() + find_package(hipfort COMPONENTS hip CONFIG REQUIRED) target_link_libraries(${a_target} PRIVATE hipfort::hip hipfort::hipfort-amdgcn) elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang") @@ -572,7 +584,7 @@ endif() if (MFC_POST_PROCESS) MFC_SETUP_TARGET(TARGET post_process SOURCES "${post_process_SRCs}" - MPI SILO HDF5 FFTW) + MPI SILO HDF5 FFTW LAPACK) # -O0 is in response to https://github.com/MFlowCode/MFC-develop/issues/95 target_compile_options(post_process PRIVATE -O0) diff --git a/README.md b/README.md index 88fa55abbc..80cf296db9 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ It's rather straightforward. We'll give a brief intro. here for MacOS. Using [brew](https://brew.sh), install MFC's dependencies: ```shell -brew install coreutils python cmake fftw hdf5 gcc boost open-mpi +brew install coreutils python cmake fftw hdf5 gcc boost open-mpi lapack ``` You're now ready to build and test MFC! Put it to a convenient directory via @@ -165,7 +165,9 @@ They are organized below. * Shock and interface capturing schemes * First-order upwinding - * WENO reconstructions of order 3, 5, and 7 + * MUSCL (order 2) + * Slope limiters: minmod, monotonized central, Van Albada, Van Leer, superbee + * WENO reconstructions (orders 3, 5, and 7) * WENO variants: WENO-JS, WENO-M, WENO-Z, TENO * Monotonicity-preserving reconstructions * Reliable handling of large density ratios @@ -187,7 +189,7 @@ They are organized below. * Ideal weak scaling to 100% of the largest GPU and superchip supercomputers * \>36K AMD APUs (MI300A) on [LLNL El Capitan](https://hpc.llnl.gov/hardware/compute-platforms/el-capitan) * \>3K AMD APUs (MI300A) on [LLNL Tuolumne](https://hpc.llnl.gov/hardware/compute-platforms/tuolumne) - * \>33K AMD GPUs (MI250X) on the first exascale computer, [OLCF Frontier](https://www.olcf.ornl.gov/frontier/) + * \>33K AMD GPUs (MI250X) on [OLCF Frontier](https://www.olcf.ornl.gov/frontier/) * \>10K NVIDIA GPUs (V100) on [OLCF Summit](https://www.olcf.ornl.gov/summit/) * Near compute roofline behavior * RDMA (remote data memory access; GPU-GPU direct communication) via GPU-aware MPI on NVIDIA (CUDA-aware MPI) and AMD GPU systems @@ -197,7 +199,7 @@ They are organized below. * [Fypp](https://fypp.readthedocs.io/en/stable/fypp.html) metaprogramming for code readability, performance, and portability * Continuous Integration (CI) - * \>300 Regression tests with each PR. + * > 500 Regression tests with each PR. * Performed with GNU (GCC), Intel (oneAPI), Cray (CCE), and NVIDIA (NVHPC) compilers on NVIDIA and AMD GPUs. * Line-level test coverage reports via [Codecov](https://app.codecov.io/gh/MFlowCode/MFC) and `gcov` * Benchmarking to avoid performance regressions and identify speed-ups diff --git a/docs/documentation/case.md b/docs/documentation/case.md index 8cb8d96ac9..5f1d739530 100644 --- a/docs/documentation/case.md +++ b/docs/documentation/case.md @@ -379,6 +379,9 @@ Details of implementation of viscosity in MFC can be found in [Coralic (2015)](r | `mixture_err` | Logical | Mixture properties correction | | `time_stepper` | Integer | Runge--Kutta order [1-3] | | `adap_dt` | Logical | Strang splitting scheme with adaptive time stepping | +| `recon_type` | Integer | Reconstruction Type: [1] WENO; [2] MUSCL | +| `adap_dt_tol` | Real | Tolerance for adaptive time stepping in Strang splitting scheme| +| `adap_dt_max_iters` | Integer | Max iteration for adaptive time stepping in Strang splitting scheme | | `weno_order` | Integer | WENO order [1,3,5] | | `weno_eps` | Real | WENO perturbation (avoid division by zero) | | `mapped_weno` | Logical | WENO-M (WENO with mapping of nonlinear weights) | @@ -388,6 +391,11 @@ Details of implementation of viscosity in MFC can be found in [Coralic (2015)](r | `teno_CT` | Real | TENO threshold for smoothness detection | | `null_weights` | Logical | Null WENO weights at boundaries | | `mp_weno` | Logical | Monotonicity preserving WENO | +| `muscl_order` | Integer | MUSCL order [1,2] | +| `muscl_lim` | Integer | MUSCL Slope Limiter: [1] minmod; [2] monotonized central; [3] Van Albada; [4] Van Leer; [5] SUPERBEE | +| `int_comp` | Logical | THINC Interface Compression | +| `ic_eps` | Real | Interface compression threshold (default: 1e-4) | +| `ic_beta` | Real | Interface compression sharpness parameter (default: 1.6) | | `riemann_solver` | Integer | Riemann solver algorithm: [1] HLL*; [2] HLLC; [3] Exact*; [4] HLLD (only for MHD) | | `low_Mach` | Integer | Low Mach number correction for HLLC Riemann solver: [0] None; [1] Pressure (Chen et al. 2022); [2] Velocity (Thornber et al. 2008) | | `avg_state` | Integer | Averaged state evaluation method: [1] Roe average*; [2] Arithmetic mean | @@ -453,7 +461,7 @@ The effect and use of the source term are assessed by [Schmidmayer et al., 2019] - `time_stepper` specifies the order of the Runge-Kutta (RK) time integration scheme that is used for temporal integration in simulation, from the 1st to 5th order by corresponding integer. Note that `time_stepper = 3` specifies the total variation diminishing (TVD), third order RK scheme ([Gottlieb and Shu, 1998](references.md)). -- `adap_dt` activates the Strang operator splitting scheme which splits flux and source terms in time marching, and an adaptive time stepping strategy is implemented for the source term. It requires ``bubbles_euler = 'T'``, ``polytropic = 'T'``, ``adv_n = 'T'`` and `time_stepper = 3`. Additionally, it can be used with ``bubbles_lagrange = 'T'`` and `time_stepper = 3` +- `adap_dt` activates the Strang operator splitting scheme which splits flux and source terms in time marching, and an adaptive time stepping strategy is implemented for the source term. It requires ``bubbles_euler = 'T'``, ``polytropic = 'T'``, ``adv_n = 'T'`` and `time_stepper = 3`. Additionally, it can be used with ``bubbles_lagrange = 'T'`` and `time_stepper = 3`. `adap_dt_tol` and `adap_dt_max_iters` are 1e-4 and 100, respectively, by default. - `weno_order` specifies the order of WENO scheme that is used for spatial reconstruction of variables by an integer of 1, 3, 5, and 7, that correspond to the 1st, 3rd, 5th, and 7th order, respectively. @@ -474,7 +482,14 @@ It is recommended to set `weno_eps` to $10^{-6}$ for WENO-JS, and to $10^{-40}$ - `mp_weno` activates monotonicity preservation in the WENO reconstruction (MPWENO) such that the values of reconstructed variables do not reside outside the range spanned by WENO stencil ([Balsara and Shu, 2000](references.md); [Suresh and Huynh, 1997](references.md)). -- `riemann_solver` specifies the choice of the Riemann solver that is used in simulation by an integer from 1 through 3. +- `muscl_order` specifies the order of the MUSCL scheme that is used for spatial reconstruction of variables by an integer of 1, or 2, that corresponds to the 1st, and 2nd order respectively. When using `muscl_order = 2`, `muscl_lim` must be defined. + +- `muscl_lim` specifies the slope limiter that is used in 2nd order MUSCL Reconstruction by an integer from 1 through 5. +`muscl_lim = 1`, `2`, `3`, `4`, and `5` correspond to minmod, monotonized central, Van Albada, Van Leer, and SUPERBEE, respectively. + +- `int_comp` activates interface compression using THINC used in MUSCL Reconstruction, with control parameters (`ic_eps`, and `ic_beta`). + +- `riemann_solver` specifies the choice of the Riemann solver that is used in simulation by an integer from 1 through 4. `riemann_solver = 1`, `2`, and `3` correspond to HLL, HLLC, and Exact Riemann solver, respectively ([Toro, 2013](references.md)). `riemann_solver = 4` is only for MHD simulations. It resolves 5 of the full seven-wave structure of the MHD equations ([Miyoshi and Kusano, 2005](references.md)). @@ -574,6 +589,7 @@ To restart the simulation from $k$-th time step, see [Restarting Cases](running. | `omega_wrt(i)` | Logical | Add the $i$-direction vorticity to the database | | `schlieren_wrt` | Logical | Add the numerical schlieren to the database| | `qm_wrt` | Logical | Add the Q-criterion to the database| +| `liutex_wrt` | Logical | Add the Liutex to the database| | `tau_wrt` | Logical | Add the elastic stress components to the database| | `fd_order` | Integer | Order of finite differences for computing the vorticity and the numerical Schlieren function [1,2,4] | | `schlieren_alpha(i)` | Real | Intensity of the numerical Schlieren computed via `alpha(i)` | @@ -613,7 +629,7 @@ If `file_per_process` is true, then pre_process, simulation, and post_process mu - `output_partial_domain` activates the output of part of the domain specified by `[x,y,z]_output%beg` and `[x,y,z]_output%end`. This is useful for large domains where only a portion of the domain is of interest. It is not supported when `precision = 1` and `format = 1`. -It also cannot be enabled with `flux_wrt`, `heat_ratio_wrt`, `pres_inf_wrt`, `c_wrt`, `omega_wrt`, `ib`, `schlieren_wrt`, or `qm_wrt`. +It also cannot be enabled with `flux_wrt`, `heat_ratio_wrt`, `pres_inf_wrt`, `c_wrt`, `omega_wrt`, `ib`, `schlieren_wrt`, `qm_wrt`, or 'liutex_wrt'. ### 8. Acoustic Source {#acoustic-source} @@ -743,7 +759,6 @@ Implementation of the parameters into the model follow [Ando (2010)](references. | `polydisperse` | Logical | Polydispersity in equilibrium bubble radius R0 | | `nb` | Integer | Number of bins: [1] Monodisperse; [$>1$] Polydisperse | | `poly_sigma` | Real | Standard deviation for probability density function of polydisperse bubble populations | -| `R0_type` | Integer | Quadrature rule for probability density function of polydisperse bubble populations | | `Ca` | Real | Cavitation number | | `Web` | Real | Weber number | | `Re_inv` | Real | Inverse Reynolds number | @@ -761,15 +776,12 @@ When ``polytropic = 'F'``, the gas compression is modeled as non-polytropic due - `thermal` specifies a model for heat transfer across the bubble interface by an integer from 1 through 3. `thermal = 1`, `2`, and `3` correspond to no heat transfer (adiabatic gas compression), isothermal heat transfer, and heat transfer with a constant heat transfer coefficient based on [Preston et al., 2007](references.md), respectively. -- `polydisperse` activates polydispersity in the bubble model through a probability density function (PDF) of the equilibrium bubble radius. +- `polydisperse` activates polydispersity in the bubble model through a probability density function (PDF) of the equilibrium bubble radius. Simpson's rule is used for integrating the log-normal PDF of equilibrium bubble radius for polydisperse populations. - `R0ref` specifies the reference bubble radius. - `nb` specifies the number of discrete bins that define the probability density function (PDF) of the equilibrium bubble radius. -- `R0_type` specifies the quadrature rule for integrating the log-normal PDF of equilibrium bubble radius for polydisperse populations. -`R0_type = 1` corresponds to Simpson's rule. - - `poly_sigma` specifies the standard deviation of the log-normal PDF of equilibrium bubble radius for polydisperse populations. - `Ca`, `Web`, and `Re_inv` respectively specify the Cavitation number, Weber number, and the inverse Reynolds number that characterize the offset of the gas pressure from the vapor pressure, surface tension, and liquid viscosity when the polytropic gas compression model is used. diff --git a/docs/documentation/getting-started.md b/docs/documentation/getting-started.md index d407a59a1c..885c528cb9 100644 --- a/docs/documentation/getting-started.md +++ b/docs/documentation/getting-started.md @@ -14,7 +14,6 @@ cd MFC MFC can be built in multiple ways on various operating systems. Please select your desired configuration from the list bellow: -

*nix

- **On supported clusters:** Load environment modules @@ -31,15 +30,14 @@ sudo apt upgrade sudo apt install tar wget make cmake gcc g++ \ python3 python3-dev python3-venv \ openmpi-bin libopenmpi-dev \ - libhdf5-dev libfftw3-dev + libhdf5-dev libfftw3-dev \ + libblas-dev liblapack-dev ``` -If you wish to build MFC using [NVidia's NVHPC SDK](https://developer.nvidia.com/hpc-sdk), +If you wish to build MFC using [NVIDIA's NVHPC SDK](https://developer.nvidia.com/hpc-sdk), first follow the instructions [here](https://developer.nvidia.com/nvidia-hpc-sdk-downloads). -
-

Windows

On Windows, you can either use Intel Compilers with the standard Microsoft toolchain, @@ -96,16 +94,13 @@ You will also have access to the `.sln` Microsoft Visual Studio solution files f
- - -

MacOS

Using [Homebrew](https://brew.sh/) you can install the necessary dependencies before configuring your environment: ```shell -brew install coreutils python cmake fftw hdf5 gcc boost open-mpi +brew install coreutils python cmake fftw hdf5 gcc boost open-mpi lapack echo -e "export BOOST_INCLUDE='$(brew --prefix --installed boost)/include'" | tee -a ~/.bash_profile ~/.zshrc . ~/.bash_profile 2>/dev/null || . ~/.zshrc 2>/dev/null ! [ -z "${BOOST_INCLUDE+x}" ] && echo 'Environment is ready!' || echo 'Error: $BOOST_INCLUDE is unset. Please adjust the previous commands to fit with your environment.' diff --git a/docs/documentation/gpuDebugging.md b/docs/documentation/gpuDebugging.md deleted file mode 100644 index 3400137c39..0000000000 --- a/docs/documentation/gpuDebugging.md +++ /dev/null @@ -1,156 +0,0 @@ -# Debugging Tools and Tips for GPUs - -## Compiler agnostic tools - -## OpenMP tools -```bash -OMP_DISPLAY_ENV=true | false | verbose -``` -- Prints out the internal control values and environment variables at the beginning of the program if `true` or `verbose` -- `verbose` will also print out vendor-specific internal control values and environment variables - -```bash -OMP_TARGET_OFFLOAD = MANDATORY | DISABLED | DEFAULT -``` -- Quick way to turn off off-load (`DISABLED`) or make it abort if a GPU isn't found (`MANDATORY`) -- Great first test: does the problem disappear when you drop back to the CPU? - -```bash -OMP_THREAD_LIMIT= -``` -- Sets the maximum number of OpenMP threads to use in a contention group -- Might be useful in checking for issues with contention or race conditions - -```bash -OMP_DISPLAY_AFFINITY=TRUE -``` -- Will display affinity bindings for each OpenMP thread, containing hostname, process identifier, OS thread identifier, OpenMP thread identifier, and affinity binding. - -## Cray Compiler Tools - -### Cray General Options - -```bash -CRAY_ACC_DEBUG: 0 (off), 1, 2, 3 (very noisy) -``` - -- Dumps a time-stamped log line (`ACC: ...`) for every allocation, data transfer, kernel launch, wait, etc. Great first stop when "nothing seems to run on the GPU". -- Outputs on STDERR by default. Can be changed by setting `CRAY_ACC_DEBUG_FILE`. - - Recognizes `stderr`, `stdout`, and `process`. - - `process` automatically generates a new file based on `pid` (each MPI process will have a different file) -- While this environment variable specifies ACC, it can be used for both OpenACC and OpenMP - -```bash -CRAY_ACC_FORCE_EARLY_INIT=1 -``` - -- Force full GPU initialization at program start so you can see start-up hangs immediately -- Default behavior without an environment variable is to defer initialization on first use -- Device initialization includes initializing the GPU vendor’s low-level device runtime library (e.g., libcuda for NVIDIA GPUs) and establishing all necessary software contexts for interacting with the device - -### Cray OpenACC Options - -```bash -CRAY_ACC_PRESENT_DUMP_SAVE_NAMES=1 -``` -- Will cause `acc_present_dump()` to output variable names and file locations in addition to variable mappings -- Add `acc_present_dump()` around hotspots to help find problems with data movements - - Helps more if adding `CRAY_ACC_DEBUG` environment variable - -## NVHPC Compiler Options - -### NVHPC General Options - -```bash -STATIC_RANDOM_SEED=1 -``` -- Forces the seed returned by `RANDOM_SEED` to be constant, so it generates the same sequence of random numbers -- Useful for testing issues with randomized data - -```bash -NVCOMPILER_TERM=option[,option] -``` -- `[no]debug`: Enables/disables just-in-time debugging (debugging invoked on error) -- `[no]trace`: Enables/disables stack traceback on error - -### NVHPC OpenACC Options - -```bash -NVCOMPILER_ACC_NOTIFY= -``` -- Assign the environment variable to a bitmask to print out information to stderr for the following - - kernel launches: 1 - - data transfers: 2 - - region entry/exit: 4 - - wait operation of synchronizations with the device: 8 - - device memory allocations and deallocations: 16 -- 1 (kernels only) is the usual first step.3 (kernels + copies) is great for "why is it so slow?" - -```bash -NVCOMPILER_ACC_TIME=1 -``` -- Lightweight profiler -- prints a tidy end-of-run table with per-region and per-kernel times and bytes moved -- Do not use with CUDA profiler at the same time - -```bash -NVCOMPILER_ACC_DEBUG=1 -``` -- Spews everything the runtime sees: host/device addresses, mapping events, present-table look-ups, etc. -- Great for "partially present" or "pointer went missing" errors. -- [Doc for NVCOMPILER_ACC_DEBUG](https://docs.nvidia.com/hpc-sdk/archive/20.9/pdf/hpc209openacc_gs.pdf) - - Ctrl+F for `NVCOMPILER_ACC_DEBUG` - -### NVHPC OpenMP Options - -```bash -LIBOMPTARGET_PROFILE=run.json -``` -- Emits a Chrome-trace (JSON) timeline you can open in chrome://tracing or Speedscope -- Great lightweight profiler when Nsight is overkill. -- Granularity in µs via `LIBOMPTARGET_PROFILE_GRANULARITY` (default 500). - -```bash -LIBOMPTARGET_INFO= -``` -- Prints out different types of runtime information -- Human-readable log of data-mapping inserts/updates, kernel launches, copies, waits. -- Perfect first stop for "why is nothing copied?" -- Flags - - Print all data arguments upon entering an OpenMP device kernel: 0x01 - - Indicate when a mapped address already exists in the device mapping table: 0x02 - - Dump the contents of the device pointer map at kernel exit: 0x04 - - Indicate when an entry is changed in the device mapping table: 0x08 - - Print OpenMP kernel information from device plugins: 0x10 - - Indicate when data is copied to and from the device: 0x20 - -```bash -LIBOMPTARGET_DEBUG=1 -``` -- Developer-level trace (host-side) -- Much noisier than `INFO` -- Only works if the runtime was built with `-DOMPTARGET_DEBUG`. - -```bash -LIBOMPTARGET_JIT_OPT_LEVEL=-O{0,1,2,3} -``` -- This environment variable can be used to change the optimization pipeline used to optimize the embedded device code as part of the device JIT. -- The value corresponds to the `-O{0,1,2,3}` command line argument passed to clang. - -```bash -LIBOMPTARGET_JIT_SKIP_OPT=1 -``` -- This environment variable can be used to skip the optimization pipeline during JIT compilation. -- If set, the image will only be passed through the backend. -- The backend is invoked with the `LIBOMPTARGET_JIT_OPT_LEVEL` flag. - -## Compiler Documentation - -- [Cray & OpenMP Docs](https://cpe.ext.hpe.com/docs/24.11/cce/man7/intro_openmp.7.html#environment-variables) -- [Cray & OpenACC Docs](https://cpe.ext.hpe.com/docs/24.11/cce/man7/intro_openacc.7.html#environment-variables) -- [NVHPC & OpenACC Docs](https://docs.nvidia.com/hpc-sdk/compilers/hpc-compilers-user-guide/index.html?highlight=NVCOMPILER_#environment-variables) -- [NVHPC & OpenMP Docs](https://docs.nvidia.com/hpc-sdk/compilers/hpc-compilers-user-guide/index.html?highlight=NVCOMPILER_#id2) -- [LLVM & OpenMP Docs](https://openmp.llvm.org/design/Runtimes.html) - - NVHPC is built on top of LLVM -- [OpenMP Docs](https://www.openmp.org/spec-html/5.1/openmp.html) -- [OpenACC Docs](https://www.openacc.org/sites/default/files/inline-files/OpenACC.2.7.pdf) diff --git a/docs/documentation/gpuParallelization.md b/docs/documentation/gpuParallelization.md index 8579914485..c40d3c57d9 100644 --- a/docs/documentation/gpuParallelization.md +++ b/docs/documentation/gpuParallelization.md @@ -564,3 +564,160 @@ Uses FYPP eval directive using `$:`
------------------------------------------------------------------------------------------ + +# Debugging Tools and Tips for GPUs + +## Compiler agnostic tools + +## OpenMP tools +```bash +OMP_DISPLAY_ENV=true | false | verbose +``` +- Prints out the internal control values and environment variables at the beginning of the program if `true` or `verbose` +- `verbose` will also print out vendor-specific internal control values and environment variables + +```bash +OMP_TARGET_OFFLOAD = MANDATORY | DISABLED | DEFAULT +``` +- Quick way to turn off off-load (`DISABLED`) or make it abort if a GPU isn't found (`MANDATORY`) +- Great first test: does the problem disappear when you drop back to the CPU? + +```bash +OMP_THREAD_LIMIT= +``` +- Sets the maximum number of OpenMP threads to use in a contention group +- Might be useful in checking for issues with contention or race conditions + +```bash +OMP_DISPLAY_AFFINITY=TRUE +``` +- Will display affinity bindings for each OpenMP thread, containing hostname, process identifier, OS thread identifier, OpenMP thread identifier, and affinity binding. + +## Cray Compiler Tools + +### Cray General Options + +```bash +CRAY_ACC_DEBUG: 0 (off), 1, 2, 3 (very noisy) +``` + +- Dumps a time-stamped log line (`ACC: ...`) for every allocation, data transfer, kernel launch, wait, etc. Great first stop when "nothing seems to run on the GPU". +- Outputs on STDERR by default. Can be changed by setting `CRAY_ACC_DEBUG_FILE`. + - Recognizes `stderr`, `stdout`, and `process`. + - `process` automatically generates a new file based on `pid` (each MPI process will have a different file) +- While this environment variable specifies ACC, it can be used for both OpenACC and OpenMP + +```bash +CRAY_ACC_FORCE_EARLY_INIT=1 +``` + +- Force full GPU initialization at program start so you can see start-up hangs immediately +- Default behavior without an environment variable is to defer initialization on first use +- Device initialization includes initializing the GPU vendor’s low-level device runtime library (e.g., libcuda for NVIDIA GPUs) and establishing all necessary software contexts for interacting with the device + +### Cray OpenACC Options + +```bash +CRAY_ACC_PRESENT_DUMP_SAVE_NAMES=1 +``` +- Will cause `acc_present_dump()` to output variable names and file locations in addition to variable mappings +- Add `acc_present_dump()` around hotspots to help find problems with data movements + - Helps more if adding `CRAY_ACC_DEBUG` environment variable + +## NVHPC Compiler Options + +### NVHPC General Options + +```bash +STATIC_RANDOM_SEED=1 +``` +- Forces the seed returned by `RANDOM_SEED` to be constant, so it generates the same sequence of random numbers +- Useful for testing issues with randomized data + +```bash +NVCOMPILER_TERM=option[,option] +``` +- `[no]debug`: Enables/disables just-in-time debugging (debugging invoked on error) +- `[no]trace`: Enables/disables stack traceback on error + +### NVHPC OpenACC Options + +```bash +NVCOMPILER_ACC_NOTIFY= +``` +- Assign the environment variable to a bitmask to print out information to stderr for the following + - kernel launches: 1 + - data transfers: 2 + - region entry/exit: 4 + - wait operation of synchronizations with the device: 8 + - device memory allocations and deallocations: 16 +- 1 (kernels only) is the usual first step.3 (kernels + copies) is great for "why is it so slow?" + +```bash +NVCOMPILER_ACC_TIME=1 +``` +- Lightweight profiler +- prints a tidy end-of-run table with per-region and per-kernel times and bytes moved +- Do not use with CUDA profiler at the same time + +```bash +NVCOMPILER_ACC_DEBUG=1 +``` +- Spews everything the runtime sees: host/device addresses, mapping events, present-table look-ups, etc. +- Great for "partially present" or "pointer went missing" errors. +- [Doc for NVCOMPILER_ACC_DEBUG](https://docs.nvidia.com/hpc-sdk/archive/20.9/pdf/hpc209openacc_gs.pdf) + - Ctrl+F for `NVCOMPILER_ACC_DEBUG` + +### NVHPC OpenMP Options + +```bash +LIBOMPTARGET_PROFILE=run.json +``` +- Emits a Chrome-trace (JSON) timeline you can open in chrome://tracing or Speedscope +- Great lightweight profiler when Nsight is overkill. +- Granularity in µs via `LIBOMPTARGET_PROFILE_GRANULARITY` (default 500). + +```bash +LIBOMPTARGET_INFO= +``` +- Prints out different types of runtime information +- Human-readable log of data-mapping inserts/updates, kernel launches, copies, waits. +- Perfect first stop for "why is nothing copied?" +- Flags + - Print all data arguments upon entering an OpenMP device kernel: 0x01 + - Indicate when a mapped address already exists in the device mapping table: 0x02 + - Dump the contents of the device pointer map at kernel exit: 0x04 + - Indicate when an entry is changed in the device mapping table: 0x08 + - Print OpenMP kernel information from device plugins: 0x10 + - Indicate when data is copied to and from the device: 0x20 + +```bash +LIBOMPTARGET_DEBUG=1 +``` +- Developer-level trace (host-side) +- Much noisier than `INFO` +- Only works if the runtime was built with `-DOMPTARGET_DEBUG`. + +```bash +LIBOMPTARGET_JIT_OPT_LEVEL=-O{0,1,2,3} +``` +- This environment variable can be used to change the optimization pipeline used to optimize the embedded device code as part of the device JIT. +- The value corresponds to the `-O{0,1,2,3}` command line argument passed to clang. + +```bash +LIBOMPTARGET_JIT_SKIP_OPT=1 +``` +- This environment variable can be used to skip the optimization pipeline during JIT compilation. +- If set, the image will only be passed through the backend. +- The backend is invoked with the `LIBOMPTARGET_JIT_OPT_LEVEL` flag. + +## Compiler Documentation + +- [Cray & OpenMP Docs](https://cpe.ext.hpe.com/docs/24.11/cce/man7/intro_openmp.7.html#environment-variables) +- [Cray & OpenACC Docs](https://cpe.ext.hpe.com/docs/24.11/cce/man7/intro_openacc.7.html#environment-variables) +- [NVHPC & OpenACC Docs](https://docs.nvidia.com/hpc-sdk/compilers/hpc-compilers-user-guide/index.html?highlight=NVCOMPILER_#environment-variables) +- [NVHPC & OpenMP Docs](https://docs.nvidia.com/hpc-sdk/compilers/hpc-compilers-user-guide/index.html?highlight=NVCOMPILER_#id2) +- [LLVM & OpenMP Docs](https://openmp.llvm.org/design/Runtimes.html) + - NVHPC is built on top of LLVM +- [OpenMP Docs](https://www.openmp.org/spec-html/5.1/openmp.html) +- [OpenACC Docs](https://www.openacc.org/sites/default/files/inline-files/OpenACC.2.7.pdf) diff --git a/docs/documentation/papers.md b/docs/documentation/papers.md index 4250c78639..51b7629f09 100644 --- a/docs/documentation/papers.md +++ b/docs/documentation/papers.md @@ -1,5 +1,19 @@ # Papers +MFC 5.0: An exascale many-physics flow solver. [Wilfong, B., Le Berre, H., Radhakrishnan, A., Gupta, A., Vaca-Revelo, D., Adam , D., Yu, H., Lee, H., Chreim, J. R., Carcana Barbosa, M., Zhang, Y., Cisneros-Garibay, E., Gnanaskandan, A., Rodriguez Jr., M., Budiardja, R. D., Abbott, S., Colonius, T., & Bryngelson, S. H. (2025) MFC 5.0: An exascale many-physics flow solver. arXiv:2503.07953. Equal contribution.](https://doi.org/10.48550/arXiv.2503.07953) + +```bibtex +@article{Wilfong_2025, + author = {Wilfong, Benjamin and {Le Berre}, Henry and Radhakrishnan, Anand and Gupta, Ansh and Vaca-Revelo, Diego and Adam, Dimitrios and Yu, Haocheng and Lee, Hyeoksu and Chreim, Jose Rodolfo and {Carcana Barbosa}, Mirelys and Zhang, Yanjun and Cisneros-Garibay, Esteban and Gnanaskandan, Aswin and {Rodriguez Jr.}, Mauro and Budiardja, Reuben D. and Abbott, Stephen and Colonius, Tim and Bryngelson, Spencer H.}, + title = {{MFC 5.0: A}n exascale many-physics flow solver}, + journal = {arXiv preprint arXiv:2503.07953}, + year = {2025}, + doi = {10.48550/arXiv.2503.07953} +} +``` + +
+ MFC: An open-source high-order multi-component, multi-phase, and multi-scale compressible flow solver. [S. H. Bryngelson, K. Schmidmayer, V. Coralic, K. Maeda, J. Meng, T. Colonius (2021) Computer Physics Communications **266**, 107396](https://doi.org/10.1016/j.cpc.2020.107396) ```bibtex diff --git a/docs/documentation/readme.md b/docs/documentation/readme.md index 5ca45150e4..4ce5b6b6e1 100644 --- a/docs/documentation/readme.md +++ b/docs/documentation/readme.md @@ -3,15 +3,14 @@ ## User Documentation - [Getting Started](getting-started.md) -- [Testing MFC](testing.md) +- [Testing](testing.md) - [Case Files](case.md) - [Example Cases](examples.md) -- [Running MFC](running.md) +- [Running](running.md) - [Flow Visualization](visualization.md) - [Performance](expectedPerformance.md) -- [GPU Parallelization](gpuParallelization.md) -- [GPU Debugging](gpuDebugging.md) -- [MFC's Authors](authors.md) +- [GPU Offloading](gpuParallelization.md) +- [Authors](authors.md) - [References](references.md) ## Code/API Documentation diff --git a/docs/documentation/references.md b/docs/documentation/references.md index 6106b96ecd..98ce8d45d1 100644 --- a/docs/documentation/references.md +++ b/docs/documentation/references.md @@ -69,3 +69,5 @@ - Powell, K. G. (1994). An approximate Riemann solver for magnetohydrodynamics: (That works in more than one dimension). In Upwind and high-resolution schemes (pp. 570-583). Springer. - Cao, S., Zhang, Y., Liao, D., Zhong, P., and Wang, K. G. (2019). Shock-induced damage and dynamic fracture in cylindrical bodies submerged in liquid. International Journal of Solids and Structures, 169:55–71. Elsevier. + +- Xu, W., Gao, Y., Deng, Y., Liu, J., and Liu, C. (2019). An explicit expression for the calculation of the Rortex vector. Physics of Fluids, 31(9).. \ No newline at end of file diff --git a/docs/documentation/testing.md b/docs/documentation/testing.md index 15b1ca3618..e139c5b201 100644 --- a/docs/documentation/testing.md +++ b/docs/documentation/testing.md @@ -16,6 +16,7 @@ A test is considered passing when our error tolerances are met in order to maint - `--percent` (`%`) to specify a percentage of the test suite to select at random and test - `--max-attempts` (`-m`) the maximum number of attempts to make on a test before considering it failed - `--no-examples` skips the testing of cases in the examples folder +- `--rdma-mpi` runs additional tests where RDMA MPI is enabled. To specify a computer, pass the `-c` flag to `./mfc.sh run` like so: ```shell diff --git a/examples/0D_bubblecollapse_adap/case.py b/examples/0D_bubblecollapse_adap/case.py index af7bb051c5..6b3fa639f9 100644 --- a/examples/0D_bubblecollapse_adap/case.py +++ b/examples/0D_bubblecollapse_adap/case.py @@ -118,6 +118,7 @@ "adv_n": "T", # adap_dt "adap_dt": "T", + "adap_dt_max_iters": 200, # Gas compression model "polytropic": "T", "thermal": 1, diff --git a/examples/1D_poly_bubscreen/case.py b/examples/1D_poly_bubscreen/case.py index df69501e4c..e73eff2e92 100644 --- a/examples/1D_poly_bubscreen/case.py +++ b/examples/1D_poly_bubscreen/case.py @@ -157,7 +157,6 @@ "bubbles_euler": "T", "bubble_model": 2, "polytropic": "T", - "R0_type": 1, "thermal": 3, "R0ref": myr0, "nb": 1, diff --git a/examples/1D_qbmm/case.py b/examples/1D_qbmm/case.py index 5298782f5a..926ad49a14 100644 --- a/examples/1D_qbmm/case.py +++ b/examples/1D_qbmm/case.py @@ -171,7 +171,6 @@ "bubble_model": 2, "polytropic": "F", "polydisperse": "T", - "R0_type": 1, "poly_sigma": 0.3, "thermal": 3, "R0ref": myr0, diff --git a/examples/1D_sodshocktube_muscl/case.py b/examples/1D_sodshocktube_muscl/case.py new file mode 100755 index 0000000000..ec0d2cb3f8 --- /dev/null +++ b/examples/1D_sodshocktube_muscl/case.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +import math +import json + +# Numerical setup +Nx = 399 +dx = 1.0 / (1.0 * (Nx + 1)) + +Tend, Nt = 0.1, 1000 +mydt = Tend / (1.0 * Nt) + +# Configuring case dictionary +print( + json.dumps( + { + # Logistics + "run_time_info": "T", + # Computational Domain Parameters + "x_domain%beg": 0.0e00, + "x_domain%end": 1.0e00, + "m": Nx, + "n": 0, + "p": 0, + "dt": mydt, + "t_step_start": 0, + "t_step_stop": int(Nt), + "t_step_save": int(math.ceil(Nt / 10.0)), + # Simulation Algorithm Parameters + "num_patches": 2, + "model_eqns": 2, + "alt_soundspeed": "F", + "num_fluids": 1, + "mpp_lim": "F", + "mixture_err": "F", + "time_stepper": 3, + "recon_type": 2, + "muscl_order": 2, + "muscl_lim": 2, + "int_comp": "T", + "riemann_solver": 2, + "wave_speeds": 1, + "avg_state": 2, + "bc_x%beg": -3, + "bc_x%end": -3, + # Formatted Database Files Structure Parameters + "format": 1, + "precision": 2, + "prim_vars_wrt": "T", + "parallel_io": "T", + # Patch 1 L + "patch_icpp(1)%geometry": 1, + "patch_icpp(1)%x_centroid": 0.25, + "patch_icpp(1)%length_x": 0.5, + "patch_icpp(1)%vel(1)": 0.0, + "patch_icpp(1)%pres": 1.0, + "patch_icpp(1)%alpha_rho(1)": 1.0e00, + "patch_icpp(1)%alpha(1)": 1.0, + # Patch 2 R + "patch_icpp(2)%geometry": 1, + "patch_icpp(2)%x_centroid": 0.75, + "patch_icpp(2)%length_x": 0.5, + "patch_icpp(2)%vel(1)": 0.0, + "patch_icpp(2)%pres": 0.1, + "patch_icpp(2)%alpha_rho(1)": 0.125e00, + "patch_icpp(2)%alpha(1)": 1.0, + # Fluids Physical Parameters + "fluid_pp(1)%gamma": 1.0e00 / (1.4 - 1.0e00), + "fluid_pp(1)%pi_inf": 0.0, + } + ) +) diff --git a/examples/2D_advection_muscl/case.py b/examples/2D_advection_muscl/case.py new file mode 100644 index 0000000000..016857d491 --- /dev/null +++ b/examples/2D_advection_muscl/case.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +import json + +# Configuring case dictionary +print( + json.dumps( + { + # Logistics + "run_time_info": "T", + # Computational Domain Parameters + "x_domain%beg": 0.0e00, + "x_domain%end": 1.0e00, + "y_domain%beg": 0.0e00, + "y_domain%end": 1.0e00, + "m": 99, + "n": 99, + "p": 0, + "dt": 5.0e-07, + "t_step_start": 0, + "t_step_stop": 1000, + "t_step_save": 100, + # Simulation Algorithm Parameters + "num_patches": 2, + "model_eqns": 3, + "alt_soundspeed": "F", + "num_fluids": 2, + "mpp_lim": "T", + "mixture_err": "T", + "time_stepper": 3, + "recon_type": 2, + "muscl_order": 2, + "muscl_lim": 2, + "int_comp": "T", + "null_weights": "F", + "riemann_solver": 2, + "wave_speeds": 1, + "avg_state": 2, + "bc_x%beg": -3, + "bc_x%end": -3, + "bc_y%beg": -3, + "bc_y%end": -3, + # Formatted Database Files Structure Parameters + "format": 1, + "precision": 2, + "prim_vars_wrt": "T", + "parallel_io": "T", + # Patch 1: Base + "patch_icpp(1)%geometry": 3, + "patch_icpp(1)%x_centroid": 0.5e00, + "patch_icpp(1)%y_centroid": 0.5e00, + "patch_icpp(1)%length_x": 1.0e00, + "patch_icpp(1)%length_y": 1.0e00, + "patch_icpp(1)%vel(1)": 100.0e00, + "patch_icpp(1)%vel(2)": 100.0e00, + "patch_icpp(1)%pres": 1.0e05, + "patch_icpp(1)%alpha_rho(1)": 1000.0e00, + "patch_icpp(1)%alpha_rho(2)": 1.0, + "patch_icpp(1)%alpha(1)": 1.0e-12, + "patch_icpp(1)%alpha(2)": 1.0 - 1.0e-12, + # Patch 2: Density to transport + "patch_icpp(2)%geometry": 2, + "patch_icpp(2)%smoothen": "T", + "patch_icpp(2)%smooth_patch_id": 1, + "patch_icpp(2)%smooth_coeff": 0.5e00, + "patch_icpp(2)%x_centroid": 0.1e00, + "patch_icpp(2)%y_centroid": 0.1e00, + "patch_icpp(2)%radius": 0.1e00, + "patch_icpp(2)%alter_patch(1)": "T", + "patch_icpp(2)%vel(1)": 100.0e00, + "patch_icpp(2)%vel(2)": 100.0e00, + "patch_icpp(2)%pres": 1.0e05, + "patch_icpp(2)%alpha_rho(1)": 1.0, + "patch_icpp(2)%alpha_rho(2)": 1.0, + "patch_icpp(2)%alpha(1)": 0, + "patch_icpp(2)%alpha(2)": 1.0, + # Fluids Physical Parameters + "fluid_pp(1)%gamma": 1.0e00 / (2.35e00 - 1.0e00), + "fluid_pp(1)%pi_inf": 2.35e00 * 1.0e09 / (2.35e00 - 1.0e00), + "fluid_pp(2)%gamma": 1.0e00 / (1.4e00 - 1.0e00), + "fluid_pp(2)%pi_inf": 0.0e00, + } + ) +) diff --git a/examples/2D_bubbly_steady_shock/case.py b/examples/2D_bubbly_steady_shock/case.py index 96fcdd3868..5e14c72e43 100644 --- a/examples/2D_bubbly_steady_shock/case.py +++ b/examples/2D_bubbly_steady_shock/case.py @@ -191,7 +191,6 @@ "bubble_model": 2, "polytropic": "T", "polydisperse": "F", - "R0_type": 1, "poly_sigma": 0.3, "thermal": 3, "R0ref": x0, diff --git a/examples/2D_riemann_test_muscl/case.py b/examples/2D_riemann_test_muscl/case.py new file mode 100644 index 0000000000..abf4a2fd5c --- /dev/null +++ b/examples/2D_riemann_test_muscl/case.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +import json +import math + +# Configuring case dictionary +print( + json.dumps( + { + # Logistics + "run_time_info": "T", + # Computational Domain Parameters + "x_domain%beg": 0.0, + "x_domain%end": 1.0, + "y_domain%beg": 0.0, + "y_domain%end": 1.0, + "m": 499, + "n": 499, + "p": 0, + "dt": 8e-05, + "t_step_start": 0, + "t_step_stop": 1000, + "t_step_save": 100, + # Simulation Algorithm Parameters + "num_patches": 4, + "model_eqns": 2, + "alt_soundspeed": "F", + "num_fluids": 1, + "mpp_lim": "F", + "mixture_err": "T", + "time_stepper": 3, + # "mp_weno": "F", + "recon_type": 2, + # "weno_order": 5, + # "weno_eps": 1e-16, + "muscl_order": 2, + "muscl_lim": 1, + "int_comp": "T", + "riemann_solver": 2, + "wave_speeds": 1, + "avg_state": 2, + "bc_x%beg": -3, + "bc_x%end": -3, + "bc_y%beg": -3, + "bc_y%end": -3, + # Formatted Database Files Structure Parameters + "format": 1, + "precision": 2, + "prim_vars_wrt": "T", + "parallel_io": "T", + # Patch 1: Base + "patch_icpp(1)%geometry": 3, + "patch_icpp(1)%x_centroid": 0.4, + "patch_icpp(1)%y_centroid": 0.4, + "patch_icpp(1)%length_x": 0.8, + "patch_icpp(1)%length_y": 0.8, + "patch_icpp(1)%vel(1)": 4 / math.sqrt(11), + "patch_icpp(1)%vel(2)": 4 / math.sqrt(11), + "patch_icpp(1)%pres": 9 / 310, + "patch_icpp(1)%alpha_rho(1)": 77 / 558, + "patch_icpp(1)%alpha(1)": 1, + # Patch 1: Base + "patch_icpp(2)%geometry": 3, + "patch_icpp(2)%x_centroid": 0.4, + "patch_icpp(2)%y_centroid": 0.9, + "patch_icpp(2)%length_x": 0.8, + "patch_icpp(2)%length_y": 0.2, + "patch_icpp(2)%vel(1)": 4 / math.sqrt(11), + "patch_icpp(2)%vel(2)": 0, + "patch_icpp(2)%pres": 0.3, + "patch_icpp(2)%alpha_rho(1)": 33 / 62, + "patch_icpp(2)%alpha(1)": 1, + # Patch 1: Base + "patch_icpp(3)%geometry": 3, + "patch_icpp(3)%x_centroid": 0.9, + "patch_icpp(3)%y_centroid": 0.4, + "patch_icpp(3)%length_x": 0.2, + "patch_icpp(3)%length_y": 0.8, + "patch_icpp(3)%vel(1)": 0, + "patch_icpp(3)%vel(2)": 4 / math.sqrt(11), + "patch_icpp(3)%pres": 0.3, + "patch_icpp(3)%alpha_rho(1)": 33 / 62, + "patch_icpp(3)%alpha(1)": 1, + # Patch 1: Base + "patch_icpp(4)%geometry": 3, + "patch_icpp(4)%x_centroid": 0.9, + "patch_icpp(4)%y_centroid": 0.9, + "patch_icpp(4)%length_x": 0.2, + "patch_icpp(4)%length_y": 0.2, + "patch_icpp(4)%vel(1)": 0, + "patch_icpp(4)%vel(2)": 0, + "patch_icpp(4)%pres": 1.5, + "patch_icpp(4)%alpha_rho(1)": 1.5, + "patch_icpp(4)%alpha(1)": 1.0, + # Fluids Physical Parameters + "fluid_pp(1)%gamma": 1.0e00 / (1.4e00 - 1.0e00), + "fluid_pp(1)%pi_inf": 0.0e00, + } + ) +) diff --git a/examples/2D_shockdroplet_muscl/case.py b/examples/2D_shockdroplet_muscl/case.py new file mode 100755 index 0000000000..5a6b73ba16 --- /dev/null +++ b/examples/2D_shockdroplet_muscl/case.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +import math +import json + +Ma = 1.4 +ps = 238558 +rho_post_a = 2.18 +rho_a = 1.204 +rho_w = 1000 +gam_a = 1.4 +gam_w = 6.12 +pi_w = 3.43e8 +vel = 226 +rho = 1 +c_l = math.sqrt(1.4 * ps / rho) +eps = 1e-9 + +D = 0.048 +Ny = 299.0 +Nx = 1199.0 +dx = 0.25 / Nx # 8.3e-6 + +time_end = 0.005 # 50us +cfl = 0.25 + +dt = cfl * dx / c_l # 5.3E-9 +Nt = int(time_end / dt) # 10000 + +print( + json.dumps( + { + # Logistics + "run_time_info": "F", + # Computational Domain Parameters + "x_domain%beg": -4 * D, + "x_domain%end": 20 * D, + "y_domain%beg": 0, + "y_domain%end": 6 * D, + "stretch_y": "T", + "a_y": 3.67, + "y_a": -5.7 * D, + "y_b": 5.7 * D, + "loops_y": 2, + "m": int(Nx), + "n": int(Ny), + "p": 0, + "dt": dt, + "t_step_start": 0, + "t_step_stop": Nt, + "t_step_save": math.ceil(Nt / 100), + # Simulation Algorithm Parameters + "num_patches": 3, + "model_eqns": 2, + "alt_soundspeed": "F", + "num_fluids": 2, + "mpp_lim": "T", + "mixture_err": "T", + "time_stepper": 3, + "recon_type": 2, + "muscl_order": 2, + "muscl_lim": 4, + "int_comp": "T", + "null_weights": "F", + "riemann_solver": 2, + "wave_speeds": 1, + "avg_state": 2, + "bc_x%beg": -6, # 11, + "bc_x%end": -6, # 12 + "bc_y%beg": -2, + "bc_y%end": -3, + # Formatted Database Files Structure Parameters + "format": 1, + "precision": 2, + "prim_vars_wrt": "T", + "parallel_io": "T", + # Patch 1: Background + "patch_icpp(1)%geometry": 3, + "patch_icpp(1)%x_centroid": 8 * D, + "patch_icpp(1)%y_centroid": 6 * D, + "patch_icpp(1)%length_x": 24 * D, + "patch_icpp(1)%length_y": 14 * D, + "patch_icpp(1)%vel(1)": 0.0, + "patch_icpp(1)%vel(2)": 0.0e00, + "patch_icpp(1)%pres": 101325.0, + "patch_icpp(1)%alpha_rho(1)": eps * 1000, + "patch_icpp(1)%alpha_rho(2)": (1 - eps) * 1.17, + "patch_icpp(1)%alpha(1)": eps, + "patch_icpp(1)%alpha(2)": 1 - eps, + # Patch 2: Shocked state + "patch_icpp(2)%geometry": 3, + "patch_icpp(2)%alter_patch(1)": "T", + "patch_icpp(2)%x_centroid": -2.5 * D, + "patch_icpp(2)%y_centroid": 6 * D, + "patch_icpp(2)%length_x": 3 * D, + "patch_icpp(2)%length_y": 14 * D, + "patch_icpp(2)%vel(1)": vel, + "patch_icpp(2)%vel(2)": 0.0e00, + "patch_icpp(2)%pres": ps, + "patch_icpp(2)%alpha_rho(1)": eps * 1000, + "patch_icpp(2)%alpha_rho(2)": (1 - eps) * rho_post_a, + "patch_icpp(2)%alpha(1)": eps, + "patch_icpp(2)%alpha(2)": 1 - eps, + # Patch 3: Bubble + "patch_icpp(3)%geometry": 2, + "patch_icpp(3)%x_centroid": 0, + "patch_icpp(3)%y_centroid": 0, + "patch_icpp(3)%radius": D / 2, + "patch_icpp(3)%alter_patch(1)": "T", + "patch_icpp(3)%vel(1)": 0.0, + "patch_icpp(3)%vel(2)": 0.0e00, + "patch_icpp(3)%pres": 101325.0, + "patch_icpp(3)%alpha_rho(1)": (1 - eps) * rho_w, + "patch_icpp(3)%alpha_rho(2)": eps * 1.17, + "patch_icpp(3)%alpha(1)": 1 - eps, # 0.95 + "patch_icpp(3)%alpha(2)": eps, # 0.05, + # Fluids Physical Parameters + "fluid_pp(1)%gamma": 1.0e00 / (gam_w - 1.0e00), + "fluid_pp(1)%pi_inf": pi_w * gam_w / (gam_w - 1.0e00), + "fluid_pp(2)%gamma": 1.0e00 / (gam_a - 1.0e00), + "fluid_pp(2)%pi_inf": 0.0e00, + } + ) +) diff --git a/examples/2D_whale_bubble_annulus/case.py b/examples/2D_whale_bubble_annulus/case.py index 15afc66b0a..f610ebd17e 100755 --- a/examples/2D_whale_bubble_annulus/case.py +++ b/examples/2D_whale_bubble_annulus/case.py @@ -152,7 +152,6 @@ "bubbles_euler": "T", "bubble_model": 3, "polytropic": "T", - "R0_type": 1, "thermal": 3, "R0ref": myr0, "nb": 1, diff --git a/examples/3D_rayleigh_taylor_muscl/case.py b/examples/3D_rayleigh_taylor_muscl/case.py new file mode 100644 index 0000000000..6cf9000080 --- /dev/null +++ b/examples/3D_rayleigh_taylor_muscl/case.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +import math +import json + +lam = 0.2 +h = 1.2 +k = 2 * math.pi / lam +amp = 0.05 / k + +# Numerical setup +x0 = 0 +x1 = lam / 2 +y0 = 0.0 +y1 = h +z0 = 0 +z1 = lam / 2 + +Nx = 99 +Ny = 1199 +Nz = 99 + +eps = 1e-6 + +dx = lam / 2 / (Nx + 1) +c = math.sqrt(1.4 * 1e5 / 1) +cfl = 0.4 +dt = cfl * dx / c + +Nt = math.ceil(0.2 / dt) +Ns = math.ceil(Nt / 100) + +# Configuration case dictionary +data = { + # Logistics + "run_time_info": "T", + # Computational Domain + "x_domain%beg": x0, + "x_domain%end": x1, + "y_domain%beg": y0, + "y_domain%end": y1, + "z_domain%beg": z0, + "z_domain%end": z1, + "m": Nx, + "n": Ny, + "p": Nz, + "cyl_coord": "F", + "dt": dt, + "t_step_start": 0, + "t_step_stop": Nt, + "t_step_save": Ns, + # Simulation Algorithm + "model_eqns": 2, + "alt_soundspeed": "F", + "mixture_err": "T", + "mpp_lim": "T", + "time_stepper": 3, + "recon_type": 2, + "muscl_order": 2, + "muscl_lim": 4, + "int_comp": "T", + "avg_state": 2, + "riemann_solver": 2, + "wave_speeds": 1, + "bc_x%beg": -2, + "bc_x%end": -3, + "bc_y%beg": -16, + "bc_y%end": -16, + "bc_z%beg": -2, + "bc_z%end": -3, + "num_patches": 1, + "num_fluids": 2, + "viscous": "T", + # Database Structure Parameters + "format": 1, + "precision": 2, + "prim_vars_wrt": "T", + "parallel_io": "T", + # Fluid Parameters (Heavy Gas) + "fluid_pp(1)%gamma": 1.0e00 / (1.4e00 - 1.0e00), + "fluid_pp(1)%pi_inf": 0.0e00, + "fluid_pp(1)%Re(1)": 1 / 0.0219, + # Fluid Parameters (Light Gas) + "fluid_pp(2)%gamma": 1.0e00 / (1.4e00 - 1.0e00), + "fluid_pp(2)%pi_inf": 0.0e00, + "fluid_pp(2)%Re(1)": 1 / 0.0073, + # Body Forces + "bf_y": "T", + "k_y": 0.0, + "w_y": 0.0, + "p_y": 0.0, + "g_y": -98.1, + # Water Patch + "patch_icpp(1)%geometry": 9, + "patch_icpp(1)%hcid": 300, + "patch_icpp(1)%x_centroid": 0, + "patch_icpp(1)%y_centroid": h / 2, + "patch_icpp(1)%z_centroid": 0, + "patch_icpp(1)%length_x": lam, + "patch_icpp(1)%length_y": h, + "patch_icpp(1)%length_z": h, + "patch_icpp(1)%vel(1)": 0.0, + "patch_icpp(1)%vel(2)": 0.0, + "patch_icpp(1)%vel(3)": 0.0, + "patch_icpp(1)%pres": 1e5, + "patch_icpp(1)%alpha_rho(1)": (1 - eps), + "patch_icpp(1)%alpha_rho(2)": eps * 1, + "patch_icpp(1)%alpha(1)": 1 - eps, + "patch_icpp(1)%alpha(2)": eps, +} + +print(json.dumps(data)) diff --git a/examples/3D_shockdroplet_muscl/case.py b/examples/3D_shockdroplet_muscl/case.py new file mode 100644 index 0000000000..e2476ed4c4 --- /dev/null +++ b/examples/3D_shockdroplet_muscl/case.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python3 +import math +import json + +# athmospheric pressure - Pa (used as reference value) +patm = 101325 + +# Initial Droplet Diameter / Reference length - m +D0 = 1.0e-3 + +# cavity to droplet ratio +CtD = 0.06 + +# cavity relative eccentricity (distance between radii) +ecc = 0.564 + +# initial shock distance from the y axis. Note that the droplet center is located at y = 0. Thus, the distance from the shock to +# the droplet is about D0/8 +ISD = 5.0 / 8 * D0 + +## pre-shock properties - AIR + +# pressure - Pa +p0a = patm + +# density - kg/m3 +rho0a = 1.204 + +# gamma +gama = 1.40 + +# pi infinity - Pa +pia = 0 + +# speed of sound - M/s +c_a = math.sqrt(gama * (p0a + pia) / rho0a) + +## Droplet - WATER + +# surface tension - N / m +st = 0.00e0 + +# Delta Pressure - Pa +DP = -st * 4 / D0 + +# initial pressure inside the droplet - Pa +p0w = p0a - DP + +# density - kg/m3 +rho0w = 1000 + +# gama +gamw = 6.12 + +# pi infty - Pa +piw = 3.43e08 + +# speed of sound - m/s +c_w = math.sqrt(gamw * (p0w + piw) / rho0w) + +# Shock Mach number of interest. Note that the post-shock properties can be defined in terms of either +# Min or psOp0a. Just comment/uncomment appropriatelly +Min = 2.4 + +## Pos to pre shock ratios - AIR + +# pressure +psOp0a = (Min**2 - 1) * 2 * gama / (gama + 1) + 1 +# psOp0a = 4.5 + +# density +rhosOrho0a = (1 + (gama + 1) / (gama - 1) * psOp0a) / ((gama + 1) / (gama - 1) + psOp0a) + +# Mach number of the shocked region - just a checker, as it must return "Min" +Ms = math.sqrt((gama + 1.0) / (2.0 * gama) * (psOp0a - 1.0) * (p0a / (p0a + pia)) + 1.0) + +# shock speed of sound - m/s +ss = Ms * c_a + +## post-shock - AIR + +# pressure - Pa +ps = psOp0a * p0a + +# density - kg / m3 +rhos = rhosOrho0a * rho0a + +# post shock speed of sound - m/s +c_s = math.sqrt(gama * (ps + pia) / rhos) + +# velocity at the post shock - m/s +vel = c_a / gama * (psOp0a - 1.0) * p0a / (p0a + pia) / Ms + +## Domain boundaries - m + +# x direction +xb = -8.4707 * D0 +xe = 9.6226 * D0 + +# xb = -10 * D0 +# xe = 10 * D0 + +# y direction +yb = 0 * D0 +ye = 10 * D0 + +# y direction +zb = 0 * D0 +ze = 10 * D0 + +# Stretching factor, to make sure the domaing is sufficiently large after the mesh stretch +StF = 4.0 + +# number of elements into y direction +Ny = 100 + +# number of elements into z direction +Nz = 100 + +# number of elements into x direction +Nx = Ny * 2 + +# grid delta x if mesh were uniform in x direction - m. Note that I do not need a measure for dy +dx = (xe - xb) / Nx + +# I calculating tend twice; first is an estimate, second is +# the actual value used. This is because I am getting errors in the +# post process part every time I approximate the actual Nt by an integer +# number (think of a smarter way). + +# dimensionless time +ttilde = 1.92 + +# auxiliary simulation physical time - s. This is not YET the total simulation time, as it will be corrected so as to avoid +# mismatches in simulation and post_process parts. Note that I wrote it this way so I have better control over the # of autosaves +tendA = ttilde * D0 / vel + +# "CFL" number that I use to control both temporal and spatial discretizations, such that the ratio dx/dt remains constant for a given +# simulation +cfl = 0.05 + +# time-step - s +dt = cfl * dx / ss + +# Save Frequency. Note that the number of autosaves will be SF + 1, as th IC (0.dat) is also saved +SF = 400 + +## making Nt divisible by SF +# 1 - ensure NtA goes slightly beyond tendA +NtA = int(tendA // dt + 1) + +# Array of saves. It is the same as Nt/Sf = t_step_save +AS = int(NtA // SF + 1) + +# Nt = total number of steps. Note that Nt >= NtA (so at least tendA is completely simulated) +Nt = AS * SF + +# total simulation time - s. Note that tend >= tendA +tend = Nt * dt + +# Configuring case dictionary +print( + json.dumps( + { + # Logistics + "run_time_info": "T", + # Computational Domain Parameters + "x_domain%beg": xb, + "x_domain%end": xe, + "y_domain%beg": yb, + "y_domain%end": ye, + "z_domain%beg": zb, + "z_domain%end": ze, + "stretch_x": "T", + "a_x": 20, + "x_a": -1.2 * D0, + "x_b": 1.2 * D0, + "stretch_y": "T", + "a_y": 20, + "y_a": -0.0 * D0, + "y_b": 1.2 * D0, + "stretch_z": "T", + "a_z": 20, + "z_a": -0.0 * D0, + "z_b": 1.2 * D0, + "m": Nx, + "n": Ny, + "p": Nz, + "cyl_coord": "F", + "dt": dt, + "t_step_start": 0, + "t_step_stop": 50000, + "t_step_save": 100, + # Simulation Algorithm Parameters + "num_patches": 3, + "model_eqns": 2, + "alt_soundspeed": "F", + "num_fluids": 2, + "mpp_lim": "T", + "mixture_err": "T", + "time_stepper": 3, + "recon_type": 2, + "muscl_order": 2, + "muscl_lim": 3, + "int_comp": "T", + "riemann_solver": 2, + "wave_speeds": 1, + "avg_state": 2, + "bc_x%beg": -6, + "bc_x%end": -6, + "bc_y%beg": -2, + "bc_y%end": -3, + "bc_z%beg": -2, + "bc_z%end": -3, + # Formatted Database Files Structure Parameters + "format": 1, + "precision": 2, + "prim_vars_wrt": "T", + "parallel_io": "T", + # I will use 1 for WATER properties, and 2 for AIR properties + # Patch 1: Background (AIR - 2) + "patch_icpp(1)%geometry": 9, + "patch_icpp(1)%x_centroid": (xb + xe) / 2 * StF, + "patch_icpp(1)%y_centroid": (yb + ye) / 2 * StF, + "patch_icpp(1)%z_centroid": (yb + ye) / 2 * StF, + "patch_icpp(1)%length_x": (xe - xb) * StF, + "patch_icpp(1)%length_y": (ye - yb) * StF, + "patch_icpp(1)%length_z": (ze - zb) * StF, + "patch_icpp(1)%vel(1)": 0.0e00, + "patch_icpp(1)%vel(2)": 0.0e00, + "patch_icpp(1)%vel(3)": 0.0e00, + "patch_icpp(1)%pres": p0a, + "patch_icpp(1)%alpha_rho(1)": 0.0e00, + "patch_icpp(1)%alpha_rho(2)": rho0a, + "patch_icpp(1)%alpha(1)": 0.0e00, + "patch_icpp(1)%alpha(2)": 1.0e00, + # Patch 2: Shocked state (AIR - 2) + "patch_icpp(2)%geometry": 9, + "patch_icpp(2)%alter_patch(1)": "T", + "patch_icpp(2)%x_centroid": -ISD - (xe - xb) / 2 * StF, + "patch_icpp(2)%y_centroid": (yb + ye) / 2 * StF, + "patch_icpp(2)%z_centroid": (zb + ze) / 2 * StF, + "patch_icpp(2)%length_x": (xe - xb) * StF, + "patch_icpp(2)%length_y": (ye - yb) * StF, + "patch_icpp(2)%length_z": (ze - zb) * StF, + "patch_icpp(2)%vel(1)": vel, + "patch_icpp(2)%vel(2)": 0.0e00, + "patch_icpp(2)%vel(3)": 0.0e00, + "patch_icpp(2)%pres": ps, + "patch_icpp(2)%alpha_rho(1)": 0.0e00, + "patch_icpp(2)%alpha_rho(2)": rhos, + "patch_icpp(2)%alpha(1)": 0.0e00, + "patch_icpp(2)%alpha(2)": 1.0e00, + # Patch 3: Droplet (WATER - 1) + "patch_icpp(3)%geometry": 8, + "patch_icpp(3)%x_centroid": 0.0e00, + "patch_icpp(3)%y_centroid": 0.0e00, + "patch_icpp(3)%z_centroid": 0.0e00, + "patch_icpp(3)%radius": D0 / 2, + "patch_icpp(3)%alter_patch(1)": "T", + "patch_icpp(3)%vel(1)": 0.0e00, + "patch_icpp(3)%vel(2)": 0.0e00, + "patch_icpp(3)%vel(3)": 0.0e00, + "patch_icpp(3)%pres": p0w, + "patch_icpp(3)%alpha_rho(1)": rho0w, + "patch_icpp(3)%alpha_rho(2)": 0.0e00, + "patch_icpp(3)%alpha(1)": 1.0e00, + "patch_icpp(3)%alpha(2)": 0.0e00, + # Fluids Physical Parameters + "fluid_pp(1)%gamma": 1.0e00 / (gamw - 1), + "fluid_pp(1)%pi_inf": gamw * piw / (gamw - 1), + "fluid_pp(2)%gamma": 1.0e00 / (gama - 1), + "fluid_pp(2)%pi_inf": gama * pia / (gama - 1), + } + ) +) diff --git a/examples/3D_turb_mixing/README.md b/examples/3D_turb_mixing/README.md new file mode 100644 index 0000000000..82a3e0d1aa --- /dev/null +++ b/examples/3D_turb_mixing/README.md @@ -0,0 +1,4 @@ +# 3D Turbulent Mixing layer (3D) + +## Liutex visualization at transitional state + diff --git a/examples/3D_turb_mixing/case.py b/examples/3D_turb_mixing/case.py index 4055e57b28..5ff57c0e34 100644 --- a/examples/3D_turb_mixing/case.py +++ b/examples/3D_turb_mixing/case.py @@ -96,6 +96,7 @@ "omega_wrt(2)": "T", "omega_wrt(3)": "T", "qm_wrt": "T", + "liutex_wrt": "T", # Patch 1 "patch_icpp(1)%geometry": 9, "patch_icpp(1)%x_centroid": Lx / 2.0, diff --git a/examples/3D_turb_mixing/result.png b/examples/3D_turb_mixing/result.png new file mode 100644 index 0000000000000000000000000000000000000000..cd5e47b1fd0fa82a921c5338688b3dcc62d3c434 GIT binary patch literal 2110786 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�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%0A+XPar*OaCkK`=(y)=n-(Lw9K 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

Y-+>7P` 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%0D#H>9?Zh>lgZp<;}4E;Zh>(o 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%0A~?W@!V1bQfn;g(8@_MX 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 aPL^%a(74ZrW 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�kch?$@?m9-v^%d0`yT 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 z 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

||z9T)Zk%MFJ+zH5LE%x{ASQf_d(4Gv=k-0( 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%0AT_i^60x3z_Qu35&~Z`imtoN@7atT}xj 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

B5f5;pLh#hYu#MJlH`!W_Mkk{NQDtYWy}}X? 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≥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

{r{!f1Lli{+CYPMP_} zwk_e*=e;15w>~rX&?kNPjbCi^z(x=J+V{YQkjtrzm;&rKh*iHZ3dx4DJOt@fM(|K-NwEnI)5IQPKmh12 z94oCZIxQKf$H+Ov?UMH^d+pnkyl37R7$uE@%)sgAsCYfAUlk@PZA}G6aZXe zngo322tZP91#$zi8r~oXNzj$pdjtmZ00a$4rUQPdekCYnX8e{-^`ROd2>2tuC&6i^ zzl&fMZ72AcLpeipJf1BO1CQ`F1S<* z$<1;`miRFcpFP|iYABcDoK%Hkn!vr~hI+_WpC^zeStFkSXAzH-;QI9dYzE^e2{>jN z+~ZkS2pWzBe(h&t z;8Cz$;@t|t$Bun_!U*8n1f-q>>mh?cus~r0iXS3$mKjy4O=8^C&`79cY%JMPf_h5< zfnK1I2&5)ZQtIm?vz-1NK^3HJb8Gxv2Fh`ksH<+<7D0d!R2oJA%bbs|dgD6Lv;V*& z;g-*Qj5P&Oka0Zj^wXG9d{6nx;?l}+&w~$zU6egimQ5CL%j$ggL~ql83zRso7t zZcx2I`yu!v$w}g4Zv1L_B+7mQ?2b^@p#(s0k^t{A_GXr~9!qjc{GqP|TFgY2*qH`m znnfSf=A)`WA7+5aF0iiFXuB#^miO$M^csNV5am?5OXs~3%7d*Wr(<~=3AC1DkZ5Ue z+rY6wUdtVnqU2_<8+kr#Hzi=P1p=a~foOkbS=R%Up|$Lo>T{6{2l34Hb<7S*c>>C? zd}(KDIIwSjCS`)cc!A8t{RFW_Ar};4=LN_mD0S_9 zC{#iy6@-#J5y@c^9RNKnrPX@USz+<;z432*v=P{|rV~z$;{x%j)VwAHQ#@tq!ANbJ&_3h@Uz1<2f(8BviF* zh7`6O_TP4M==k1uqb<$lA$*2>?8;g1`T$w(>!jP*(2f86%sp`bzy4F$b6`KJBLITT z{ZxQ;_i2H_OjJ_l-K*$tZBTJ_Jp>%a9ROCpW(iV_zL0y$&;W!}z_D*%g1`_qLsHE)$O^C_LOpXQg>@=m+k?fGIjOMp&b_FH1@?kwi3W_cRPwg`Wvi)Ie^8SWfZB{OB-4?MbK#!^8G9S z?605D&$oT~s*p212`TM`PKO7EA;e@BqjZFw!`|7au09?oUVmYh(#-6o zx!M-`F$J4b*}NG-4L(|;8vs+V8{ZLS2T2x!u@Xa6_Y;7hfKVWeJPWX+pRo+-VsOY( zYbYy10FyW;Af5#%mH`n|Vhk%YlI#V(UDrAMPU8C_b}#|Ss(7k1%;B%}4m%#}ptAPH za&`6iN~-f|qgUxyN!tnS7;|BvXAKoKnY&M-N3C)Z9=Nm4HU^6BB8a;De|= zaikL>4xk}&sr`^mRfNi@sHS`|3KppHB=La?Au`pdD#CNC^2jYhlIPSOTaGRtP%{V8 zl!`2t|DM23vZ;n<_SADO|HJ4T9=-7^u`dcqR@i~6$)m6K`|l24{o4;g+=rM#S-~WP zwMI$;*UxHIVHYIo`@i!olsh0q z(fHO@+Nb}E59s+r-@<-gY^9f zK5;JlR;d6mv&<5EmQb8wt(LG4j%TA-#WUKEL#V-3)KrJ(zv8u__4t!RH@?X|*Z*fM zmwUmR-x0|@Hf(}($yfjJBN5E6so;JCN5g?R09pJ~OQU&ROi(CB(PdzQvgp_W{iahc zxCHgi%J2XRrTqZs8TcVSH-8%ach#6C>AxlVC@P{*DoG_eRkLDwC&s)8@{=}zM{vc) zYp*cg{=NO}c&G|t`6~hL6iNqnTh=uT`w96x145QWFF|7${L&2P3lwPUviK}#zcl95 zV8ymjRolQm38}9g^<~til6ew}*yp>tQPrgECS%pswh5IiNPnY4asHU)yi_}K?R%zZKK;CK+)1Z~BS(&ehacX}QDh?Y0}vNO!jjzR+)>dGOT?N4oW~bY z6-Fgb2@=^Uklg8~1OUAIvL&U)A@5oC&9a{b<&~kXt~%b!d1Dzz{j?J1PlEZ7%KB9K zSsN5dn~-TF!8PSk`np%;!!?py@;FO!reHsr#im($y9=(@;`mS`SQJBOE62u5_U-7Q z%r+o$5eh+*ql5T0l$^s)t3W-kj`FpYjNRQ32UoBi&%OLzp?=pHj9pq(_c}z$H_PGv z`#*d%u9sH)p|`yM13ddP`_+GNf4K4Up9)Emv&!*bosX7r?qWVvp~T~!B1v})lA->d zB`H>(Y0<)YWU8ULX$-0)9-8y0&Ghqc4| z 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