Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
waLBerla
waLBerla
Commits
e34c7998
Commit
e34c7998
authored
Jul 13, 2021
by
Markus Holzer
Browse files
Merge branch 'mr_reduce_packinfo_generation' into 'master'
Reduce Packinfo Generation See merge request
walberla/walberla!464
parents
03b9f95f
477250d5
Pipeline
#33234
passed with stages
in 482 minutes and 33 seconds
Changes
10
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
python/pystencils_walberla/codegen.py
View file @
e34c7998
...
...
@@ -146,6 +146,8 @@ def generate_selective_sweep(generation_context, class_name, selection_tree, int
def
generate_pack_info_for_field
(
generation_context
,
class_name
:
str
,
field
:
Field
,
direction_subset
:
Optional
[
Tuple
[
Tuple
[
int
,
int
,
int
]]]
=
None
,
operator
=
None
,
gl_to_inner
=
False
,
**
create_kernel_params
):
"""Creates a pack info for a pystencils field assuming a pull-type stencil, packing all cell elements.
...
...
@@ -155,18 +157,21 @@ def generate_pack_info_for_field(generation_context, class_name: str, field: Fie
field: pystencils field for which to generate pack info
direction_subset: optional sequence of directions for which values should be packed
otherwise a D3Q27 stencil is assumed
operator: optional operator for, e.g., reduction pack infos
gl_to_inner: communicates values from ghost layers of sender to interior of receiver
**create_kernel_params: remaining keyword arguments are passed to `pystencils.create_kernel`
"""
if
not
direction_subset
:
direction_subset
=
tuple
((
i
,
j
,
k
)
for
i
,
j
,
k
in
product
(
*
[(
-
1
,
0
,
1
)]
*
3
))
all_index_accesses
=
[
field
(
*
ind
)
for
ind
in
product
(
*
[
range
(
s
)
for
s
in
field
.
index_shape
])]
return
generate_pack_info
(
generation_context
,
class_name
,
{
direction_subset
:
all_index_accesses
},
**
create_kernel_params
)
return
generate_pack_info
(
generation_context
,
class_name
,
{
direction_subset
:
all_index_accesses
},
operator
=
operator
,
gl_to_inner
=
gl_to_inner
,
**
create_kernel_params
)
def
generate_pack_info_from_kernel
(
generation_context
,
class_name
:
str
,
assignments
:
Sequence
[
Assignment
],
kind
=
'pull'
,
**
create_kernel_params
):
kind
=
'pull'
,
operator
=
None
,
**
create_kernel_params
):
"""Generates a waLBerla GPU PackInfo from a (pull) kernel.
Args:
...
...
@@ -175,6 +180,7 @@ def generate_pack_info_from_kernel(generation_context, class_name: str, assignme
assignments: list of assignments from the compute kernel - generates PackInfo for "pull" part only
i.e. the kernel is expected to only write to the center
kind: can either be pull or push
operator: optional operator for, e.g., reduction pack infos
**create_kernel_params: remaining keyword arguments are passed to `pystencils.create_kernel`
"""
assert
kind
in
(
'push'
,
'pull'
)
...
...
@@ -207,12 +213,12 @@ def generate_pack_info_from_kernel(generation_context, class_name: str, assignme
spec
[(
comm_dir
,)].
add
(
fa
)
else
:
raise
ValueError
(
"Invalid 'kind' parameter"
)
return
generate_pack_info
(
generation_context
,
class_name
,
spec
,
**
create_kernel_params
)
return
generate_pack_info
(
generation_context
,
class_name
,
spec
,
operator
=
operator
,
**
create_kernel_params
)
def
generate_pack_info
(
generation_context
,
class_name
:
str
,
directions_to_pack_terms
:
Dict
[
Tuple
[
Tuple
],
Sequence
[
Field
.
Access
]],
namespace
=
'pystencils'
,
namespace
=
'pystencils'
,
operator
=
None
,
gl_to_inner
=
False
,
**
create_kernel_params
):
"""Generates a waLBerla GPU PackInfo
...
...
@@ -222,6 +228,8 @@ def generate_pack_info(generation_context, class_name: str,
directions_to_pack_terms: maps tuples of directions to read field accesses, specifying which values have to be
packed for which direction
namespace: inner namespace of the generated class
operator: optional operator for, e.g., reduction pack infos
gl_to_inner: communicates values from ghost layers of sender to interior of receiver
**create_kernel_params: remaining keyword arguments are passed to `pystencils.create_kernel`
"""
items
=
[(
e
[
0
],
sorted
(
e
[
1
],
key
=
lambda
x
:
str
(
x
)))
for
e
in
directions_to_pack_terms
.
items
()]
...
...
@@ -274,7 +282,10 @@ def generate_pack_info(generation_context, class_name: str,
pack_ast
=
create_kernel
(
pack_assignments
,
**
create_kernel_params
,
ghost_layers
=
0
)
pack_ast
.
function_name
=
'pack_{}'
.
format
(
"_"
.
join
(
direction_strings
))
pack_ast
.
assumed_inner_stride_one
=
create_kernel_params
[
'cpu_vectorize_info'
][
'assume_inner_stride_one'
]
unpack_assignments
=
[
Assignment
(
term
,
buffer
(
i
))
for
i
,
term
in
enumerate
(
terms
)]
if
operator
is
None
:
unpack_assignments
=
[
Assignment
(
term
,
buffer
(
i
))
for
i
,
term
in
enumerate
(
terms
)]
else
:
unpack_assignments
=
[
Assignment
(
term
,
operator
(
term
,
buffer
(
i
)))
for
i
,
term
in
enumerate
(
terms
)]
unpack_ast
=
create_kernel
(
unpack_assignments
,
**
create_kernel_params
,
ghost_layers
=
0
)
unpack_ast
.
function_name
=
'unpack_{}'
.
format
(
"_"
.
join
(
direction_strings
))
unpack_ast
.
assumed_inner_stride_one
=
create_kernel_params
[
'cpu_vectorize_info'
][
'assume_inner_stride_one'
]
...
...
@@ -296,6 +307,7 @@ def generate_pack_info(generation_context, class_name: str,
'dtype'
:
dtype
,
'field_name'
:
field_names
.
pop
(),
'namespace'
:
namespace
,
'gl_to_inner'
:
gl_to_inner
,
}
env
=
Environment
(
loader
=
PackageLoader
(
'pystencils_walberla'
),
undefined
=
StrictUndefined
)
add_pystencils_filters_to_jinja_env
(
env
)
...
...
python/pystencils_walberla/templates/CpuPackInfo.tmpl.cpp
View file @
e34c7998
...
...
@@ -37,7 +37,11 @@ void {{class_name}}::pack(Direction dir, unsigned char * byte_buffer, IBlock * b
{{
fused_kernel
|
generate_block_data_to_field_extraction
(
parameters_to_ignore
=
[
'
buffer
'
])
|
indent
(
4
)}}
CellInterval
ci
;
{
%
if
gl_to_inner
-%
}
{{
field_name
}}
->
getGhostRegion
(
dir
,
ci
,
1
,
false
);
{
%-
else
-%
}
{{
field_name
}}
->
getSliceBeforeGhostLayer
(
dir
,
ci
,
1
,
false
);
{
%-
endif
%
}
switch
(
dir
)
{
...
...
@@ -63,7 +67,11 @@ void {{class_name}}::unpack(Direction dir, unsigned char * byte_buffer, IBlock *
{{
fused_kernel
|
generate_block_data_to_field_extraction
(
parameters_to_ignore
=
[
'
buffer
'
])
|
indent
(
4
)}}
CellInterval
ci
;
{
%
if
gl_to_inner
-%
}
{{
field_name
}}
->
getSliceBeforeGhostLayer
(
dir
,
ci
,
1
,
false
);
{
%-
else
-%
}
{{
field_name
}}
->
getGhostRegion
(
dir
,
ci
,
1
,
false
);
{
%-
endif
%
}
auto
communciationDirection
=
stencil
::
inverseDir
[
dir
];
switch
(
communciationDirection
)
...
...
python/pystencils_walberla/templates/GpuPackInfo.tmpl.cpp
View file @
e34c7998
...
...
@@ -35,7 +35,11 @@ void {{class_name}}::pack(Direction dir, unsigned char * byte_buffer, IBlock * b
{{
fused_kernel
|
generate_block_data_to_field_extraction
(
parameters_to_ignore
=
[
'
buffer
'
])
|
indent
(
4
)}}
CellInterval
ci
;
{
%
if
gl_to_inner
-%
}
{{
field_name
}}
->
getGhostRegion
(
dir
,
ci
,
1
,
false
);
{
%-
else
-%
}
{{
field_name
}}
->
getSliceBeforeGhostLayer
(
dir
,
ci
,
1
,
false
);
{
%-
endif
%
}
switch
(
dir
)
{
...
...
@@ -61,7 +65,11 @@ void {{class_name}}::unpack(Direction dir, unsigned char * byte_buffer, IBlock *
{{
fused_kernel
|
generate_block_data_to_field_extraction
(
parameters_to_ignore
=
[
'
buffer
'
])
|
indent
(
4
)}}
CellInterval
ci
;
{
%
if
gl_to_inner
-%
}
{{
field_name
}}
->
getSliceBeforeGhostLayer
(
dir
,
ci
,
1
,
false
);
{
%-
else
-%
}
{{
field_name
}}
->
getGhostRegion
(
dir
,
ci
,
1
,
false
);
{
%-
endif
%
}
auto
communciationDirection
=
stencil
::
inverseDir
[
dir
];
switch
(
communciationDirection
)
...
...
src/cuda/communication/UniformGPUScheme.impl.h
View file @
e34c7998
...
...
@@ -118,6 +118,7 @@ UniformGPUScheme<Stencil>::UniformGPUScheme( weak_ptr <StructuredBlockForest> bf
auto
parallelSection
=
parallelSectionManager_
.
parallelSection
(
stream
);
for
(
auto
recvInfo
=
bufferSystemGPU_
.
begin
();
recvInfo
!=
bufferSystemGPU_
.
end
();
++
recvInfo
)
{
recvInfo
.
buffer
().
clear
();
for
(
auto
&
header
:
headers_
[
recvInfo
.
rank
()]
)
{
auto
block
=
dynamic_cast
<
Block
*
>
(
forest
->
getBlock
(
header
.
blockId
));
...
...
@@ -141,6 +142,7 @@ UniformGPUScheme<Stencil>::UniformGPUScheme( weak_ptr <StructuredBlockForest> bf
{
auto
&
gpuBuffer
=
bufferSystemGPU_
.
sendBuffer
(
recvInfo
.
rank
());
recvInfo
.
buffer
().
clear
();
gpuBuffer
.
clear
();
for
(
auto
&
header
:
headers_
[
recvInfo
.
rank
()]
)
{
auto
block
=
dynamic_cast
<
Block
*
>
(
forest
->
getBlock
(
header
.
blockId
));
...
...
tests/cuda/CMakeLists.txt
View file @
e34c7998
...
...
@@ -47,4 +47,10 @@ waLBerla_generate_target_from_python(NAME MicroBenchmarkGpuLbmGenerated FILE cod
OUT_FILES MicroBenchmarkStreamKernel.cu MicroBenchmarkCopyKernel.cu MicroBenchmarkStreamKernel.h MicroBenchmarkCopyKernel.h
)
waLBerla_compile_test
(
FILES codegen/MicroBenchmarkGpuLbm.cpp DEPENDS MicroBenchmarkGpuLbmGenerated
)
waLBerla_generate_target_from_python
(
NAME CodegenGeneratedGPUFieldPackInfo FILE codegen/GeneratedFieldPackInfoTestGPU.py
OUT_FILES ScalarFieldCommunicationGPU.cu ScalarFieldCommunicationGPU.h
ScalarFieldPullReductionGPU.cu ScalarFieldPullReductionGPU.h
)
waLBerla_compile_test
(
FILES codegen/GeneratedFieldPackInfoTestGPU.cpp
DEPENDS blockforest core field CodegenGeneratedGPUFieldPackInfo
)
waLBerla_execute_test
(
NAME GeneratedFieldPackInfoTestGPU
)
endif
()
\ No newline at end of file
tests/cuda/codegen/GeneratedFieldPackInfoTestGPU.cpp
0 → 100644
View file @
e34c7998
//======================================================================================================================
//
// This file is part of waLBerla. waLBerla 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.
//
// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
//
//! \file GeneratedFieldPackInfoTestGPU.cpp
//! \ingroup field
//! \author Helen Schottenhamml <helen.schottenhamml@fau.de>
//! \brief Tests if a GPU Field is correctly communicated using generated pack info
//
//======================================================================================================================
#include
"field/AddToStorage.h"
#include
"field/GhostLayerField.h"
#include
"blockforest/Initialization.h"
#include
"core/debug/TestSubsystem.h"
#include
"core/Environment.h"
#include
"cuda/FieldCopy.h"
#include
"cuda/communication/UniformGPUScheme.h"
#include
"stencil/D3Q27.h"
// include generated files
#include
"ScalarFieldCommunicationGPU.h"
#include
"ScalarFieldPullReductionGPU.h"
namespace
walberla
{
using
Stencil_T
=
stencil
::
D3Q27
;
cuda
::
GPUField
<
int
>
*
createGPUField
(
IBlock
*
const
block
,
StructuredBlockStorage
*
const
storage
)
{
return
new
cuda
::
GPUField
<
int
>
(
storage
->
getNumberOfXCells
(
*
block
),
// number of cells in x direction
storage
->
getNumberOfYCells
(
*
block
),
// number of cells in y direction
storage
->
getNumberOfZCells
(
*
block
),
// number of cells in z direction
1
,
// fSize
1
,
// number of ghost layers
field
::
fzyx
);
}
cuda
::
GPUField
<
int
>
*
createSmallGPUField
(
IBlock
*
const
,
StructuredBlockStorage
*
const
)
{
return
new
cuda
::
GPUField
<
int
>
(
2
,
2
,
2
,
1
,
1
,
field
::
fzyx
);
}
void
testScalarField
(
std
::
shared_ptr
<
blockforest
::
StructuredBlockForest
>
&
sbf
,
BlockDataID
gpuFieldId
)
{
cuda
::
communication
::
UniformGPUScheme
<
Stencil_T
>
us
{
sbf
};
us
.
addPackInfo
(
std
::
make_shared
<
pystencils
::
ScalarFieldCommunicationGPU
>
(
gpuFieldId
));
for
(
auto
&
block
:
*
sbf
)
{
auto
&
gpuField
=
*
(
block
.
getData
<
cuda
::
GPUField
<
int
>
>
(
gpuFieldId
));
field
::
GhostLayerField
<
int
,
1
>
cpuField
(
gpuField
.
xSize
(),
gpuField
.
ySize
(),
gpuField
.
zSize
(),
1
,
0
,
field
::
fzyx
);
cpuField
.
setWithGhostLayer
(
0
);
WALBERLA_CHECK_EQUAL
(
cpuField
.
xSize
(),
2
)
WALBERLA_CHECK_EQUAL
(
cpuField
.
ySize
(),
2
)
WALBERLA_CHECK_EQUAL
(
cpuField
.
zSize
(),
2
)
// initialize the bottom boundary
cpuField
(
0
,
0
,
0
)
=
1
;
cpuField
(
0
,
1
,
0
)
=
2
;
cpuField
(
1
,
0
,
0
)
=
3
;
cpuField
(
1
,
1
,
0
)
=
4
;
cuda
::
fieldCpy
(
gpuField
,
cpuField
);
// communicate
us
.
communicate
();
cuda
::
fieldCpy
(
cpuField
,
gpuField
);
WALBERLA_CHECK_EQUAL
(
cpuField
(
0
,
0
,
+
2
),
1
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
0
,
1
,
+
2
),
2
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
1
,
0
,
+
2
),
3
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
1
,
1
,
+
2
),
4
)
}
}
void
testScalarFieldPullReduction
(
std
::
shared_ptr
<
blockforest
::
StructuredBlockForest
>
&
sbf
,
BlockDataID
gpuFieldId
)
{
cuda
::
communication
::
UniformGPUScheme
<
Stencil_T
>
us1
{
sbf
};
us1
.
addPackInfo
(
std
::
make_shared
<
pystencils
::
ScalarFieldPullReductionGPU
>
(
gpuFieldId
));
cuda
::
communication
::
UniformGPUScheme
<
Stencil_T
>
us2
{
sbf
};
us2
.
addPackInfo
(
std
::
make_shared
<
pystencils
::
ScalarFieldCommunicationGPU
>
(
gpuFieldId
));
for
(
auto
&
block
:
*
sbf
)
{
auto
&
gpuField
=
*
(
block
.
getData
<
cuda
::
GPUField
<
int
>
>
(
gpuFieldId
));
field
::
GhostLayerField
<
int
,
1
>
cpuField
(
gpuField
.
xSize
(),
gpuField
.
ySize
(),
gpuField
.
zSize
(),
1
,
0
,
field
::
fzyx
);
cpuField
.
setWithGhostLayer
(
0
);
WALBERLA_CHECK_EQUAL
(
cpuField
.
xSize
(),
2
)
WALBERLA_CHECK_EQUAL
(
cpuField
.
ySize
(),
2
)
WALBERLA_CHECK_EQUAL
(
cpuField
.
zSize
(),
2
)
// initialize the bottom ghost layer cells
cpuField
(
0
,
0
,
-
1
)
=
1
;
cpuField
(
0
,
1
,
-
1
)
=
2
;
cpuField
(
1
,
0
,
-
1
)
=
3
;
cpuField
(
1
,
1
,
-
1
)
=
4
;
// initialize the top interior cells
cpuField
(
0
,
0
,
1
)
=
1
;
cpuField
(
0
,
1
,
1
)
=
1
;
cpuField
(
1
,
0
,
1
)
=
1
;
cpuField
(
1
,
1
,
1
)
=
1
;
cuda
::
fieldCpy
(
gpuField
,
cpuField
);
// communicate pull += reduction
us1
.
communicate
();
cuda
::
fieldCpy
(
cpuField
,
gpuField
);
// check values in top ghost layer
WALBERLA_CHECK_EQUAL
(
cpuField
(
0
,
0
,
2
),
0
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
0
,
1
,
2
),
0
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
1
,
0
,
2
),
0
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
1
,
1
,
2
),
0
)
// check values in top interior cells
WALBERLA_CHECK_EQUAL
(
cpuField
(
0
,
0
,
1
),
2
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
0
,
1
,
1
),
3
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
1
,
0
,
1
),
4
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
1
,
1
,
1
),
5
)
// communicate to sync ghost layers
us2
.
communicate
();
cuda
::
fieldCpy
(
cpuField
,
gpuField
);
// check values in bottom ghost layer
WALBERLA_CHECK_EQUAL
(
cpuField
(
0
,
0
,
-
1
),
2
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
0
,
1
,
-
1
),
3
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
1
,
0
,
-
1
),
4
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
1
,
1
,
-
1
),
5
)
// check values in top interior cells
WALBERLA_CHECK_EQUAL
(
cpuField
(
0
,
0
,
1
),
2
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
0
,
1
,
1
),
3
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
1
,
0
,
1
),
4
)
WALBERLA_CHECK_EQUAL
(
cpuField
(
1
,
1
,
1
),
5
)
}
}
int
main
(
int
argc
,
char
**
argv
)
{
using
blockforest
::
createUniformBlockGrid
;
debug
::
enterTestMode
();
Environment
walberlaEnv
(
argc
,
argv
);
// Create a BlockForest with 2x2x2 cells per block
uint_t
processes
=
uint_c
(
MPIManager
::
instance
()
->
numProcesses
()
);
auto
blocks
=
createUniformBlockGrid
(
processes
,
1
,
1
,
//blocks
2
,
2
,
2
,
//cells
1
,
//dx
true
,
//one block per process
true
,
true
,
true
);
//periodicity
// Create a Field with the same number of cells as the block
BlockDataID
scalarGPUFieldId
=
blocks
->
addStructuredBlockData
<
cuda
::
GPUField
<
int
>
>
(
&
createGPUField
,
"ScalarGPUField"
);
testScalarField
(
blocks
,
scalarGPUFieldId
);
// Create a BlockForest with 8x8x8 cells per block
blocks
=
createUniformBlockGrid
(
processes
,
1
,
1
,
//blocks
8
,
8
,
8
,
//cells
1
,
//dx
true
,
//one block per process
true
,
true
,
true
);
//periodicity
// Create a Field with one quarter as many cells per dimension, i.e. a field with the same size as the one above
scalarGPUFieldId
=
blocks
->
addStructuredBlockData
<
cuda
::
GPUField
<
int
>
>
(
&
createSmallGPUField
,
"ScalarGPUField"
);
testScalarField
(
blocks
,
scalarGPUFieldId
);
testScalarFieldPullReduction
(
blocks
,
scalarGPUFieldId
);
return
0
;
}
}
// namespace walberla
int
main
(
int
argc
,
char
*
argv
[]
)
{
return
walberla
::
main
(
argc
,
argv
);
}
\ No newline at end of file
tests/cuda/codegen/GeneratedFieldPackInfoTestGPU.py
0 → 100644
View file @
e34c7998
import
operator
as
op
import
pystencils
as
ps
from
pystencils_walberla
import
CodeGeneration
,
generate_pack_info_for_field
with
CodeGeneration
()
as
ctx
:
layout
=
'fzyx'
field
=
ps
.
fields
(
"field: int32[3D]"
,
layout
=
layout
)
# communication
generate_pack_info_for_field
(
ctx
,
'ScalarFieldCommunicationGPU'
,
field
,
target
=
'gpu'
)
generate_pack_info_for_field
(
ctx
,
'ScalarFieldPullReductionGPU'
,
field
,
target
=
'gpu'
,
operator
=
op
.
add
,
gl_to_inner
=
True
)
tests/field/CMakeLists.txt
View file @
e34c7998
...
...
@@ -77,4 +77,11 @@ waLBerla_generate_target_from_python(NAME CodeGenMultipleFieldSwaps FILE codegen
OUT_FILES MultipleFieldSwaps.cpp MultipleFieldSwaps.h
)
waLBerla_compile_test
(
FILES codegen/MultipleFieldSwaps.cpp DEPENDS gui timeloop CodeGenMultipleFieldSwaps
)
waLBerla_execute_test
(
NAME MultipleFieldSwaps
)
waLBerla_generate_target_from_python
(
NAME CodegenGeneratedCPUFieldPackInfo FILE codegen/GeneratedFieldPackInfoTest.py
OUT_FILES ScalarFieldCommunication.cpp ScalarFieldCommunication.h
ScalarFieldPullReduction.cpp ScalarFieldPullReduction.h
)
waLBerla_compile_test
(
FILES codegen/GeneratedFieldPackInfoTest.cpp
DEPENDS blockforest core field CodegenGeneratedCPUFieldPackInfo
)
waLBerla_execute_test
(
NAME GeneratedFieldPackInfoTest
)
endif
()
tests/field/codegen/GeneratedFieldPackInfoTest.cpp
0 → 100644
View file @
e34c7998
//======================================================================================================================
//
// This file is part of waLBerla. waLBerla 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.
//
// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
//
//! \file GeneratedFieldPackInfoTest.cpp
//! \ingroup field
//! \author Martin Bauer <martin.bauer@fau.de>
//! \author Christoph Rettinger <christoph.rettinger@fau.de>
//! \author Helen Schottenhamml <helen.schottenhamml@fau.de>
//! \brief Tests if a Field is correctly packed into buffers using generated pack info
//
//======================================================================================================================
#include
"field/AddToStorage.h"
#include
"field/GhostLayerField.h"
#include
"blockforest/Initialization.h"
#include
"core/debug/TestSubsystem.h"
#include
"core/Environment.h"
#include
"field/communication/PackInfo.h"
#include
"field/communication/UniformPullReductionPackInfo.h"
#include
<cstring>
// include generated files
#include
"ScalarFieldCommunication.h"
#include
"ScalarFieldPullReduction.h"
namespace
walberla
{
void
testScalarField
(
IBlock
*
block
,
BlockDataID
fieldId
)
{
GhostLayerField
<
int
,
1
>
&
field
=
*
(
block
->
getData
<
GhostLayerField
<
int
,
1
>
>
(
fieldId
));
field
.
setWithGhostLayer
(
0
);
WALBERLA_CHECK_EQUAL
(
field
.
xSize
(),
2
);
WALBERLA_CHECK_EQUAL
(
field
.
ySize
(),
2
);
WALBERLA_CHECK_EQUAL
(
field
.
zSize
(),
2
);
// initialize the bottom boundary
field
(
0
,
0
,
0
)
=
1
;
field
(
0
,
1
,
0
)
=
2
;
field
(
1
,
0
,
0
)
=
3
;
field
(
1
,
1
,
0
)
=
4
;
// -------------- Local Communication Test ----------------------
// communicate periodic from bottom to top
pystencils
::
ScalarFieldCommunication
pi
(
fieldId
);
pi
.
communicateLocal
(
block
,
block
,
stencil
::
B
);
WALBERLA_CHECK_EQUAL
(
field
(
0
,
0
,
+
2
),
1
);
WALBERLA_CHECK_EQUAL
(
field
(
0
,
1
,
+
2
),
2
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
0
,
+
2
),
3
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
1
,
+
2
),
4
);
// -------------- Buffer Communication Test ---------------------
// Reset
field
(
0
,
0
,
2
)
=
0
;
field
(
0
,
1
,
2
)
=
0
;
field
(
1
,
0
,
2
)
=
0
;
field
(
1
,
1
,
2
)
=
0
;
mpi
::
GenericSendBuffer
<>
sendBuf
;
pi
.
packData
(
block
,
stencil
::
B
,
sendBuf
);
// Manually copy over the send to the receive buffer
mpi
::
GenericRecvBuffer
<>
recvBuf
;
recvBuf
.
resize
(
sendBuf
.
size
()
);
memcpy
(
recvBuf
.
ptr
(),
sendBuf
.
ptr
(),
sendBuf
.
size
()
*
sizeof
(
mpi
::
GenericSendBuffer
<>::
ElementType
)
);
pi
.
unpackData
(
block
,
stencil
::
T
,
recvBuf
);
WALBERLA_CHECK_EQUAL
(
field
(
0
,
0
,
+
2
),
1
);
WALBERLA_CHECK_EQUAL
(
field
(
0
,
1
,
+
2
),
2
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
0
,
+
2
),
3
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
1
,
+
2
),
4
);
}
void
testScalarFieldPullReduction
(
IBlock
*
block
,
BlockDataID
fieldId
)
{
GhostLayerField
<
int
,
1
>
&
field
=
*
(
block
->
getData
<
GhostLayerField
<
int
,
1
>
>
(
fieldId
));
field
.
setWithGhostLayer
(
0
);
WALBERLA_CHECK_EQUAL
(
field
.
xSize
(),
2
);
WALBERLA_CHECK_EQUAL
(
field
.
ySize
(),
2
);
WALBERLA_CHECK_EQUAL
(
field
.
zSize
(),
2
);
// initialize the bottom ghost layer cells
field
(
0
,
0
,
-
1
)
=
1
;
field
(
0
,
1
,
-
1
)
=
2
;
field
(
1
,
0
,
-
1
)
=
3
;
field
(
1
,
1
,
-
1
)
=
4
;
// initialize the top interior cells
field
(
0
,
0
,
1
)
=
1
;
field
(
0
,
1
,
1
)
=
1
;
field
(
1
,
0
,
1
)
=
1
;
field
(
1
,
1
,
1
)
=
1
;
// communicate periodic from bottom to top with uniform pull scheme
pystencils
::
ScalarFieldPullReduction
pi1
(
fieldId
);
pi1
.
communicateLocal
(
block
,
block
,
stencil
::
B
);
// check values in top ghost layer
WALBERLA_CHECK_EQUAL
(
field
(
0
,
0
,
2
),
0
);
WALBERLA_CHECK_EQUAL
(
field
(
0
,
1
,
2
),
0
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
0
,
2
),
0
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
1
,
2
),
0
);
// check values in top interior cells
WALBERLA_CHECK_EQUAL
(
field
(
0
,
0
,
1
),
2
);
WALBERLA_CHECK_EQUAL
(
field
(
0
,
1
,
1
),
3
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
0
,
1
),
4
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
1
,
1
),
5
);
// communicate periodic from top to bottom with standard form to sync ghost layers
pystencils
::
ScalarFieldCommunication
pi2
(
fieldId
);
pi2
.
communicateLocal
(
block
,
block
,
stencil
::
T
);
// check values in bottom ghost layer
WALBERLA_CHECK_EQUAL
(
field
(
0
,
0
,
-
1
),
2
);
WALBERLA_CHECK_EQUAL
(
field
(
0
,
1
,
-
1
),
3
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
0
,
-
1
),
4
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
1
,
-
1
),
5
);
// check values in top interior cells
WALBERLA_CHECK_EQUAL
(
field
(
0
,
0
,
1
),
2
);
WALBERLA_CHECK_EQUAL
(
field
(
0
,
1
,
1
),
3
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
0
,
1
),
4
);
WALBERLA_CHECK_EQUAL
(
field
(
1
,
1
,
1
),
5
);
}
int
main
(
int
argc
,
char
**
argv
)
{
using
blockforest
::
createUniformBlockGrid
;
debug
::
enterTestMode
();
Environment
walberlaEnv
(
argc
,
argv
);
// Create a BlockForest with 2x2x2 cells per block
uint_t
processes
=
uint_c
(
MPIManager
::
instance
()
->
numProcesses
()
);
auto
blocks
=
createUniformBlockGrid
(
processes
,
1
,
1
,
//blocks
2
,
2
,
2
,
//cells
1
,
//dx
false
,
//one block per process
true
,
true
,
true
);
//periodicity
// Create a Field with the same number of cells as the block
BlockDataID
scalarFieldId
=
field
::
addToStorage
<
GhostLayerField
<
int
,
1
>
>
(
blocks
,
"ScalarField"
);
for
(
auto
blockIt
=
blocks
->
begin
();
blockIt
!=
blocks
->
end
();
++
blockIt
)
// block loop
testScalarField
(
&
(
*
blockIt
),
scalarFieldId
);
// Create a BlockForest with 8x8x8 cells per block
blocks
=
createUniformBlockGrid
(
processes
,
1
,
1
,
//blocks
8
,
8
,
8
,
//cells
1
,
//dx
false
,
//one block per process
true
,
true
,
true
);
//periodicity
// Create a Field with one quarter as many cells per dimension, i.e. a field with the same size as the one above
auto
getSize
=
[](
const
shared_ptr
<
StructuredBlockStorage
>
&
,
IBlock
*
const
)
{