2020-07-10 04:13:55 -05:00
/*
Copyright 2020 Equinor ASA
This file is part of the Open Porous Media project ( OPM ) .
OPM is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
OPM is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with OPM . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <config.h> // CMake
# include <cstdlib>
# include <cstring>
# include <opm/common/OpmLog/OpmLog.hpp>
# include <opm/common/ErrorMacros.hpp>
2021-02-23 07:15:47 -06:00
2020-11-11 11:34:10 -06:00
# include <opm/simulators/linalg/bda/WellContributions.hpp>
2020-07-10 04:13:55 -05:00
namespace Opm
{
2020-12-22 05:57:01 -06:00
WellContributions : : WellContributions ( std : : string accelerator_mode ) {
if ( accelerator_mode . compare ( " cusparse " ) = = 0 ) {
2020-07-17 15:00:37 -05:00
cuda_gpu = true ;
}
2020-12-22 05:57:01 -06:00
else if ( accelerator_mode . compare ( " opencl " ) = = 0 ) {
2020-07-17 15:00:37 -05:00
opencl_gpu = true ;
}
2020-12-22 05:57:01 -06:00
else if ( accelerator_mode . compare ( " fpga " ) = = 0 ) {
// unused for FPGA, but must be defined to avoid error
}
2020-11-11 11:34:10 -06:00
else {
2020-12-22 05:57:01 -06:00
OPM_THROW ( std : : logic_error , " Invalid accelerator mode " ) ;
2020-11-11 11:34:10 -06:00
}
2020-07-17 15:00:37 -05:00
}
2020-07-10 04:13:55 -05:00
WellContributions : : ~ WellContributions ( )
{
// delete MultisegmentWellContributions
2020-11-11 11:34:10 -06:00
for ( auto ms : multisegments ) {
2020-07-10 04:13:55 -05:00
delete ms ;
}
multisegments . clear ( ) ;
2020-11-11 11:34:10 -06:00
# if HAVE_CUDA
2020-07-17 15:00:37 -05:00
if ( cuda_gpu ) {
freeCudaMemory ( ) ; // should come before 'delete[] h_x'
}
# endif
2020-11-11 11:34:10 -06:00
if ( num_std_wells > 0 ) {
delete [ ] val_pointers ;
}
# if HAVE_OPENCL
if ( opencl_gpu ) {
if ( num_ms_wells > 0 ) {
delete [ ] h_x ;
delete [ ] h_y ;
}
}
# endif
}
# if HAVE_OPENCL
void WellContributions : : setOpenCLEnv ( cl : : Context * context_ , cl : : CommandQueue * queue_ ) {
this - > context = context_ ;
this - > queue = queue_ ;
}
2021-05-28 09:03:40 -05:00
void WellContributions : : setKernel ( bda : : stdwell_apply_kernel_type * kernel_ ,
bda : : stdwell_apply_no_reorder_kernel_type * kernel_no_reorder_ ) {
2020-11-11 11:34:10 -06:00
this - > kernel = kernel_ ;
2021-01-13 04:54:40 -06:00
this - > kernel_no_reorder = kernel_no_reorder_ ;
}
void WellContributions : : setReordering ( int * h_toOrder_ , bool reorder_ )
{
this - > h_toOrder = h_toOrder_ ;
this - > reorder = reorder_ ;
2020-11-11 11:34:10 -06:00
}
void WellContributions : : apply_stdwells ( cl : : Buffer d_x , cl : : Buffer d_y , cl : : Buffer d_toOrder ) {
const unsigned int work_group_size = 32 ;
const unsigned int total_work_items = num_std_wells * work_group_size ;
const unsigned int lmem1 = sizeof ( double ) * work_group_size ;
const unsigned int lmem2 = sizeof ( double ) * dim_wells ;
cl : : Event event ;
2021-01-13 04:54:40 -06:00
if ( reorder ) {
event = ( * kernel ) ( cl : : EnqueueArgs ( * queue , cl : : NDRange ( total_work_items ) , cl : : NDRange ( work_group_size ) ) ,
* d_Cnnzs_ocl , * d_Dnnzs_ocl , * d_Bnnzs_ocl , * d_Ccols_ocl , * d_Bcols_ocl , d_x , d_y , d_toOrder , dim , dim_wells , * d_val_pointers_ocl ,
cl : : Local ( lmem1 ) , cl : : Local ( lmem2 ) , cl : : Local ( lmem2 ) ) ;
} else {
event = ( * kernel_no_reorder ) ( cl : : EnqueueArgs ( * queue , cl : : NDRange ( total_work_items ) , cl : : NDRange ( work_group_size ) ) ,
* d_Cnnzs_ocl , * d_Dnnzs_ocl , * d_Bnnzs_ocl , * d_Ccols_ocl , * d_Bcols_ocl , d_x , d_y , dim , dim_wells , * d_val_pointers_ocl ,
cl : : Local ( lmem1 ) , cl : : Local ( lmem2 ) , cl : : Local ( lmem2 ) ) ;
}
event . wait ( ) ;
2020-11-11 11:34:10 -06:00
}
2021-01-13 04:54:40 -06:00
void WellContributions : : apply_mswells ( cl : : Buffer d_x , cl : : Buffer d_y ) {
2020-11-11 11:34:10 -06:00
if ( h_x = = nullptr ) {
h_x = new double [ N ] ;
h_y = new double [ N ] ;
}
events . resize ( 2 ) ;
queue - > enqueueReadBuffer ( d_x , CL_FALSE , 0 , sizeof ( double ) * N , h_x , nullptr , & events [ 0 ] ) ;
queue - > enqueueReadBuffer ( d_y , CL_FALSE , 0 , sizeof ( double ) * N , h_y , nullptr , & events [ 1 ] ) ;
cl : : WaitForEvents ( events ) ;
events . clear ( ) ;
// actually apply MultisegmentWells
for ( Opm : : MultisegmentWellContribution * well : multisegments ) {
2021-01-13 04:54:40 -06:00
well - > setReordering ( h_toOrder , reorder ) ;
2020-11-11 11:34:10 -06:00
well - > apply ( h_x , h_y ) ;
}
// copy vector y from CPU to GPU
events . resize ( 1 ) ;
queue - > enqueueWriteBuffer ( d_y , CL_FALSE , 0 , sizeof ( double ) * N , h_y , nullptr , & events [ 0 ] ) ;
events [ 0 ] . wait ( ) ;
events . clear ( ) ;
}
void WellContributions : : apply ( cl : : Buffer d_x , cl : : Buffer d_y , cl : : Buffer d_toOrder ) {
if ( num_std_wells > 0 ) {
apply_stdwells ( d_x , d_y , d_toOrder ) ;
}
if ( num_ms_wells > 0 ) {
2021-01-13 04:54:40 -06:00
apply_mswells ( d_x , d_y ) ;
2020-11-11 11:34:10 -06:00
}
2020-07-17 15:00:37 -05:00
}
2020-11-11 11:34:10 -06:00
# endif
2020-07-17 15:00:37 -05:00
void WellContributions : : addMatrix ( [[maybe_unused]] MatrixType type, [[maybe_unused]] int *colIndices, [[maybe_unused]] double *values, [[maybe_unused]] unsigned int val_size )
2020-07-10 04:13:55 -05:00
{
2020-11-11 11:34:10 -06:00
if ( ! allocated ) {
OPM_THROW ( std : : logic_error , " Error cannot add wellcontribution before allocating memory in WellContributions " ) ;
}
2020-07-17 15:00:37 -05:00
2020-07-10 04:13:55 -05:00
# if HAVE_CUDA
2020-07-17 15:00:37 -05:00
if ( cuda_gpu ) {
2020-07-10 04:13:55 -05:00
addMatrixGpu ( type , colIndices , values , val_size ) ;
2020-07-17 15:00:37 -05:00
}
# endif
# if HAVE_OPENCL
if ( opencl_gpu ) {
switch ( type ) {
2020-09-24 14:34:46 -05:00
case MatrixType : : C :
2020-11-11 11:34:10 -06:00
events . resize ( 2 ) ;
queue - > enqueueWriteBuffer ( * d_Cnnzs_ocl , CL_FALSE , sizeof ( double ) * num_blocks_so_far * dim * dim_wells , sizeof ( double ) * val_size * dim * dim_wells , values , nullptr , & events [ 0 ] ) ;
queue - > enqueueWriteBuffer ( * d_Ccols_ocl , CL_FALSE , sizeof ( int ) * num_blocks_so_far , sizeof ( int ) * val_size , colIndices , nullptr , & events [ 1 ] ) ;
cl : : WaitForEvents ( events ) ;
events . clear ( ) ;
2020-09-24 14:34:46 -05:00
break ;
case MatrixType : : D :
2020-11-11 11:34:10 -06:00
events . resize ( 1 ) ;
queue - > enqueueWriteBuffer ( * d_Dnnzs_ocl , CL_FALSE , sizeof ( double ) * num_std_wells_so_far * dim_wells * dim_wells , sizeof ( double ) * dim_wells * dim_wells , values , nullptr , & events [ 0 ] ) ;
events [ 0 ] . wait ( ) ;
events . clear ( ) ;
2020-09-24 14:34:46 -05:00
break ;
case MatrixType : : B :
2020-11-11 11:34:10 -06:00
events . resize ( 2 ) ;
queue - > enqueueWriteBuffer ( * d_Bnnzs_ocl , CL_FALSE , sizeof ( double ) * num_blocks_so_far * dim * dim_wells , sizeof ( double ) * val_size * dim * dim_wells , values , nullptr , & events [ 0 ] ) ;
queue - > enqueueWriteBuffer ( * d_Bcols_ocl , CL_FALSE , sizeof ( int ) * num_blocks_so_far , sizeof ( int ) * val_size , colIndices , nullptr , & events [ 1 ] ) ;
cl : : WaitForEvents ( events ) ;
events . clear ( ) ;
val_pointers [ num_std_wells_so_far ] = num_blocks_so_far ;
if ( num_std_wells_so_far = = num_std_wells - 1 ) {
val_pointers [ num_std_wells ] = num_blocks ;
events . resize ( 1 ) ;
queue - > enqueueWriteBuffer ( * d_val_pointers_ocl , CL_FALSE , 0 , sizeof ( unsigned int ) * ( num_std_wells + 1 ) , val_pointers , nullptr , & events [ 0 ] ) ;
events [ 0 ] . wait ( ) ;
events . clear ( ) ;
}
2020-09-24 14:34:46 -05:00
break ;
default :
OPM_THROW ( std : : logic_error , " Error unsupported matrix ID for WellContributions::addMatrix() " ) ;
2020-07-17 15:00:37 -05:00
}
}
# endif
2020-11-11 11:34:10 -06:00
if ( MatrixType : : B = = type ) {
num_blocks_so_far + = val_size ;
num_std_wells_so_far + + ;
}
2020-07-17 15:00:37 -05:00
# if !HAVE_CUDA && !HAVE_OPENCL
OPM_THROW ( std : : logic_error , " Error cannot add StandardWell matrix on GPU because neither CUDA nor OpenCL were found by cmake " ) ;
2020-07-10 04:13:55 -05:00
# endif
}
void WellContributions : : setBlockSize ( unsigned int dim_ , unsigned int dim_wells_ )
{
dim = dim_ ;
dim_wells = dim_wells_ ;
2020-09-28 16:01:42 -05:00
if ( dim ! = 3 | | dim_wells ! = 4 ) {
std : : ostringstream oss ;
oss < < " WellContributions::setBlockSize error: dim and dim_wells must be equal to 3 and 4, repectivelly, otherwise the add well contributions kernel won't work. \n " ;
OPM_THROW ( std : : logic_error , oss . str ( ) ) ;
}
2020-07-10 04:13:55 -05:00
}
2020-07-17 15:00:37 -05:00
void WellContributions : : addNumBlocks ( unsigned int numBlocks )
2020-07-10 04:13:55 -05:00
{
if ( allocated ) {
OPM_THROW ( std : : logic_error , " Error cannot add more sizes after allocated in WellContributions " ) ;
}
2020-07-17 15:00:37 -05:00
num_blocks + = numBlocks ;
2020-07-10 04:13:55 -05:00
num_std_wells + + ;
}
2020-09-24 14:34:46 -05:00
void WellContributions : : alloc ( )
{
if ( num_std_wells > 0 ) {
2020-11-11 11:34:10 -06:00
val_pointers = new unsigned int [ num_std_wells + 1 ] ;
# if HAVE_CUDA
if ( cuda_gpu ) {
allocStandardWells ( ) ;
}
# endif
# if HAVE_OPENCL
if ( opencl_gpu ) {
d_Cnnzs_ocl = std : : make_unique < cl : : Buffer > ( * context , CL_MEM_READ_WRITE , sizeof ( double ) * num_blocks * dim * dim_wells ) ;
d_Dnnzs_ocl = std : : make_unique < cl : : Buffer > ( * context , CL_MEM_READ_WRITE , sizeof ( double ) * num_std_wells * dim_wells * dim_wells ) ;
d_Bnnzs_ocl = std : : make_unique < cl : : Buffer > ( * context , CL_MEM_READ_WRITE , sizeof ( double ) * num_blocks * dim * dim_wells ) ;
d_Ccols_ocl = std : : make_unique < cl : : Buffer > ( * context , CL_MEM_READ_WRITE , sizeof ( int ) * num_blocks ) ;
d_Bcols_ocl = std : : make_unique < cl : : Buffer > ( * context , CL_MEM_READ_WRITE , sizeof ( int ) * num_blocks ) ;
d_val_pointers_ocl = std : : make_unique < cl : : Buffer > ( * context , CL_MEM_READ_WRITE , sizeof ( unsigned int ) * ( num_std_wells + 1 ) ) ;
}
# endif
2020-09-24 14:34:46 -05:00
allocated = true ;
}
}
2020-09-02 15:46:44 -05:00
void WellContributions : : addMultisegmentWellContribution ( unsigned int dim_ , unsigned int dim_wells_ ,
2021-04-30 05:23:46 -05:00
unsigned int Mb ,
std : : vector < double > & Bvalues , std : : vector < unsigned int > & BcolIndices , std : : vector < unsigned int > & BrowPointers ,
2020-09-30 13:10:21 -05:00
unsigned int DnumBlocks , double * Dvalues , UMFPackIndex * DcolPointers , UMFPackIndex * DrowIndices ,
2020-07-10 04:13:55 -05:00
std : : vector < double > & Cvalues )
{
2020-09-02 15:46:44 -05:00
assert ( dim = = dim_ ) ;
2021-04-30 05:23:46 -05:00
MultisegmentWellContribution * well = new MultisegmentWellContribution ( dim_ , dim_wells_ , Mb , Bvalues , BcolIndices , BrowPointers , DnumBlocks , Dvalues , DcolPointers , DrowIndices , Cvalues ) ;
2020-07-10 04:13:55 -05:00
multisegments . emplace_back ( well ) ;
+ + num_ms_wells ;
}
} //namespace Opm