Compare commits
93
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68f9353cd5 | ||
|
|
2bb5f45bb6 | ||
|
|
cf8743dd5e | ||
|
|
f5b9c0afeb | ||
|
|
cf5447d879 | ||
|
|
30558cd938 | ||
|
|
77511860ef | ||
|
|
d017504e5a | ||
|
|
88fa1d60cf | ||
|
|
da83d4961a | ||
|
|
db1e90d02c | ||
|
|
010600b18a | ||
|
|
613d1a3bcb | ||
|
|
e07760dfc2 | ||
|
|
acf49b667b | ||
|
|
09ba64bb29 | ||
|
|
bb31355d93 | ||
|
|
a483e50abf | ||
|
|
2f55b418ed | ||
|
|
313d74fa1f | ||
|
|
829905c8fc | ||
|
|
272cbe594d | ||
|
|
55e42eeefe | ||
|
|
e58de8335a | ||
|
|
a327f612be | ||
|
|
fa89c5e98c | ||
|
|
0980bda63b | ||
|
|
a1758e51e5 | ||
|
|
ccf84aab7c | ||
|
|
82abd48bba | ||
|
|
fad600cbd0 | ||
|
|
d4374a9d5f | ||
|
|
dcd3a25730 | ||
|
|
ec1ae6eaf5 | ||
|
|
0f99528c62 | ||
|
|
ddfd74e899 | ||
|
|
0248720eeb | ||
|
|
feded39641 | ||
|
|
09128b9a5d | ||
|
|
68383b462b | ||
|
|
24d5609585 | ||
|
|
670a3f9a45 | ||
|
|
7baae02d65 | ||
|
|
728a0f313b | ||
|
|
1bb624e2a8 | ||
|
|
ee7ccd6464 | ||
|
|
a3ae5a6f01 | ||
|
|
9243d00549 | ||
|
|
4fe3db5a5f | ||
|
|
55bb710cba | ||
|
|
7ad6939454 | ||
|
|
60cc94e5a1 | ||
|
|
9122ac1839 | ||
|
|
864186117d | ||
|
|
35de169fd0 | ||
|
|
0a3184ab31 | ||
|
|
a438e09caf | ||
|
|
ea03a86df2 | ||
|
|
6ef7a9e6fb | ||
|
|
db7dd30d32 | ||
|
|
a1fe3a19b1 | ||
|
|
213ccd7a4e | ||
|
|
8e78471fdf | ||
|
|
c0f8501950 | ||
|
|
c31510289f | ||
|
|
2b14134496 | ||
|
|
794a5fbfc2 | ||
|
|
746a62f017 | ||
|
|
26e9057f02 | ||
|
|
16dfa11f27 | ||
|
|
c7774e3c1c | ||
|
|
194f3d8140 | ||
|
|
3f9b44a9cd | ||
|
|
caa973d6a0 | ||
|
|
ad40704e20 | ||
|
|
d3470c07c9 | ||
|
|
06a15cb7a9 | ||
|
|
d19ff6c676 | ||
|
|
d85fbc6504 | ||
|
|
29346a87b6 | ||
|
|
3464f7a004 | ||
|
|
7de48e47ad | ||
|
|
70814c640b | ||
|
|
e9d3ae80f7 | ||
|
|
c8efc23c12 | ||
|
|
f26eb33252 | ||
|
|
05e622f837 | ||
|
|
e9f84b033f | ||
|
|
83fd119b95 | ||
|
|
4aecb86d71 | ||
|
|
776a4c1815 | ||
|
|
c870d7dc1c | ||
|
|
8519889074 |
+5
-1
@@ -652,6 +652,8 @@ foreach(TPL IN LISTS MFEM_TPLS)
|
||||
endif()
|
||||
endforeach(TPL)
|
||||
|
||||
# reverse to remove the first instance of entries in TPL_LIBRARIES
|
||||
# so later duplicates are kept (for dependency ordering)
|
||||
list(REVERSE TPL_LIBRARIES)
|
||||
list(REMOVE_DUPLICATES TPL_LIBRARIES)
|
||||
list(REVERSE TPL_LIBRARIES)
|
||||
@@ -1015,5 +1017,7 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data
|
||||
# Create 'config.mk' from 'config.mk.in' for the build and install locations and
|
||||
# define install rules for 'config.mk' and 'test.mk'
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
if (MFEM_USE_CUDA OR MFEM_USE_HIP)
|
||||
option(MFEM_EXPORT_GPU_CONFIG "Export config.mk for GPU-enabled downstream packages" ON)
|
||||
endif()
|
||||
mfem_export_mk_files()
|
||||
|
||||
@@ -701,7 +701,6 @@ endfunction(mfem_find_library)
|
||||
# Extract compile and link options needed by the given target.
|
||||
#
|
||||
function(mfem_get_target_options Target CompileOptsVar LinkOptsVar)
|
||||
|
||||
if (NOT TARGET ${Target})
|
||||
return()
|
||||
endif()
|
||||
@@ -799,7 +798,12 @@ function(mfem_get_target_options Target CompileOptsVar LinkOptsVar)
|
||||
# message(STATUS "Lib = ${Lib}")
|
||||
# Filter-out generator expressions
|
||||
if (NOT ("${Lib}" MATCHES "^\\$"))
|
||||
list(APPEND LinkOpts "${Lib}")
|
||||
if(NOT ("${Lib}" STREQUAL "dl"))
|
||||
list(APPEND LinkOpts "${Lib}")
|
||||
else()
|
||||
# for some reason libdl doesn't include the "-l"
|
||||
list(APPEND LinkOpts "-ldl")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
mfem_get_target_options(${Lib} COpts LOpts)
|
||||
@@ -888,9 +892,18 @@ function(mfem_export_mk_files)
|
||||
set(${var} NO)
|
||||
endif()
|
||||
endforeach()
|
||||
# TODO: Add support for MFEM_USE_CUDA=YES
|
||||
set(MFEM_CXX ${CMAKE_CXX_COMPILER})
|
||||
set(MFEM_HOST_CXX ${MFEM_CXX})
|
||||
if (MFEM_USE_CUDA AND MFEM_EXPORT_GPU_CONFIG)
|
||||
set(MFEM_CXX ${CMAKE_CUDA_COMPILER})
|
||||
if(MFEM_CUDA_COMPILER_IS_NVCC)
|
||||
set(MFEM_HOST_CXX ${CMAKE_CUDA_HOST_COMPILER})
|
||||
else()
|
||||
set(MFEM_HOST_CXX ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
else()
|
||||
# mfem doesn't use enable_language(HIP)
|
||||
set(MFEM_CXX ${CMAKE_CXX_COMPILER})
|
||||
set(MFEM_HOST_CXX ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
set(MFEM_CPPFLAGS "")
|
||||
get_target_property(cxx_std mfem CXX_STANDARD)
|
||||
# For now, we ignore the setting of the CXX_EXTENSIONS property. If this
|
||||
@@ -900,6 +913,50 @@ function(mfem_export_mk_files)
|
||||
string(STRIP
|
||||
"${cxx_std_flag} ${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}"
|
||||
MFEM_CXXFLAGS)
|
||||
if(MFEM_EXPORT_GPU_CONFIG)
|
||||
if (MFEM_USE_CUDA)
|
||||
set(MFEM_CXXFLAGS "${MFEM_CXXFLAGS} ${CMAKE_CUDA_FLAGS}")
|
||||
if (MFEM_CUDA_COMPILER_IS_NVCC)
|
||||
set(MFEM_CXXFLAGS "-x=cu ${MFEM_CXXFLAGS} -ccbin ${CMAKE_CXX_COMPILER} --forward-unknown-to-host-compiler")
|
||||
# The following intentionally hides CUDA deprecation warnings
|
||||
foreach(ENTRY IN LISTS CUDAToolkit_INCLUDE_DIRS)
|
||||
set(MFEM_CXXFLAGS "${MFEM_CXXFLAGS} -isystem ${ENTRY}")
|
||||
endforeach()
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18.0)
|
||||
# architecture flags not part of CMAKE_CUDA_FLAGS
|
||||
if ("all" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}"
|
||||
OR "native" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}"
|
||||
OR "all-major" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}")
|
||||
set(MFEM_CXXFLAGS "${MFEM_CXXFLAGS} -arch=${CMAKE_CUDA_ARCHITECTURES}")
|
||||
else()
|
||||
foreach (ENTRY IN LISTS CMAKE_CUDA_ARCHITECTURES)
|
||||
set(MFEM_CXXFLAGS
|
||||
"${MFEM_CXXFLAGS} -gencode arch=compute_${ENTRY},code=sm_${ENTRY}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
set(MFEM_CXXFLAGS "${MFEM_CXXFLAGS} -xcuda --cuda-path=${CUDAToolkit_LIBRARY_ROOT}")
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18.0)
|
||||
# architecture flags not part of CMAKE_CUDA_FLAGS
|
||||
if ("all" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}"
|
||||
OR "native" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}"
|
||||
OR "all-major" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}")
|
||||
# TODO: not supported
|
||||
else()
|
||||
foreach(ENTRY IN LISTS CMAKE_CUDA_ARCHITECTURES)
|
||||
set(MFEM_CXXFLAGS "-cuda-gpu-arch=sm_${ENTRY} ${MFEM_CXXFLAGS}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
elseif (MFEM_USE_HIP)
|
||||
set(MFEM_CXXFLAGS "${MFEM_CXXFLAGS} -xhip")
|
||||
foreach(ENTRY IN LISTS CMAKE_HIP_ARCHITECTURES)
|
||||
set(MFEM_CXXFLAGS "--offload-arch=${ENTRY} ${MFEM_CXXFLAGS}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
set(MFEM_TPLFLAGS "")
|
||||
foreach(dir ${TPL_INCLUDE_DIRS})
|
||||
set(MFEM_TPLFLAGS "${MFEM_TPLFLAGS} -I${dir}")
|
||||
@@ -930,6 +987,9 @@ function(mfem_export_mk_files)
|
||||
set(MFEM_SHARED NO)
|
||||
set(MFEM_STATIC YES)
|
||||
endif()
|
||||
if (MFEM_USE_CUDA)
|
||||
set(MFEM_EXT_LIBS "${MFEM_EXT_LIBS} -lcudart")
|
||||
endif()
|
||||
set(MFEM_BUILD_TAG "${CMAKE_SYSTEM}")
|
||||
set(MFEM_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
# For the next 4 variables, these are the values for the build-tree version of
|
||||
@@ -938,8 +998,15 @@ function(mfem_export_mk_files)
|
||||
set(MFEM_LIB_DIR "${PROJECT_BINARY_DIR}")
|
||||
set(MFEM_TEST_MK "${PROJECT_SOURCE_DIR}/config/test.mk")
|
||||
set(MFEM_CONFIG_EXTRA "MFEM_BUILD_DIR ?= ${PROJECT_BINARY_DIR}")
|
||||
# TODO: CUDA/HIP support:
|
||||
set(MFEM_XLINKER "${CMAKE_CXX_LINKER_WRAPPER_FLAG}")
|
||||
if (MFEM_USE_CUDA AND MFEM_EXPORT_GPU_CONFIG)
|
||||
if (MFEM_CUDA_COMPILER_IS_NVCC)
|
||||
set(MFEM_XLINKER "-Xlinker=")
|
||||
else()
|
||||
set(MFEM_XLINKER "${CMAKE_CUDA_LINKER_WRAPPER_FLAG}")
|
||||
endif()
|
||||
else()
|
||||
set(MFEM_XLINKER "${CMAKE_CXX_LINKER_WRAPPER_FLAG}")
|
||||
endif()
|
||||
set(MFEM_MPIEXEC ${MPIEXEC})
|
||||
if (NOT MFEM_MPIEXEC)
|
||||
set(MFEM_MPIEXEC "mpirun")
|
||||
@@ -987,16 +1054,21 @@ function(mfem_export_mk_files)
|
||||
# handle interfaces (e.g., SCOREC::apf)
|
||||
if ("${lib}" MATCHES "SCOREC::.*" OR "${lib}" MATCHES "Ginkgo::.*" OR "${lib}" MATCHES "ParMoonolith::.*")
|
||||
elseif (TARGET "${lib}")
|
||||
mfem_get_target_options(${lib} CompileOpts LinkOpts)
|
||||
mfem_get_target_options(${lib} CompileOpts2 LinkOpts2)
|
||||
# remove generator expressions
|
||||
string(GENEX_STRIP "${CompileOpts2}" CompileOpts)
|
||||
string(GENEX_STRIP "${LinkOpts2}" LinkOpts)
|
||||
# Removing duplicates may lead to issues:
|
||||
# list(REMOVE_DUPLICATES CompileOpts)
|
||||
# list(REMOVE_DUPLICATES LinkOpts)
|
||||
string(REPLACE ";" " " COpts "${CompileOpts}")
|
||||
string(REPLACE ";" " " LOpts "${LinkOpts}")
|
||||
# message(STATUS "${lib}[COpts]: '${COpts}'")
|
||||
# message(STATUS "${lib}[LOpts]: '${LOpts}'")
|
||||
set(MFEM_TPLFLAGS "${MFEM_TPLFLAGS} ${COpts}")
|
||||
set(MFEM_EXT_LIBS "${MFEM_EXT_LIBS} ${LOpts}")
|
||||
# message(WARNING "${lib}[LinkOpts]: ${LinkOpts}")
|
||||
# message(WARNING "${lib}[CompileOpts]: ${CompileOpts}")
|
||||
foreach(LOpt IN LISTS LinkOpts)
|
||||
set(MFEM_EXT_LIBS "${MFEM_EXT_LIBS} ${LOpt}")
|
||||
endforeach()
|
||||
foreach(COpt IN LISTS CompileOpts)
|
||||
set(MFEM_TPLFLAGS "${MFEM_TPLFLAGS} ${COpt}")
|
||||
endforeach()
|
||||
# message(FATAL_ERROR "***** interface lib found ... exiting *****")
|
||||
# handle static and shared libs
|
||||
elseif ("${suffix}" STREQUAL "${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
@@ -1004,7 +1076,7 @@ function(mfem_export_mk_files)
|
||||
get_filename_component(fullLibName ${lib} NAME_WE)
|
||||
string(REGEX REPLACE "^lib" "" libname ${fullLibName})
|
||||
set(MFEM_EXT_LIBS
|
||||
"${MFEM_EXT_LIBS} ${shared_link_flag}${dir} -L${dir} -l${libname}")
|
||||
"${MFEM_EXT_LIBS} ${shared_link_flag}${dir} -L${dir} -l${libname}")
|
||||
else()
|
||||
set(MFEM_EXT_LIBS "${MFEM_EXT_LIBS} ${lib}")
|
||||
endif()
|
||||
@@ -1013,7 +1085,7 @@ function(mfem_export_mk_files)
|
||||
# Create the build-tree version of 'config.mk'
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/config/config.mk.in"
|
||||
"${PROJECT_BINARY_DIR}/config/config.mk")
|
||||
"${PROJECT_BINARY_DIR}/config/config.mk" @ONLY)
|
||||
# Copy 'test.mk' from the source-tree to the build-tree
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/config/test.mk"
|
||||
@@ -1031,7 +1103,7 @@ function(mfem_export_mk_files)
|
||||
# Create the install-tree version of 'config.mk'
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/config/config.mk.in"
|
||||
"${PROJECT_BINARY_DIR}/config/config-install.mk")
|
||||
"${PROJECT_BINARY_DIR}/config/config-install.mk" @ONLY)
|
||||
|
||||
# Install rules for 'config.mk' and 'test.mk'
|
||||
install(FILES ${PROJECT_SOURCE_DIR}/config/test.mk
|
||||
|
||||
@@ -82,6 +82,25 @@ public:
|
||||
/// underlying #fes
|
||||
int VectorDim() const;
|
||||
|
||||
/// Copy assignment. Only the data of the base class Vector is copied.
|
||||
/** It is assumed that this object and @a rhs use FiniteElementSpace%s that
|
||||
have the same size.
|
||||
|
||||
@note Defining this method overwrites the implicitly defined copy
|
||||
assignment operator. */
|
||||
ComplexGridFunction &operator=(const ComplexGridFunction &rhs)
|
||||
{ return operator=((const Vector &)rhs); }
|
||||
|
||||
/// Copy the data from @a v.
|
||||
/** The size of @a v must be equal to double of the size of the associated
|
||||
FiniteElementSpace #fes. */
|
||||
ComplexGridFunction &operator=(const Vector &v)
|
||||
{
|
||||
MFEM_ASSERT(fes && v.Size() == 2*fes->GetVSize(), "");
|
||||
Vector::operator=(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assign constant values to the ComplexGridFunction data.
|
||||
ComplexGridFunction &operator=(const std::complex<real_t> & value)
|
||||
{ *gfr = value.real(); *gfi = value.imag(); return *this; }
|
||||
|
||||
+11
-8
@@ -90,8 +90,8 @@ void map_quadrature_data_to_fields_impl(
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("quadrature data mapping to field is not implemented for"
|
||||
" this field descriptor");
|
||||
MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
|
||||
" for this field descriptor");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +169,9 @@ void map_quadrature_data_to_fields_tensor_impl_1d(
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("quadrature data mapping to field is not implemented for"
|
||||
" this field descriptor with sum factorization on tensor product elements");
|
||||
MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
|
||||
"for this field descriptor with sum factorization on"
|
||||
" tensor product elements");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,8 +307,9 @@ void map_quadrature_data_to_fields_tensor_impl_2d(
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("quadrature data mapping to field is not implemented for"
|
||||
" this field descriptor with sum factorization on tensor product elements");
|
||||
MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
|
||||
" for this field descriptor with sum factorization on"
|
||||
" tensor product elements");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,8 +494,9 @@ void map_quadrature_data_to_fields_tensor_impl_3d(
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("quadrature data mapping to field is not implemented for"
|
||||
" this field descriptor with sum factorization on tensor product elements");
|
||||
MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
|
||||
" for this field descriptor with sum factorization on"
|
||||
" tensor product elements");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ protected:
|
||||
};
|
||||
|
||||
/// @brief Uniform parameter space
|
||||
class UniformParameterSpace final : public ParameterSpace
|
||||
class UniformParameterSpace : public ParameterSpace
|
||||
{
|
||||
public:
|
||||
/// @brief Constructor for a uniform parameter space
|
||||
|
||||
+82
-5
@@ -1044,9 +1044,50 @@ void VectorFiniteElement::SetDerivMembers()
|
||||
switch (map_type)
|
||||
{
|
||||
case H_DIV:
|
||||
deriv_type = DIV;
|
||||
deriv_range_type = SCALAR;
|
||||
deriv_map_type = INTEGRAL;
|
||||
switch (dim)
|
||||
{
|
||||
case 3: // div: 3D H_DIV -> 3D INTEGRAL
|
||||
deriv_type = DIV;
|
||||
deriv_range_type = SCALAR;
|
||||
deriv_map_type = INTEGRAL;
|
||||
break;
|
||||
case 2: // div: 2D H_DIV -> 2D INTEGRAL
|
||||
deriv_type = DIV;
|
||||
deriv_range_type = SCALAR;
|
||||
deriv_map_type = INTEGRAL;
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Invalid dimension, Dim = " << dim);
|
||||
}
|
||||
break;
|
||||
case H_DIV_R2D:
|
||||
switch (dim)
|
||||
{
|
||||
case 2: // div: 2D H_DIV_R2D -> 2D INTEGRAL
|
||||
deriv_type = DIV;
|
||||
deriv_range_type = SCALAR;
|
||||
deriv_map_type = INTEGRAL;
|
||||
break;
|
||||
case 1: // div: 1D H_DIV_R2D -> 1D INTEGRAL
|
||||
deriv_type = DIV;
|
||||
deriv_range_type = SCALAR;
|
||||
deriv_map_type = INTEGRAL;
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Invalid dimension, Dim = " << dim);
|
||||
}
|
||||
break;
|
||||
case H_DIV_R1D:
|
||||
switch (dim)
|
||||
{
|
||||
case 1: // div: 1D H_DIV_R1D -> 1D INTEGRAL
|
||||
deriv_type = DIV;
|
||||
deriv_range_type = SCALAR;
|
||||
deriv_map_type = INTEGRAL;
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Invalid dimension, Dim = " << dim);
|
||||
}
|
||||
break;
|
||||
case H_CURL:
|
||||
switch (dim)
|
||||
@@ -1064,13 +1105,49 @@ void VectorFiniteElement::SetDerivMembers()
|
||||
break;
|
||||
case 1:
|
||||
deriv_type = NONE;
|
||||
deriv_range_type = SCALAR;
|
||||
deriv_map_type = INTEGRAL;
|
||||
deriv_range_type = UNKNOWN_RANGE_TYPE;
|
||||
deriv_map_type = UNKNOWN_MAP_TYPE;
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Invalid dimension, Dim = " << dim);
|
||||
}
|
||||
break;
|
||||
case H_CURL_R2D:
|
||||
switch (dim)
|
||||
{
|
||||
case 2:
|
||||
// curl: 2D H_CURL_R2D -> H_DIV_R2D
|
||||
deriv_type = CURL;
|
||||
deriv_range_type = VECTOR;
|
||||
deriv_map_type = H_DIV_R2D;
|
||||
break;
|
||||
case 1:
|
||||
// curl: 1D H_CURL_R2D -> H_DIV_R2D
|
||||
deriv_type = CURL;
|
||||
deriv_range_type = VECTOR;
|
||||
deriv_map_type = H_DIV_R2D;
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Invalid dimension, Dim = " << dim);
|
||||
}
|
||||
break;
|
||||
case H_CURL_R1D:
|
||||
switch (dim)
|
||||
{
|
||||
case 1:
|
||||
// curl: 1D H_CURL_R1D -> H_DIV_R1D
|
||||
deriv_type = CURL;
|
||||
deriv_range_type = VECTOR;
|
||||
deriv_map_type = H_DIV_R1D;
|
||||
break;
|
||||
case 0:
|
||||
deriv_type = NONE;
|
||||
deriv_range_type = UNKNOWN_RANGE_TYPE;
|
||||
deriv_map_type = UNKNOWN_MAP_TYPE;
|
||||
default:
|
||||
MFEM_ABORT("Invalid dimension, Dim = " << dim);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Invalid MapType = " << map_type);
|
||||
}
|
||||
|
||||
+31
-3
@@ -295,10 +295,20 @@ public:
|
||||
$ u(x) = (1/w) \hat u(\hat x) $ */
|
||||
H_DIV, /**< For vector fields; preserves surface integrals of the
|
||||
normal component $ u(x) = (J/w) \hat u(\hat x) $ */
|
||||
H_CURL /**< For vector fields; preserves line integrals of the
|
||||
H_CURL, /**< For vector fields; preserves line integrals of the
|
||||
tangential component
|
||||
$ u(x) = J^{-t} \hat u(\hat x) $ (square J),
|
||||
$ u(x) = J(J^t J)^{-1} \hat u(\hat x) $ (general J) */
|
||||
H_DIV_R2D, /**< For 3-component vector fields in 2D; equivalent to a
|
||||
direct sum of an H_DIV basis and an INTEGRAL basis */
|
||||
H_CURL_R2D,/**< For 3-component vector fields in 2D; equivalent to a
|
||||
direct sum of an H_CURL basis and a VALUE basis */
|
||||
H_DIV_R1D, /**< For 3-component vector fields in 1D; equivalent to a
|
||||
direct sum of a VALUE basis and a pair of INTEGRAL
|
||||
bases */
|
||||
H_CURL_R1D /**< For 3-component vector fields in 1D; equivalent to a
|
||||
direct sum of an INTEGRAL basis and a pair of VALUE
|
||||
bases */
|
||||
};
|
||||
|
||||
/** @brief Enumeration for DerivType: defines which derivative method
|
||||
@@ -330,12 +340,28 @@ public:
|
||||
int GetDim() const { return dim; }
|
||||
|
||||
/** @brief Returns the vector dimension for vector-valued finite elements,
|
||||
which is also the dimension of the interpolation operation. */
|
||||
which is also the dimension of the interpolation operation and the
|
||||
width of the DenseMatrix argument in
|
||||
CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape). */
|
||||
int GetRangeDim() const { return vdim; }
|
||||
|
||||
/// Returns the dimension of the curl for vector-valued finite elements.
|
||||
/** @brief Returns the vector dimension, in physical space, for
|
||||
vector-valued finite elements, which is also the width of the
|
||||
DenseMatrix argument in
|
||||
CalcPhysVShape(ElementTransformation &Trans, DenseMatrix &shape). */
|
||||
int GetPhysRangeDim(int /* space_dim */) const { return vdim; }
|
||||
|
||||
/** Returns the dimension of the curl for vector-valued finite elements,
|
||||
which is also the width of the DenseMatrix argument in
|
||||
CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape). */
|
||||
int GetCurlDim() const { return cdim; }
|
||||
|
||||
/** Returns the dimension, in physical space, of the curl for vector-valued
|
||||
finite elements, which is also the width of the DenseMatrix argument in
|
||||
CalcPhysCurlShape(ElementTransformation &Trans, DenseMatrix &curl_shape).
|
||||
*/
|
||||
int GetPhysCurlDim(int /* space_dim */) const { return cdim; }
|
||||
|
||||
/// Returns the Geometry::Type of the reference element.
|
||||
Geometry::Type GetGeomType() const { return geom_type; }
|
||||
|
||||
@@ -990,6 +1016,8 @@ protected:
|
||||
public:
|
||||
VectorFiniteElement(int D, Geometry::Type G, int Do, int O, int M,
|
||||
int F = FunctionSpace::Pk);
|
||||
|
||||
int GetPhysRangeDim(int space_dim) const { return space_dim; }
|
||||
};
|
||||
|
||||
/// @brief Class for computing 1D special polynomials and their associated basis
|
||||
|
||||
+4
-4
@@ -2531,7 +2531,7 @@ void ND_FuentesPyramidElement::calcCurlBasis(const int p,
|
||||
|
||||
ND_R1D_PointElement::ND_R1D_PointElement(int p)
|
||||
: VectorFiniteElement(1, Geometry::POINT, 2, p,
|
||||
H_CURL, FunctionSpace::Pk)
|
||||
H_CURL_R1D, FunctionSpace::Pk)
|
||||
{
|
||||
// VectorFiniteElement::SetDerivMembers doesn't support 0D H_CURL elements
|
||||
// so we mimic a 1D element and then correct the dimension here.
|
||||
@@ -2562,7 +2562,7 @@ ND_R1D_SegmentElement::ND_R1D_SegmentElement(const int p,
|
||||
const int cb_type,
|
||||
const int ob_type)
|
||||
: VectorFiniteElement(1, Geometry::SEGMENT, 3 * p + 2, p,
|
||||
H_CURL, FunctionSpace::Pk),
|
||||
H_CURL_R1D, FunctionSpace::Pk),
|
||||
dof2tk(dof),
|
||||
cbasis1d(poly1d.GetBasis(p, VerifyClosed(cb_type))),
|
||||
obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(ob_type)))
|
||||
@@ -2839,7 +2839,7 @@ ND_R2D_SegmentElement::ND_R2D_SegmentElement(const int p,
|
||||
const int cb_type,
|
||||
const int ob_type)
|
||||
: VectorFiniteElement(1, Geometry::SEGMENT, 2 * p + 1, p,
|
||||
H_CURL, FunctionSpace::Pk),
|
||||
H_CURL_R2D, FunctionSpace::Pk),
|
||||
dof2tk(dof),
|
||||
cbasis1d(poly1d.GetBasis(p, VerifyClosed(cb_type))),
|
||||
obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(ob_type)))
|
||||
@@ -3023,7 +3023,7 @@ void ND_R2D_SegmentElement::Project(VectorCoefficient &vc,
|
||||
ND_R2D_FiniteElement::ND_R2D_FiniteElement(int p, Geometry::Type G, int Do,
|
||||
const real_t *tk_fe)
|
||||
: VectorFiniteElement(2, G, Do, p,
|
||||
H_CURL, FunctionSpace::Pk),
|
||||
H_CURL_R2D, FunctionSpace::Pk),
|
||||
tk(tk_fe),
|
||||
dof_map(dof),
|
||||
dof2tk(dof)
|
||||
|
||||
@@ -663,6 +663,9 @@ public:
|
||||
const int cb_type = BasisType::GaussLobatto,
|
||||
const int ob_type = BasisType::GaussLegendre);
|
||||
|
||||
int GetPhysRangeDim(int space_dim) const { return 2; }
|
||||
int GetPhysCurlDim(int space_dim) const { return 1; }
|
||||
|
||||
void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const override;
|
||||
|
||||
@@ -705,6 +708,9 @@ private:
|
||||
DenseMatrix &I) const;
|
||||
|
||||
public:
|
||||
int GetPhysRangeDim(int space_dim) const { return 3; }
|
||||
int GetPhysCurlDim(int space_dim) const { return 3; }
|
||||
|
||||
using FiniteElement::CalcVShape;
|
||||
using FiniteElement::CalcPhysCurlShape;
|
||||
|
||||
|
||||
+3
-3
@@ -2006,7 +2006,7 @@ RT_R1D_SegmentElement::RT_R1D_SegmentElement(const int p,
|
||||
const int cb_type,
|
||||
const int ob_type)
|
||||
: VectorFiniteElement(1, Geometry::SEGMENT, 3 * p + 4, p + 1,
|
||||
H_DIV, FunctionSpace::Pk),
|
||||
H_DIV_R1D, FunctionSpace::Pk),
|
||||
dof2nk(dof),
|
||||
cbasis1d(poly1d.GetBasis(p + 1, VerifyClosed(cb_type))),
|
||||
obasis1d(poly1d.GetBasis(p, VerifyOpen(ob_type)))
|
||||
@@ -2281,7 +2281,7 @@ const real_t RT_R2D_SegmentElement::nk[2] = { 0.,1.};
|
||||
RT_R2D_SegmentElement::RT_R2D_SegmentElement(const int p,
|
||||
const int ob_type)
|
||||
: VectorFiniteElement(1, Geometry::SEGMENT, p + 1, p + 1,
|
||||
H_DIV, FunctionSpace::Pk),
|
||||
H_DIV_R2D, FunctionSpace::Pk),
|
||||
dof2nk(dof),
|
||||
obasis1d(poly1d.GetBasis(p, VerifyOpen(ob_type)))
|
||||
{
|
||||
@@ -2392,7 +2392,7 @@ void RT_R2D_SegmentElement::LocalInterpolation(const VectorFiniteElement &cfe,
|
||||
RT_R2D_FiniteElement::RT_R2D_FiniteElement(int p, Geometry::Type G, int Do,
|
||||
const real_t *nk_fe)
|
||||
: VectorFiniteElement(2, G, Do, p + 1,
|
||||
H_DIV, FunctionSpace::Pk),
|
||||
H_DIV_R2D, FunctionSpace::Pk),
|
||||
nk(nk_fe),
|
||||
dof_map(dof),
|
||||
dof2nk(dof)
|
||||
|
||||
@@ -510,6 +510,9 @@ public:
|
||||
RT_R2D_SegmentElement(const int p,
|
||||
const int ob_type = BasisType::GaussLegendre);
|
||||
|
||||
int GetPhysRangeDim(int space_dim) const { return 2; }
|
||||
int GetPhysCurlDim(int space_dim) const { return 0; }
|
||||
|
||||
void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const override;
|
||||
|
||||
@@ -547,6 +550,9 @@ private:
|
||||
DenseMatrix &I) const;
|
||||
|
||||
public:
|
||||
int GetPhysRangeDim(int space_dim) const { return 3; }
|
||||
int GetPhysCurlDim(int space_dim) const { return 0; }
|
||||
|
||||
using FiniteElement::CalcVShape;
|
||||
|
||||
void CalcVShape(ElementTransformation &Trans,
|
||||
|
||||
+11
-5
@@ -321,12 +321,17 @@ void ParL2FaceRestriction::DoubleValuedConformingMult(
|
||||
const int vd = vdim;
|
||||
const bool t = byvdim;
|
||||
const int threshold = ndofs;
|
||||
const int nsdofs = pfes.GetFaceNbrVSize();
|
||||
const int nsdofs = pfes.GetFaceNbrVSize() / vd;
|
||||
auto d_indices1 = scatter_indices1.Read();
|
||||
auto d_indices2 = scatter_indices2.Read();
|
||||
auto d_x = Reshape(x.Read(), t?vd:ndofs, t?ndofs:vd);
|
||||
auto d_x_shared = Reshape(face_nbr_data.Read(),
|
||||
t?vd:nsdofs, t?nsdofs:vd);
|
||||
const int ne_shared = nsdofs / elem_dofs;
|
||||
const int nedof = elem_dofs;
|
||||
// Note: the shape of face_nbr_data, as determined by
|
||||
// ParFiniteElementSpace::ExchangeFaceNbrData, is (elem_dofs, vdim,
|
||||
// ne_shared), independent of the ordering (byNODES or byVDIM) of the finite
|
||||
// element space.
|
||||
auto d_x_shared = Reshape(face_nbr_data.Read(), elem_dofs, vd, ne_shared);
|
||||
auto d_y = Reshape(y.Write(), nface_dofs, vd, 2, nf);
|
||||
mfem::forall(nfdofs, [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
@@ -346,8 +351,9 @@ void ParL2FaceRestriction::DoubleValuedConformingMult(
|
||||
}
|
||||
else if (idx2>=threshold) // shared boundary
|
||||
{
|
||||
d_y(dof, c, 1, face) = d_x_shared(t?c:(idx2-threshold),
|
||||
t?(idx2-threshold):c);
|
||||
const int e_shared = (idx2 - threshold) / nedof;
|
||||
const int i_shared = (idx2 - threshold) % nedof;
|
||||
d_y(dof, c, 1, face) = d_x_shared(i_shared,c,e_shared);
|
||||
}
|
||||
else // true boundary
|
||||
{
|
||||
|
||||
+3
-6
@@ -1398,20 +1398,17 @@ void L2FaceRestriction::PermuteAndSetSharedFaceDofsScatterIndices2(
|
||||
const int dim = fes.GetMesh()->Dimension();
|
||||
const int dof1d = fes.GetTypicalFE()->GetOrder()+1;
|
||||
fes.GetTypicalFE()->GetFaceMap(face_id2, face_map);
|
||||
Array<int> face_nbr_dofs;
|
||||
const ParFiniteElementSpace &pfes =
|
||||
static_cast<const ParFiniteElementSpace&>(this->fes);
|
||||
pfes.GetFaceNbrElementVDofs(elem_index, face_nbr_dofs);
|
||||
|
||||
for (int face_dof_elem1 = 0; face_dof_elem1 < face_dofs; ++face_dof_elem1)
|
||||
{
|
||||
const int face_dof_elem2 = PermuteFaceL2(dim, face_id1, face_id2,
|
||||
orientation, dof1d, face_dof_elem1);
|
||||
const int volume_dof_elem2 = face_map[face_dof_elem2];
|
||||
const int global_dof_elem2 = face_nbr_dofs[volume_dof_elem2];
|
||||
// Encode the volume DOF index and element index
|
||||
const int global_dof_elem2 = elem_index*elem_dofs + volume_dof_elem2;
|
||||
const int restriction_dof_elem2 = face_dofs*face_index + face_dof_elem1;
|
||||
// Trick to differentiate dof location inter/shared
|
||||
scatter_indices2[restriction_dof_elem2] = ndofs+global_dof_elem2;
|
||||
scatter_indices2[restriction_dof_elem2] = ndofs + global_dof_elem2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
+1
-14
@@ -22,14 +22,6 @@
|
||||
//#define _WIN32
|
||||
//#define _aligned_malloc(s,a) malloc(s)
|
||||
|
||||
#ifdef NVTX_DEBUG_HPP
|
||||
#undef NVTX_COLOR
|
||||
#define NVTX_COLOR ::nvtx::kGold
|
||||
#include NVTX_DEBUG_HPP
|
||||
#else
|
||||
#define dbg(...)
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
@@ -768,12 +760,7 @@ private:
|
||||
switch (mt)
|
||||
{
|
||||
case MT::HOST_DEBUG:
|
||||
if (GetEnv("MFEM_MMU_STD"))
|
||||
{
|
||||
dbg("Using STD memory space for debug device!");
|
||||
return new StdHostMemorySpace();
|
||||
}
|
||||
dbg("Using MMU memory space for debug device!");
|
||||
if (GetEnv("MFEM_MMU_STD")) { return new StdHostMemorySpace(); }
|
||||
return new MmuHostMemorySpace();
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
case MT::HOST_UMPIRE:
|
||||
|
||||
+62
-1
@@ -284,7 +284,7 @@ void RK4Solver::Init(TimeDependentOperator &f_)
|
||||
int n = f->Width();
|
||||
y.SetSize(n, mem_type);
|
||||
k.SetSize(n, mem_type);
|
||||
z.SetSize(n, mem_type);
|
||||
z.SetSize(n, mem_type);
|
||||
}
|
||||
|
||||
void RK4Solver::Step(Vector &x, real_t &t, real_t &dt)
|
||||
@@ -316,6 +316,67 @@ void RK4Solver::Step(Vector &x, real_t &t, real_t &dt)
|
||||
t += dt;
|
||||
}
|
||||
|
||||
void RK4Solver::SetSolution(const Vector& x, real_t ts)
|
||||
{
|
||||
hist.clear(); //we need only the last time step at time ts
|
||||
StepRecord rec{ts,x};
|
||||
hist.push_back(rec);
|
||||
}
|
||||
|
||||
void RK4Solver::AdjointStep(Vector &lambda, real_t &t, real_t &dt)
|
||||
{
|
||||
MFEM_VERIFY(!hist.empty(), "No forward history.");
|
||||
MFEM_VERIFY(adj_mode == AdjointMode::Discrete, "Wrong adjoint mode.");
|
||||
|
||||
//Restore the solution history, i.e., perform a forward step.
|
||||
auto rec = hist.back();
|
||||
hist.pop_back();
|
||||
const real_t tn = rec.t;
|
||||
const real_t h = dt;
|
||||
const Vector &xn = rec.x;
|
||||
// Recompute forward stage states and stage RHS:
|
||||
f->SetTime(tn);
|
||||
f->Mult(xn, k1); // k1
|
||||
add(xn, h/2.0, k1, y2); // y2
|
||||
|
||||
f->SetTime(tn+h/2.0);
|
||||
f->Mult(y2, k); // k2
|
||||
add(xn, h/2.0, k, y3); // y3
|
||||
|
||||
f->Mult(y3, k); // k3
|
||||
add(xn, h, k, y4); // y4
|
||||
|
||||
|
||||
//set the initial values for a1,a2,a3,a4
|
||||
a1.Set(h/6.0,lambda);
|
||||
a2.Set(h/3.0,lambda);
|
||||
a3.Set(h/3.0,lambda);
|
||||
a4.Set(h/6.0,lambda);
|
||||
|
||||
//stage 4
|
||||
f->SetTime(tn+h);
|
||||
f->JacobianMultTranspose(y4, a4, k);
|
||||
lambda.Add(1.0,k);
|
||||
a3.Add(h,k);
|
||||
|
||||
//stage 3
|
||||
f->SetTime(tn+h/2.0);
|
||||
f->JacobianMultTranspose(y3, a3, k);
|
||||
lambda.Add(1.0,k);
|
||||
a2.Add(h/2.0,k);
|
||||
|
||||
//stage 2
|
||||
f->SetTime(tn+h/2.0);
|
||||
f->JacobianMultTranspose(y2, a2, k);
|
||||
lambda.Add(1.0,k);
|
||||
a1.Add(h/2.0,k);
|
||||
|
||||
//stage 1
|
||||
f->SetTime(tn);
|
||||
f->JacobianMultTranspose(xn, a1, k);
|
||||
lambda.Add(1.0,k);
|
||||
}
|
||||
|
||||
ExplicitRKSolver::ExplicitRKSolver(int s_, const real_t *a_, const real_t *b_,
|
||||
const real_t *c_)
|
||||
{
|
||||
|
||||
+135
@@ -190,6 +190,78 @@ public:
|
||||
while (t < tf) { Step(x, t, dt); }
|
||||
}
|
||||
|
||||
/// @brief The enum defines the supported adjoint modes.
|
||||
enum class AdjointMode { None, Continuous, Discrete };
|
||||
|
||||
AdjointMode adj_mode= AdjointMode::None;
|
||||
|
||||
/// Sets the solution at time ts. The solution will be used by the adjoint step
|
||||
/// to recompute the internal stages/steps between ts and the time t used in the
|
||||
/// AdjointStep operator.
|
||||
/// SetSolution(x,ts); and then calling AdjointStep(lambda, t, dt), will
|
||||
/// first restore the solution/parametrization between ts and t (if required by
|
||||
/// the time integration scheme) and then execute the adjoint step.
|
||||
virtual void SetSolution(const Vector& x, real_t ts){}
|
||||
|
||||
|
||||
/// Return primal state x(t) for t in the recorded time interval.
|
||||
/// Default false => solver does not provide primal interpolation access.
|
||||
virtual bool GetForwardSolution(real_t t, Vector &x) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Perform one backward step for the adjoint variable lambda.
|
||||
/// dt > 0 requests stepping from t to t - dt.
|
||||
/// The solver may adjust dt (adaptive / grid snapping) and returns dt used.
|
||||
/** @param[in,out] lambda Approximate solution.
|
||||
@param[in,out] t Time associated with the approximate solution @a x.
|
||||
@param[in,out] dt Time step size.
|
||||
*/
|
||||
virtual void AdjointStep(Vector &lambda, real_t &t, real_t &dt)
|
||||
{
|
||||
MFEM_ABORT("Adjoint stepping is not supported by this ODESolver.");
|
||||
}
|
||||
|
||||
/// Perform adjoint integration from time @a t [in] to time @a tf [in].
|
||||
/** @param[in,out] lambda Approximate adjoint solution.
|
||||
@param[in,out] t Time associated with the approximate solution @a lambda.
|
||||
@param[in,out] dt Time step size.
|
||||
@param[in] t0 Requested final time. (t0<t)
|
||||
*/
|
||||
virtual void AdjointRun(Vector &lambda, real_t &t, real_t &dt, real_t t0)
|
||||
{
|
||||
MFEM_VERIFY(t0 <= t, "AdjointRun expects t0 <= t.");
|
||||
while (t > t0) {
|
||||
real_t d = std::min(dt, t - t0);
|
||||
AdjointStep(lambda, t, d);
|
||||
dt = d;
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable adjoint functionality and tell the solver
|
||||
/// what to record during forward stepping.
|
||||
/// Default: abort (adjoint mode is not supported).
|
||||
virtual void EnableAdjoint(AdjointMode mod)
|
||||
{
|
||||
if(AdjointMode::None!=mod)
|
||||
{
|
||||
MFEM_ABORT("Adjoint is not supported by the ODESolver.");
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true of the ODESolver supports the AdjointMode
|
||||
/// and false if not.
|
||||
virtual bool SupportsAdjoint(AdjointMode mod) const
|
||||
{
|
||||
if(AdjointMode::None==mod)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns how many State vectors the ODE requires
|
||||
virtual int GetStateSize() { return 0; };
|
||||
|
||||
@@ -309,10 +381,73 @@ class RK4Solver : public ODESolver
|
||||
private:
|
||||
Vector y, k, z;
|
||||
|
||||
//storage for the adjoint solver
|
||||
/// @brief stores the state x at time t
|
||||
struct StepRecord{
|
||||
real_t t;
|
||||
Vector x;
|
||||
};
|
||||
|
||||
/// @brief stores several steps
|
||||
std::vector<StepRecord> hist;
|
||||
|
||||
Vector k1,y2,y3,y4; //RK4 stages
|
||||
Vector a1,a2,a3,a4; //adjoint vectors
|
||||
|
||||
public:
|
||||
void Init(TimeDependentOperator &f_) override;
|
||||
|
||||
void Step(Vector &x, real_t &t, real_t &dt) override;
|
||||
|
||||
/// Return true of the ODESolver supports the AdjointMode and false
|
||||
/// if not.
|
||||
virtual bool SupportsAdjoint(AdjointMode mod) const override
|
||||
{
|
||||
if(AdjointMode::Discrete==mod)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Enable adjoint functionality and tell the solver
|
||||
/// what to record during forward stepping.
|
||||
/// Default: abort (adjoint mode is not supported).
|
||||
virtual void EnableAdjoint(AdjointMode mod) override
|
||||
{
|
||||
if(AdjointMode::Continuous==mod)
|
||||
{
|
||||
MFEM_ABORT("Continuous adjoint not supported by the RK4Solver.");
|
||||
}
|
||||
adj_mode=mod;
|
||||
|
||||
// allocate the storage memeory
|
||||
if(AdjointMode::Discrete==mod){
|
||||
int n = f->Width();
|
||||
k1.SetSize(n, mem_type);
|
||||
y2.SetSize(n, mem_type);
|
||||
y3.SetSize(n, mem_type);
|
||||
y4.SetSize(n, mem_type);
|
||||
|
||||
a1.SetSize(n, mem_type);
|
||||
a2.SetSize(n, mem_type);
|
||||
a3.SetSize(n, mem_type);
|
||||
a4.SetSize(n, mem_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AdjointStep(Vector &lam, real_t &t, real_t &dt) override;
|
||||
|
||||
//Two posible ways to restore the histroy
|
||||
//1) Use Step(Vector &x, real_t &t, real_t &dt) in discrete adjoint mode and record the internal states
|
||||
//2) Use additional Method SetState(const Vector &x, real_t ts);
|
||||
// Calling AdjointStep(lam,t,dt) should restore the history between ts and t, and then execute the
|
||||
// adjoint step in reverse to time t-dt with the recorded discrete states between ts and t.
|
||||
// Here we will use SetSolution
|
||||
virtual void SetSolution(const Vector& x, real_t ts) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -640,6 +640,15 @@ public:
|
||||
virtual int SUNMassMult(const Vector &x, Vector &v);
|
||||
|
||||
virtual ~TimeDependentOperator() { }
|
||||
|
||||
/// y = (df/dx(x,t))^T * w
|
||||
/// Default uses GetGradient(x).MultTranspose(w,y).
|
||||
virtual void JacobianMultTranspose(const Vector &x,
|
||||
const Vector &w,
|
||||
Vector &y) const
|
||||
{
|
||||
GetGradient(x).MultTranspose(w, y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
+44
-78
@@ -38,6 +38,13 @@
|
||||
#if PETSC_VERSION_LT(3,19,0)
|
||||
#define PETSC_SUCCESS 0
|
||||
#endif
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
#define PetscContainerSetCtxDestroy(A,B) PetscContainerSetUserDestroy(A,B)
|
||||
typedef PetscErrorCode (PetscCtxDestroyFn)(void**);
|
||||
#endif
|
||||
#if PETSC_VERSION_LT(3,24,0)
|
||||
typedef PetscErrorCode KSPMonitorFn(KSP,PetscInt,PetscReal,void*);
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
@@ -77,13 +84,17 @@ static PetscErrorCode __mfem_mat_shell_apply_transpose(Mat,Vec,Vec);
|
||||
static PetscErrorCode __mfem_mat_shell_destroy(Mat);
|
||||
static PetscErrorCode __mfem_mat_shell_copy(Mat,Mat,MatStructure);
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
static PetscErrorCode __mfem_array_container_destroy(void*);
|
||||
static PetscErrorCode __mfem_matarray_container_destroy(void *);
|
||||
#else
|
||||
static PetscErrorCode __mfem_array_container_destroy(void**);
|
||||
static PetscErrorCode __mfem_matarray_container_destroy(void**);
|
||||
typedef void *PetscCtxRt;
|
||||
#elif PETSC_VERSION_LT(3,25,0)
|
||||
typedef void **PetscCtxRt;
|
||||
#endif
|
||||
static PetscErrorCode __mfem_array_container_destroy(PetscCtxRt);
|
||||
static PetscErrorCode __mfem_matarray_container_destroy(PetscCtxRt);
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
static PetscErrorCode __mfem_monitor_ctx_destroy(void**);
|
||||
#else
|
||||
static PetscErrorCode __mfem_monitor_ctx_destroy(PetscCtxRt);
|
||||
#endif
|
||||
|
||||
// auxiliary functions
|
||||
static PetscErrorCode Convert_Array_IS(MPI_Comm,bool,const mfem::Array<int>*,
|
||||
@@ -1317,11 +1328,7 @@ BlockDiagonalConstructor(MPI_Comm comm,
|
||||
|
||||
ierr = PetscContainerCreate(comm,&c); CCHKERRQ(comm,ierr);
|
||||
ierr = PetscContainerSetPointer(c,ptrs[i]); CCHKERRQ(comm,ierr);
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
|
||||
#else
|
||||
ierr = PetscContainerSetCtxDestroy(c,__mfem_array_container_destroy);
|
||||
#endif
|
||||
CCHKERRQ(comm,ierr);
|
||||
ierr = PetscObjectCompose((PetscObject)A,names[i],(PetscObject)c);
|
||||
CCHKERRQ(comm,ierr);
|
||||
@@ -1648,11 +1655,7 @@ void PetscParMatrix::ConvertOperator(MPI_Comm comm, const Operator &op, Mat* A,
|
||||
PetscContainer c;
|
||||
ierr = PetscContainerCreate(comm,&c); CCHKERRQ(comm,ierr);
|
||||
ierr = PetscContainerSetPointer(c,vmatsl2l); PCHKERRQ(c,ierr);
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
ierr = PetscContainerSetUserDestroy(c,__mfem_matarray_container_destroy);
|
||||
#else
|
||||
ierr = PetscContainerSetCtxDestroy(c,__mfem_matarray_container_destroy);
|
||||
#endif
|
||||
PCHKERRQ(c,ierr);
|
||||
ierr = PetscObjectCompose((PetscObject)(*A),"_MatIS_PtAP_l2l",(PetscObject)c);
|
||||
PCHKERRQ((*A),ierr);
|
||||
@@ -1748,11 +1751,7 @@ void PetscParMatrix::ConvertOperator(MPI_Comm comm, const Operator &op, Mat* A,
|
||||
|
||||
ierr = PetscContainerCreate(PETSC_COMM_SELF,&c); PCHKERRQ(B,ierr);
|
||||
ierr = PetscContainerSetPointer(c,ptrs[i]); PCHKERRQ(B,ierr);
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
|
||||
#else
|
||||
ierr = PetscContainerSetCtxDestroy(c,__mfem_array_container_destroy);
|
||||
#endif
|
||||
PCHKERRQ(B,ierr);
|
||||
ierr = PetscObjectCompose((PetscObject)(B),names[i],(PetscObject)c);
|
||||
PCHKERRQ(B,ierr);
|
||||
@@ -2198,11 +2197,7 @@ PetscParMatrix * RAP(PetscParMatrix *Rt, PetscParMatrix *A, PetscParMatrix *P)
|
||||
ierr = PetscContainerCreate(PetscObjectComm((PetscObject)B),&c);
|
||||
PCHKERRQ(B,ierr);
|
||||
ierr = PetscContainerSetPointer(c,vmatsl2l); PCHKERRQ(c,ierr);
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
ierr = PetscContainerSetUserDestroy(c,__mfem_matarray_container_destroy);
|
||||
#else
|
||||
ierr = PetscContainerSetCtxDestroy(c,__mfem_matarray_container_destroy);
|
||||
#endif
|
||||
PCHKERRQ(c,ierr);
|
||||
ierr = PetscObjectCompose((PetscObject)B,"_MatIS_PtAP_l2l",(PetscObject)c);
|
||||
PCHKERRQ(B,ierr);
|
||||
@@ -2485,7 +2480,6 @@ void PetscSolver::SetMaxIter(int max_iter)
|
||||
|
||||
void PetscSolver::SetPrintLevel(int plev)
|
||||
{
|
||||
typedef PetscErrorCode (*myPetscFunc)(void**);
|
||||
PetscViewerAndFormat *vf = NULL;
|
||||
PetscViewer viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm(obj));
|
||||
|
||||
@@ -2498,7 +2492,6 @@ void PetscSolver::SetPrintLevel(int plev)
|
||||
{
|
||||
// there are many other options, see the function KSPSetFromOptions() in
|
||||
// src/ksp/ksp/interface/itcl.c
|
||||
typedef PetscErrorCode (*myMonitor)(KSP,PetscInt,PetscReal,void*);
|
||||
KSP ksp = (KSP)obj;
|
||||
if (plev >= 0)
|
||||
{
|
||||
@@ -2507,29 +2500,29 @@ void PetscSolver::SetPrintLevel(int plev)
|
||||
if (plev == 1)
|
||||
{
|
||||
#if PETSC_VERSION_LT(3,15,0)
|
||||
ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorDefault,vf,
|
||||
ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorDefault,vf,
|
||||
#else
|
||||
ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorResidual,vf,
|
||||
ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorResidual,vf,
|
||||
#endif
|
||||
(myPetscFunc)PetscViewerAndFormatDestroy);
|
||||
(PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
|
||||
PCHKERRQ(ksp,ierr);
|
||||
}
|
||||
else if (plev > 1)
|
||||
{
|
||||
ierr = KSPSetComputeSingularValues(ksp,PETSC_TRUE); PCHKERRQ(ksp,ierr);
|
||||
ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorSingularValue,vf,
|
||||
(myPetscFunc)PetscViewerAndFormatDestroy);
|
||||
ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorSingularValue,vf,
|
||||
(PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
|
||||
PCHKERRQ(ksp,ierr);
|
||||
if (plev > 2)
|
||||
{
|
||||
ierr = PetscViewerAndFormatCreate(viewer,PETSC_VIEWER_DEFAULT,&vf);
|
||||
PCHKERRQ(viewer,ierr);
|
||||
#if PETSC_VERSION_LT(3,15,0)
|
||||
ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorTrueResidualNorm,vf,
|
||||
ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorTrueResidualNorm,vf,
|
||||
#else
|
||||
ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorTrueResidual,vf,
|
||||
ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorTrueResidual,vf,
|
||||
#endif
|
||||
(myPetscFunc)PetscViewerAndFormatDestroy);
|
||||
(PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
|
||||
PCHKERRQ(ksp,ierr);
|
||||
}
|
||||
}
|
||||
@@ -2545,7 +2538,7 @@ void PetscSolver::SetPrintLevel(int plev)
|
||||
if (plev > 0)
|
||||
{
|
||||
ierr = SNESMonitorSet(snes,(myMonitor)SNESMonitorDefault,vf,
|
||||
(myPetscFunc)PetscViewerAndFormatDestroy);
|
||||
(PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
|
||||
PCHKERRQ(snes,ierr);
|
||||
}
|
||||
}
|
||||
@@ -5329,21 +5322,27 @@ static PetscErrorCode __mfem_pc_shell_destroy(PC pc)
|
||||
PetscFunctionReturn(PETSC_SUCCESS);
|
||||
}
|
||||
|
||||
static PetscErrorCode __mfem_array_container_destroy(PetscCtxRt ptr)
|
||||
{
|
||||
PetscErrorCode ierr;
|
||||
|
||||
PetscFunctionBeginUser;
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
|
||||
static PetscErrorCode __mfem_array_container_destroy(void *ptr)
|
||||
{
|
||||
PetscErrorCode ierr;
|
||||
|
||||
PetscFunctionBeginUser;
|
||||
ierr = PetscFree(ptr); CHKERRQ(ierr);
|
||||
#else
|
||||
ierr = PetscFree(*(void**)ptr); CHKERRQ(ierr);
|
||||
#endif
|
||||
PetscFunctionReturn(PETSC_SUCCESS);
|
||||
}
|
||||
|
||||
static PetscErrorCode __mfem_matarray_container_destroy(void *ptr)
|
||||
static PetscErrorCode __mfem_matarray_container_destroy(PetscCtxRt ptr)
|
||||
{
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
mfem::Array<Mat> *a = (mfem::Array<Mat>*)ptr;
|
||||
PetscErrorCode ierr;
|
||||
#else
|
||||
mfem::Array<Mat> *a = *(mfem::Array<Mat>**)ptr;
|
||||
#endif
|
||||
PetscErrorCode ierr;
|
||||
|
||||
PetscFunctionBeginUser;
|
||||
for (int i=0; i<a->Size(); i++)
|
||||
@@ -5356,41 +5355,16 @@ static PetscErrorCode __mfem_matarray_container_destroy(void *ptr)
|
||||
PetscFunctionReturn(PETSC_SUCCESS);
|
||||
}
|
||||
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
static PetscErrorCode __mfem_monitor_ctx_destroy(void **ctx)
|
||||
#else
|
||||
|
||||
static PetscErrorCode __mfem_array_container_destroy(void **ptr)
|
||||
static PetscErrorCode __mfem_monitor_ctx_destroy(PetscCtxRt ctx)
|
||||
#endif
|
||||
{
|
||||
PetscErrorCode ierr;
|
||||
|
||||
PetscFunctionBeginUser;
|
||||
ierr = PetscFree(*ptr); CHKERRQ(ierr);
|
||||
PetscFunctionReturn(PETSC_SUCCESS);
|
||||
}
|
||||
|
||||
static PetscErrorCode __mfem_matarray_container_destroy(void **ptr)
|
||||
{
|
||||
mfem::Array<Mat> *a = (mfem::Array<Mat>*)*ptr;
|
||||
PetscErrorCode ierr;
|
||||
|
||||
PetscFunctionBeginUser;
|
||||
for (int i=0; i<a->Size(); i++)
|
||||
{
|
||||
Mat M = (*a)[i];
|
||||
MPI_Comm comm = PetscObjectComm((PetscObject)M);
|
||||
ierr = MatDestroy(&M); CCHKERRQ(comm,ierr);
|
||||
}
|
||||
delete a;
|
||||
PetscFunctionReturn(PETSC_SUCCESS);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static PetscErrorCode __mfem_monitor_ctx_destroy(void **ctx)
|
||||
{
|
||||
PetscErrorCode ierr;
|
||||
|
||||
PetscFunctionBeginUser;
|
||||
ierr = PetscFree(*ctx); CHKERRQ(ierr);
|
||||
ierr = PetscFree(*(void**)ctx); CHKERRQ(ierr);
|
||||
PetscFunctionReturn(PETSC_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -5635,11 +5609,7 @@ static PetscErrorCode MatConvert_hypreParCSR_AIJ(hypre_ParCSRMatrix* hA,Mat* pA)
|
||||
|
||||
ierr = PetscContainerCreate(comm,&c); CHKERRQ(ierr);
|
||||
ierr = PetscContainerSetPointer(c,ptrs[i]); CHKERRQ(ierr);
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
|
||||
#else
|
||||
ierr = PetscContainerSetCtxDestroy(c,__mfem_array_container_destroy);
|
||||
#endif
|
||||
CHKERRQ(ierr);
|
||||
ierr = PetscObjectCompose((PetscObject)(*pA),names[i],(PetscObject)c);
|
||||
CHKERRQ(ierr);
|
||||
@@ -5733,11 +5703,7 @@ static PetscErrorCode MatConvert_hypreParCSR_IS(hypre_ParCSRMatrix* hA,Mat* pA)
|
||||
|
||||
ierr = PetscContainerCreate(PETSC_COMM_SELF,&c); CHKERRQ(ierr);
|
||||
ierr = PetscContainerSetPointer(c,ptrs[i]); CHKERRQ(ierr);
|
||||
#if PETSC_VERSION_LT(3,23,0)
|
||||
ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
|
||||
#else
|
||||
ierr = PetscContainerSetCtxDestroy(c,__mfem_array_container_destroy);
|
||||
#endif
|
||||
CHKERRQ(ierr);
|
||||
ierr = PetscObjectCompose((PetscObject)lA,names[i],(PetscObject)c);
|
||||
CHKERRQ(ierr);
|
||||
|
||||
@@ -126,11 +126,11 @@ EXAMPLE_TEST_DIRS := examples
|
||||
MINIAPP_SUBDIRS = common electromagnetics meshing performance tools \
|
||||
toys nurbs gslib adjoint solvers shifted mtop parelag tribol autodiff dfem \
|
||||
hooke multidomain dpg hdiv-linear-solver spde diag-smoothers contact \
|
||||
fluids/navier fluids/schrodinger-flow
|
||||
fluids/navier fluids/schrodinger-flow plasma
|
||||
MINIAPP_DIRS := $(addprefix miniapps/,$(MINIAPP_SUBDIRS))
|
||||
MINIAPP_TEST_DIRS := $(filter-out %/common,$(MINIAPP_DIRS))
|
||||
MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics meshing tools \
|
||||
toys shifted dpg diag-smoothers fluids/navier)
|
||||
toys shifted dpg diag-smoothers fluids/navier plasma)
|
||||
|
||||
EM_DIRS = $(EXAMPLE_DIRS) $(MINIAPP_DIRS)
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ add_subdirectory(multidomain)
|
||||
add_subdirectory(nurbs)
|
||||
add_subdirectory(parelag)
|
||||
add_subdirectory(performance)
|
||||
add_subdirectory(plasma)
|
||||
add_subdirectory(shifted)
|
||||
add_subdirectory(solvers)
|
||||
add_subdirectory(spde)
|
||||
|
||||
@@ -26,5 +26,10 @@ if(MFEM_USE_MPI AND MFEM_USE_DOUBLE)
|
||||
MAIN mtop_test_iso_elasticity.cpp
|
||||
${PAR_MTOP_COMMON_FILES}
|
||||
LIBRARIES mfem)
|
||||
add_mfem_miniapp(tst_rk4_adj
|
||||
MAIN tst_rk4_adj.cpp
|
||||
${PAR_MTOP_COMMON_FILES}
|
||||
LIBRARIES mfem)
|
||||
|
||||
|
||||
endif (MFEM_USE_MPI AND MFEM_USE_DOUBLE)
|
||||
|
||||
@@ -31,6 +31,11 @@ add_mfem_miniapp(mtop_test_adjoint_le
|
||||
${EX_COMMON_FILES}
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(mtop_test_adjoint_op
|
||||
MAIN test_adjoint_op.cpp
|
||||
${EX_COMMON_FILES}
|
||||
LIBRARIES mfem)
|
||||
|
||||
|
||||
endif (MFEM_USE_MPI)
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,329 +1,289 @@
|
||||
// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
#ifndef LINEAR_ELASTICITY_HPP
|
||||
#define LINEAR_ELASTICITY_HPP
|
||||
|
||||
#include "mfem.hpp"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class LinearElasticityTimeDependentOperator: public mfem::TimeDependentOperator
|
||||
|
||||
class LinearElasticityTimeDependentOperator : public mfem::TimeDependentOperator
|
||||
{
|
||||
public:
|
||||
|
||||
LinearElasticityTimeDependentOperator(mfem::ParMesh &mesh_, int vorder =1);
|
||||
LinearElasticityTimeDependentOperator(mfem::ParMesh &mesh_, int vorder =1);
|
||||
|
||||
virtual ~LinearElasticityTimeDependentOperator() { }
|
||||
virtual ~LinearElasticityTimeDependentOperator() override
|
||||
{
|
||||
}
|
||||
|
||||
void Mult(const mfem::Vector &x, mfem::Vector &y) const override;
|
||||
void MultInvMass(const mfem::Vector &x, mfem::Vector &y) const;
|
||||
|
||||
virtual void AdjointMult(const mfem::Vector &x, mfem::Vector &y) const;
|
||||
virtual void Mult(const mfem::Vector &x, mfem::Vector &y) const override;
|
||||
|
||||
void ImplicitSolve(const mfem::real_t dt,
|
||||
const mfem::Vector &x,
|
||||
mfem::Vector &k) override;
|
||||
void JacobianMultTranspose(const mfem::Vector &x,
|
||||
const mfem::Vector &w,
|
||||
mfem::Vector &y) const override;
|
||||
|
||||
// sets the objective integraand which will be integrated with the state of the system
|
||||
void SetObjective(std::shared_ptr<mfem::Operator> op_);
|
||||
virtual void ImplicitSolve(const mfem::real_t dt,
|
||||
const mfem::Vector &x,
|
||||
mfem::Vector &k) override;
|
||||
|
||||
// Assemble the explicit operators
|
||||
// must be called after setting all material coefficients
|
||||
// and before time stepping
|
||||
void AssembleExplicit();
|
||||
|
||||
void SetDensity(mfem::Coefficient &rho)
|
||||
{
|
||||
density = std::make_shared<mfem::CoefficientVector>(*qs,
|
||||
mfem::CoefficientStorage::FULL);
|
||||
cdensity = ρ
|
||||
density->Project(rho);
|
||||
}
|
||||
// Assemble the explicit operators
|
||||
// must be called after setting all material coefficients
|
||||
// and before time stepping
|
||||
void AssembleExplicit();
|
||||
|
||||
// l1, m1 are the Lame parameters for material 1
|
||||
// l2, m2 are the Lame parameters for material 2
|
||||
void SetElasticityCoefficients(mfem::Coefficient& l1_,
|
||||
mfem::Coefficient& m1_,
|
||||
mfem::Coefficient& l2_,
|
||||
mfem::Coefficient& m2_)
|
||||
{
|
||||
l1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
l2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
m1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
m2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
void SetDensity(mfem::Coefficient &rho)
|
||||
{
|
||||
density = std::make_shared<mfem::CoefficientVector>(*qs, mfem::CoefficientStorage::FULL);
|
||||
cdensity = ρ
|
||||
density->Project(rho);
|
||||
}
|
||||
|
||||
l1->Project(l1_);
|
||||
m1->Project(m1_);
|
||||
l2->Project(l2_);
|
||||
m2->Project(m2_);
|
||||
}
|
||||
|
||||
// rho1 and rho2 are the density coefficients for material 1 and 2
|
||||
void SetDensityMaterialCoefficients(mfem::Coefficient& rho1_,
|
||||
mfem::Coefficient& rho2_)
|
||||
{
|
||||
dens1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
dens2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
// l1, m1 are the Lame parameters for material 1
|
||||
// l2, m2 are the Lame parameters for material 2
|
||||
void SetElasticityCoefficients(mfem::Coefficient& l1_,
|
||||
mfem::Coefficient& m1_,
|
||||
mfem::Coefficient& l2_,
|
||||
mfem::Coefficient& m2_)
|
||||
{
|
||||
l1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
l2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
m1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
m2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
|
||||
cdens1 = &rho1_;
|
||||
cdens2 = &rho2_;
|
||||
l1->Project(l1_);
|
||||
m1->Project(m1_);
|
||||
l2->Project(l2_);
|
||||
m2->Project(m2_);
|
||||
}
|
||||
|
||||
dens1->Project(rho1_);
|
||||
dens2->Project(rho2_);
|
||||
}
|
||||
|
||||
// c1 and c2 are velocity proportional damping coefficients for material 1 and 2
|
||||
// both of them are considered to be time dependent
|
||||
void SetDampingMaterialCoefficients(mfem::Coefficient& c1_,
|
||||
mfem::Coefficient& c2_)
|
||||
{
|
||||
cm1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
cm2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
// rho1 and rho2 are the density coefficients for material 1 and 2
|
||||
void SetDensityMaterialCoefficients(mfem::Coefficient& rho1_,
|
||||
mfem::Coefficient& rho2_)
|
||||
{
|
||||
dens1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
dens2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
|
||||
cm1->Project(c1_);
|
||||
cm2->Project(c2_);
|
||||
}
|
||||
cdens1 = &rho1_;
|
||||
cdens2 = &rho2_;
|
||||
|
||||
// dl1, dm1 are the strain velocity proportional damping coefficients
|
||||
// for material 1 and dl2, dm2 for material 2
|
||||
// all of them are considered to be time dependent
|
||||
void SetDampingMaterialCoefficients(mfem::Coefficient& dl1_,
|
||||
mfem::Coefficient& dm1_,
|
||||
mfem::Coefficient& dl2_,
|
||||
mfem::Coefficient& dm2_)
|
||||
{
|
||||
dl1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
dl2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
dm1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
dm2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
dens1->Project(rho1_);
|
||||
dens2->Project(rho2_);
|
||||
}
|
||||
|
||||
dl1->Project(dl1_);
|
||||
dm1->Project(dm1_);
|
||||
dl2->Project(dl2_);
|
||||
dm2->Project(dm2_);
|
||||
}
|
||||
// c1 and c2 are velocity proportional damping coefficients for material 1 and 2
|
||||
// both of them are considered to be time dependent
|
||||
void SetDampingMaterialCoefficients(mfem::Coefficient& c1_,
|
||||
mfem::Coefficient& c2_)
|
||||
{
|
||||
cm1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
cm2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
|
||||
mfem::ParGridFunction& GetDisplacement() { return displ; }
|
||||
mfem::ParGridFunction& GetVelocity() { return veloc; }
|
||||
mfem::Array<int>& GetTrueBlockOffsets() { return block_true_offsets;}
|
||||
cm1->Project(c1_);
|
||||
cm2->Project(c2_);
|
||||
}
|
||||
|
||||
mfem::Vector& GetState() {return sol;}
|
||||
// dl1, dm1 are the strain velocity proportional damping coefficients
|
||||
// for material 1 and dl2, dm2 for material 2
|
||||
// all of them are considered to be time dependent
|
||||
void SetDampingMaterialCoefficients(mfem::Coefficient& dl1_,
|
||||
mfem::Coefficient& dm1_,
|
||||
mfem::Coefficient& dl2_,
|
||||
mfem::Coefficient& dm2_)
|
||||
{
|
||||
dl1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
dl2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
dm1.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
dm2.reset(new mfem::CoefficientVector(*qs, mfem::CoefficientStorage::FULL));
|
||||
|
||||
const mfem::ParFiniteElementSpace* GetFESpace() { return fespace.get();}
|
||||
dl1->Project(dl1_);
|
||||
dm1->Project(dm1_);
|
||||
dl2->Project(dl2_);
|
||||
dm2->Project(dm2_);
|
||||
}
|
||||
|
||||
void SetZeroBdr(int bdr_attr)
|
||||
{
|
||||
zero_bdrs.insert(bdr_attr);
|
||||
}
|
||||
mfem::ParGridFunction& GetDisplacement() { return displ; }
|
||||
mfem::ParGridFunction& GetVelocity() { return veloc; }
|
||||
mfem::Array<int>& GetTrueBlockOffsets(){ return block_true_offsets;}
|
||||
|
||||
void SetBdrLoad(int attr)
|
||||
{
|
||||
bdr_loads_markers.insert(attr);
|
||||
}
|
||||
mfem::Vector& GetState(){return sol;}
|
||||
|
||||
void SetVolForce(mfem::real_t period, mfem::real_t amplitude, mfem::real_t rad,
|
||||
mfem::real_t xc=0.0, mfem::real_t yc=0.0, mfem::real_t zc=0.0,
|
||||
mfem::real_t L=5.0, mfem::real_t t0=0.0, mfem::real_t n=2.0)
|
||||
{
|
||||
// copy data to the host
|
||||
mfem::real_t* pvol_force_mem = vol_force_mem.HostReadWrite();
|
||||
mfem::ParFiniteElementSpace* GetFESpace(){ return fespace.get();}
|
||||
|
||||
pvol_force_mem[1] = period;
|
||||
pvol_force_mem[2] = amplitude;
|
||||
pvol_force_mem[3] = rad;
|
||||
pvol_force_mem[4] = xc;
|
||||
pvol_force_mem[5] = yc;
|
||||
pvol_force_mem[6] = zc;
|
||||
void SetZeroBdr(int bdr_attr)
|
||||
{
|
||||
zero_bdrs.insert(bdr_attr);
|
||||
}
|
||||
|
||||
pvol_force_mem[7] = L;
|
||||
pvol_force_mem[8] = t0;
|
||||
pvol_force_mem[9] = n;
|
||||
void SetBdrLoad(int attr)
|
||||
{
|
||||
bdr_loads_markers.insert(attr);
|
||||
}
|
||||
|
||||
// copy data to the device
|
||||
vol_force_mem.Read();
|
||||
}
|
||||
void SetVolForce(mfem::real_t period, mfem::real_t amplitude, mfem::real_t rad,
|
||||
mfem::real_t xc=0.0, mfem::real_t yc=0.0, mfem::real_t zc=0.0,
|
||||
mfem::real_t L=5.0, mfem::real_t t0=0.0, mfem::real_t n=2.0)
|
||||
{
|
||||
// copy data to the host
|
||||
mfem::real_t* pvol_force_mem = vol_force_mem.HostReadWrite();
|
||||
|
||||
void AddState(mfem::real_t t, mfem::Vector& state)
|
||||
{
|
||||
int cind=adjoint_data.ind % adjoint_data.max_states;
|
||||
adjoint_data.states[cind]=state;
|
||||
adjoint_data.times[cind]=t;
|
||||
adjoint_data.ind++;
|
||||
}
|
||||
pvol_force_mem[1] = period;
|
||||
pvol_force_mem[2] = amplitude;
|
||||
pvol_force_mem[3] = rad;
|
||||
pvol_force_mem[4] = xc;
|
||||
pvol_force_mem[5] = yc;
|
||||
pvol_force_mem[6] = zc;
|
||||
|
||||
pvol_force_mem[7] = L;
|
||||
pvol_force_mem[8] = t0;
|
||||
pvol_force_mem[9] = n;
|
||||
|
||||
// copy data to the device
|
||||
vol_force_mem.Read();
|
||||
}
|
||||
|
||||
private:
|
||||
mfem::ParMesh &mesh;
|
||||
int order;
|
||||
mfem::ParMesh &mesh;
|
||||
int order;
|
||||
|
||||
std::unique_ptr<mfem::FiniteElementCollection> fec;
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> fespace;
|
||||
int dim;
|
||||
int space_dim;
|
||||
std::unique_ptr<mfem::FiniteElementCollection> fec;
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> fespace;
|
||||
int dim;
|
||||
int space_dim;
|
||||
|
||||
int myrank;
|
||||
int myrank;
|
||||
|
||||
mfem::ParGridFunction *nodes;
|
||||
mfem::ParFiniteElementSpace *mfes;
|
||||
mfem::Array<int> domain_attributes;
|
||||
const mfem::IntegrationRule *ir;
|
||||
mfem::ParGridFunction *nodes;
|
||||
mfem::ParFiniteElementSpace *mfes;
|
||||
mfem::Array<int> domain_attributes;
|
||||
const mfem::IntegrationRule *ir;
|
||||
|
||||
mutable mfem::ParGridFunction displ;
|
||||
mutable mfem::ParGridFunction veloc;
|
||||
mutable mfem::ParGridFunction accel;
|
||||
mutable mfem::ParGridFunction displ;
|
||||
mutable mfem::ParGridFunction veloc;
|
||||
mutable mfem::ParGridFunction accel;
|
||||
|
||||
mutable mfem::BlockVector sol;
|
||||
mutable mfem::BlockVector rhs;
|
||||
mutable mfem::BlockVector tmp;
|
||||
mutable mfem::Vector res;
|
||||
mutable mfem::BlockVector sol;
|
||||
mutable mfem::BlockVector rhs;
|
||||
mutable mfem::BlockVector tmp;
|
||||
mutable mfem::Vector res;
|
||||
|
||||
mfem::Array<int> block_true_offsets;
|
||||
mfem::Array<int> block_true_offsets;
|
||||
|
||||
std::unique_ptr<mfem::future::UniformParameterSpace> ups;
|
||||
std::unique_ptr<mfem::QuadratureSpace> qs;
|
||||
std::unique_ptr<mfem::FaceQuadratureSpace> fqs;
|
||||
std::unique_ptr<mfem::future::UniformParameterSpace> ups;
|
||||
std::unique_ptr<mfem::QuadratureSpace> qs;
|
||||
std::unique_ptr<mfem::FaceQuadratureSpace> fqs;
|
||||
|
||||
// linear elasticty coefficients in dFEM form
|
||||
// l1, m1 - material 1
|
||||
// l2, m2 - material 2
|
||||
std::unique_ptr<mfem::CoefficientVector> l1, l2;
|
||||
std::unique_ptr<mfem::CoefficientVector> m1, m2;
|
||||
// linear elasticty coefficients in dFEM form
|
||||
// l1, m1 - material 1
|
||||
// l2, m2 - material 2
|
||||
std::unique_ptr<mfem::CoefficientVector> l1, l2;
|
||||
std::unique_ptr<mfem::CoefficientVector> m1, m2;
|
||||
|
||||
// linear elasticity damping coefficients in dFEM form
|
||||
// strain proportional damping for material 1 and 2
|
||||
std::unique_ptr<mfem::CoefficientVector> dl1, dl2;
|
||||
std::unique_ptr<mfem::CoefficientVector> dm1, dm2;
|
||||
// linear elasticity damping coefficients in dFEM form
|
||||
// strain proportional damping for material 1 and 2
|
||||
std::unique_ptr<mfem::CoefficientVector> dl1, dl2;
|
||||
std::unique_ptr<mfem::CoefficientVector> dm1, dm2;
|
||||
|
||||
// damping mass coefficients in dFEM form
|
||||
// (velocity proportional damping) for material 1 and 2
|
||||
std::unique_ptr<mfem::CoefficientVector> cm1, cm2;
|
||||
// damping mass coefficients in dFEM form
|
||||
// (velocity proportional damping) for material 1 and 2
|
||||
std::unique_ptr<mfem::CoefficientVector> cm1, cm2;
|
||||
|
||||
// density coefficients in dFEM form for material 1 and 2
|
||||
std::unique_ptr<mfem::CoefficientVector> dens1, dens2;
|
||||
mfem::Coefficient *cdens1, *cdens2;
|
||||
// density coefficients in dFEM form for material 1 and 2
|
||||
std::unique_ptr<mfem::CoefficientVector> dens1, dens2;
|
||||
mfem::Coefficient *cdens1, *cdens2;
|
||||
|
||||
// density coefficient for topology optimization
|
||||
std::shared_ptr<mfem::CoefficientVector> density;
|
||||
mfem::Coefficient *cdensity;
|
||||
// density coefficient for topology optimization
|
||||
std::shared_ptr<mfem::CoefficientVector> density;
|
||||
mfem::Coefficient *cdensity;
|
||||
|
||||
static constexpr int FDispl = 0; //grid function displacement
|
||||
static constexpr int FVeloc = 1; //grid function velocity
|
||||
// elasticity Coefficient Vectors
|
||||
static constexpr int Lambda1 = 2, Lambda2 = 3, Mu1 = 4, Mu2 = 5;
|
||||
// damping Coefficient Vectors
|
||||
static constexpr int DLambda1 = 6, DMu1 = 7, DLambda2 = 8, DMu2 = 9;
|
||||
static constexpr int CMass1 = 10, CMass2 = 11; // damping mass coeff vectors
|
||||
static constexpr int Dens1 = 12, Dens2 = 13; // density Coefficient Vectors
|
||||
// density for topology optimization
|
||||
static constexpr int Density = 14; // coefficient vector
|
||||
static constexpr int Coords = 15; // coordinates grid function
|
||||
|
||||
// DFEM forward related definitions
|
||||
std::unique_ptr<mfem::future::DifferentiableOperator> dfem_forward_op;
|
||||
std::unique_ptr<mfem::future::DifferentiableOperator> dfem_mass_op;
|
||||
std::unique_ptr<mfem::future::DifferentiableOperator> dfem_damp_op;
|
||||
std::unique_ptr<mfem::future::DifferentiableOperator> dfem_vol_force_op;
|
||||
|
||||
std::unique_ptr<mfem::HypreParMatrix> M_lor;
|
||||
static constexpr int FDispl = 0; //grid function displacement
|
||||
static constexpr int FVeloc = 1; //grid function velocity
|
||||
// elasticity Coefficient Vectors
|
||||
static constexpr int Lambda1 = 2, Lambda2 = 3, Mu1 = 4, Mu2 = 5;
|
||||
// damping Coefficient Vectors
|
||||
static constexpr int DLambda1 = 6, DMu1 = 7, DLambda2 = 8, DMu2 = 9;
|
||||
static constexpr int CMass1 = 10, CMass2 = 11; // damping mass coeff vectors
|
||||
static constexpr int Dens1 = 12, Dens2 = 13; // density Coefficient Vectors
|
||||
// density for topology optimization
|
||||
static constexpr int Density = 14; // coefficient vector
|
||||
static constexpr int Coords = 15; // coordinates grid function
|
||||
|
||||
std::unique_ptr<mfem::CGSolver> cg;
|
||||
std::unique_ptr<mfem::HypreBoomerAMG> amg;
|
||||
// DFEM forward related definitions
|
||||
std::unique_ptr<mfem::future::DifferentiableOperator> dfem_forward_op;
|
||||
std::unique_ptr<mfem::future::DifferentiableOperator> dfem_mass_op;
|
||||
std::unique_ptr<mfem::future::DifferentiableOperator> dfem_damp_op;
|
||||
std::unique_ptr<mfem::future::DifferentiableOperator> dfem_vol_force_op;
|
||||
|
||||
// zero bdrs
|
||||
std::set<int> zero_bdrs;
|
||||
std::unique_ptr<mfem::HypreParMatrix> M_lor;
|
||||
|
||||
// time dependent memory vector for dynamic force
|
||||
// the force is applied on all boundary attributes in bdr_loads_markers
|
||||
std::set<int> bdr_loads_markers;
|
||||
mutable mfem::Vector bdr_force_mem; // [0] - time, [1] - period, [2] - amplitude
|
||||
std::unique_ptr<mfem::CGSolver> cg;
|
||||
std::unique_ptr<mfem::HypreBoomerAMG> amg;
|
||||
|
||||
// volumetric force parameters
|
||||
// A*sin(2*pi*t/T)*cos^n (pi (t-t_0)/L)
|
||||
// [0] - time, [1] - period, [2] - amplitude, [3] - radius
|
||||
// [4],[5],[6] - point coordinates of the center of the force application
|
||||
// [7] - L total train length - could be proportional to the period [1]
|
||||
// [8] - t_0 center of the train
|
||||
// [9] - n the envelope power
|
||||
mutable mfem::Vector vol_force_mem;
|
||||
// zero bdrs
|
||||
std::set<int> zero_bdrs;
|
||||
|
||||
// zero bdr dofs - constructed during the corrsponding Assemble calls
|
||||
mfem::Array<int> ess_tdof_list;
|
||||
// time dependent memory vector for dynamic force
|
||||
// the force is applied on all boundary attributes in bdr_loads_markers
|
||||
std::set<int> bdr_loads_markers;
|
||||
mutable mfem::Vector bdr_force_mem; // [0] - time, [1] - period, [2] - amplitude
|
||||
|
||||
//objective/constraints integrand
|
||||
//obj->Mult(x,y)
|
||||
//takes state vector s and returns y which consists of multiple objectives/constraints
|
||||
std::shared_ptr<mfem::Operator> obj;
|
||||
// volumetric force parameters
|
||||
// A*sin(2*pi*t/T)*cos^n (pi (t-t_0)/L)
|
||||
// [0] - time, [1] - period, [2] - amplitude, [3] - radius
|
||||
// [4],[5],[6] - point coordinates of the center of the force application
|
||||
// [7] - L total train length - could be proportional to the period [1]
|
||||
// [8] - t_0 center of the train
|
||||
// [9] - n the envelope power
|
||||
mutable mfem::Vector vol_force_mem;
|
||||
|
||||
// zero bdr dofs - constructed during the corrsponding Assemble calls
|
||||
mfem::Array<int> ess_tdof_list;
|
||||
|
||||
struct
|
||||
{
|
||||
mfem::real_t Tfinal;
|
||||
mfem::Vector states[2];
|
||||
mfem::real_t times[2];
|
||||
int ind=0;
|
||||
int max_states=2;
|
||||
} adjoint_data;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class ExampleObjectiveIntegrand: public mfem::Operator
|
||||
{
|
||||
public:
|
||||
|
||||
ExampleObjectiveIntegrand(mfem::ParFiniteElementSpace* fes_,
|
||||
std::shared_ptr<mfem::Coefficient> objc);
|
||||
ExampleObjectiveIntegrand(mfem::ParFiniteElementSpace* fes_,
|
||||
std::shared_ptr<mfem::Coefficient> objc={});
|
||||
|
||||
void SetCoefficients( std::shared_ptr<mfem::Coefficient> objc);
|
||||
|
||||
//evaluates the QoIs y[1] for a given state x[2 x fes_->GetTrueVSize()]
|
||||
virtual void Mult(const mfem::Vector &x, mfem::Vector &y) const override;
|
||||
void SetCoefficients( std::shared_ptr<mfem::Coefficient> objc);
|
||||
|
||||
mfem::real_t EvalScalar(const mfem::Vector &x) const
|
||||
{
|
||||
mfem::Vector y(1);
|
||||
Mult(x, y);
|
||||
return y[0];
|
||||
}
|
||||
//evaluates the QoIs y[1] for a given state x[2 x fes_->GetTrueVSize()]
|
||||
virtual void Mult(const mfem::Vector &x, mfem::Vector &y) const override;
|
||||
|
||||
void EvalGradient(const mfem::Vector &x, mfem::Vector &grad) const;
|
||||
mfem::real_t EvalScalar(const mfem::Vector &x) const
|
||||
{
|
||||
mfem::Vector y(1);
|
||||
Mult(x, y);
|
||||
return y[0];
|
||||
}
|
||||
|
||||
void EvalGradient(const mfem::Vector &x, mfem::Vector &grad) const;
|
||||
|
||||
|
||||
private:
|
||||
std::shared_ptr<mfem::Coefficient> co;
|
||||
mfem::ParFiniteElementSpace* fes;
|
||||
mutable mfem::ParGridFunction disp;
|
||||
mutable mfem::ParGridFunction velo;
|
||||
std::shared_ptr<mfem::Coefficient> co;
|
||||
mfem::ParFiniteElementSpace* fes;
|
||||
mutable mfem::ParGridFunction disp;
|
||||
mutable mfem::ParGridFunction velo;
|
||||
|
||||
mfem::Operator* grad;
|
||||
mfem::Operator* grad;
|
||||
|
||||
mfem::Array<int> block_true_offsets;
|
||||
|
||||
static constexpr int FDispl = 0; //grid function displacement
|
||||
static constexpr int FVeloc = 1; //grid function velocity
|
||||
static constexpr int Density = 14; // coefficient vector
|
||||
static constexpr int Coords = 15; // coordinates grid function
|
||||
mutable mfem::Vector res;
|
||||
|
||||
// DFEM related definitions (3 objectives)
|
||||
std::unique_ptr<mfem::future::DifferentiableOperator> obj;
|
||||
std::unique_ptr<mfem::ParBilinearForm> mass;
|
||||
|
||||
// density coefficient for computing the objective function
|
||||
std::shared_ptr<mfem::CoefficientVector> density;
|
||||
|
||||
mfem::Array<int> block_true_offsets;
|
||||
|
||||
//uniform parameter space
|
||||
std::unique_ptr<mfem::future::UniformParameterSpace> ups;
|
||||
//quadrature space for the coefficient
|
||||
std::unique_ptr<mfem::QuadratureSpace> qs;
|
||||
|
||||
mfem::ParGridFunction *nodes;
|
||||
mfem::ParFiniteElementSpace *mfes;
|
||||
mfem::Array<int> domain_attributes;
|
||||
const mfem::IntegrationRule *ir;
|
||||
|
||||
mutable mfem::Vector res;
|
||||
};
|
||||
|
||||
#endif // LINEAR_ELASTICITY_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,545 @@
|
||||
#include "linear_elasticity.hpp"
|
||||
|
||||
#include "../chpt/dynamic_checkpointing.hpp"
|
||||
#include "../chpt/fixed_slot_checkpoint_storage.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <cstring>
|
||||
|
||||
using namespace mfem;
|
||||
using namespace std;
|
||||
|
||||
constexpr auto MESH_TRI = MFEM_SOURCE_DIR "/miniapps/mtop/examples/dyn_hex2d_tri.msh";
|
||||
constexpr auto MESH_QUAD = MFEM_SOURCE_DIR "/miniapps/mtop/examples/dyn_hex2d_quad.msh";
|
||||
|
||||
struct State
|
||||
{
|
||||
mfem::real_t time = 0.0; //time of the state
|
||||
mfem::real_t dt=0.0;
|
||||
mfem::real_t obj = 0.0; //accumulated objective
|
||||
mfem::BlockVector v; //state of the system
|
||||
};
|
||||
|
||||
// Snapshot = *view* (non-owning) used only during Store() packing and Read() callback
|
||||
struct StateSnapshotView
|
||||
{
|
||||
mfem::real_t time = 0.0;
|
||||
mfem::real_t dt=0.0;
|
||||
mfem::real_t obj = 0.0;
|
||||
|
||||
// Points to n*sizeof(real_t) bytes:
|
||||
// - during Store(): points to current State::v data (host)
|
||||
// - during Read(): points into the storage slot bytes (valid only during callback)
|
||||
const unsigned char *v_bytes = nullptr;
|
||||
};
|
||||
|
||||
class StateSnapshotViewPacker
|
||||
{
|
||||
public:
|
||||
explicit StateSnapshotViewPacker(int n) : n_(n)
|
||||
{
|
||||
MFEM_VERIFY(n_ > 0, "StateSnapshotViewPacker: n must be > 0.");
|
||||
}
|
||||
|
||||
std::size_t SlotBytes() const
|
||||
{
|
||||
return (std::size_t)(3 + n_) * sizeof(mfem::real_t);
|
||||
}
|
||||
|
||||
void Pack(const StateSnapshotView &s, void *dst) const
|
||||
{
|
||||
MFEM_VERIFY(dst != nullptr, "Pack: dst is null.");
|
||||
MFEM_VERIFY(s.v_bytes != nullptr, "Pack: snapshot v_bytes is null.");
|
||||
|
||||
unsigned char *b = static_cast<unsigned char*>(dst);
|
||||
|
||||
std::memcpy(b + 0*sizeof(mfem::real_t), &s.time, sizeof(mfem::real_t));
|
||||
std::memcpy(b + 1*sizeof(mfem::real_t), &s.dt, sizeof(mfem::real_t));
|
||||
std::memcpy(b + 2*sizeof(mfem::real_t), &s.obj, sizeof(mfem::real_t));
|
||||
|
||||
std::memcpy(b + 3*sizeof(mfem::real_t),
|
||||
s.v_bytes,
|
||||
(std::size_t)n_ * sizeof(mfem::real_t));
|
||||
}
|
||||
|
||||
// Important: Unpack returns a *view* pointing into src bytes (no allocation).
|
||||
void Unpack(const void *src, StateSnapshotView &out) const
|
||||
{
|
||||
MFEM_VERIFY(src != nullptr, "Unpack: src is null.");
|
||||
|
||||
const unsigned char *b = static_cast<const unsigned char*>(src);
|
||||
|
||||
std::memcpy(&out.time, b + 0*sizeof(mfem::real_t), sizeof(mfem::real_t));
|
||||
std::memcpy(&out.dt, b + 1*sizeof(mfem::real_t), sizeof(mfem::real_t));
|
||||
std::memcpy(&out.obj, b + 2*sizeof(mfem::real_t), sizeof(mfem::real_t));
|
||||
|
||||
out.v_bytes = b + 3*sizeof(mfem::real_t);
|
||||
}
|
||||
|
||||
int VectorSize() const { return n_; }
|
||||
|
||||
private:
|
||||
int n_ = 0;
|
||||
};
|
||||
|
||||
struct AdjState
|
||||
{
|
||||
mfem::real_t time;
|
||||
mfem::real_t obj;
|
||||
mfem::BlockVector adj;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief The IsoElasticyLambdaCoeff class converts E modulus of elasticity
|
||||
/// and Poisson's ratio to Lame's lambda coefficient
|
||||
class IsoElasticyLambdaCoeff : public mfem::Coefficient
|
||||
{
|
||||
mfem::Coefficient *E, *nu;
|
||||
|
||||
public:
|
||||
/// Constructor - takes as inputs E modulus and Poisson's ratio
|
||||
IsoElasticyLambdaCoeff(mfem::Coefficient *E,
|
||||
mfem::Coefficient *nu):
|
||||
E(E), nu(nu) { }
|
||||
|
||||
/// Evaluates the Lame's lambda coefficient
|
||||
real_t Eval(mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip) override
|
||||
{
|
||||
const real_t EE = E->Eval(T, ip);
|
||||
const real_t nn = nu->Eval(T, ip);
|
||||
constexpr auto Lambda = [](const real_t E, const real_t nu)
|
||||
{
|
||||
return E * nu / (1.0 + nu) / (1.0 - 2.0 * nu);
|
||||
};
|
||||
return Lambda(EE, nn);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief The IsoElasticySchearCoeff class converts E modulus of elasticity
|
||||
/// and Poisson's ratio to Shear coefficient
|
||||
///
|
||||
class IsoElasticySchearCoeff : public mfem::Coefficient
|
||||
{
|
||||
mfem::Coefficient *E, *nu;
|
||||
|
||||
public:
|
||||
/// Constructor - takes as inputs E modulus and Poisson's ratio
|
||||
IsoElasticySchearCoeff(mfem::Coefficient *E_, mfem::Coefficient *nu_):
|
||||
E(E_), nu(nu_) { }
|
||||
|
||||
/// Evaluates the shear coefficient coefficient
|
||||
real_t Eval(mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip) override
|
||||
{
|
||||
const real_t EE = E->Eval(T, ip);
|
||||
const real_t nn = nu->Eval(T, ip);
|
||||
constexpr auto Schear = [](const real_t E, const real_t nu)
|
||||
{
|
||||
return E / (2.0 * (1.0 + nu));
|
||||
};
|
||||
return Schear(EE, nn);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Initialize MPI and HYPRE.
|
||||
Mpi::Init();
|
||||
Hypre::Init();
|
||||
|
||||
// Parse command-line options.
|
||||
const char *mesh_file = MESH_QUAD;
|
||||
const char *device_config = "cpu";
|
||||
int order = 3;
|
||||
bool mesh_tri = false;
|
||||
bool mesh_quad = false;
|
||||
int par_ref_levels = 1;
|
||||
bool paraview = true;
|
||||
bool visualization = true;
|
||||
int ode_solver_type = 4;
|
||||
real_t Tfinal = 0.07;
|
||||
real_t dt = 0.005;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&mesh_tri, "-tri", "--triangular", "-no-tri",
|
||||
"--no-triangular", "Enable or not triangular mesh.");
|
||||
args.AddOption(&mesh_quad, "-quad", "--quadrilateral", "-no-quad",
|
||||
"--no-quadrilateral", "Enable or not quadrilateral mesh.");
|
||||
args.AddOption(&par_ref_levels, "-prl", "--par-ref-levels",
|
||||
"Number of parallel mesh refinement levels.");
|
||||
args.AddOption(¶view, "-pa", "--paraview", "-no-pa",
|
||||
"--no-paraview", "Enable or not Paraview output.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization", "Enable or not visualization.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
ODESolver::Types.c_str());
|
||||
|
||||
args.AddOption(&Tfinal, "-T",
|
||||
"--tfinal", "Terminate when accumulated time reaches Tfinal.");
|
||||
args.AddOption(&dt, "-dt", "--dt", "Time step.");
|
||||
|
||||
args.ParseCheck();
|
||||
|
||||
// Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
if (Mpi::Root()) { device.Print(); }
|
||||
|
||||
// Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh mesh(mesh_tri ? MESH_TRI : mesh_quad ? MESH_QUAD : mesh_file, 1, 1);
|
||||
const int dim = mesh.Dimension();
|
||||
|
||||
// Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement. We choose
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
// more than 1000 elements.
|
||||
{
|
||||
const int ref_levels =
|
||||
(int)floor(log(1000. / mesh.GetNE()) / log(2.) / dim);
|
||||
for (int l = 0; l < ref_levels; l++) { mesh.UniformRefinement(); }
|
||||
}
|
||||
if (Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of elements: " << mesh.GetNE() << std::endl;
|
||||
}
|
||||
|
||||
// Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
for (int l = 0; l < par_ref_levels; l++) { pmesh.UniformRefinement(); }
|
||||
|
||||
// Allocate the time dependent linear elasticity operator
|
||||
LinearElasticityTimeDependentOperator lin_elasticity_op(pmesh, order);
|
||||
|
||||
// Set the material coefficients
|
||||
ConstantCoefficient rho_coef(0.5); // density coefficient for topology optimization
|
||||
|
||||
// Set elasticity coefficients for material 1 and 2
|
||||
ConstantCoefficient E1(0.1);
|
||||
ConstantCoefficient E2(1.0);
|
||||
ConstantCoefficient nu1(0.3);
|
||||
ConstantCoefficient nu2(0.3);
|
||||
|
||||
//Lame coefficients
|
||||
IsoElasticyLambdaCoeff lambda1(&E1, &nu1);
|
||||
IsoElasticySchearCoeff mu1(&E1, &nu1);
|
||||
IsoElasticyLambdaCoeff lambda2(&E2, &nu2);
|
||||
IsoElasticySchearCoeff mu2(&E2, &nu2);
|
||||
|
||||
// Set density coefficients for material 1 and 2
|
||||
ConstantCoefficient dens1_coef(0.5);
|
||||
ConstantCoefficient dens2_coef(1.0);
|
||||
|
||||
// Set damping coefficients
|
||||
ProductCoefficient cm1_coef(0.02, dens1_coef);
|
||||
ProductCoefficient cm2_coef(0.02, dens2_coef);
|
||||
|
||||
ProductCoefficient cl1_coef(0.01, lambda1);
|
||||
ProductCoefficient cmu1_coef(0.01, mu1);
|
||||
ProductCoefficient cl2_coef(0.01, lambda2);
|
||||
ProductCoefficient cmu2_coef(0.01, mu2);
|
||||
|
||||
lin_elasticity_op.SetElasticityCoefficients(lambda1, mu1, lambda2, mu2);
|
||||
|
||||
lin_elasticity_op.SetDensityMaterialCoefficients(dens1_coef, dens2_coef);
|
||||
|
||||
lin_elasticity_op.SetDampingMaterialCoefficients(cm1_coef, cm2_coef);
|
||||
lin_elasticity_op.SetDampingMaterialCoefficients(cl1_coef, cmu1_coef,
|
||||
cl2_coef, cmu2_coef);
|
||||
|
||||
lin_elasticity_op.SetDensity(rho_coef);
|
||||
|
||||
//set bottom bdr to zero (both the velocities and the displacements)
|
||||
lin_elasticity_op.SetZeroBdr(1);
|
||||
|
||||
lin_elasticity_op.SetVolForce(1.0 /*period*/, 1.0 /*amplitude*/, 0.2 /*radius*/,
|
||||
0.0 /*x center*/ , 0.0 /*y center*/, 0.0 /*z center*/,
|
||||
5.0 /* train length*/, 2.5 /*center of the train*/, 2.0 /*power*/);
|
||||
|
||||
lin_elasticity_op.AssembleExplicit();
|
||||
|
||||
// test mult explicit
|
||||
{
|
||||
BlockVector tst; tst.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
tst=0.0; //tst.Randomize();
|
||||
tst.UseDevice(true); tst.Read();
|
||||
|
||||
BlockVector grd; grd.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
grd=0.0;
|
||||
lin_elasticity_op.Mult(tst,grd);
|
||||
lin_elasticity_op.GetVelocity().SetFromTrueDofs(grd.GetBlock(1));
|
||||
}
|
||||
|
||||
std::shared_ptr<ExampleObjectiveIntegrand> eobj=
|
||||
std::make_shared<ExampleObjectiveIntegrand>(lin_elasticity_op.GetFESpace());
|
||||
//set the objective for the integration process
|
||||
|
||||
ParaViewDataCollection paraview_dc("isoel", &pmesh);
|
||||
paraview_dc.SetPrefixPath("ParaView");
|
||||
paraview_dc.SetLevelsOfDetail(order);
|
||||
paraview_dc.SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc.SetHighOrderOutput(true);
|
||||
paraview_dc.RegisterField("disp", &(lin_elasticity_op.GetDisplacement()));
|
||||
paraview_dc.RegisterField("velo", &(lin_elasticity_op.GetVelocity()));
|
||||
|
||||
// 4. Define the ODE solver used for time integration. Several explicit
|
||||
// Runge-Kutta methods are available.
|
||||
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
|
||||
|
||||
lin_elasticity_op.SetTime(0.0);
|
||||
ode_solver->Init(lin_elasticity_op);
|
||||
|
||||
//random perturbation of the initial conditions
|
||||
BlockVector p; p.Update(lin_elasticity_op.GetTrueBlockOffsets()); p=0.0;
|
||||
Vector tmpv(p.GetBlock(0)); tmpv=0.0;
|
||||
|
||||
//Forward computations
|
||||
{
|
||||
int s=10; //number of snapshots to be stored by the checkpointing process
|
||||
|
||||
//define the packer object
|
||||
int n=lin_elasticity_op.GetState().Size();
|
||||
StateSnapshotViewPacker packer(n);
|
||||
|
||||
// storage stores StateSnapshotView snapshots using fixed-size slots
|
||||
using Storage=mfem::FixedSlotMemoryCheckpointStorage<StateSnapshotView, StateSnapshotViewPacker>;
|
||||
Storage storage(s, packer);
|
||||
|
||||
// Snapshot type is StateSnapshotView
|
||||
using Checkpointing = mfem::DynamicCheckpointing<StateSnapshotView, Storage>;
|
||||
Checkpointing ckpt(s, storage);
|
||||
|
||||
// Returns view of the State and avoids data transfer
|
||||
auto make_snapshot = [&](const State &u) -> StateSnapshotView
|
||||
{
|
||||
MFEM_VERIFY(u.v.Size() == n, "make_snapshot: State.v size changed!");
|
||||
|
||||
// Ensure host access if MFEM device is in use:
|
||||
const mfem::real_t *vh = u.v.HostRead();
|
||||
|
||||
StateSnapshotView snap;
|
||||
snap.time = u.time;
|
||||
snap.obj = u.obj;
|
||||
snap.v_bytes = reinterpret_cast<const unsigned char*>(vh);
|
||||
return snap;
|
||||
};
|
||||
|
||||
//Transfers data from the snaphot view to the State u_out.
|
||||
auto restore_snapshot = [&](const StateSnapshotView &snap, State &u_out)
|
||||
{
|
||||
u_out.time = snap.time;
|
||||
u_out.obj = snap.obj;
|
||||
|
||||
if (u_out.v.Size() != n) { u_out.v.SetSize(n); }
|
||||
|
||||
mfem::real_t *vh = u_out.v.HostWrite();
|
||||
std::memcpy(vh,
|
||||
snap.v_bytes,
|
||||
(std::size_t)n * sizeof(mfem::real_t));
|
||||
|
||||
//make sure that the date is on the device
|
||||
u_out.v.Read(true);
|
||||
};
|
||||
|
||||
using Step = mfem::DynamicCheckpointing<StateSnapshotView, Storage>::Step;
|
||||
|
||||
|
||||
//execute one integration step
|
||||
auto primal_step = [&](State &u_st, Step i)
|
||||
{
|
||||
//begin with curent state u_st
|
||||
real_t t=u_st.time;
|
||||
real_t ldt=dt;
|
||||
real_t obj=u_st.obj;
|
||||
|
||||
//make sure the integration does not overjump Tfinal
|
||||
if((t+ldt)>Tfinal){
|
||||
ldt=Tfinal-t;
|
||||
}
|
||||
|
||||
//advance u_st
|
||||
ode_solver->Step(u_st.v,t,ldt);
|
||||
//update objective
|
||||
obj=eobj->EvalScalar(u_st.v);
|
||||
|
||||
//return updated u_st
|
||||
u_st.dt=t-u_st.time;
|
||||
u_st.time=t;
|
||||
u_st.obj=obj;
|
||||
};
|
||||
|
||||
|
||||
auto adjoint_step = [&](AdjState &adj_st, const State &u_st, Step i)
|
||||
{
|
||||
real_t t=u_st.time;
|
||||
real_t ldt=u_st.dt;
|
||||
real_t obj=u_st.obj;
|
||||
|
||||
ode_solver->EnableAdjoint(mfem::ODESolver::AdjointMode::Discrete);
|
||||
ode_solver->SetSolution(u_st.v,t);
|
||||
ode_solver->AdjointStep(adj_st.adj,t,ldt);
|
||||
ode_solver->EnableAdjoint(mfem::ODESolver::AdjointMode::None);
|
||||
adj_st.time=t;
|
||||
adj_st.obj=obj;
|
||||
};
|
||||
|
||||
BlockVector x0; x0.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
x0=0.0;
|
||||
|
||||
//optimization loop
|
||||
for(int ii=0;ii<1;ii++){
|
||||
|
||||
ParaViewDataCollection paraview_dc("frw", &pmesh);
|
||||
paraview_dc.SetPrefixPath("ParaView");
|
||||
paraview_dc.SetLevelsOfDetail(order);
|
||||
paraview_dc.SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc.SetHighOrderOutput(true);
|
||||
paraview_dc.RegisterField("disp", &(lin_elasticity_op.GetDisplacement()));
|
||||
paraview_dc.RegisterField("velo", &(lin_elasticity_op.GetVelocity()));
|
||||
|
||||
|
||||
State u;
|
||||
//u.v.SetSize(lin_elasticity_op.GetState().Size());
|
||||
u.v.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
u.obj=0.0;
|
||||
u.time=0.0;
|
||||
u.dt=0.0;
|
||||
|
||||
//set initial state to 0
|
||||
u.v=0.0;
|
||||
u.v.Set(1.0,x0);
|
||||
|
||||
// Forward sweep (unknown number of steps)
|
||||
real_t t = 0.0;
|
||||
Step i = 0;
|
||||
|
||||
paraview_dc.SetCycle(0);
|
||||
paraview_dc.SetTime(t);
|
||||
lin_elasticity_op.GetVelocity().SetFromTrueDofs(u.v.GetBlock(1));
|
||||
lin_elasticity_op.GetDisplacement().SetFromTrueDofs(u.v.GetBlock(0));
|
||||
paraview_dc.Save();
|
||||
|
||||
|
||||
while(t<Tfinal)
|
||||
{
|
||||
ckpt.ForwardStep(i,u, primal_step, make_snapshot);
|
||||
t=u.time;
|
||||
++i;
|
||||
|
||||
if((i%5)==0){
|
||||
paraview_dc.SetCycle(i+1);
|
||||
paraview_dc.SetTime(t);
|
||||
lin_elasticity_op.GetVelocity().SetFromTrueDofs(u.v.GetBlock(1));
|
||||
lin_elasticity_op.GetDisplacement().SetFromTrueDofs(u.v.GetBlock(0));
|
||||
paraview_dc.Save();
|
||||
}
|
||||
}
|
||||
|
||||
//Do one more time step without checkpointing
|
||||
//advance u_st
|
||||
ode_solver->Step(u.v,t,dt);
|
||||
//update objective
|
||||
real_t obj=eobj->EvalScalar(u.v);
|
||||
|
||||
{
|
||||
paraview_dc.SetCycle(i+1);
|
||||
paraview_dc.SetTime(t);
|
||||
lin_elasticity_op.GetVelocity().SetFromTrueDofs(u.v.GetBlock(1));
|
||||
lin_elasticity_op.GetDisplacement().SetFromTrueDofs(u.v.GetBlock(0));
|
||||
paraview_dc.Save();
|
||||
}
|
||||
|
||||
if(Mpi::Root())
|
||||
{
|
||||
std::cout<<"Total number of steps i="<<i<<" t="<<t<<" obj="<<obj<<std::endl;
|
||||
std::cout<<"Start adjoint steps!"<<std::endl;
|
||||
}
|
||||
|
||||
ParGridFunction adisp(lin_elasticity_op.GetDisplacement());
|
||||
ParGridFunction avelo(lin_elasticity_op.GetVelocity());
|
||||
ParaViewDataCollection paraview_ac("adj", &pmesh);
|
||||
paraview_ac.SetPrefixPath("ParaView");
|
||||
paraview_ac.SetLevelsOfDetail(order);
|
||||
paraview_ac.SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_ac.SetHighOrderOutput(true);
|
||||
paraview_ac.RegisterField("adisp", &(adisp));
|
||||
paraview_ac.RegisterField("avelo", &(avelo));
|
||||
|
||||
// define the adjoint state
|
||||
AdjState adj_st;
|
||||
//adj_st.adj.SetSize(lin_elasticity_op.GetState().Size());
|
||||
adj_st.adj.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
adj_st.adj=0.0;
|
||||
eobj->EvalGradient(u.v,adj_st.adj);
|
||||
adj_st.obj=obj;
|
||||
adj_st.time=t;
|
||||
|
||||
paraview_ac.SetCycle(i);
|
||||
paraview_ac.SetTime(t);
|
||||
lin_elasticity_op.MultInvMass(adj_st.adj.GetBlock(0),tmpv);
|
||||
adisp.SetFromTrueDofs(tmpv);
|
||||
lin_elasticity_op.MultInvMass(adj_st.adj.GetBlock(1),tmpv);
|
||||
avelo.SetFromTrueDofs(tmpv);
|
||||
paraview_ac.Save();
|
||||
|
||||
|
||||
//step backward
|
||||
const Step m=i;
|
||||
|
||||
//tmp state for stepping backward
|
||||
State u_wrk;
|
||||
//u_wrk.v.SetSize(lin_elasticity_op.GetState().Size());
|
||||
u_wrk.v.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
u_wrk.obj=0.0;
|
||||
u_wrk.time=0.0;
|
||||
u_wrk.dt=0.0;
|
||||
|
||||
for (Step i = m - 1; i >= 0; --i)
|
||||
{
|
||||
ckpt.BackwardStep(i,adj_st, u_wrk,
|
||||
primal_step, adjoint_step,
|
||||
make_snapshot, restore_snapshot);
|
||||
|
||||
if((i%5)==0){
|
||||
paraview_ac.SetCycle(i);
|
||||
paraview_ac.SetTime(adj_st.time);
|
||||
//adisp.SetFromTrueDofs(adj_st.adj.GetBlock(0));
|
||||
//avelo.SetFromTrueDofs(adj_st.adj.GetBlock(1));
|
||||
lin_elasticity_op.MultInvMass(adj_st.adj.GetBlock(0),tmpv);
|
||||
adisp.SetFromTrueDofs(tmpv);
|
||||
lin_elasticity_op.MultInvMass(adj_st.adj.GetBlock(1),tmpv);
|
||||
avelo.SetFromTrueDofs(tmpv);
|
||||
paraview_ac.Save();
|
||||
}
|
||||
|
||||
if (i == 0) { break; }
|
||||
}
|
||||
|
||||
lin_elasticity_op.MultInvMass(adj_st.adj.GetBlock(0),tmpv);
|
||||
x0.GetBlock(0).Add(-0.1,tmpv);
|
||||
lin_elasticity_op.MultInvMass(adj_st.adj.GetBlock(1),tmpv);
|
||||
x0.GetBlock(1).Add(-0.1,tmpv);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,26 +1,17 @@
|
||||
#include "linear_elasticity.hpp"
|
||||
|
||||
// #include "../chpt/dynamic_checkpointing.hpp"
|
||||
// #include "../chpt/fixed_slot_checkpoint_storage.hpp"
|
||||
#include "../chpt/dynamic_checkpointing.hpp"
|
||||
#include "../chpt/fixed_slot_checkpoint_storage.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <cstring>
|
||||
|
||||
using namespace mfem;
|
||||
using namespace std;
|
||||
|
||||
#ifdef NVTX_DEBUG_HPP
|
||||
#undef NVTX_COLOR
|
||||
#define NVTX_COLOR ::nvtx::kCyan
|
||||
#include NVTX_DEBUG_HPP
|
||||
#else
|
||||
#define dbg(...)
|
||||
#endif
|
||||
|
||||
constexpr auto MESH_TRI = MFEM_SOURCE_DIR
|
||||
"/miniapps/mtop/examples/dyn_hex2d_tri.msh";
|
||||
constexpr auto MESH_QUAD = MFEM_SOURCE_DIR
|
||||
"/miniapps/mtop/examples/dyn_hex2d_quad.msh";
|
||||
constexpr auto MESH_TRI = MFEM_SOURCE_DIR "/miniapps/mtop/examples/dyn_hex2d_tri.msh";
|
||||
constexpr auto MESH_QUAD = MFEM_SOURCE_DIR "/miniapps/mtop/examples/dyn_hex2d_quad.msh";
|
||||
|
||||
struct State
|
||||
{
|
||||
@@ -157,8 +148,6 @@ public:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
dbg();
|
||||
|
||||
// Initialize MPI and HYPRE.
|
||||
Mpi::Init();
|
||||
Hypre::Init();
|
||||
@@ -170,8 +159,7 @@ int main(int argc, char *argv[])
|
||||
bool mesh_tri = false;
|
||||
bool mesh_quad = false;
|
||||
int par_ref_levels = 1;
|
||||
int max_steps = 1000;
|
||||
bool paraview = false;
|
||||
bool paraview = true;
|
||||
bool visualization = true;
|
||||
int ode_solver_type = 4;
|
||||
|
||||
@@ -188,29 +176,26 @@ int main(int argc, char *argv[])
|
||||
"--no-quadrilateral", "Enable or not quadrilateral mesh.");
|
||||
args.AddOption(&par_ref_levels, "-prl", "--par-ref-levels",
|
||||
"Number of parallel mesh refinement levels.");
|
||||
args.AddOption(&max_steps, "-ms", "--max-steps",
|
||||
"Maximum number of time steps.");
|
||||
args.AddOption(¶view, "-pa", "--paraview", "-no-pa",
|
||||
"--no-paraview", "Enable or not Paraview output.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization", "Enable or not visualization.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
ODESolver::Types.c_str());
|
||||
|
||||
args.ParseCheck();
|
||||
dbg("mesh_file: {}", mesh_file);
|
||||
|
||||
// Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
if (Mpi::Root()) { device.Print(); }
|
||||
|
||||
|
||||
// Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh mesh(mesh_tri ? MESH_TRI : mesh_quad ? MESH_QUAD : mesh_file, 1, 1);
|
||||
const int dim = mesh.Dimension();
|
||||
|
||||
|
||||
// Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement. We choose
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
@@ -223,7 +208,6 @@ int main(int argc, char *argv[])
|
||||
if (Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of elements: " << mesh.GetNE() << std::endl;
|
||||
dbg("Number of elements: {}", mesh.GetNE());
|
||||
}
|
||||
|
||||
// Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
@@ -231,15 +215,14 @@ int main(int argc, char *argv[])
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
for (int l = 0; l < par_ref_levels; l++) { pmesh.UniformRefinement(); }
|
||||
for (int l = 0; l < par_ref_levels; l++) { pmesh.UniformRefinement(); }
|
||||
|
||||
// Allocate the time dependent linear elasticity operator
|
||||
LinearElasticityTimeDependentOperator lin_elasticity_op(pmesh, order);
|
||||
|
||||
// Set the material coefficients
|
||||
ConstantCoefficient rho_coef(
|
||||
0.5); // density coefficient for topology optimization
|
||||
|
||||
ConstantCoefficient rho_coef(0.5); // density coefficient for topology optimization
|
||||
|
||||
// Set elasticity coefficients for material 1 and 2
|
||||
ConstantCoefficient E1(0.1);
|
||||
ConstantCoefficient E2(1.0);
|
||||
@@ -266,27 +249,27 @@ int main(int argc, char *argv[])
|
||||
ProductCoefficient cmu2_coef(0.01, mu2);
|
||||
|
||||
lin_elasticity_op.SetElasticityCoefficients(lambda1, mu1, lambda2, mu2);
|
||||
|
||||
|
||||
lin_elasticity_op.SetDensityMaterialCoefficients(dens1_coef, dens2_coef);
|
||||
|
||||
|
||||
lin_elasticity_op.SetDampingMaterialCoefficients(cm1_coef, cm2_coef);
|
||||
lin_elasticity_op.SetDampingMaterialCoefficients(cl1_coef, cmu1_coef,
|
||||
cl2_coef, cmu2_coef);
|
||||
|
||||
lin_elasticity_op.SetDensity(rho_coef);
|
||||
|
||||
|
||||
//set bottom bdr to zero (both the velocities and the displacements)
|
||||
lin_elasticity_op.SetZeroBdr(1);
|
||||
|
||||
lin_elasticity_op.SetVolForce(1.0 /*period*/, 1.0 /*amplitude*/, 0.2 /*radius*/,
|
||||
0.0 /*x center*/, 0.0 /*y center*/, 0.0 /*z center*/,
|
||||
0.0 /*x center*/ , 0.0 /*y center*/, 0.0 /*z center*/,
|
||||
5.0 /* train length*/, 2.5 /*center of the train*/, 2.0 /*power*/);
|
||||
|
||||
lin_elasticity_op.AssembleExplicit();
|
||||
|
||||
// test mult explicit
|
||||
{
|
||||
BlockVector tst; tst.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
BlockVector tst; tst.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
tst=0.0; //tst.Randomize();
|
||||
tst.UseDevice(true); tst.Read();
|
||||
|
||||
@@ -294,7 +277,7 @@ int main(int argc, char *argv[])
|
||||
grd=0.0;
|
||||
lin_elasticity_op.Mult(tst,grd);
|
||||
lin_elasticity_op.GetVelocity().SetFromTrueDofs(grd.GetBlock(1));
|
||||
}
|
||||
}
|
||||
|
||||
ParaViewDataCollection paraview_dc("isoel", &pmesh);
|
||||
paraview_dc.SetPrefixPath("ParaView");
|
||||
@@ -380,7 +363,7 @@ int main(int argc, char *argv[])
|
||||
};
|
||||
|
||||
|
||||
// Initial condition
|
||||
// Initial condition
|
||||
StateCheckPoint spt; spt.obj=-1.0; spt.time=-1.0; spt.state=(lin_elasticity_op.GetState());
|
||||
|
||||
Step i=0;
|
||||
@@ -398,7 +381,7 @@ int main(int argc, char *argv[])
|
||||
std::cout<<" Total number of steps="<<m<<std::endl;
|
||||
}
|
||||
|
||||
AdjState ast; ast.obj=1.0; ast.time=spt.time;
|
||||
AdjState ast; ast.obj=1.0; ast.time=spt.time;
|
||||
ast.adj=(lin_elasticity_op.GetState());
|
||||
ast.grd=(lin_elasticity_op.GetState());
|
||||
|
||||
@@ -409,19 +392,77 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
ckpt.BackwardStep(j, ast, spt, primal_step, adjoint_step, make_snapshot, restore_snapshot);
|
||||
|
||||
|
||||
if (j == 0) { break; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
//Test Jacobian transpose
|
||||
{
|
||||
BlockVector x; x.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
BlockVector w; w.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
BlockVector d; d.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
BlockVector g; g.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
x.Randomize();
|
||||
|
||||
real_t t = 0.0;
|
||||
|
||||
ExampleObjectiveIntegrand* obj=new ExampleObjectiveIntegrand(lin_elasticity_op.GetFESpace());
|
||||
|
||||
lin_elasticity_op.Mult(x,d);
|
||||
real_t oo=obj->EvalScalar(d);
|
||||
if(Mpi::Root())
|
||||
{
|
||||
std::cout<<"t="<<t<<" oo="<<oo<<std::endl;
|
||||
}
|
||||
|
||||
obj->EvalGradient(d,w);
|
||||
lin_elasticity_op.JacobianMultTranspose(x,w,g); //the gradient is in g
|
||||
|
||||
//FD check
|
||||
{
|
||||
BlockVector rnd; rnd.Update(lin_elasticity_op.GetTrueBlockOffsets());
|
||||
rnd.Randomize();
|
||||
real_t sca=1.0;
|
||||
|
||||
real_t ipr=mfem::InnerProduct(pmesh.GetComm(),rnd,g);
|
||||
|
||||
for(int i=0;i<20;i++){
|
||||
w.Set(sca,rnd);
|
||||
w.Add(1.0,x);
|
||||
lin_elasticity_op.Mult(w,d);
|
||||
real_t co=obj->EvalScalar(d);
|
||||
|
||||
w.Set(-sca,rnd);
|
||||
w.Add(1.0,x);
|
||||
lin_elasticity_op.Mult(w,d);
|
||||
real_t mo=obj->EvalScalar(d);
|
||||
|
||||
|
||||
if(Mpi::Root())
|
||||
{
|
||||
std::cout<<"s="<<sca<<" o="<<oo<<" c="<<co<<" gr="
|
||||
<<ipr<<" fd="<<(co-oo)/sca
|
||||
<<" cd="<<(co-mo)/(2.0*sca)<<std::endl;
|
||||
}
|
||||
sca=sca/2;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
delete obj;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//test time integration
|
||||
/*
|
||||
{
|
||||
real_t t = 0.0;
|
||||
|
||||
@@ -429,6 +470,16 @@ int main(int argc, char *argv[])
|
||||
//set initial conditions at time t
|
||||
tsol=0.0;
|
||||
|
||||
ExampleObjectiveIntegrand* obj=new ExampleObjectiveIntegrand(lin_elasticity_op.GetFESpace());
|
||||
|
||||
real_t oo=obj->EvalScalar(tsol);
|
||||
if(Mpi::Root())
|
||||
{
|
||||
std::cout<<"t="<<t<<" oo="<<oo<<std::endl;
|
||||
}
|
||||
|
||||
delete obj;
|
||||
|
||||
// 4. Define the ODE solver used for time integration. Several explicit
|
||||
// Runge-Kutta methods are available.
|
||||
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
|
||||
@@ -445,47 +496,34 @@ int main(int argc, char *argv[])
|
||||
real_t dt_real = 0.005;
|
||||
//ode_solver->Run(tsol, t, dt_real, 1.0);
|
||||
|
||||
for (int i=0; i< std::min(max_steps, 6000); i++)
|
||||
{
|
||||
dbg("#{}", i);
|
||||
for(int i=0;i<2000; i++){
|
||||
ode_solver->Step(tsol, t, dt_real);
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
std::cout << "t: " << t << std::endl;
|
||||
std::cout << "t: " << t << std::endl;
|
||||
}
|
||||
|
||||
if (paraview && (i%5)==0)
|
||||
{
|
||||
dbg("Paraview output at step {} time {}", i, t);
|
||||
if((i%5)==0){
|
||||
paraview_dc.SetCycle(i+1);
|
||||
paraview_dc.SetTime(t);
|
||||
lin_elasticity_op.GetVelocity().SetFromTrueDofs(tsol.GetBlock(1));
|
||||
lin_elasticity_op.GetDisplacement().SetFromTrueDofs(tsol.GetBlock(0));
|
||||
paraview_dc.Save();
|
||||
}
|
||||
|
||||
if (socketstream glvis; visualization && (i%10)==0 &&
|
||||
((glvis.open("localhost", 19916)),
|
||||
(glvis.is_open() ? glvis.precision(8) : 0),
|
||||
(glvis.is_open() ? (glvis << "mgjR" << std::endl, 0) : 0),
|
||||
(glvis.is_open())))
|
||||
{
|
||||
dbg("GLVis output at step {} time {}", i, t);
|
||||
glvis << "parallel " << Mpi::WorldSize() << " " << Mpi::WorldRank() << "\n";
|
||||
|
||||
lin_elasticity_op.GetVelocity().SetFromTrueDofs(tsol.GetBlock(1));
|
||||
ParGridFunction velocity(lin_elasticity_op.GetVelocity());
|
||||
|
||||
// lin_elasticity_op.GetDisplacement().SetFromTrueDofs(tsol.GetBlock(0));
|
||||
// ParGridFunction displacement(lin_elasticity_op.GetDisplacement());
|
||||
|
||||
glvis << "solution\n" << pmesh << velocity << std::flush;
|
||||
glvis << "keys g\n" << std::flush; // pause
|
||||
}
|
||||
}
|
||||
|
||||
obj=new ExampleObjectiveIntegrand(lin_elasticity_op.GetFESpace());
|
||||
oo=obj->EvalScalar(tsol);
|
||||
if(Mpi::Root())
|
||||
{
|
||||
std::cout<<"t="<<t<<" oo="<<oo<<std::endl;
|
||||
}
|
||||
|
||||
delete obj;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
if (paraview)
|
||||
|
||||
@@ -0,0 +1,538 @@
|
||||
#include "mfem.hpp"
|
||||
|
||||
|
||||
class InterpCoeff: public mfem::Coefficient
|
||||
{
|
||||
public:
|
||||
InterpCoeff(std::shared_ptr<mfem::Coefficient> c1_,
|
||||
std::shared_ptr<mfem::Coefficient> c2_,
|
||||
std::shared_ptr<mfem::Coefficient> rho_)
|
||||
: c1(c1_), c2(c2_), rho(rho_)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual mfem::real_t Eval (mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip)
|
||||
{
|
||||
mfem::real_t v1=c1->Eval(T,ip);
|
||||
mfem::real_t v2=c2->Eval(T,ip);
|
||||
mfem::real_t r=rho->Eval(T,ip);
|
||||
|
||||
return v1*r+v2*(1.0-r);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<mfem::Coefficient> c1;
|
||||
std::shared_ptr<mfem::Coefficient> c2;
|
||||
std::shared_ptr<mfem::Coefficient> rho;
|
||||
};
|
||||
|
||||
|
||||
namespace mfem{
|
||||
|
||||
class PAExplicitDiffusionOperator : public TimeDependentOperator
|
||||
{
|
||||
private:
|
||||
ParFiniteElementSpace &pfes;
|
||||
Array<int> ess_tdof_list;
|
||||
|
||||
// Partially assembled bilinear forms (no assembled sparse matrices)
|
||||
ParBilinearForm k_form; // diffusion stiffness
|
||||
|
||||
// Minv(i) = 1 / diag(M)(i) on TRUE dofs
|
||||
Vector Minv;
|
||||
mutable Vector tmpv;
|
||||
|
||||
public:
|
||||
/// ess_bdr: boundary attribute marker (size = pmesh->bdr_attributes.Max()), 1 -> essential (Dirichlet)
|
||||
/// kappa: diffusivity coefficient
|
||||
PAExplicitDiffusionOperator(ParFiniteElementSpace &pfes_,
|
||||
const Array<int> &ess_tdof_list_,
|
||||
Coefficient &kappa)
|
||||
: TimeDependentOperator(pfes_.GetTrueVSize(), 0.0, TimeDependentOperator::EXPLICIT),
|
||||
pfes(pfes_),
|
||||
k_form(&pfes_),
|
||||
Minv(height),
|
||||
tmpv(height)
|
||||
{
|
||||
// Essential TRUE dofs
|
||||
// pfes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
ess_tdof_list=ess_tdof_list_;
|
||||
|
||||
// --- Mass operator (PA) ---
|
||||
auto mifi=new MassIntegrator();
|
||||
int order=pfes.GetOrder(0);
|
||||
IntegrationRules gll_rules(0, Quadrature1D::GaussLobatto);
|
||||
const IntegrationRule &ir_ni = gll_rules.Get(pfes.GetParMesh()->GetTypicalElementGeometry(),
|
||||
2 * order - 1);
|
||||
mifi->SetIntRule(&ir_ni);
|
||||
|
||||
ParBilinearForm m_form(&pfes); // mass
|
||||
m_form.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
m_form.AddDomainIntegrator(mifi);
|
||||
m_form.Assemble();
|
||||
|
||||
// Diagonal on TRUE dofs (works with PA in ParBilinearForm)
|
||||
Vector Mdiag(height);
|
||||
m_form.AssembleDiagonal(Mdiag);
|
||||
|
||||
Minv = Mdiag;
|
||||
Minv.Reciprocal();
|
||||
|
||||
// --- Diffusion operator (PA) ---
|
||||
k_form.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
k_form.AddDomainIntegrator(new DiffusionIntegrator(kappa));
|
||||
k_form.Assemble();
|
||||
}
|
||||
|
||||
/// Compute du_dt = -Minv .* (K u)
|
||||
void Mult(const Vector &u, Vector &du_dt) const override
|
||||
{
|
||||
du_dt = 0.0;
|
||||
|
||||
// du_dt += -1 * (P^T K_local P) u (true-dof action; PA supported)
|
||||
k_form.TrueAddMult(u, du_dt, -1.0);
|
||||
|
||||
// Apply diagonal inverse mass
|
||||
du_dt *= Minv;
|
||||
|
||||
// Strongly enforce Dirichlet: derivative is zero on essential tdofs
|
||||
if (ess_tdof_list.Size())
|
||||
{
|
||||
du_dt.SetSubVector(ess_tdof_list, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
const Array<int> &GetEssentialTrueDofs() const { return ess_tdof_list; }
|
||||
|
||||
/// y = (df/dx(x,t))^T * w
|
||||
void JacobianMultTranspose(const Vector &x,
|
||||
const Vector &w,
|
||||
Vector &y) const override
|
||||
{
|
||||
y=0.0;
|
||||
tmpv.Set(1.0,w);
|
||||
if (ess_tdof_list.Size()){
|
||||
tmpv.SetSubVector(ess_tdof_list, 0.0);}
|
||||
// Apply diagonal inverse mass
|
||||
tmpv*=Minv;
|
||||
// y += -1 * (P^T K_local P) u (true-dof action; PA supported)
|
||||
k_form.TrueAddMult(tmpv, y, -1.0);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class DiffusionTDOP:public mfem::TimeDependentOperator
|
||||
{
|
||||
public:
|
||||
DiffusionTDOP(mfem::ParMesh* mesh_, int vorder =1, int dorder=1):order(vorder)
|
||||
{
|
||||
mesh=mesh_;
|
||||
int dim=mesh->Dimension();
|
||||
fec.reset(new mfem::H1_FECollection(vorder,dim));
|
||||
fes.reset(new mfem::ParFiniteElementSpace(mesh,fec.get()));
|
||||
|
||||
dfec.reset(new mfem::H1_FECollection(dorder,dim));
|
||||
dfes.reset(new mfem::ParFiniteElementSpace(mesh,dfec.get()));
|
||||
|
||||
gfdens.SetSpace(dfes.get());
|
||||
|
||||
|
||||
//the state vector of the TDOP consists of [solution, density, obj]
|
||||
siz_u=fes->GetTrueVSize(); //solution
|
||||
siz_d=dfes->GetTrueVSize(); //design
|
||||
siz_f=1; //objective;
|
||||
|
||||
block_true_offsets.SetSize(4);
|
||||
block_true_offsets[0] = 0;
|
||||
block_true_offsets[1] = siz_u;
|
||||
block_true_offsets[2] = siz_d;
|
||||
block_true_offsets[3] = siz_f;
|
||||
block_true_offsets.PartialSum();
|
||||
|
||||
//set the width and the height of the operator
|
||||
this->width= block_true_offsets[3];
|
||||
this->height= block_true_offsets[3];
|
||||
}
|
||||
|
||||
const mfem::ParFiniteElementSpace* GetStateFES(){ return fes.get(); }
|
||||
const mfem::ParFiniteElementSpace* GetDesignFEM(){ return dfes.get(); }
|
||||
|
||||
virtual
|
||||
~DiffusionTDOP()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SetLoad(int ind, std::shared_ptr<mfem::Coefficient> l)
|
||||
{
|
||||
load[ind]=l;
|
||||
}
|
||||
|
||||
void SetZeroBC(int ind)
|
||||
{
|
||||
zero_bc.insert(ind);
|
||||
}
|
||||
|
||||
// free the allocated bilinear forms, matrices and solvers
|
||||
void Reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// Asembles the load, the mass and the stiffness matrices for
|
||||
/// a give true vector tvdens with densities varying from 0 to 1
|
||||
/// and a given time t.
|
||||
void Assemble(const mfem::Vector& tvdens, mfem::real_t t)
|
||||
{
|
||||
|
||||
gfdens.SetFromTrueDofs(tvdens);
|
||||
gfc.reset(new mfem::GridFunctionCoefficient(&gfdens));
|
||||
|
||||
if(nullptr==kbf.get())
|
||||
{
|
||||
// set constrained dofs
|
||||
SetEssTDofs(ess_tdofv);
|
||||
//allocate the system matrices and solvers
|
||||
//allocate diagonal mass matrix and its inverse
|
||||
{
|
||||
mfem::IntegrationRules gll_rules(0, mfem::Quadrature1D::GaussLobatto);
|
||||
const mfem::IntegrationRule &ir_ni = gll_rules.Get(mesh->GetTypicalElementGeometry(),
|
||||
2 * order - 1);
|
||||
|
||||
mfem::ParBilinearForm mform(fes.get());
|
||||
mform.SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
||||
cs.reset(new InterpCoeff(cs1,cs2,gfc));
|
||||
auto *mblfi = new mfem::MassIntegrator(*cs);
|
||||
mblfi->SetIntRule(&ir_ni);
|
||||
mform.AddDomainIntegrator(mblfi);
|
||||
|
||||
mfem::Vector diag(fes->GetTrueVSize());
|
||||
mform.AssembleDiagonal(diag);
|
||||
minv=diag;
|
||||
minv.Reciprocal();
|
||||
// Ensure essential dofs stay fixed: zero inverse there (extra safety)
|
||||
if (ess_tdofv.Size())
|
||||
{
|
||||
minv.SetSubVector(ess_tdofv, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
//allocate the stiffness matrix
|
||||
{
|
||||
kap.reset(new InterpCoeff(kap1,kap2,gfc));
|
||||
kbf.reset(new mfem::ParBilinearForm(fes.get()));
|
||||
kbf->SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
||||
kbf->AddDomainIntegrator(new mfem::DiffusionIntegrator(*kap));
|
||||
kbf->Assemble();
|
||||
}
|
||||
}
|
||||
|
||||
//allocate the RHS
|
||||
|
||||
|
||||
}
|
||||
|
||||
virtual
|
||||
void Mult(const mfem::Vector& x, mfem::Vector& y) const override
|
||||
{
|
||||
mfem::BlockVector bx(const_cast<mfem::Vector&>(x), block_true_offsets);
|
||||
mfem::BlockVector by(y, block_true_offsets);
|
||||
//compute the time derivatives
|
||||
//compute the time derivative of the objective
|
||||
}
|
||||
|
||||
|
||||
void SetEssTDofs(mfem::Array<int>& ess_dofs)
|
||||
{
|
||||
ess_dofs.DeleteAll();
|
||||
|
||||
mfem::Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
ess_bdr=0;
|
||||
for (auto it=zero_bc.begin(); it!=zero_bc.end(); ++it)
|
||||
{
|
||||
int attr = *it;
|
||||
ess_bdr[attr-1] = 1;
|
||||
}
|
||||
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_dofs);
|
||||
}
|
||||
|
||||
/// Sets Dirichlet dofs to zero
|
||||
void SetEssTDofs(mfem::Vector& v) const
|
||||
{
|
||||
mfem::Array<int> loc_tdofs;
|
||||
mfem::Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
ess_bdr=0;
|
||||
for (auto it=zero_bc.begin(); it!=zero_bc.end(); ++it)
|
||||
{
|
||||
int attr = *it;
|
||||
ess_bdr[attr-1] = 1;
|
||||
}
|
||||
|
||||
fes->GetEssentialTrueDofs(ess_bdr, loc_tdofs);
|
||||
|
||||
for (int j=0; j<loc_tdofs.Size(); j++)
|
||||
{
|
||||
v[loc_tdofs[j]]=0.0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
int order;
|
||||
mfem::ParMesh* mesh;
|
||||
std::unique_ptr<mfem::FiniteElementCollection> fec;
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> fes;
|
||||
|
||||
std::unique_ptr<mfem::FiniteElementCollection> dfec;
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> dfes;
|
||||
|
||||
std::unique_ptr<mfem::HypreBoomerAMG> prec;
|
||||
std::unique_ptr<mfem::CGSolver> ls;
|
||||
|
||||
std::shared_ptr<mfem::Coefficient> kap1, kap2;
|
||||
std::shared_ptr<mfem::Coefficient> cs1, cs2;
|
||||
std::shared_ptr<InterpCoeff> cs,kap;
|
||||
std::shared_ptr<mfem::GridFunctionCoefficient> gfc;
|
||||
mfem::ParGridFunction gfdens;
|
||||
|
||||
std::map<int, std::shared_ptr<mfem::Coefficient>> load;
|
||||
std::set<int> zero_bc;
|
||||
// holds the constrained DOFs
|
||||
mfem::Array<int> ess_tdofv;
|
||||
|
||||
mfem::Array<int> block_true_offsets;
|
||||
int siz_u;
|
||||
int siz_d;
|
||||
int siz_f;
|
||||
|
||||
std::unique_ptr<mfem::ParBilinearForm> kbf;
|
||||
mfem::Vector minv;
|
||||
|
||||
};
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
constexpr auto MESH_TRI = MFEM_SOURCE_DIR "/miniapps/mtop/sq_2D_9_tri.mesh";
|
||||
constexpr auto MESH_QUAD = MFEM_SOURCE_DIR "/miniapps/mtop/sq_2D_9_quad.mesh";
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Initialize MPI and HYPRE.
|
||||
Mpi::Init();
|
||||
Hypre::Init();
|
||||
|
||||
// Parse command-line options.
|
||||
const char *mesh_file = MESH_QUAD;
|
||||
const char *device_config = "cpu";
|
||||
int order = 2;
|
||||
bool pa = false;
|
||||
bool dfem = false;
|
||||
bool mesh_tri = false;
|
||||
bool mesh_quad = false;
|
||||
int par_ref_levels = 1;
|
||||
bool paraview = false;
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&dfem, "-dfem", "--dFEM", "-no-dfem", "--no-dFEM",
|
||||
"Enable or not dFEM.");
|
||||
args.AddOption(&mesh_tri, "-tri", "--triangular", "-no-tri",
|
||||
"--no-triangular", "Enable or not triangular mesh.");
|
||||
args.AddOption(&mesh_quad, "-quad", "--quadrilateral", "-no-quad",
|
||||
"--no-quadrilateral", "Enable or not quadrilateral mesh.");
|
||||
args.AddOption(&par_ref_levels, "-prl", "--par-ref-levels",
|
||||
"Number of times to refine the mesh uniformly in parallel.");
|
||||
args.AddOption(¶view, "-pv", "--paraview", "-no-pv", "--no-paraview",
|
||||
"Enable or not Paraview visualization");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.ParseCheck();
|
||||
MFEM_VERIFY(!(pa && dfem), "pa and dfem cannot be both set");
|
||||
|
||||
// Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
if (Mpi::Root()) { device.Print(); }
|
||||
|
||||
// Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh mesh(mesh_tri ? MESH_TRI : mesh_quad ? MESH_QUAD : mesh_file, 1, 1);
|
||||
const int dim = mesh.Dimension();
|
||||
|
||||
// Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement. We choose
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
// more than 1000 elements.
|
||||
{
|
||||
const int ref_levels =
|
||||
(int)floor(log(1000. / mesh.GetNE()) / log(2.) / dim);
|
||||
for (int l = 0; l < ref_levels; l++) { mesh.UniformRefinement(); }
|
||||
}
|
||||
if (Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of elements: " << mesh.GetNE() << std::endl;
|
||||
}
|
||||
|
||||
// Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
for (int l = 0; l < par_ref_levels; l++) { pmesh.UniformRefinement(); }
|
||||
|
||||
mfem::H1_FECollection fec(order, pmesh.Dimension());
|
||||
mfem::ParFiniteElementSpace pfes(&pmesh, &fec);
|
||||
|
||||
mfem::Array<int> ess_tdof_list;
|
||||
{
|
||||
// Dirichlet boundary marker (example: all boundary attributes)
|
||||
mfem::Array<int> ess_bdr(pmesh.bdr_attributes.Max());
|
||||
ess_bdr = 0;
|
||||
ess_bdr[9]=1.0;
|
||||
pfes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
|
||||
mfem::ConstantCoefficient kappa(1.0);
|
||||
|
||||
mfem::PAExplicitDiffusionOperator oper(pfes, ess_tdof_list, kappa);
|
||||
|
||||
// Initial condition as a ParGridFunction
|
||||
mfem::ParGridFunction u_gf(&pfes);
|
||||
u_gf = 0.0;
|
||||
// replace with projection
|
||||
{
|
||||
mfem::FunctionCoefficient fc([](const Vector &x) -> real_t
|
||||
{ return std::sin(4.0*x[0]*M_PI)*std::sin(4.0*x[1]*M_PI); });
|
||||
//project
|
||||
u_gf.ProjectCoefficient(fc);
|
||||
}
|
||||
|
||||
|
||||
// True dof vector state
|
||||
mfem::Vector u;
|
||||
u_gf.GetTrueDofs(u);
|
||||
|
||||
// Enforce homogeneous Dirichlet initially
|
||||
u.SetSubVector(oper.GetEssentialTrueDofs(), 0.0);
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
|
||||
// set paraview output
|
||||
ParaViewDataCollection paraview_dc("tdiff", &pmesh);
|
||||
paraview_dc.SetPrefixPath("ParaView");
|
||||
paraview_dc.SetLevelsOfDetail(order);
|
||||
paraview_dc.SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc.SetHighOrderOutput(true);
|
||||
paraview_dc.RegisterField("temp", &u_gf);
|
||||
|
||||
// Pick an explicit solver
|
||||
mfem::RK4Solver ode;
|
||||
ode.Init(oper);
|
||||
|
||||
double t = 0.0;
|
||||
double dt = 1e-5; // diffusion CFL ~ O(h^2); must be small
|
||||
|
||||
paraview_dc.SetCycle(0);
|
||||
paraview_dc.SetTime(t);
|
||||
paraview_dc.Save();
|
||||
|
||||
|
||||
/*
|
||||
for (int ti = 0; ti < 10; ti++)
|
||||
{
|
||||
ode.Step(u, t, dt);
|
||||
|
||||
// Keep Dirichlet dofs pinned (avoid drift)
|
||||
u.SetSubVector(oper.GetEssentialTrueDofs(), 0.0);
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
paraview_dc.SetCycle(ti+1);
|
||||
paraview_dc.SetTime(t);
|
||||
paraview_dc.Save();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
//test the RK4 adjoint
|
||||
{
|
||||
Vector x;
|
||||
{
|
||||
mfem::FunctionCoefficient fc([](const Vector &x) -> real_t
|
||||
{ return std::sin(4.0*x[0]*M_PI)*std::sin(4.0*x[1]*M_PI); });
|
||||
//project
|
||||
u_gf.ProjectCoefficient(fc);
|
||||
}
|
||||
u_gf.GetTrueDofs(x);
|
||||
// Enforce homogeneous Dirichlet initially
|
||||
x.SetSubVector(oper.GetEssentialTrueDofs(), 0.0);
|
||||
u_gf.SetFromTrueDofs(x);
|
||||
u.Set(1.0,x);
|
||||
|
||||
Vector vone(x); vone=1.0;
|
||||
|
||||
//compute one step
|
||||
t=0.0;
|
||||
ode.Step(x, t, dt);
|
||||
//compute objective
|
||||
real_t obj=mfem::InnerProduct(pmesh.GetComm(),x,vone);
|
||||
|
||||
//compute the adjoint
|
||||
mfem::Vector lam(u.Size()); lam=0.0;
|
||||
{
|
||||
ode.EnableAdjoint(mfem::ODESolver::AdjointMode::Discrete);
|
||||
ode.SetSolution(u,0.0); //set the solution at t=0.0;
|
||||
lam.Set(1.0,vone);
|
||||
ode.AdjointStep(lam,t,dt); //on exit lam is the adjoint at t-dt
|
||||
}
|
||||
|
||||
mfem::Vector rnd(u.Size()); rnd.Randomize();
|
||||
rnd.SetSubVector(oper.GetEssentialTrueDofs(), 0.0);
|
||||
|
||||
real_t iprod=mfem::InnerProduct(pmesh.GetComm(),rnd,lam);
|
||||
|
||||
real_t sca=1.0;
|
||||
for(int i=0;i<20;i++){
|
||||
x.Set(sca,rnd);
|
||||
x.Add(1.0,u);
|
||||
t=0.0;
|
||||
ode.Step(x, t, dt);
|
||||
real_t pobj=mfem::InnerProduct(pmesh.GetComm(),x,vone);
|
||||
|
||||
x.Set(-sca,rnd);
|
||||
x.Add(1.0,u);
|
||||
t=0.0;
|
||||
ode.Step(x, t, dt);
|
||||
real_t mobj=mfem::InnerProduct(pmesh.GetComm(),x,vone);
|
||||
|
||||
if(mfem::Mpi::Root())
|
||||
{
|
||||
std::cout<<" scale="<<sca<<" "<<" o="<<obj<<" p="<<pobj
|
||||
<<" do="<<(pobj-mobj)/(2.0*sca)
|
||||
<<" oo="<<(obj-mobj)/sca
|
||||
<<" to="<<iprod<<std::endl;
|
||||
}
|
||||
|
||||
sca=sca/10.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
# Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
|
||||
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
# LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability visit https://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
list(APPEND PLASMA_COMMON_SOURCES)
|
||||
|
||||
list(APPEND PLASMA_COMMON_HEADERS
|
||||
plasma.hpp)
|
||||
|
||||
convert_filenames_to_full_paths(PLASMA_COMMON_SOURCES)
|
||||
convert_filenames_to_full_paths(PLASMA_COMMON_HEADERS)
|
||||
|
||||
set(PLASMA_COMMON_FILES
|
||||
EXTRA_SOURCES ${PLASMA_COMMON_SOURCES}
|
||||
EXTRA_HEADERS ${PLASMA_COMMON_HEADERS})
|
||||
|
||||
endif()
|
||||
@@ -0,0 +1,85 @@
|
||||
# Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
|
||||
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
# LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability visit https://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/plasma/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_MINIAPPS =
|
||||
PAR_MINIAPPS =
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
MINIAPPS = $(SEQ_MINIAPPS)
|
||||
else
|
||||
MINIAPPS = $(PAR_MINIAPPS) $(SEQ_MINIAPPS)
|
||||
endif
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .cpp .mk
|
||||
.PHONY: all lib-common clean clean-build clean-exec
|
||||
.PRECIOUS: %.o
|
||||
|
||||
COMMON_LIB = -L$(MFEM_BUILD_DIR)/miniapps/common -lmfem-common
|
||||
|
||||
# If MFEM_SHARED is set, add the ../common rpath
|
||||
COMMON_LIB += $(if $(MFEM_SHARED:YES=),,\
|
||||
$(if $(MFEM_USE_CUDA:YES=),$(CXX_XLINKER),$(CUDA_XLINKER))-rpath,$(abspath\
|
||||
$(MFEM_BUILD_DIR)/miniapps/common))
|
||||
|
||||
COMMON_O=
|
||||
|
||||
# Remove built-in rules
|
||||
%: %.cpp
|
||||
%.o: %.cpp
|
||||
|
||||
all: $(MINIAPPS)
|
||||
|
||||
# Rules for building the miniapps
|
||||
%: $(SRC)%.cpp $(COMMON_O) $(MFEM_LIB_FILE) $(CONFIG_MK) | lib-common
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) $< -o $@ $(COMMON_O) $(COMMON_LIB) \
|
||||
$(MFEM_LIBS)
|
||||
|
||||
# Rules for compiling miniapp dependencies
|
||||
$(COMMON_O) $(addsuffix _solver.o,$(MINIAPPS)): \
|
||||
%.o: $(SRC)%.cpp $(SRC)%.hpp $(CONFIG_MK)
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) -c $(<) -o $(@)
|
||||
|
||||
# Rule for building lib-common
|
||||
lib-common:
|
||||
$(MAKE) -C $(MFEM_BUILD_DIR)/miniapps/common
|
||||
|
||||
MFEM_TESTS = MINIAPPS
|
||||
include $(MFEM_TEST_MK)
|
||||
|
||||
# Testing: Specific execution options
|
||||
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
|
||||
|
||||
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
|
||||
|
||||
# Generate an error message if the MFEM library is not built and exit
|
||||
$(MFEM_LIB_FILE):
|
||||
$(error The MFEM library is not built)
|
||||
|
||||
clean: clean-build clean-exec
|
||||
|
||||
clean-build:
|
||||
rm -f *.o *~ $(SEQ_MINIAPPS) $(PAR_MINIAPPS)
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_PLASMA_HPP
|
||||
#define MFEM_PLASMA_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace plasma
|
||||
{
|
||||
|
||||
// Physical Constants
|
||||
|
||||
// Permittivity of Free Space (units F/m)
|
||||
static const real_t epsilon0_ = 8.8541878176e-12;
|
||||
|
||||
// Permeability of Free Space (units H/m)
|
||||
static const real_t mu0_ = 4.0e-7 * M_PI;
|
||||
|
||||
// Speed of light in Free Space (units m/s)
|
||||
static const real_t c0_ = 1.0 / sqrt(epsilon0_ * mu0_);
|
||||
|
||||
// Impedance of Free Space (units Ohm)
|
||||
static const real_t Z0_ = sqrt(mu0_ / epsilon0_);
|
||||
|
||||
static const real_t q_ = 1.602176634e-19; // Elementary charge in coulombs
|
||||
static const real_t eV_ = 1.602176634e-19; // 1 eV in Joules
|
||||
static const real_t amu_ = 1.660539040e-27; // Atomic mass unit in kilograms
|
||||
static const real_t me_kg_ = 9.10938356e-31; // Mass of electron in kilograms
|
||||
static const real_t me_u_ = 5.4857990907e-4; // Mass of electron in a.m.u
|
||||
|
||||
/**
|
||||
Returns the cyclotron frequency in radians/second
|
||||
m is the mass in a.m.u
|
||||
q is the charge in units of elementary electric charge
|
||||
B is the magnetic field magnitude in tesla
|
||||
*/
|
||||
inline real_t cyclotronFrequency(real_t B, real_t m, real_t q)
|
||||
{
|
||||
return fabs(q * q_ * B / (m * amu_));
|
||||
}
|
||||
|
||||
typedef std::complex<real_t> complex_t;
|
||||
|
||||
} // namespace plasma
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_PLASMA_HPP
|
||||
|
||||
@@ -295,8 +295,13 @@ namespace Catch {
|
||||
// Otherwise all supported compilers support COUNTER macro,
|
||||
// but user still might want to turn it off
|
||||
#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )
|
||||
#if ( !(defined(__clang__) && __clang_major__ >= 22 ) )
|
||||
// don't use __COUNTER__ if compiling with clang 22+ to avoid compiler warning
|
||||
// https://github.com/llvm/llvm-project/pull/162662
|
||||
// TODO: can enable if building with C2y
|
||||
#define CATCH_INTERNAL_CONFIG_COUNTER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -117,3 +117,52 @@ TEST_CASE("Vector FE Face Restriction", "[FaceRestriction]")
|
||||
gf2 -= gf;
|
||||
REQUIRE(gf2.Normlinf() == MFEM_Approx(0.0));
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
TEST_CASE("L2 Face Restriction", "[FaceRestriction][Parallel]")
|
||||
{
|
||||
const int dim = GENERATE(2, 3);
|
||||
constexpr int nx = 3;
|
||||
constexpr int order = 2;
|
||||
constexpr int vdim = 2;
|
||||
const Ordering::Type ordering = GENERATE(Ordering::byNODES, Ordering::byVDIM);
|
||||
|
||||
Mesh serial_mesh = MakeCartesianMesh(nx, dim);
|
||||
ParMesh mesh(MPI_COMM_WORLD, serial_mesh);
|
||||
|
||||
L2_FECollection fec(order, dim, BasisType::GaussLobatto);
|
||||
ParFiniteElementSpace fes(&mesh, &fec, vdim, ordering);
|
||||
|
||||
auto *R = fes.GetFaceRestriction(ElementDofOrdering::LEXICOGRAPHIC,
|
||||
FaceType::Interior);
|
||||
|
||||
Vector vals({1.0, 2.0});
|
||||
VectorConstantCoefficient coeff(vals);
|
||||
|
||||
ParGridFunction gf(&fes);
|
||||
gf.ProjectCoefficient(coeff);
|
||||
|
||||
Vector face_vec(R->Height());
|
||||
R->Mult(gf, face_vec);
|
||||
|
||||
const int nf = mesh.GetNFbyType(FaceType::Interior);
|
||||
const int face_dofs = fes.GetTypicalTraceElement()->GetDof();
|
||||
auto h_face_vec = Reshape(face_vec.HostRead(), face_dofs, vdim, 2, nf);
|
||||
|
||||
for (int f = 0; f < nf; ++f)
|
||||
{
|
||||
for (int m = 0; m < 2; ++m)
|
||||
{
|
||||
for (int c = 0; c < vdim; ++c)
|
||||
{
|
||||
for (int i = 0; i < face_dofs; ++i)
|
||||
{
|
||||
REQUIRE(h_face_vec(i, c, m, f) == vals[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -281,8 +281,10 @@ TEST_CASE("Nedelec Segment Finite Element",
|
||||
REQUIRE( fe.GetRangeType() == (int) FiniteElement::VECTOR );
|
||||
REQUIRE( fe.GetMapType() == (int) FiniteElement::H_CURL );
|
||||
REQUIRE( fe.GetDerivType() == (int) FiniteElement::NONE );
|
||||
REQUIRE( fe.GetDerivRangeType() == (int) FiniteElement::SCALAR );
|
||||
REQUIRE( fe.GetDerivMapType() == (int) FiniteElement::INTEGRAL);
|
||||
REQUIRE( fe.GetDerivRangeType() ==
|
||||
(int) FiniteElement::UNKNOWN_RANGE_TYPE);
|
||||
REQUIRE( fe.GetDerivMapType() ==
|
||||
(int) FiniteElement::UNKNOWN_MAP_TYPE);
|
||||
}
|
||||
}
|
||||
SECTION("Sizes for p = " + std::to_string(p))
|
||||
|
||||
Reference in New Issue
Block a user