Compare commits

...
Author SHA1 Message Date
Stowell, Mark L 872822da4f Merge remote-tracking branch 'origin/master' into entity-sets-dev 2021-12-07 19:11:39 -08:00
Veselin Dobrev 7e8d8b1d55 Merge pull request #2592 from mfem/pw-coefs-dev
Adding Piecewise coefficient classes [pw-coefs-dev]
2021-12-07 17:39:34 -08:00
Stowell, Mark L fd5505407d Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/pncmesh.hpp
2021-12-07 15:01:43 -08:00
Stowell, Mark L d5c48cb3cc Improving comment for new classes 2021-12-07 13:54:45 -08:00
Veselin Dobrev acb9cfa321 Merge pull request #2631 from white238/task/white238/guard_add_test
Guard add_test calls with MFEM_ENABLE_TESTING
2021-12-07 12:49:58 -08:00
Tzanio Kolev 7ef0a77597 Merge pull request #2668 from mfem/refine-operator-bug-fix
Bug-fix: Adding appropriate doftransformations for high-order ND tet elements in RefineOperator/PRefineOperator Mult and MultTranspose
2021-12-05 19:35:37 -08:00
Socratis Petrides 6a86ca8d49 typo 2021-11-30 11:43:47 -08:00
Socratis Petrides c08b31c078 Merge branch 'master' into refine-operator-bug-fix 2021-11-30 11:38:22 -08:00
Socratis Petrides 54e78ee991 removing test from examples and adding ND and RT case in trasfer unit tests 2021-11-30 11:37:49 -08:00
Veselin Dobrev edb69e0180 Add missing newline at the end of a file 2021-11-22 22:10:52 -08:00
Socratis Petrides ad96dc5c61 adding checks for TensorProductElementPRefineOperator which is not implemented for ND/RT 2021-11-18 11:17:35 -08:00
Socratis Petrides de58c7ae08 minor 2021-11-17 18:54:24 -08:00
Socratis Petrides e9412379ce adding CG instead of UMFPack in the test. Adding quantitative error measure 2021-11-17 18:53:54 -08:00
Socratis Petrides 330b94fd41 Additional unit tests for InvTransformDual 2021-11-17 17:48:37 -08:00
Socratis Petrides 15cc865fba Adding DofTransformations in PrefinementOperator::Mult/MultTranspose 2021-11-17 17:47:57 -08:00
Socratis Petrides f60e6a6ac3 Bug fix RefinementOperator::MultTranspose 2021-11-17 17:47:19 -08:00
Socratis Petrides 75ae4e2c9b adding DofTransformation::InvTransformDual 2021-11-17 17:44:16 -08:00
Socratis Petrides f6c10448f2 small bug-fix refine-operatorr::MultTranspose() 2021-11-17 14:10:49 -08:00
Stowell, Mark L f58ad62b48 Adding new unit test to cmake file 2021-11-09 16:14:10 -08:00
Stowell, Mark L 64dd0fc417 Add unit tests for piecewise coefficients 2021-11-09 15:31:23 -08:00
Stowell, Mark L 2607e5fd98 Adding methods to remove entries from piecewise coefficients 2021-11-09 15:30:45 -08:00
Stowell, Mark L f569c190b6 Renaming AddCoefficient methods as UpdateCoefficient 2021-11-09 15:30:21 -08:00
Stowell, Mark L 131f8cc308 Switching to "const" variable to aid compiler optimizations 2021-11-09 12:07:41 -08:00
Stowell, Mark L 601a780a11 Switching to MFEM_VERIFY in initializers 2021-11-09 12:07:11 -08:00
Stowell, Mark L 23be84b089 Fixing typos (thanks @dylan-copeland!) 2021-11-09 12:06:26 -08:00
Chris White 586659c973 guard add_test with MFEM_ENABLE_TESTING 2021-11-02 15:46:06 -07:00
Stowell, Mark L 678cceaf1e Merge remote-tracking branch 'origin/master' into pw-coefs-dev
# Conflicts:
#	fem/coefficient.cpp
2021-11-02 12:08:00 -07:00
Stowell, Mark L 594711d99f Fixing Doxygen comments 2021-10-05 18:55:25 -07:00
Stowell, Mark L c8cb364d86 Adding Piecewise coefficient classes 2021-10-05 18:45:00 -07:00
Stowell, Mark L ccf27151f5 Remove a warning 2021-07-06 17:12:03 -07:00
Stowell, Mark L ae9f953b20 Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	fem/fespace.cpp
#	fem/fespace.hpp
#	general/sets.hpp
#	general/stable3d.hpp
#	mesh/mesh.cpp
#	mesh/mesh_readers.cpp
#	mesh/ncmesh.cpp
#	mesh/ncmesh.hpp
#	mesh/pmesh.cpp
#	mesh/pncmesh.cpp
2021-07-06 17:11:43 -07:00
Stowell, Mark L 7667f4c3f1 make style 2020-02-20 11:20:03 -08:00
Stowell, Mark L 092bf6c883 Using the new triangle face support 2020-02-20 11:18:15 -08:00
Stowell, Mark L fe921e8c83 Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/mesh.cpp
#	mesh/ncmesh.cpp
#	mesh/ncmesh.hpp
#	mesh/pncmesh.cpp
2020-02-20 11:02:35 -08:00
Stowell, Mark L 1dbdfe33e0 Merge remote-tracking branch 'origin/master' into entity-sets-dev 2019-05-01 10:07:25 -07:00
Stowell, Mark L f23d0a333d Merge remote-tracking branch 'origin/master' into entity-sets-dev 2019-04-12 14:46:26 -07:00
Stowell, Mark L a7ceecdcca Merge remote-tracking branch 'origin/master' into entity-sets-dev 2019-04-09 14:46:06 -07:00
Stowell, Mark L 5ed4c7b407 Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/ncmesh.cpp
2019-04-01 11:07:50 -07:00
Stowell, Mark L 99ae185c6a Adding user defined AMR limit 2019-03-17 17:46:56 -07:00
Stowell, Mark L d29134d0e7 Adding checks for non-null pointers before accessing same 2019-03-17 17:46:13 -07:00
Stowell, Mark L 180ee2a9c6 Adding AMR test code 2019-03-17 10:45:22 -07:00
Stowell, Mark L 207efd476d Merge remote-tracking branch 'origin/master' into entity-sets-dev 2019-01-20 00:02:39 -08:00
Stowell, Mark L 88f5ec5fec Merge remote-tracking branch 'origin/master' into entity-sets-dev 2018-12-23 17:26:43 -08:00
Stowell, Mark L 0ee86ac277 Merge remote-tracking branch 'origin/master' into entity-sets-dev 2018-11-26 14:59:10 -08:00
Stowell, Mark L 4268ec6a55 Post merge bugfix 2018-11-12 21:08:45 -08:00
Stowell, Mark L dfa9340302 Test meshes for mixed meshes with entity sets 2018-11-11 14:20:08 -08:00
Stowell, Mark L c2004e4eb4 Merge remote-tracking branch 'origin/master' into entity-sets-dev 2018-11-08 17:59:05 -08:00
Stowell, Mark L 2afa90dd44 make style 2018-11-08 09:21:36 -08:00
Stowell, Mark L dbb0d57f10 Starting mixed mesh refinement in entity sets 2018-11-08 09:20:44 -08:00
Stowell, Mark L 13f205f111 Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/pmesh.cpp
#	mesh/pncmesh.hpp
2018-11-07 22:59:17 -08:00
Stowell, Mark L 7f0c88bfaa Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/mesh.cpp
2018-10-10 21:56:22 -07:00
Stowell, Mark L b2a89fefbc no message 2018-09-25 13:23:08 -07:00
Stowell, Mark L 3ac0168600 Adding "Tier" to STable3D::Print output 2018-09-08 17:34:20 -07:00
Stowell, Mark L 68db9e6ea9 Cleaning up merge conflicts 2018-09-08 17:22:45 -07:00
Stowell, Mark L 3d6227f2cf Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/mesh.hpp
#	mesh/mesh_readers.cpp
#	mesh/ncmesh.cpp
#	mesh/ncmesh.hpp
#	mesh/pncmesh.cpp
#	mesh/pncmesh.hpp
2018-09-08 15:09:02 -07:00
Stowell, Mark L 67bfaa60d4 file format change 2017-08-22 19:58:53 -07:00
Stowell, Mark L c434761551 Style and debugging changes 2017-08-22 19:58:23 -07:00
Stowell, Mark L 710f6bd8e6 Adding two example codes for testing 2017-08-14 15:54:58 -07:00
Stowell, Mark L 9175575dcb Added CollectFaceVertices to entity set closure method. 2017-08-14 10:23:46 -07:00
Stowell, Mark L 3de54b7d06 Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	fem/pfespace.cpp
2017-08-11 14:47:52 -07:00
Stowell, Mark L 1a721e699a Closure seems to work on 2D meshes though I suspect it is still incomplete 2017-07-21 16:02:58 -07:00
Stowell, Mark L 607cf3c355 Run through "make style" 2017-07-21 09:12:32 -07:00
Stowell, Mark L b32c0d9430 Nearly working. There is still an issue related to missing dofs from neighboring processors. 2017-07-20 16:03:52 -07:00
Stowell, Mark L dd6f843634 This commit is a mess but I need to move the code to another platform for debugging 2017-07-17 15:04:21 -07:00
Stowell, Mark L 911fb9925d Changed internal data structure to std::set<int> rather from std::vector<int> 2017-07-08 22:27:17 -07:00
Stowell, Mark L 58f39f31fe Small updates to serial test driver. 2017-07-07 15:40:19 -07:00
Stowell, Mark L 40da819bc6 Adding an NCEntitySet class to store and manage NCMesh specific data. 2017-07-07 15:39:51 -07:00
Stowell, Mark L 802c6f11f1 Moving NCMesh specific data related to Entity Sets into a separate class to keep NCMesh clean. 2017-07-07 15:39:13 -07:00
Stowell, Mark L 08369c3086 Test programs for validating EntitySet behavior 2017-06-29 15:25:39 -07:00
Stowell, Mark L 4002955677 Preliminary support for Entity Sets in NCMesh class. This contains a lot of debugging output which will be removed once the parallel implementation is finished. 2017-06-29 15:25:03 -07:00
Stowell, Mark L 4283d54ad9 Fixing Mesh::Swap so that it is aware of the EntitySet member data in the Mesh class 2017-06-29 15:23:32 -07:00
Stowell, Mark L c6e3427808 Storing the coarse set information for use with the NCMesh class 2017-06-29 15:22:02 -07:00
Stowell, Mark L 7a927ae3b6 Merge remote-tracking branch 'origin/master' into entity-sets-dev 2017-06-22 15:13:12 -07:00
Tzanio aa334eb386 Sets of mesh entities feature developed internally at LLNL.
This pull request introduces two new classes; EntitySet and ParEntitySet. These
are intended to provide additional flexibility to the way MFEM tags groups of
mesh entities. These groups can be used for applying sources, boundary
conditions, post processing, etc..

MFEM currently assigns an integer attribute to each element or boundary
element. These attributes are then used by looping over all elements and
searching for attributes of interest. This is fine for large groups of elements
but for small groups this involves a large loop to locate a small number of
things.

EntitySets provide a way to loop over small groups of entities more
efficiently. They also generalize to groups of vertices, edges, faces, or
elements which can be very convenient.

The current implementation works for sets defined on quadrilateral or hexahedral
meshes in serial and parallel, with or without uniform refinement. Triangle and
tetrahedral meshes have not been tested. Support for non-conforming meshes has
not been started. If I can convince others of the value of these entity sets
then we can add support for these other mesh types.

Based on the following commits by Mark Stowell:

- Adding element access operators.

- Declaring "Size()" methods as "const".

- Added a comment for clarification.

- First draft of EntitySets class.

- Run through astyle.

- Adding methods to lookup VDofs and TrueDofs by set information.

- Adding a method to compute a Vertex to Edge table.

- Adding a non-const operator[] method.

- Adding a Load method.

- Testing the EntitySets::Load method.

- Mesh::NumOfEdges is not set even when the edge_vertex Table has been created.

- Adding Vertex to Face table.

- Testing face sets.

- Switched to using the STable3D face_tbl rather than creating a vertex to face
  table.

- Switched to using the Vertex to Vertex table.

- Adding support for QuadUniformRefinement with entity sets.

- Added copy constructor

- Adding support for entity sets in ParFiniteElementSpace

- Initial changes to support entity sets in parallel.

- Testing QuadUniformRefinement in parallel

- Adding test codes for entity sets.

- Adding parallel version of entity set code.

- Adding test meshes

- Improveing the way edge_vertex is protecgted in the mesh class.

- Adding support for parallel uniform refinement of quad meshes.

- Adding a method to return the number of rows in a table.

- Adding a RowIterator like the one in DSTable.

- Adding a fourth integer to the STable3D so that we don't lose the fourth value
  supplied to Push4.

- Changed the behavior when an entry is not found to match the behavior of
  DSTable and Table which return -1. Previously this object would issue an abort
  upon failure.

- Building faces array if face sets are read from disk.

- Adding a face_vertex table similar to the edge_vertex table.

- Adding support for face sets. This does not quite work yet but I don't want to
  lose these changes.

- Adding face sets for testing.

- Added a Print method to STable3D for debugging purposes.

- Fixed face sets in parallel with uniform refinement.

- Adding options to select the traditional boundary condition or one based on
  entity sets.

- Cleaned up the mesh file by adding more interesting sets rather than test
  sets.

- Adding code to display information about the entity sets.
2017-05-02 17:33:45 -07:00
53 changed files with 7169 additions and 413 deletions
+62 -60
View File
@@ -82,78 +82,80 @@ include_directories(BEFORE ${PROJECT_BINARY_DIR})
add_mfem_examples(ALL_EXE_SRCS)
# Add a test for each example
foreach(SRC_FILE ${ALL_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
if (MFEM_ENABLE_TESTING)
foreach(SRC_FILE ${ALL_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
set(THIS_TEST_OPTIONS "-no-vis")
if (${TEST_NAME} MATCHES "ex0p?")
set(THIS_TEST_OPTIONS)
endif()
if (${TEST_NAME} MATCHES "ex10p*")
list(APPEND THIS_TEST_OPTIONS "-tf" "5")
elseif(${TEST_NAME} MATCHES "ex15p*")
list(APPEND THIS_TEST_OPTIONS "-e" "1")
elseif(${TEST_NAME} MATCHES "ex27p*")
list(APPEND THIS_TEST_OPTIONS "-dg")
endif()
set(THIS_TEST_OPTIONS "-no-vis")
if (${TEST_NAME} MATCHES "ex0p?")
set(THIS_TEST_OPTIONS)
endif()
if (${TEST_NAME} MATCHES "ex10p*")
list(APPEND THIS_TEST_OPTIONS "-tf" "5")
elseif(${TEST_NAME} MATCHES "ex15p*")
list(APPEND THIS_TEST_OPTIONS "-e" "1")
elseif(${TEST_NAME} MATCHES "ex27p*")
list(APPEND THIS_TEST_OPTIONS "-dg")
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26
# parallel examples with device support:
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
elseif (MFEM_USE_HIP)
set(MFEM_TEST_DEVICE "hip")
endif()
if (MFEM_TEST_DEVICE)
foreach(TEST_NAME ${DEVICE_EXAMPLES})
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
elseif (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_np=${MFEM_MPI_NP}
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
# If STRUMPACK is enabled, add a test run that uses it.
if (MFEM_USE_STRUMPACK)
add_test(NAME ex11p_strumpack_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--strumpack"
${MPIEXEC_POSTFLAGS})
endif()
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26
# parallel examples with device support:
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
elseif (MFEM_USE_HIP)
set(MFEM_TEST_DEVICE "hip")
endif()
if (MFEM_TEST_DEVICE)
foreach(TEST_NAME ${DEVICE_EXAMPLES})
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
elseif (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
# If SuperLU_DIST is enabled, add a test run that uses it.
if (MFEM_USE_SUPERLU)
add_test(NAME ex11p_superlu_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--superlu"
${MPIEXEC_POSTFLAGS})
# If STRUMPACK is enabled, add a test run that uses it.
if (MFEM_USE_STRUMPACK)
add_test(NAME ex11p_strumpack_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--strumpack"
${MPIEXEC_POSTFLAGS})
endif()
# If SuperLU_DIST is enabled, add a test run that uses it.
if (MFEM_USE_SUPERLU)
add_test(NAME ex11p_superlu_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--superlu"
${MPIEXEC_POSTFLAGS})
endif()
endif()
# Include the examples/amgx directory if AmgX is enabled
+26 -24
View File
@@ -50,30 +50,32 @@ add_mfem_examples(AMGX_EXAMPLES_SRCS ${PFX} copy_amgx_json_files test_amgx)
# which builds the examples and runs:
# ctest -R amgx
# Command line options for the tests.
# Example 1/1p:
set(EX1_TEST_OPTS)
set(EX1P_TEST_OPTS)
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 1/1p:
set(EX1_TEST_OPTS)
set(EX1P_TEST_OPTS)
# Add the tests: one test per source file.
foreach(SRC_FILE ${AMGX_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${AMGX_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+17 -17
View File
@@ -30,22 +30,22 @@ set(PREFIX caliper_)
add_mfem_examples(CALIPER_EXE_SRCS ${PREFIX})
# Add a test for each example
foreach(SRC_FILE ${CALIPER_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
set(THIS_TEST_OPTIONS "-no-vis")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (MFEM_ENABLE_TESTING)
foreach(SRC_FILE ${CALIPER_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
set(THIS_TEST_OPTIONS "-no-vis")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+266
View File
@@ -0,0 +1,266 @@
// MFEM Example 1
//
// Compile with: make ex1
//
// Sample runs: ex1 -m ../data/square-disc.mesh
// ex1 -m ../data/star.mesh
// ex1 -m ../data/escher.mesh
// ex1 -m ../data/fichera.mesh
// ex1 -m ../data/square-disc-p2.vtk -o 2
// ex1 -m ../data/square-disc-p3.mesh -o 3
// ex1 -m ../data/square-disc-nurbs.mesh -o -1
// ex1 -m ../data/disc-nurbs.mesh -o -1
// ex1 -m ../data/pipe-nurbs.mesh -o -1
// ex1 -m ../data/star-surf.mesh
// ex1 -m ../data/square-disc-surf.mesh
// ex1 -m ../data/inline-segment.mesh
// ex1 -m ../data/amr-quad.mesh
// ex1 -m ../data/amr-hex.mesh
// ex1 -m ../data/fichera-amr.mesh
// ex1 -m ../data/mobius-strip.mesh
// ex1 -m ../data/mobius-strip.mesh -o -1 -sc
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int rs = -1;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Refine the mesh 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 50,000
// elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
cout << "Calling RandomRefinement " << ra << " times." << endl;
for (int l = 0; l < ra; l++)
{
mesh->RandomRefinement(0.2);
}
cout << "Done with refinement" << endl;
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
if ( mesh->ncmesh )
{
mesh->ncmesh->PrintStats(cout);
ofstream ofsV("vp.out");
ofstream ofsE("ce.out");
mesh->ncmesh->PrintVertexParents(ofsV);
mesh->ncmesh->PrintCoarseElements(ofsE);
}
// 4. Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
cout << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
LinearForm *b = new LinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(fespace);
x = 0.0;
// 8. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
PCG(A, M, B, X, 1, 200, 1e-12, 0.0);
#else
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
// 11. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 12. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 13. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 14. Free the used memory.
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete mesh;
return 0;
}
+388
View File
@@ -0,0 +1,388 @@
// MFEM Example 1 - Parallel Version
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 4 ex1p -m ../data/square-disc.mesh
// mpirun -np 4 ex1p -m ../data/star.mesh
// mpirun -np 4 ex1p -m ../data/escher.mesh
// mpirun -np 4 ex1p -m ../data/fichera.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/pipe-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/ball-nurbs.mesh -o 2
// mpirun -np 4 ex1p -m ../data/star-surf.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-surf.mesh
// mpirun -np 4 ex1p -m ../data/inline-segment.mesh
// mpirun -np 4 ex1p -m ../data/amr-quad.mesh
// mpirun -np 4 ex1p -m ../data/amr-hex.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh -o -1 -sc
//
// The following are examples of using EntitySets to define
// homogeneous Dirichlet boundary condition. These examples
// require a modified mesh file and a specialized version of
// example 1 called "ex1p_es".
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 0 -bs Origin
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 1 -bs Axes
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 1 -bs "Negative Axes"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 2 -bs "Interior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 2 -bs "Exterior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 3 -bs "Interior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 3 -bs "Exterior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 3 -bs "Steps"
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. 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 = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. 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 10,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. 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.
cout << "creating ParMesh from serial mesh" << endl;
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
cout << "done creating ParMesh from serial mesh" << endl;
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
/*
We now have a ParEntitySets object which marshals the data stored
in EntitySets objects. The data has now been pruned so that each
rank only contains indices of local entities.
The NCEntitySets object remains unchanged...
If we have an NC mesh a different path is taken and the
EntitySets are ignored.
1) ParNCMesh is created from NCMesh
a) Creates a ParNCEntitySets object from ncmesh (every rank contains
information to find every entity)
2) ParNCMesh is pruned which involves renumbering elements and vertices
3) ParMesh is initialized from ParNCMesh
4) ParNCMesh::OnMeshUpdated is called
5) Mesh::GenerateNCFaceInfo is called
*/
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
/*
RandomRefinement will end up calling
ParMesh::NonconformingRefinement which will create a new ParMesh
object using the ParNCMesh object and then call
ParMesh::OnMeshUpdated on this new mesh.
*/
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (pmesh->GetNodes())
{
fec = pmesh->GetNodes()->OwnFEC();
if (myid == 0)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
for (int i=0; i<num_procs; i++)
{
if (myid == i)
{
cout << "Number of Dirichlet dofs on proc " << i << ": "
<< ess_tdof_list.Size() << endl;
}
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm *b = new ParLinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(fespace);
x = 0.0;
// 10. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
// 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreSolver *amg = new HypreBoomerAMG(A);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(200);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*amg);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 14. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 15. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 16. Free the used memory.
delete pcg;
delete amg;
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete pmesh;
MPI_Finalize();
return 0;
}
+411
View File
@@ -0,0 +1,411 @@
// MFEM Example 3 - Parallel Version
//
// Compile with: make ex3p
//
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
// mpirun -np 4 ex3p -m ../data/escher.mesh
// mpirun -np 4 ex3p -m ../data/fichera.mesh
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
//
// Description: This example code solves a simple electromagnetic diffusion
// problem corresponding to the second order definite Maxwell
// equation curl curl E + E = f with boundary condition
// E x n = <given tangential field>. Here, we use a given exact
// solution E and compute the corresponding r.h.s. f.
// We discretize with Nedelec finite elements in 2D or 3D.
//
// The example demonstrates the use of H(curl) finite element
// spaces with the curl-curl and the (vector finite element) mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Static condensation is
// also illustrated.
//
// We recommend viewing examples 1-2 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution, E, and r.h.s., f. See below for implementation.
//void E_exact(const Vector &, Vector &);
//void f_exact(const Vector &, Vector &);
//double freq = 1.0, kappa;
void f_const(const Vector &, Vector &);
int dim;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../data/beam-tet.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
/*
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
" solution.");
*/
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// kappa = freq * M_PI;
// 3. 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 = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. 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 1,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. 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. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
pmesh->ReorientTetMesh();
pmesh->ent_sets->PrintSetInfo(cout);
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
if (myid == 0)
{
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
VectorFunctionCoefficient f(sdim, f_const);
ParLinearForm *b = new ParLinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
// VectorFunctionCoefficient E(sdim, E_exact);
// x.ProjectCoefficient(E);
x = 0.0;
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl + sigma I, by adding the curl-curl and the
// mass domain integrators.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
// 12. Define and apply a parallel PCG solver for AX=B with the AMS
// preconditioner from hypre.
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
HypreSolver *ams = new HypreAMS(A, prec_fespace);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*ams);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
/*
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(E);
if (myid == 0)
{
cout << "\n|| E_h - E ||_{L^2} = " << err << '\n' << endl;
}
}
*/
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
delete pcg;
delete ams;
delete a;
delete sigma;
delete muinv;
delete b;
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
/*
void E_exact(const Vector &x, Vector &E)
{
if (dim == 3)
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(2));
E(2) = sin(kappa * x(0));
}
else
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(0));
if (x.Size() == 3) { E(2) = 0.0; }
}
}
void f_exact(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
}
else
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
if (x.Size() == 3) { f(2) = 0.0; }
}
}
*/
void f_const(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = 1.0;
f(1) = 1.0;
f(2) = 1.0;
}
else
{
f(0) = 1.0;
f(1) = 1.0;
if (x.Size() == 3) { f(2) = 0.0; }
}
}
+438
View File
@@ -0,0 +1,438 @@
// MFEM Example 4 - Parallel Version
//
// Compile with: make ex4p
//
// Sample runs: mpirun -np 4 ex4p -m ../data/square-disc.mesh
// mpirun -np 4 ex4p -m ../data/star.mesh
// mpirun -np 4 ex4p -m ../data/beam-tet.mesh
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh
// mpirun -np 4 ex4p -m ../data/escher.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/fichera.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/fichera-q2.vtk
// mpirun -np 4 ex4p -m ../data/fichera-q3.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/square-disc-nurbs.mesh -o 3
// mpirun -np 4 ex4p -m ../data/beam-hex-nurbs.mesh -o 3
// mpirun -np 4 ex4p -m ../data/periodic-square.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/periodic-cube.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/amr-quad.mesh
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
//
// Description: This example code solves a simple 2D/3D H(div) diffusion
// problem corresponding to the second order definite equation
// -grad(alpha div F) + beta F = f with boundary condition F dot n
// = <given normal field>. Here, we use a given exact solution F
// and compute the corresponding r.h.s. f. We discretize with
// Raviart-Thomas finite elements.
//
// The example demonstrates the use of H(div) finite element
// spaces with the grad-div and H(div) vector finite element mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Bilinear form
// hybridization and static condensation are also illustrated.
//
// We recommend viewing examples 1-3 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution, F, and r.h.s., f. See below for implementation.
//void F_exact(const Vector &, Vector &);
//void f_exact(const Vector &, Vector &);
//double freq = 1.0, kappa;
void f_const(const Vector &, Vector &);
int dim;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool set_bc = true;
bool static_cond = false;
bool hybridization = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
"Impose or not essential boundary conditions.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
// args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
// " solution.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
"--no-hybridization", "Enable hybridization.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// kappa = freq * M_PI;
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume, as well as periodic meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. 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 1,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. 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. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them (this is needed in the ADS solver below).
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
}
pmesh->ReorientTetMesh();
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = new RT_FECollection(order-1, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = set_bc ? 1 : 0;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
if (myid == 0)
{
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
VectorFunctionCoefficient f(sdim, f_const);
ParLinearForm *b = new ParLinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary faces will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
// VectorFunctionCoefficient F(sdim, F_exact);
// x.ProjectCoefficient(F);
x = 0.0;
// 10. Set up the parallel bilinear form corresponding to the H(div)
// diffusion operator grad alpha div + beta I, by adding the div-div and
// the mass domain integrators.
Coefficient *alpha = new ConstantCoefficient(1.0);
Coefficient *beta = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation,
// hybridization, etc.
FiniteElementCollection *hfec = NULL;
ParFiniteElementSpace *hfes = NULL;
if (static_cond)
{
a->EnableStaticCondensation();
}
else if (hybridization)
{
hfec = new DG_Interface_FECollection(order-1, dim);
hfes = new ParFiniteElementSpace(pmesh, hfec);
a->EnableHybridization(hfes, new NormalTraceJumpIntegrator(),
ess_tdof_list);
}
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
HYPRE_Int glob_size = A.GetGlobalNumRows();
if (myid == 0)
{
cout << "Size of linear system: " << glob_size << endl;
}
// 12. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
// the 3D ADS preconditioners from hypre. If using hybridization, the
// system is preconditioned with hypre's BoomerAMG.
HypreSolver *prec = NULL;
CGSolver *pcg = new CGSolver(A.GetComm());
pcg->SetOperator(A);
pcg->SetRelTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(1);
if (hybridization) { prec = new HypreBoomerAMG(A); }
else
{
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
if (dim == 2) { prec = new HypreAMS(A, prec_fespace); }
else { prec = new HypreADS(A, prec_fespace); }
}
pcg->SetPreconditioner(*prec);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
/*
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(F);
if (myid == 0)
{
cout << "\n|| F_h - F ||_{L^2} = " << err << '\n' << endl;
}
}
*/
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
delete pcg;
delete prec;
delete hfes;
delete hfec;
delete a;
delete alpha;
delete beta;
delete b;
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
/*
// The exact solution (for non-surface meshes)
void F_exact(const Vector &p, Vector &F)
{
int dim = p.Size();
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
if (dim == 3)
{
F(2) = 0.0;
}
}
// The right hand side
void f_exact(const Vector &p, Vector &f)
{
int dim = p.Size();
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
double temp = 1 + 2*kappa*kappa;
f(0) = temp*cos(kappa*x)*sin(kappa*y);
f(1) = temp*cos(kappa*y)*sin(kappa*x);
if (dim == 3)
{
f(2) = 0;
}
}
*/
void f_const(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = 1.0;
f(1) = 1.0;
f(2) = 1.0;
}
else
{
f(0) = 1.0;
f(1) = 1.0;
if (x.Size() == 3) { f(2) = 0.0; }
}
}
+325
View File
@@ -0,0 +1,325 @@
// MFEM Example 6 - Parallel Version
//
// Compile with: make ex6p
//
// Sample runs: mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 1
// mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex6p -m ../data/square-disc-nurbs.mesh -o 2
// mpirun -np 4 ex6p -m ../data/star.mesh -o 3
// mpirun -np 4 ex6p -m ../data/escher.mesh -o 2
// mpirun -np 4 ex6p -m ../data/fichera.mesh -o 2
// mpirun -np 4 ex6p -m ../data/disc-nurbs.mesh -o 2
// mpirun -np 4 ex6p -m ../data/ball-nurbs.mesh
// mpirun -np 4 ex6p -m ../data/pipe-nurbs.mesh
// mpirun -np 4 ex6p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex6p -m ../data/square-disc-surf.mesh -o 2
// mpirun -np 4 ex6p -m ../data/amr-quad.mesh
//
// Description: This is a version of Example 1 with a simple adaptive mesh
// refinement loop. The problem being solved is again the Laplace
// equation -Delta u = 1 with homogeneous Dirichlet boundary
// conditions. The problem is solved on a sequence of meshes which
// are locally refined in a conforming (triangles, tetrahedrons)
// or non-conforming (quadrilaterals, hexahedra) manner according
// to a simple ZZ error estimator.
//
// The example demonstrates MFEM's capability to work with both
// conforming and nonconforming refinements, in 2D and 3D, on
// linear, curved and surface meshes. Interpolation of functions
// from coarse to fine meshes, as well as persistent GLVis
// visualization are also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
static int max_dofs = 100000;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int bt = EntitySets::INVALID;
const char *bs = "";
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&max_dofs, "-md", "--max-dofs",
"Maximum number of degrees of freedom.");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. 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 = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution.
// Also project a NURBS mesh to a piecewise-quadratic curved mesh. Make
// sure that the mesh is non-conforming.
if (mesh->NURBSext)
{
mesh->UniformRefinement();
mesh->SetCurvature(2);
}
mesh->EnsureNCMesh();
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
// 5. Define a parallel mesh by partitioning the serial mesh.
// Once the parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh.pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh.pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
// 6. Define a finite element space on the mesh. The polynomial order is
// one (linear) by default, but this can be changed on the command line.
H1_FECollection fec(order, dim);
ParFiniteElementSpace fespace(&pmesh, &fec);
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace.GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
// 7. As in Example 1p, we set up bilinear and linear forms corresponding to
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the main loop.
ParBilinearForm a(&fespace);
ParLinearForm b(&fespace);
ConstantCoefficient one(1.0);
BilinearFormIntegrator *integ = new DiffusionIntegrator(one);
a.AddDomainIntegrator(integ);
b.AddDomainIntegrator(new DomainLFIntegrator(one));
// 8. The solution vector x and the associated finite element grid function
// will be maintained over the AMR iterations. We initialize it to zero.
ParGridFunction x(&fespace);
x = 0;
// 9. Connect to GLVis.
char vishost[] = "localhost";
int visport = 19916;
socketstream sout;
if (visualization)
{
sout.open(vishost, visport);
if (!sout)
{
if (myid == 0)
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
cout << "GLVis visualization disabled.\n";
}
visualization = false;
}
sout.precision(8);
}
// 10. Set up an error estimator. Here we use the Zienkiewicz-Zhu estimator
// with L2 projection in the smoothing step to better handle hanging
// nodes and parallel partitioning. We need to supply a space for the
// discontinuous flux (L2) and a space for the smoothed flux (H(div) is
// used here).
L2_FECollection flux_fec(order, dim);
ParFiniteElementSpace flux_fes(&pmesh, &flux_fec, sdim);
RT_FECollection smooth_flux_fec(order-1, dim);
ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec);
// Another possible option for the smoothed flux space:
// H1_FECollection smooth_flux_fec(order, dim);
// ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec, dim);
L2ZienkiewiczZhuEstimator estimator(*integ, x, flux_fes, smooth_flux_fes);
// 11. A refiner selects and refines elements based on a refinement strategy.
// The strategy here is to refine elements with errors larger than a
// fraction of the maximum element error. Other strategies are possible.
// The refiner will call the given error estimator.
ThresholdRefiner refiner(estimator);
refiner.SetTotalErrorFraction(0.7);
// 12. The main AMR loop. In each iteration we solve the problem on the
// current mesh, visualize the solution, and refine the mesh.
// const int max_dofs = 100000;
for (int it = 0; ; it++)
{
HYPRE_Int global_dofs = fespace.GlobalTrueVSize();
if (myid == 0)
{
cout << "\nAMR iteration " << it << endl;
cout << "Number of unknowns: " << global_dofs << endl;
}
// 13. Assemble the stiffness matrix and the right-hand side. Note that
// MFEM doesn't care at this point that the mesh is nonconforming
// and parallel. The FE space is considered 'cut' along hanging
// edges/faces, and also across processor boundaries.
a.Assemble();
b.Assemble();
// 14. Create the parallel linear system: eliminate boundary conditions,
// constrain hanging nodes and nodes across processor boundaries.
// The system will be solved for true (unconstrained/unique) DOFs only.
// Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace.GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
HypreParMatrix A;
Vector B, X;
const int copy_interior = 1;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
// 15. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreBoomerAMG amg;
amg.SetPrintLevel(0);
CGSolver pcg(A.GetComm());
pcg.SetPreconditioner(amg);
pcg.SetOperator(A);
pcg.SetRelTol(1e-6);
pcg.SetMaxIter(200);
pcg.SetPrintLevel(3); // print the first and the last iterations only
pcg.Mult(B, X);
// 16. Extract the parallel grid function corresponding to the finite element
// approximation X. This is the local solution on each processor.
a.RecoverFEMSolution(X, b, x);
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
sout << "parallel " << num_procs << " " << myid << "\n";
sout << "solution\n" << pmesh << x << flush;
}
if (global_dofs > max_dofs)
{
if (myid == 0)
{
cout << "Reached the maximum number of dofs. Stop." << endl;
}
break;
}
// 18. Call the refiner to modify the mesh. The refiner calls the error
// estimator to obtain element errors, then it selects elements to be
// refined and finally it modifies the mesh. The Stop() method can be
// used to determine if a stopping criterion was met.
refiner.Apply(pmesh);
if (refiner.Stop())
{
if (myid == 0)
{
cout << "Stopping criterion satisfied. Stop." << endl;
}
break;
}
// 19. Update the finite element space (recalculate the number of DOFs,
// etc.) and create a grid function update matrix. Apply the matrix
// to any GridFunctions over the space. In this case, the update
// matrix is an interpolation matrix so the updated GridFunction will
// still represent the same function as before refinement.
fespace.Update();
x.Update();
// 20. Load balance the mesh, and update the space and solution. Currently
// available only for nonconforming meshes.
if (pmesh.Nonconforming())
{
pmesh.Rebalance();
// Update the space and the GridFunction. This time the update matrix
// redistributes the GridFunction among the processors.
fespace.Update();
x.Update();
}
// 21. Inform also the bilinear and linear forms that the space has
// changed.
a.Update();
b.Update();
}
MPI_Finalize();
return 0;
}
+162
View File
@@ -0,0 +1,162 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
3
elements
14
1 4 13 15 21 25
1 4 12 13 15 21
1 4 13 21 22 25
1 4 15 24 21 25
1 4 13 15 25 16
1 5 0 1 4 3 9 10 13 12
1 5 8 9 12 11 17 18 21 20
1 5 2 3 6 5 11 12 15 14
1 6 3 4 6 12 13 15
1 6 4 7 6 13 16 15
1 6 12 13 21 9 10 18
1 6 13 22 21 10 19 18
1 6 11 14 20 12 15 21
1 6 15 21 24 14 20 23
boundary
30
1 3 5 6 3 2
2 2 3 6 4
2 2 4 6 7
3 3 3 4 1 0
4 3 11 12 9 8
5 3 2 3 12 11
6 3 0 1 10 9
7 2 9 10 18
7 2 10 19 18
8 3 8 9 18 17
9 3 1 4 13 10
10 3 4 7 16 13
11 2 13 16 25
11 2 13 25 22
12 3 10 13 22 19
13 3 7 6 15 16
14 3 6 5 14 15
15 3 15 14 23 24
16 2 16 15 25
16 2 15 24 25
17 3 5 2 11 14
18 3 3 0 9 12
19 3 11 8 17 20
20 2 11 20 14
20 2 14 20 23
21 3 17 18 21 20
22 3 18 19 22 21
23 2 21 22 25
23 2 21 25 24
24 3 20 21 24 23
vertices
26
3
0 -1 -1
1 -1 -1
-1 0 -1
0 0 -1
1 0 -1
-1 1 -1
0 1 -1
1 1 -1
-1 -1 0
0 -1 0
1 -1 0
-1 0 0
0 0 0
1 0 0
-1 1 0
0 1 0
1 1 0
-1 -1 1
0 -1 1
1 -1 1
-1 0 1
0 0 1
1 0 1
-1 1 1
0 1 1
1 1 1
MFEM sets v1.0
vertex_sets
1
Origin
1
12
edge_sets
2
Axes
3
12 13
12 15
12 21
Negative Axes
3
12 9
12 11
12 3
face_sets
2
Interior Corner
3
3 11 12 9 8
3 2 3 12 11
3 3 0 9 12
Exterior Corner
15
2 13 16 25
2 13 25 22
2 16 15 25
2 15 24 25
2 21 22 25
2 21 25 24
3 10 13 22 19
3 4 7 16 13
3 1 4 13 10
3 7 6 15 16
3 6 5 14 15
3 15 14 23 24
3 20 21 24 23
3 18 19 22 21
3 17 18 21 20
element_sets
3
Interior Corner
3
5 6 7
Exterior Corner
5
0 1 2 3 4
Steps
3
6 8 9
+145
View File
@@ -0,0 +1,145 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
3
elements
7
1 5 0 1 4 3 9 10 13 12
1 5 3 4 7 6 12 13 16 15
1 5 2 3 6 5 11 12 15 14
1 5 8 9 12 11 17 18 21 20
1 5 9 10 13 12 18 19 22 21
1 5 12 13 16 15 21 22 25 24
1 5 11 12 15 14 20 21 24 23
boundary
24
1 3 5 6 3 2
2 3 6 7 4 3
3 3 3 4 1 0
4 3 11 12 9 8
5 3 2 3 12 11
6 3 0 1 10 9
7 3 9 10 19 18
8 3 8 9 18 17
9 3 1 4 13 10
10 3 4 7 16 13
11 3 13 16 25 22
12 3 10 13 22 19
13 3 7 6 15 16
14 3 6 5 14 15
15 3 15 14 23 24
16 3 16 15 24 25
17 3 5 2 11 14
18 3 3 0 9 12
19 3 11 8 17 20
20 3 14 11 20 23
21 3 17 18 21 20
22 3 18 19 22 21
23 3 21 22 25 24
24 3 20 21 24 23
vertices
26
3
0 -1 -1
1 -1 -1
-1 0 -1
0 0 -1
1 0 -1
-1 1 -1
0 1 -1
1 1 -1
-1 -1 0
0 -1 0
1 -1 0
-1 0 0
0 0 0
1 0 0
-1 1 0
0 1 0
1 1 0
-1 -1 1
0 -1 1
1 -1 1
-1 0 1
0 0 1
1 0 1
-1 1 1
0 1 1
1 1 1
MFEM sets v1.0
vertex_sets
1
Origin
1
12
edge_sets
2
Axes
3
12 13
12 15
12 21
Negative Axes
3
12 9
12 11
12 3
face_sets
2
Interior Corner
3
3 11 12 9 8
3 2 3 12 11
3 3 0 9 12
Exterior Corner
12
3 13 16 25 22
3 16 15 24 25
3 21 22 25 24
3 10 13 22 19
3 4 7 16 13
3 1 4 13 10
3 7 6 15 16
3 6 5 14 15
3 15 14 23 24
3 20 21 24 23
3 18 19 22 21
3 17 18 21 20
element_sets
3
Interior Corner
3
0 2 3
Exterior Corner
1
5
Steps
2
1 3
+25 -23
View File
@@ -31,29 +31,31 @@ add_mfem_examples(GINKGO_EXAMPLES_SRCS ${PFX} "" test_ginkgo)
# which builds the examples and runs:
# ctest -R ginkgo
# Command line options for the tests.
set(EX1_COMMON_OPTS ex1 -m ../data/star.mesh --use_gko_solver)
set(EX1_TEST_OPTS ${EX9_COMMON_OPTS})
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
set(EX1_COMMON_OPTS ex1 -m ../data/star.mesh --use_gko_solver)
set(EX1_TEST_OPTS ${EX9_COMMON_OPTS})
# Add the tests: one test per source file.
foreach(SRC_FILE ${GINKGO_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${GINKGO_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+27 -25
View File
@@ -33,31 +33,33 @@ add_mfem_examples(HIOP_EXAMPLES_SRCS ${PFX} "" test_hiop)
# which builds the examples and runs:
# ctest -R hiop
# Command line options for the tests.
# Example 9:
set(EX9_COMMON_OPTS -m ../../data/periodic-segment.mesh -p 0 -dt 0.005)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 )
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS})
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 9:
set(EX9_COMMON_OPTS -m ../../data/periodic-segment.mesh -p 0 -dt 0.005)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 )
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS})
# Add the tests: one test per source file.
foreach(SRC_FILE ${HIOP_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${HIOP_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+28 -26
View File
@@ -94,30 +94,32 @@ if (MFEM_USE_SLEPC)
endif()
# Add the tests: one test per command-line-variable.
set(TEST_OPTIONS_VARS
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
if (MFEM_USE_SLEPC)
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
endif()
foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS})
string(REGEX REPLACE "^(.+)_ARGS" "\\1" TEST_NAME_UC ${TEST_OPTIONS_VAR})
string(REGEX REPLACE "^([^_]+)" "\\1P" TEST_NAME_UC ${TEST_NAME_UC})
string(TOLOWER ${TEST_NAME_UC} TEST_NAME_FULL)
string(REGEX REPLACE "^([^_]+).*" "\\1" TEST_NAME ${TEST_NAME_FULL})
set(TEST_NAME_FULL ${PFX}${TEST_NAME_FULL})
set(TEST_NAME ${PFX}${TEST_NAME})
set(TEST_OPTIONS "-no-vis" ${${TEST_OPTIONS_VAR}})
# message(STATUS "${TEST_NAME_FULL} --> ${TEST_NAME} ${TEST_OPTIONS}")
# All PETSC tests are parallel.
if (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME_FULL}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
if (MFEM_ENABLE_TESTING)
set(TEST_OPTIONS_VARS
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
if (MFEM_USE_SLEPC)
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
endif()
endforeach()
foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS})
string(REGEX REPLACE "^(.+)_ARGS" "\\1" TEST_NAME_UC ${TEST_OPTIONS_VAR})
string(REGEX REPLACE "^([^_]+)" "\\1P" TEST_NAME_UC ${TEST_NAME_UC})
string(TOLOWER ${TEST_NAME_UC} TEST_NAME_FULL)
string(REGEX REPLACE "^([^_]+).*" "\\1" TEST_NAME ${TEST_NAME_FULL})
set(TEST_NAME_FULL ${PFX}${TEST_NAME_FULL})
set(TEST_NAME ${PFX}${TEST_NAME})
set(TEST_OPTIONS "-no-vis" ${${TEST_OPTIONS_VAR}})
# message(STATUS "${TEST_NAME_FULL} --> ${TEST_NAME} ${TEST_OPTIONS}")
# All PETSC tests are parallel.
if (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME_FULL}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+32 -30
View File
@@ -37,37 +37,39 @@ add_mfem_examples(PUMI_EXAMPLES_SRCS ${PFX} "" test_pumi)
# which builds the examples and runs:
# ctest -R pumi
# Command line options for the tests.
# TODO...
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# TODO...
# Set the number of processors for the parallel examples. The value of
# MFEM_MPI_NP is ignored.
set(EX1_TEST_NP 1)
set(EX1P_TEST_NP 8)
set(EX2_TEST_NP 1)
set(EX6P_TEST_NP 8)
# Set the number of processors for the parallel examples. The value of
# MFEM_MPI_NP is ignored.
set(EX1_TEST_NP 1)
set(EX1P_TEST_NP 8)
set(EX2_TEST_NP 1)
set(EX6P_TEST_NP 8)
# Add the tests: one test per source file.
foreach(SRC_FILE ${PUMI_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${PUMI_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
# All PUMI examples require MPI
if (FALSE)
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
set(TEST_NP ${${UP_TEST_NAME}_TEST_NP})
add_test(NAME ${TEST_NAME}_np=${TEST_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${TEST_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
# All PUMI examples require MPI
if (FALSE)
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
set(TEST_NP ${${UP_TEST_NAME}_TEST_NP})
add_test(NAME ${TEST_NAME}_np=${TEST_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${TEST_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+158
View File
@@ -0,0 +1,158 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
2
elements
30
1 3 0 11 26 14
1 3 0 14 27 17
1 3 0 17 28 20
1 3 0 20 29 23
1 3 0 23 30 11
1 2 11 1 26
1 2 1 12 26
1 3 26 12 3 13
1 2 26 13 2
1 2 14 26 2
1 2 14 2 27
1 2 2 15 27
1 3 27 15 5 16
1 2 27 16 4
1 2 17 27 4
1 2 17 4 28
1 2 4 18 28
1 3 28 18 7 19
1 2 28 19 6
1 2 20 28 6
1 2 20 6 29
1 2 6 21 29
1 3 29 21 9 22
1 2 29 22 8
1 2 23 29 8
1 2 23 8 30
1 2 8 24 30
1 3 30 24 10 25
1 2 30 25 1
1 2 11 30 1
boundary
20
1 1 13 2
1 1 12 3
1 1 16 4
1 1 15 5
1 1 19 6
1 1 18 7
1 1 22 8
1 1 21 9
1 1 25 1
1 1 24 10
1 1 3 13
1 1 1 12
1 1 5 16
1 1 2 15
1 1 7 19
1 1 4 18
1 1 9 22
1 1 6 21
1 1 10 25
1 1 8 24
vertices
31
2
0 0
1 0
0.309017 0.951057
1.30902 0.951057
-0.809017 0.587785
-0.5 1.53884
-0.809017 -0.587785
-1.61803 0
0.309017 -0.951057
-0.5 -1.53884
1.30902 -0.951057
0.5 0
1.15451 0.475529
0.809019 0.951057
0.154508 0.475529
-0.0954915 1.24495
-0.654508 1.06331
-0.404508 0.293893
-1.21352 0.293893
-1.21352 -0.293892
-0.404508 -0.293893
-0.654508 -1.06331
-0.0954915 -1.24495
0.154508 -0.475529
0.809019 -0.951057
1.15451 -0.475529
0.654509 0.475529
-0.25 0.769421
-0.809016 0
-0.25 -0.76942
0.654509 -0.475529
MFEM sets v1.0
vertex_sets
3
Origin
1
0
Tent
5
1 2 4 6 8
Gazebo
5
3 5 7 9 10
edge_sets
2
Columbine
5
1 11
2 14
4 17
6 20
8 23
Lily
5
0 11
0 14
0 17
0 20
0 23
element_sets
3
Flying Squirrel
3
7 17 27
Sea Lion
4
12 17 22 27
Pinwheel
5
8 13 18 23 28
+143
View File
@@ -0,0 +1,143 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
2
elements
20
1 3 0 11 26 14
1 3 0 14 27 17
1 3 0 17 28 20
1 3 0 20 29 23
1 3 0 23 30 11
1 3 11 1 12 26
1 3 26 12 3 13
1 3 14 26 13 2
1 3 14 2 15 27
1 3 27 15 5 16
1 3 17 27 16 4
1 3 17 4 18 28
1 3 28 18 7 19
1 3 20 28 19 6
1 3 20 6 21 29
1 3 29 21 9 22
1 3 23 29 22 8
1 3 23 8 24 30
1 3 30 24 10 25
1 3 11 30 25 1
boundary
20
1 1 13 2
1 1 12 3
1 1 16 4
1 1 15 5
1 1 19 6
1 1 18 7
1 1 22 8
1 1 21 9
1 1 25 1
1 1 24 10
1 1 3 13
1 1 1 12
1 1 5 16
1 1 2 15
1 1 7 19
1 1 4 18
1 1 9 22
1 1 6 21
1 1 10 25
1 1 8 24
vertices
31
2
0 0
1 0
0.309017 0.951057
1.30902 0.951057
-0.809017 0.587785
-0.5 1.53884
-0.809017 -0.587785
-1.61803 0
0.309017 -0.951057
-0.5 -1.53884
1.30902 -0.951057
0.5 0
1.15451 0.475529
0.809019 0.951057
0.154508 0.475529
-0.0954915 1.24495
-0.654508 1.06331
-0.404508 0.293893
-1.21352 0.293893
-1.21352 -0.293892
-0.404508 -0.293893
-0.654508 -1.06331
-0.0954915 -1.24495
0.154508 -0.475529
0.809019 -0.951057
1.15451 -0.475529
0.654509 0.475529
-0.25 0.769421
-0.809016 0
-0.25 -0.76942
0.654509 -0.475529
MFEM sets v1.0
vertex_sets
3
Origin
1
0
Tent
5
1 2 4 6 8
Gazebo
5
3 5 7 9 10
edge_sets
2
Columbine
5
1 11
2 14
4 17
6 20
8 23
Lily
5
0 11
0 14
0 17
0 20
0 23
element_sets
2
Flying Squirrel
3
6 12 18
Sea Lion
4
9 12 15 18
+32 -30
View File
@@ -41,36 +41,38 @@ add_mfem_examples(SUNDIALS_EXAMPLES_SRCS ${PFX} "" test_sundials)
# which builds the examples and runs:
# ctest -R sundials
# Command line options for the tests.
# Example 9: test CVODE with CV_ADAMS (non-stiff implicit) time stepping
set(EX9_COMMON_OPTS -m ../../data/periodic-hexagon.mesh -p 0 -s 7)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 -dt 0.0018 -vs 25)
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS} -rp 1 -dt 0.0009 -vs 50)
# Example 10: test CVODE with CV_BDF (stiff implicit) time stepping
set(EX10_COMMON_OPTS -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10)
set(EX10_TEST_OPTS ${EX10_COMMON_OPTS} -r 2)
set(EX10P_TEST_OPTS ${EX10_COMMON_OPTS} -rp 1)
# Example 16: use the default options
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 9: test CVODE with CV_ADAMS (non-stiff implicit) time stepping
set(EX9_COMMON_OPTS -m ../../data/periodic-hexagon.mesh -p 0 -s 7)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 -dt 0.0018 -vs 25)
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS} -rp 1 -dt 0.0009 -vs 50)
# Example 10: test CVODE with CV_BDF (stiff implicit) time stepping
set(EX10_COMMON_OPTS -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10)
set(EX10_TEST_OPTS ${EX10_COMMON_OPTS} -r 2)
set(EX10P_TEST_OPTS ${EX10_COMMON_OPTS} -rp 1)
# Example 16: use the default options
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+26 -25
View File
@@ -32,31 +32,32 @@ add_mfem_examples(SUPERLU_EXAMPLES_SRCS ${PFX} "" test_superlu)
# The SuperLU tests can be run separately using the target "test_superlu"
# which builds the examples and runs:
# ctest -R superlu
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 1: Test SuperLU on the simple Poisson problem
set(EX1_COMMON_OPTS -m ../../data/star.mesh -p 2)
set(EX1P_TEST_OPTS ${EX1_COMMON_OPTS})
# Command line options for the tests.
# Example 1: Test SuperLU on the simple Poisson problem
set(EX1_COMMON_OPTS -m ../../data/star.mesh -p 2)
set(EX1P_TEST_OPTS ${EX1_COMMON_OPTS})
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUPERLU_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUPERLU_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+169
View File
@@ -28,6 +28,52 @@ double PWConstCoefficient::Eval(ElementTransformation & T,
return (constants(att-1));
}
void PWCoefficient::InitMap(const Array<int> & attr,
const Array<Coefficient*> & coefs)
{
MFEM_VERIFY(attr.Size() == coefs.Size(),
"PWCoefficient: "
"Attribute and coefficient arrays have incompatible "
"dimensions.");
for (int i=0; i<attr.Size(); i++)
{
if (coefs[i] != NULL)
{
UpdateCoefficient(attr[i], *coefs[i]);
}
}
}
void PWCoefficient::SetTime(double t)
{
Coefficient::SetTime(t);
std::map<int, Coefficient*>::iterator p = pieces.begin();
for (; p != pieces.end(); p++)
{
if (p->second != NULL)
{
p->second->SetTime(t);
}
}
}
double PWCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
const int att = T.Attribute;
std::map<int, Coefficient*>::const_iterator p = pieces.find(att);
if (p != pieces.end())
{
if ( p->second != NULL)
{
return p->second->Eval(T, ip);
}
}
return 0.0;
}
double FunctionCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
@@ -120,6 +166,63 @@ void VectorCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
}
}
void PWVectorCoefficient::InitMap(const Array<int> & attr,
const Array<VectorCoefficient*> & coefs)
{
MFEM_VERIFY(attr.Size() == coefs.Size(),
"PWVectorCoefficient: "
"Attribute and coefficient arrays have incompatible "
"dimensions.");
for (int i=0; i<attr.Size(); i++)
{
if (coefs[i] != NULL)
{
UpdateCoefficient(attr[i], *coefs[i]);
}
}
}
void PWVectorCoefficient::UpdateCoefficient(int attr, VectorCoefficient & coef)
{
MFEM_VERIFY(coef.GetVDim() == vdim,
"PWVectorCoefficient::UpdateCoefficient: "
"VectorCoefficient has incompatible dimension.");
pieces[attr] = &coef;
}
void PWVectorCoefficient::SetTime(double t)
{
VectorCoefficient::SetTime(t);
std::map<int, VectorCoefficient*>::iterator p = pieces.begin();
for (; p != pieces.end(); p++)
{
if (p->second != NULL)
{
p->second->SetTime(t);
}
}
}
void PWVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
const int att = T.Attribute;
std::map<int, VectorCoefficient*>::const_iterator p = pieces.find(att);
if (p != pieces.end())
{
if ( p->second != NULL)
{
p->second->Eval(V, T, ip);
return;
}
}
V.SetSize(vdim);
V = 0.0;
}
void VectorFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
@@ -331,6 +434,72 @@ void VectorRestrictedCoefficient::Eval(
}
}
void PWMatrixCoefficient::InitMap(const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs)
{
MFEM_VERIFY(attr.Size() == coefs.Size(),
"PWMatrixCoefficient: "
"Attribute and coefficient arrays have incompatible "
"dimensions.");
for (int i=0; i<attr.Size(); i++)
{
if (coefs[i] != NULL)
{
UpdateCoefficient(attr[i], *coefs[i]);
}
}
}
void PWMatrixCoefficient::UpdateCoefficient(int attr, MatrixCoefficient & coef)
{
MFEM_VERIFY(coef.GetHeight() == height,
"PWMatrixCoefficient::UpdateCoefficient: "
"MatrixCoefficient has incompatible height.");
MFEM_VERIFY(coef.GetWidth() == width,
"PWMatrixCoefficient::UpdateCoefficient: "
"MatrixCoefficient has incompatible width.");
if (symmetric)
{
MFEM_VERIFY(coef.IsSymmetric(),
"PWMatrixCoefficient::UpdateCoefficient: "
"MatrixCoefficient has incompatible symmetry.");
}
pieces[attr] = &coef;
}
void PWMatrixCoefficient::SetTime(double t)
{
MatrixCoefficient::SetTime(t);
std::map<int, MatrixCoefficient*>::iterator p = pieces.begin();
for (; p != pieces.end(); p++)
{
if (p->second != NULL)
{
p->second->SetTime(t);
}
}
}
void PWMatrixCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
const int att = T.Attribute;
std::map<int, MatrixCoefficient*>::const_iterator p = pieces.find(att);
if (p != pieces.end())
{
if ( p->second != NULL)
{
p->second->Eval(K, T, ip);
return;
}
}
K.SetSize(height, width);
K = 0.0;
}
void MatrixFunctionCoefficient::SetTime(double t)
{
if (Q) { Q->SetTime(t); }
+269
View File
@@ -125,6 +125,87 @@ public:
const IntegrationPoint &ip);
};
/** @brief A piecewise coefficient with the pieces keyed off the element
attribute numbers.
A value of zero will be returned for any missing attribute numbers.
This object will not assume ownership of any Coefficient objects
passed to it. Consequently, the caller must ensure that the
individual Coefficient objects are not deleted while this
PWCoefficient is still in use.
\note The keys may either be domain attribute numbers or boundary
attribute numbers. If the PWCoefficient is used with a domain
integrator the keys are assumed to be domain attribute
numbers. Similarly, if the PWCoefficient is used with a boundary
integrator the keys are assumed to be boundary attribute numbers.
*/
class PWCoefficient : public Coefficient
{
private:
/** Internal data structure to store pointers to the appropriate
coefficients for different regions of the mesh. The keys used
in the map are the mesh attribute numbers (either element
attribute or boundary element attribute depending upon
context). The values returned for any missing attributes will
be zero. The coefficient pointers may be NULL in which case a
value of zero is returned.
The Coefficient objects contained in this map are NOT owned by
this PWCoefficient object. This means that they will not be
deleted when this object is deleted also the caller must ensure
that the various Coefficient objects are not deleted while this
PWCoefficient is still needed.
*/
std::map<int, Coefficient*> pieces;
/** Convenience function to check for compatible array lengths,
loop over the arrays, and add their attribute/Coefficient pairs
to the internal data structure.
*/
void InitMap(const Array<int> & attr,
const Array<Coefficient*> & coefs);
public:
/// Constructs a piecewise coefficient
explicit PWCoefficient() {}
/// Construct the coefficient using arrays describing the pieces
/** \param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of Coefficient pointers
Any missing attributes or NULL coefficient pointers will result in a
value of zero being returned for that attribute.
\note Ownership of the Coefficient objects will NOT be
transferred to this object.
*/
PWCoefficient(const Array<int> & attr,
const Array<Coefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Set the time for time dependent coefficients
virtual void SetTime(double t);
/// Replace a set of coefficients
void UpdateCoefficients(const Array<int> & attr,
const Array<Coefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Replace a single Coefficient for a particular attribute
void UpdateCoefficient(int attr, Coefficient & coef)
{ pieces[attr] = &coef; }
/// Remove a single Coefficient for a particular attribute
void ZeroCoefficient(int attr)
{ pieces.erase(attr); }
/// Evaluate the coefficient.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
/// A general function coefficient
class FunctionCoefficient : public Coefficient
{
@@ -413,6 +494,88 @@ public:
const Vector& GetVec() { return vec; }
};
/** @brief A piecewise vector-valued coefficient with the pieces keyed off the
element attribute numbers.
A value of zero will be returned for any missing attribute numbers.
This object will not assume ownership of any VectorCoefficient
objects passed to it. Consequently, the caller must ensure that
the individual VectorCoefficient objects are not deleted while
this PWVectorCoefficient is still in use.
\note The keys may either be domain attribute numbers or boundary
attribute numbers. If the PWVectorCoefficient is used with a
domain integrator the keys are assumed to be domain attribute
numbers. Similarly, if the PWVectorCoefficient is used with a
boundary integrator the keys are assumed to be boundary attribute
numbers.
*/
class PWVectorCoefficient : public VectorCoefficient
{
private:
/** Internal data structure to store pointers to the appropriate
coefficients for different regions of the mesh. The keys used
in the map are the mesh attribute numbers (either element
attribute or boundary element attribute depending upon
context). The values returned for any missing attributes will
be zero. The coefficient pointers may be NULL in which case a
value of zero is returned.
The VectorCoefficient objects contained in this map are NOT
owned by this PWVectorCoefficient object. This means that they
will not be deleted when this object is deleted also the caller
must ensure that the various VectorCoefficient objects are not
deleted while this PWVectorCoefficient is still needed.
*/
std::map<int, VectorCoefficient*> pieces;
/** Convenience function to check for compatible array lengths,
loop over the arrays, and add their attribute/VectorCoefficient
pairs to the internal data structure.
*/
void InitMap(const Array<int> & attr,
const Array<VectorCoefficient*> & coefs);
public:
/// Constructs a piecewise vector coefficient of dimension vd
explicit PWVectorCoefficient(int vd): VectorCoefficient(vd) {}
/// Construct the coefficient using arrays describing the pieces
/** \param vd - dimension of the vector-valued result
\param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of VectorCoefficient pointers
Any missing attributes or NULL coefficient pointers will result in a
zero vector being returned for that attribute.
\note Ownership of the VectorCoefficient objects will NOT be
transferred to this object.
*/
PWVectorCoefficient(int vd, const Array<int> & attr,
const Array<VectorCoefficient*> & coefs)
: VectorCoefficient(vd) { InitMap(attr, coefs); }
/// Set the time for time dependent coefficients
virtual void SetTime(double t);
/// Replace a set of coefficients
void UpdateCoefficients(const Array<int> & attr,
const Array<VectorCoefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Replace a single Coefficient for a particular attribute
void UpdateCoefficient(int attr, VectorCoefficient & coef);
/// Remove a single VectorCoefficient for a particular attribute
void ZeroCoefficient(int attr)
{ pieces.erase(attr); }
/// Evaluate the coefficient.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
};
/// A general vector function coefficient
class VectorFunctionCoefficient : public VectorCoefficient
{
@@ -782,6 +945,112 @@ public:
};
/** @brief A piecewise matrix-valued coefficient with the pieces keyed off the
element attribute numbers.
A value of zero will be returned for any missing attribute numbers.
This object will not assume ownership of any MatrixCoefficient
objects passed to it. Consequently, the caller must ensure that
the individual MatrixCoefficient objects are not deleted while
this PWMatrixCoefficient is still in use.
\note The keys may either be domain attribute numbers or boundary
attribute numbers. If the PWMatrixCoefficient is used with a
domain integrator the keys are assumed to be domain attribute
numbers. Similarly, if the PWMatrixCoefficient is used with a
boundary integrator the keys are assumed to be boundary attribute
numbers.
*/
class PWMatrixCoefficient : public MatrixCoefficient
{
private:
/** Internal data structure to store pointers to the appropriate
coefficients for different regions of the mesh. The keys used
in the map are the mesh attribute numbers (either element
attribute or boundary element attribute depending upon
context). The values returned for any missing attributes will
be zero. The coefficient pointers may be NULL in which case a
value of zero is returned.
The MatrixCoefficient objects contained in this map are NOT
owned by this PWMatrixCoefficient object. This means that they
will not be deleted when this object is deleted also the caller
must ensure that the various MatrixCoefficient objects are not
deleted while this PWMatrixCoefficient is still needed.
*/
std::map<int, MatrixCoefficient*> pieces;
/** Convenience function to check for compatible array lengths,
loop over the arrays, and add their attribute/MatrixCoefficient
pairs to the internal data structure.
*/
void InitMap(const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs);
public:
/// Constructs a piecewise matrix coefficient of dimension dim by dim
explicit PWMatrixCoefficient(int dim, bool symm = false)
: MatrixCoefficient(dim, symm) {}
/// Constructs a piecewise matrix coefficient of dimension h by w
explicit PWMatrixCoefficient(int h, int w, bool symm = false)
: MatrixCoefficient(h, w, symm) {}
/// Construct the coefficient using arrays describing the pieces
/** \param dim - size of the square matrix-valued result
\param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of MatrixCoefficient pointers
\param symm - true if the result will be symmetric, false otherwise
Any missing attributes or NULL coefficient pointers will result in a
zero matrix being returned.
\note Ownership of the MatrixCoefficient objects will NOT be
transferred to this object.
*/
PWMatrixCoefficient(int dim, const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs,
bool symm=false)
: MatrixCoefficient(dim, symm) { InitMap(attr, coefs); }
/// Construct the coefficient using arrays describing the pieces
/** \param h - height of the matrix-valued result
\param w - width of the matrix-valued result
\param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of MatrixCoefficient pointers
\param symm - true if the result will be symmetric, false otherwise
Any missing attributes or NULL coefficient pointers will result in a
zero matrix being returned for that attribute.
\note Ownership of the MatrixCoefficient objects will NOT be
transferred to this object.
*/
PWMatrixCoefficient(int h, int w, const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs,
bool symm=false)
: MatrixCoefficient(h, w, symm) { InitMap(attr, coefs); }
/// Set the time for time dependent coefficients
virtual void SetTime(double t);
/// Replace a set of coefficients
void UpdateCoefficients(const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Replace a single coefficient for a particular attribute
void UpdateCoefficient(int attr, MatrixCoefficient & coef);
/// Remove a single MatrixCoefficient for a particular attribute
void ZeroCoefficient(int attr)
{ pieces.erase(attr); }
/// Evaluate the coefficient.
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
};
/** @brief A matrix coefficient with an optional scalar coefficient multiplier
\a q. The matrix function can either be represented by a std function or
a constant matrix provided when constructing this object. */
+74
View File
@@ -85,6 +85,11 @@ void TransformPrimal(const DofTransformation *ran_dof_trans,
}
}
void DofTransformation::InvTransformDual(Vector &v) const
{
InvTransformDual(v.GetData());
}
void TransformDual(const DofTransformation *ran_dof_trans,
const DofTransformation *dom_dof_trans,
DenseMatrix &elmat)
@@ -195,6 +200,35 @@ void VDofTransformation::TransformDual(double *v) const
}
}
void VDofTransformation::InvTransformDual(double *v) const
{
int size = doftrans_->Size();
if ((Ordering::Type)ordering_ == Ordering::byNODES)
{
for (int i=0; i<vdim_; i++)
{
doftrans_->InvTransformDual(&v[i*size]);
}
}
else
{
Vector vec(size);
for (int i=0; i<vdim_; i++)
{
for (int j=0; j<size; j++)
{
vec(j) = v[j*vdim_+i];
}
doftrans_->InvTransformDual(vec);
for (int j=0; j<size; j++)
{
v[j*vdim_+i] = vec(j);
}
}
}
}
const double ND_DofTransformation::T_data[24] =
{
1.0, 0.0, 0.0, 1.0,
@@ -291,6 +325,26 @@ ND_TriDofTransformation::TransformDual(double *v) const
}
}
void
ND_TriDofTransformation::InvTransformDual(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<1; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[3*nedofs + f*nfdofs + 2*i];
T(Fo[f]).MultTranspose(v2, &v[3*nedofs + f*nfdofs + 2*i]);
}
}
}
ND_TetDofTransformation::ND_TetDofTransformation(int p)
: ND_DofTransformation(p*(p + 2)*(p + 3)/2, p)
{
@@ -355,4 +409,24 @@ ND_TetDofTransformation::TransformDual(double *v) const
}
}
void
ND_TetDofTransformation::InvTransformDual(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<4; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[6*nedofs + f*nfdofs + 2*i];
T(Fo[f]).MultTranspose(v2, &v[6*nedofs + f*nfdofs + 2*i]);
}
}
}
} // namespace mfem
+15
View File
@@ -102,6 +102,10 @@ public:
virtual void TransformDual(double *v) const = 0;
virtual void TransformDual(Vector &v) const;
/** Inverse Transform dual DoFs */
virtual void InvTransformDual(double *v) const = 0;
virtual void InvTransformDual(Vector &v) const;
/** Transform a matrix of dual DoFs entries as computed by a
BilinearFormIntegrator before summing into a BilinearForm object. */
virtual void TransformDual(DenseMatrix &V) const;
@@ -183,10 +187,12 @@ public:
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
/** Abstract base class for high-order Nedelec spaces on elements with
@@ -235,6 +241,8 @@ public:
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
/// DoF transformation implementation for the Nedelec basis on tetrahedra
@@ -246,12 +254,15 @@ public:
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
/// DoF transformation implementation for the Nedelec basis on wedge elements
@@ -264,12 +275,16 @@ public:
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
} // namespace mfem
+183 -5
View File
@@ -561,6 +561,155 @@ void FiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
}
}
void FiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_vdofs,
int component) const
{
Array<int> vdofs, dofs;
ess_vdofs.SetSize(GetVSize());
ess_vdofs = 0;
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
if (!mesh->ent_sets->SetExists(type, set_index))
{
ostringstream oss; oss << "Entity set of type \""
<< EntitySets::GetTypeName(type)
<< "\" and index " << set_index
<< " was not found.";
MFEM_VERIFY(false, oss.str().c_str());
}
set<int>::iterator it;
for (it=(*mesh->ent_sets)(type, set_index).begin();
it!=(*mesh->ent_sets)(type, set_index).end(); it++)
{
int ent_index = *it;
cout << "collecting vdofs for entity " << ent_index << "->";
if (component < 0)
{
switch (type)
{
case EntitySets::VERTEX:
GetVertexVDofs(ent_index, vdofs);
break;
case EntitySets::EDGE:
GetEdgeVDofs(ent_index, vdofs);
break;
case EntitySets::FACE:
GetFaceVDofs(ent_index, vdofs);
break;
case EntitySets::ELEMENT:
GetElementVDofs(ent_index, vdofs);
break;
default:
mfem_error("GetEssentialVDofs: Invalid entity type");
}
vdofs.Print(cout);
mark_dofs(vdofs, ess_vdofs);
}
else
{
switch (type)
{
case EntitySets::VERTEX:
GetVertexDofs(ent_index, dofs);
break;
case EntitySets::EDGE:
GetEdgeDofs(ent_index, dofs);
break;
case EntitySets::FACE:
GetFaceDofs(ent_index, dofs);
break;
case EntitySets::ELEMENT:
GetElementDofs(ent_index, dofs);
break;
default:
mfem_error("GetEssentialDofs: Invalid entity type");
}
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
if (mesh->ncmesh)
{
Array<int> es_verts, es_edges, es_faces;
mesh->ncmesh->GetEntitySetClosure(type, set_index,
es_verts, es_edges, es_faces);
cout << "returned from get closure" << endl;
for (int i = 0; i < es_verts.Size(); i++)
{
if (es_verts[i] < GetNV())
{
if (component < 0)
{
GetVertexVDofs(es_verts[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetVertexDofs(es_verts[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
for (int i = 0; i < es_edges.Size(); i++)
{
if (es_edges[i] < GetMesh()->GetNEdges())
{
if (component < 0)
{
GetEdgeVDofs(es_edges[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetEdgeDofs(es_edges[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
for (int i = 0; i < es_faces.Size(); i++)
{
if (es_faces[i] < GetMesh()->GetNFaces())
{
if (component < 0)
{
GetFaceVDofs(es_faces[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetFaceDofs(es_faces[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
}
}
void FiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_vdofs,
int component) const
{
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
GetEssentialVDofs(type, mesh->ent_sets->GetSetIndex(type, set_name),
ess_vdofs, component);
}
void FiniteElementSpace::GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
Array<int> &ess_tdof_list,
int component)
@@ -579,6 +728,36 @@ void FiniteElementSpace::GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
MarkerToList(ess_tdofs, ess_tdof_list);
}
void FiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_tdof_list,
int component)
{
Array<int> ess_vdofs, ess_tdofs;
GetEssentialVDofs(type, set_index, ess_vdofs, component);
const SparseMatrix *R = GetConformingRestriction();
if (!R)
{
ess_tdofs.MakeRef(ess_vdofs);
}
else
{
R->BooleanMult(ess_vdofs, ess_tdofs);
}
MarkerToList(ess_tdofs, ess_tdof_list);
}
void FiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_tdof_list,
int component)
{
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
GetEssentialTrueDofs(type, mesh->ent_sets->GetSetIndex(type, set_name),
ess_tdof_list, component);
}
void FiniteElementSpace::GetBoundaryTrueDofs(Array<int> &boundary_dofs,
int component)
{
@@ -1709,8 +1888,7 @@ void FiniteElementSpace::RefinementOperator
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
x.GetSubVector(f_vdofs, subX);
old_DoFTrans[geom]->InvTransformPrimal(subX);
doftrans->InvTransformDual(subX);
for (int p = 0; p < f_dofs.Size(); ++p)
{
if (processed[DecodeDof(f_dofs[p])])
@@ -1719,9 +1897,9 @@ void FiniteElementSpace::RefinementOperator
}
}
lP.MultTranspose(subX, subY);
doftrans->TransformPrimal(subY);
y.AddElementVector(c_vdofs, subY);
lP.MultTranspose(subX, subYt);
old_DoFTrans[geom]->TransformDual(subYt);
y.AddElementVector(c_vdofs, subYt);
}
if (vdoftrans)
+26
View File
@@ -778,6 +778,19 @@ public:
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_vdofs,
int component = -1) const;
/** @brief Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess.
For spaces with 'vdim' > 1, the 'component' parameter can be used
@@ -786,6 +799,19 @@ public:
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set index. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set name. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_tdof_list,
int component = -1);
/** @brief Get a list of all boundary true dofs, @a boundary_dofs. For spaces
with 'vdim' > 1, the 'component' parameter can be used to restricts the
marked tDOFs to the specified component. Equivalent to
+47
View File
@@ -23,6 +23,8 @@
#include <limits>
#include <list>
using namespace std;
namespace mfem
{
@@ -1018,6 +1020,30 @@ void ParFiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
}
}
void ParFiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_dofs,
int component) const
{
FiniteElementSpace::GetEssentialVDofs(type, set_index, ess_dofs, component);
if (Conforming())
{
// Make sure that processors without boundary elements mark
// their boundary dofs (if they have any).
Synchronize(ess_dofs);
}
}
void ParFiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_vdofs,
int component) const
{
GetEssentialVDofs(type, pmesh->ent_sets->GetSetIndex(type, set_name),
ess_vdofs, component);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(const Array<int>
&bdr_attr_is_ess,
Array<int> &ess_tdof_list,
@@ -1047,6 +1073,27 @@ void ParFiniteElementSpace::GetEssentialTrueDofs(const Array<int>
MarkerToList(true_ess_dofs, ess_tdof_list);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_tdof_list,
int component)
{
Array<int> ess_dofs, true_ess_dofs;
GetEssentialVDofs(type, set_index, ess_dofs, component);
GetRestrictionMatrix()->BooleanMult(ess_dofs, true_ess_dofs);
MarkerToList(true_ess_dofs, ess_tdof_list);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_tdof_list,
int component)
{
GetEssentialTrueDofs(type, pmesh->ent_sets->GetSetIndex(type, set_name),
ess_tdof_list, component);
}
int ParFiniteElementSpace::GetLocalTDofNumber(int ldof) const
{
if (Nonconforming())
+26
View File
@@ -355,12 +355,38 @@ public:
Array<int> &ess_dofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_vdofs,
int component = -1) const;
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess. */
virtual void GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set index. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set name. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_tdof_list,
int component = -1);
/** If the given ldof is owned by the current processor, return its local
tdof number, otherwise return -1 */
int GetLocalTDofNumber(int ldof) const;
+27 -6
View File
@@ -913,7 +913,11 @@ TransferOperator::TransferOperator(const FiniteElementSpace& lFESpace_,
else if (lFESpace_.GetMesh()->GetNE() > 0
&& hFESpace_.GetMesh()->GetNE() > 0
&& dynamic_cast<const TensorBasisElement*>(lFESpace_.GetFE(0))
&& dynamic_cast<const TensorBasisElement*>(hFESpace_.GetFE(0)))
&& dynamic_cast<const TensorBasisElement*>(hFESpace_.GetFE(0))
&& (hFESpace_.FEColl()->GetContType() ==
mfem::FiniteElementCollection::CONTINUOUS ||
hFESpace_.FEColl()->GetContType() ==
mfem::FiniteElementCollection::DISCONTINUOUS))
{
opr = new TensorProductPRefinementTransferOperator(lFESpace_, hFESpace_);
}
@@ -961,8 +965,8 @@ void PRefinementTransferOperator::Mult(const Vector& x, Vector& y) const
for (int i = 0; i < mesh->GetNE(); i++)
{
hFESpace.GetElementDofs(i, h_dofs);
lFESpace.GetElementDofs(i, l_dofs);
DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
DofTransformation * doftrans_l = lFESpace.GetElementDofs(i, l_dofs);
const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
if (geom != cached_geom)
@@ -982,7 +986,15 @@ void PRefinementTransferOperator::Mult(const Vector& x, Vector& y) const
h_dofs.Copy(h_vdofs);
hFESpace.DofsToVDofs(vd, h_vdofs);
x.GetSubVector(l_vdofs, subX);
if (doftrans_l)
{
doftrans_l->InvTransformPrimal(subX);
}
loc_prol.Mult(subX, subY);
if (doftrans_h)
{
doftrans_h->TransformPrimal(subY);
}
y.SetSubVector(h_vdofs, subY);
}
}
@@ -1010,8 +1022,8 @@ void PRefinementTransferOperator::MultTranspose(const Vector& x,
for (int i = 0; i < mesh->GetNE(); i++)
{
hFESpace.GetElementDofs(i, h_dofs);
lFESpace.GetElementDofs(i, l_dofs);
DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
DofTransformation * doftrans_l = lFESpace.GetElementDofs(i, l_dofs);
const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
if (geom != cached_geom)
@@ -1033,6 +1045,10 @@ void PRefinementTransferOperator::MultTranspose(const Vector& x,
hFESpace.DofsToVDofs(vd, h_vdofs);
x.GetSubVector(h_vdofs, subX);
if (doftrans_h)
{
doftrans_h->InvTransformDual(subX);
}
for (int p = 0; p < h_dofs.Size(); ++p)
{
if (processed[lFESpace.DecodeDof(h_dofs[p])])
@@ -1042,6 +1058,10 @@ void PRefinementTransferOperator::MultTranspose(const Vector& x,
}
loc_prol.Mult(subX, subY);
if (doftrans_l)
{
doftrans_l->TransformDual(subY);
}
y.AddElementVector(l_vdofs, subY);
}
@@ -1085,7 +1105,8 @@ TensorProductPRefinementTransferOperator(
// must be sorted in lexicographical order
for (int i = 0; i < ir.GetNPoints(); ++i)
{
irLex.IntPoint(i) = ir.IntPoint(hdofmap[i]);
int j = hdofmap[i] >=0 ? hdofmap[i] : -1 - hdofmap[i];
irLex.IntPoint(i) = ir.IntPoint(j);
}
NE = lFESpace.GetNE();
+1
View File
@@ -69,6 +69,7 @@ void IntegerSet::Recreate(const int n, const int *p)
me.Sort();
// Remove duplicate entries
for (j = 0, i = 1; i < n; i++)
if (me[i] != me[j])
{
+7 -2
View File
@@ -36,7 +36,7 @@ public:
IntegerSet(const int n, const int *p) { Recreate(n, p); }
/// Return the size of the set.
int Size() { return me.Size(); }
int Size() const { return me.Size(); }
/// Return a reference to the sorted array of all the set entries.
operator Array<int>& () { return me; }
@@ -50,6 +50,8 @@ public:
/// Return 1 if the sets are equal and 0 otherwise.
int operator==(IntegerSet &s);
inline const int & operator[](int i) const { return me[i]; }
/** @brief Create an integer set from C-array 'p' of 'n' integers.
Overwrites any existing set data. */
void Recreate(const int n, const int *p);
@@ -64,7 +66,7 @@ private:
public:
/// Return the number of integer sets in the list.
int Size() { return TheList.Size(); }
int Size() const { return TheList.Size(); }
/// Return the value of the first element of the ith set.
int PickElementInSet(int i) { return TheList[i]->PickElement(); }
@@ -84,6 +86,9 @@ public:
/// Write the list of sets into table 't'.
void AsTable(Table &t);
inline const IntegerSet & operator[](int i) const { return *TheList[i]; }
inline IntegerSet & operator[](int i) { return *TheList[i]; }
~ListOfIntegerSets();
};
+9 -7
View File
@@ -61,7 +61,7 @@ inline void Sort3 (int &r, int &c, int &f)
}
}
int STable3D::Push (int r, int c, int f)
int STable3D::Push (int r, int c, int f, int t)
{
STable3DNode *node;
@@ -86,6 +86,7 @@ int STable3D::Push (int r, int c, int f)
#endif
node->Column = c;
node->Floor = f;
node->Tier = t;
node->Number = NElem;
node->Prev = Rows[r];
Rows[r] = node;
@@ -109,9 +110,9 @@ int STable3D::operator() (int r, int c, int f) const
}
}
MFEM_ABORT("(r,c,f) = (" << r << "," << c << "," << f << ")");
// MFEM_ABORT("(r,c,f) = (" << r << "," << c << "," << f << ")");
return 0;
return -1;
}
int STable3D::Index (int r, int c, int f) const
@@ -152,13 +153,13 @@ int STable3D::Push4 (int r, int c, int f, int t)
switch (i)
{
case 0:
return Push (c,f,t);
return Push (c,f,t,r);
case 1:
return Push (r,f,t);
return Push (r,f,t,c);
case 2:
return Push (r,c,t);
return Push (r,c,t,f);
case 3:
return Push (r,c,f);
return Push (r,c,f,t);
}
return -1;
@@ -218,6 +219,7 @@ void STable3D::Print(std::ostream & out) const
out << row
<< ' ' << node_p->Column
<< ' ' << node_p->Floor
<< ' ' << node_p->Tier
<< ' ' << node_p->Number
<< endl;
node_p = node_p->Prev;
+22 -3
View File
@@ -15,6 +15,8 @@
#include "mem_alloc.hpp"
#include "../general/globals.hpp"
#include <iostream>
namespace mfem
{
@@ -22,7 +24,7 @@ class STable3DNode
{
public:
STable3DNode *Prev;
int Column, Floor, Number;
int Column, Floor, Tier, Number;
};
/** @brief Symmetric 3D Table stored as an array of rows each of which has a
@@ -47,7 +49,7 @@ public:
/** @brief Check to see if this entry is in the table and add it to the table
if it is not there. Returns the number assigned to the table entry. */
int Push (int r, int c, int f);
int Push (int r, int c, int f, int t = -1);
/// Return the number assigned to the table entry. Abort if it's not there.
int operator() (int r, int c, int f) const;
@@ -66,13 +68,30 @@ public:
not there. */
int operator() (int r, int c, int f, int t) const;
/// Return the number of rows added to the table.
int NumberOfRows() const { return Size; }
/// Return the number of elements added to the table.
int NumberOfElements() { return NElem; }
int NumberOfElements() const { return NElem; }
/// Print out all of the table elements.
void Print(std::ostream &out = mfem::out) const;
~STable3D ();
class RowIterator
{
private:
STable3DNode *n;
public:
RowIterator (const STable3D &t, int r) { n = t.Rows[r]; }
int operator!() { return (n != NULL); }
void operator++() { n = n->Prev; }
int Column() { return (n->Column); }
int Floor() { return (n->Floor); }
int Tier() { return (n->Tier); }
int Index() { return (n->Number); }
};
};
}
+1295
View File
File diff suppressed because it is too large Load Diff
+219
View File
@@ -0,0 +1,219 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_ENTITY_SETS
#define MFEM_ENTITY_SETS
#include "../config/config.hpp"
#include "../general/table.hpp"
#include "../general/stable3d.hpp"
#include <limits>
#include <map>
#include <set>
#include <string>
#include <vector>
namespace mfem
{
class Mesh;
class NCMesh;
class NCEntitySets;
class EntitySets
{
friend class Mesh;
friend class NCMesh;
friend class NCEntitySets;
public:
enum EntityType {INVALID = -1, VERTEX = 0, EDGE = 1, FACE = 2, ELEMENT = 3};
static std::map<EntityType,std::string> EntityTypeNames;
EntitySets(Mesh & mesh);
EntitySets(const EntitySets & ent_sets);
EntitySets(Mesh & mesh, NCMesh &ncmesh);
virtual ~EntitySets();
static const std::string & GetTypeName(EntityType t);
bool SetExists(EntityType t, unsigned int s) const;
bool SetExists(EntityType t, const std::string & s) const;
void Load(std::istream &input);
void Print(std::ostream &output) const;
virtual void PrintSetInfo(std::ostream &output) const;
inline Mesh *GetMesh() const { return mesh_; }
unsigned int GetNumSets(EntityType t) const;
const std::string & GetSetName(EntityType t, unsigned int s) const;
unsigned int GetNumEntities(EntityType t, unsigned int s) const;
int GetSetIndex(EntityType t, const std::string & s) const;
unsigned int GetNumEntities(EntityType t, const std::string & s) const;
inline std::set<int> & operator()(EntityType t, unsigned int s)
{ return sets_[t][s]; }
inline const std::set<int> & operator()(EntityType t, unsigned int s) const
{ return sets_[t][s]; }
const Table * GetEdgeVertexTable() const { return edge_vertex_; }
const Table * GetFaceVertexTable() const { return face_vertex_; }
const Table * GetFaceEdgeTable() const { return face_edge_; }
// void Prune(int nelems);
protected:
void SetNumSets(EntityType t, unsigned int n)
{ sets_[t].resize(n); set_names_[t].resize(n); }
void SetSetName(EntityType t, int s, const std::string & name)
{ set_names_[t][s] = name; set_index_by_name_[t][name] = s; }
/// Make local copies of edge_vertex, face_vertex, and face_edge tables.
void CopyMeshTables();
/// Refine quadrilateral mesh.
virtual void QuadUniformRefinement();
/// Refine hexahedral mesh.
virtual void HexUniformRefinement();
/// Refine 2D mesh.
virtual void UniformRefinement2D();
/// Refine 3D mesh.
virtual void UniformRefinement3D();
private:
static void skip_comment_lines(std::istream &is, const char comment_char)
{
while (1)
{
is >> std::ws;
if (is.peek() != comment_char) { break; }
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
// Check for, and remove, a trailing '\r'.
static void filter_dos(std::string &line)
{
if (!line.empty() && *line.rbegin() == '\r')
{ line.resize(line.size()-1); }
}
static std::map<EntityType,std::string> init_type_names();
void LoadEntitySets(std::istream &input, EntityType t,
const std::string & header);
void PrintEntitySets(std::ostream &output, EntityType t,
const std::string & header) const;
void PrintEdgeSets(std::ostream &output) const;
void PrintFaceSets(std::ostream &output) const;
void PrintEntitySetInfo(std::ostream & output, EntityType t,
const std::string & ent_name) const;
void CopyEntitySets(const EntitySets & ent_sets, EntityType t);
void BuildEntitySets(NCMesh &ncmesh, EntityType t);
protected:
Mesh * mesh_;
Table * edge_vertex_;
Table * face_vertex_;
Table * face_edge_;
int NumOfVertices_;
int NumOfEdges_;
int NumOfElements_;
/** The node/edge/face/element indices needed by the finite element
space to look up DoFs. */
std::vector<std::vector<std::set<int> > > sets_;
/// Names of each entity set
std::vector<std::vector<std::string> > set_names_;
/// Indices of each entity set indexed by set name
std::vector<std::map<std::string, int> > set_index_by_name_;
};
class NCEntitySets
{
friend class EntitySets;
public:
NCEntitySets(const EntitySets & ent_sets, NCMesh &ncmesh);
NCEntitySets(const NCEntitySets & ncent_sets);
bool SetExists(EntitySets::EntityType t, unsigned int s) const;
bool SetExists(EntitySets::EntityType t, const std::string & s) const;
unsigned int GetNumSets(EntitySets::EntityType t) const;
static int GetEntitySize(EntitySets::EntityType t);
const std::string & GetSetName(EntitySets::EntityType t, int s) const;
unsigned int GetNumEntities(EntitySets::EntityType t, int s) const;
void GetEntityIndex(EntitySets::EntityType t, int s,
int i, Array<int> & inds) const;
int GetSetIndex(EntitySets::EntityType t,
const std::string & s) const;
unsigned int GetNumEntities(EntitySets::EntityType t,
const std::string & s) const;
void GetEntityIndex(EntitySets::EntityType t,
const std::string & s, int i,
Array<int> & inds) const;
inline std::vector<int> & operator()(EntitySets::EntityType t, int s)
{ return sets_[t][s]; }
inline const std::vector<int> & operator()(EntitySets::EntityType t,
int s) const
{ return sets_[t][s]; }
inline int & operator()(EntitySets::EntityType t, int s, int i)
{ return sets_[t][s][i]; }
inline int operator()(EntitySets::EntityType t, int s, int i) const
{ return sets_[t][s][i]; }
private:
void CopyNCEntitySets(const NCEntitySets & ncent_sets,
EntitySets::EntityType t);
protected:
NCMesh * ncmesh_;
/// The nodes defining the node/edge/face/element sets
std::vector<std::vector<std::vector<int> > > sets_;
/// Names of each entity set
std::vector<std::vector<std::string> > set_names_;
/// Indices of each entity set indexed by set name
std::vector<std::map<std::string, int> > set_index_by_name_;
/// Number of indices per entity
static const int entity_size_[4];
};
} // namespace mfem
#endif // MFEM_ENTITY_SETS
+70 -3
View File
@@ -1177,13 +1177,15 @@ void Mesh::Init()
own_nodes = 1;
NURBSext = NULL;
ncmesh = NULL;
ent_sets = NULL;
last_operation = Mesh::NONE;
}
void Mesh::InitTables()
{
el_to_edge =
el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
el_to_face = el_to_el = bel_to_edge = face_edge =
face_vertex = edge_vertex = NULL;
}
void Mesh::SetEmpty()
@@ -1205,6 +1207,7 @@ void Mesh::DestroyTables()
}
delete face_edge;
delete face_vertex;
delete edge_vertex;
}
@@ -1212,6 +1215,8 @@ void Mesh::DestroyPointers()
{
if (own_nodes) { delete Nodes; }
delete ent_sets;
delete ncmesh;
delete NURBSext;
@@ -3346,6 +3351,12 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
// Copy the edge-to-vertex Table, edge_vertex
edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
// Copy the face-to-vertex Table, edge_vertex
face_vertex = (mesh.face_vertex) ? new Table(*mesh.face_vertex) : NULL;
// Do not copy any of the coarse (c_*), fine (f_*) or fine/coarse (fc_*)
// data members.
// Copy the attributes and bdr_attributes
mesh.attributes.Copy(attributes);
mesh.bdr_attributes.Copy(bdr_attributes);
@@ -3396,6 +3407,9 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
Nodes = mesh.Nodes;
own_nodes = 0;
}
// Copy entity sets if present in the input mesh
ent_sets = (mesh.ent_sets) ? new EntitySets(*mesh.ent_sets) : NULL;
}
Mesh::Mesh(Mesh &&mesh) : Mesh()
@@ -5768,6 +5782,38 @@ Table *Mesh::GetEdgeVertexTable() const
return edge_vertex;
}
Table *Mesh::GetFaceVertexTable() const
{
if (face_vertex)
{
return face_vertex;
}
STable3D * faces_tbl = GetFacesTable();
int nfaces = faces_tbl->NumberOfElements();
face_vertex = new Table(nfaces, 4);
for (int i = 0; i < NumOfVertices; i++)
{
for (STable3D::RowIterator it(*faces_tbl, i); !it; ++it)
{
int j = it.Index();
face_vertex->Push(j, i);
face_vertex->Push(j, it.Column());
face_vertex->Push(j, it.Floor());
if ( it.Tier() > 0 )
{
face_vertex->Push(j, it.Tier());
}
}
}
face_vertex->Finalize();
delete faces_tbl;
return face_vertex;
}
Table *Mesh::GetVertexToElementTable()
{
int i, j, nv, *v;
@@ -6402,7 +6448,7 @@ void Mesh::GenerateNCFaceInfo()
}
}
STable3D *Mesh::GetFacesTable()
STable3D *Mesh::GetFacesTable() const
{
STable3D *faces_tbl = new STable3D(NumOfVertices);
for (int i = 0; i < NumOfElements; i++)
@@ -7657,6 +7703,11 @@ void Mesh::UniformRefinement2D_base(bool update_nodes)
NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
}
if ( ent_sets )
{
ent_sets->CopyMeshTables();
}
int quad_counter = 0;
for (int i = 0; i < NumOfElements; i++)
{
@@ -7792,6 +7843,11 @@ void Mesh::UniformRefinement2D_base(bool update_nodes)
if (update_nodes) { UpdateNodes(); }
if ( ent_sets )
{
ent_sets->UniformRefinement2D();
}
#ifdef MFEM_DEBUG
if (!Nodes || update_nodes)
{
@@ -7822,6 +7878,11 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
GetElementToFaceTable();
}
if ( ent_sets )
{
ent_sets->CopyMeshTables();
}
Array<int> f2qf_loc;
Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
f2qf.SetSize(0);
@@ -8148,7 +8209,6 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
}
AverageVertices(vv, 4, oface + f2qf[f[fi]]);
}
for (int ei = 0; ei < 9; ei++)
{
for (int k = 0; k < 2; k++)
@@ -8492,6 +8552,11 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
sequence++;
if (update_nodes) { UpdateNodes(); }
if (ent_sets)
{
ent_sets->UniformRefinement3D();
}
}
void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
@@ -8961,6 +9026,8 @@ void Mesh::Swap(Mesh& other, bool non_geometry)
mfem::Swap(geom_factors, other.geom_factors);
mfem::Swap(ent_sets, other.ent_sets);
#ifdef MFEM_USE_MEMALLOC
TetMemory.Swap(other.TetMemory);
#endif
+11 -2
View File
@@ -20,6 +20,7 @@
#include "vertex.hpp"
#include "vtk.hpp"
#include "ncmesh.hpp"
#include "entsets.hpp"
#include "../fem/eltrans.hpp"
#include "../fem/coefficient.hpp"
#include "../general/zstr.hpp"
@@ -54,9 +55,11 @@ class Mesh
#ifdef MFEM_USE_MPI
friend class ParMesh;
friend class ParNCMesh;
friend class ParEntitySets;
#endif
friend class NCMesh;
friend class NURBSExtension;
friend class EntitySets;
#ifdef MFEM_USE_ADIOS2
friend class adios2stream;
@@ -166,6 +169,7 @@ protected:
Array<int> be_to_face;
mutable Table *face_edge;
mutable Table *edge_vertex;
mutable Table *face_vertex;
IsoparametricTransformation Transformation, Transformation2;
IsoparametricTransformation BdrTransformation;
@@ -216,6 +220,8 @@ public:
Array<FaceGeometricFactors*>
face_geom_factors; ///< Optional face geometric factors.
EntitySets *ent_sets;
// Global parameter that can be used to control the removal of unused
// vertices performed when reading a mesh in MFEM format. The default value
// (true) is set in mesh_readers.cpp.
@@ -287,7 +293,7 @@ protected:
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert);
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert);
STable3D *GetFacesTable();
STable3D *GetFacesTable() const;
STable3D *GetElementToFaceTable(int ret_ftbl = 0);
/** Red refinement. Element with index i is refined. The default
@@ -1067,9 +1073,12 @@ public:
/// Returns the face-to-edge Table (3D)
Table *GetFaceEdgeTable() const;
/// Returns the edge-to-vertex Table (3D)
/// Returns the edge-to-vertex Table (2D or 3D)
Table *GetEdgeVertexTable() const;
/// Returns the face-to-vertex Table (2d or 3D)
Table *GetFaceVertexTable() const;
/// Return the indices and the orientations of all faces of element i.
void GetElementFaces(int i, Array<int> &faces, Array<int> &ori) const;
+8
View File
@@ -100,6 +100,14 @@ void Mesh::ReadMFEMMesh(std::istream &input, int version, int &curved)
curved = 1;
}
ent_sets = new EntitySets(*this);
ent_sets->Load(input);
if ( ent_sets->GetNumSets(EntitySets::FACE) > 0 && faces.Size() == 0 )
{
GetElementToFaceTable();
GenerateFaces();
}
// When visualizing solutions on non-conforming grids, PETSc
// may dump additional vertices
if (remove_unused_vertices) { RemoveUnusedVertices(); }
+404 -4
View File
@@ -185,6 +185,10 @@ NCMesh::NCMesh(const Mesh *mesh)
face->attribute = be->GetAttribute();
}
// Store entity set information if present in the Mesh
ncent_sets = (mesh->ent_sets) ?
new NCEntitySets(*mesh->ent_sets, *this) : NULL;
// copy top-level vertex coordinates (leave empty if the mesh is curved)
if (!mesh->Nodes)
{
@@ -216,6 +220,10 @@ NCMesh::NCMesh(const NCMesh &other)
other.free_element_ids.Copy(free_element_ids);
other.root_state.Copy(root_state);
other.coordinates.Copy(coordinates);
// Copy the entity set information
ncent_sets = (other.ncent_sets) ? new NCEntitySets(*other.ncent_sets) : NULL;
Update();
}
@@ -254,8 +262,11 @@ NCMesh::~NCMesh()
DeleteUnusedFaces(elemFaces);
}
}
// NOTE: in release mode, we just throw away all faces and nodes at once
#endif
delete ncent_sets;
}
NCMesh::Node::~Node()
@@ -2504,6 +2515,42 @@ void NCMesh::OnMeshUpdated(Mesh *mesh)
if (face->index < 0) { face->index = NFaces + (nghosts++); }
}
MFEM_ASSERT(nghosts == NGhostFaces, "");
if (ncent_sets)
{
std::cout << "NCMesh::OnMeshUpdated ncent_sets is non NULL" << std::endl;
if (!mesh->ent_sets)
{
std::cout << "NCMesh::OnMeshUpdated creating ent_sets from NCMesh" << std::endl;
mesh->ent_sets = new EntitySets(*mesh, *this);
std::cout << "NCMesh::OnMeshUpdated done creating ent_sets from NCMesh" <<
std::endl;
}
}
std::ostringstream ossN;
ossN << "node_on_mesh_updated.out";
std::ofstream ofsN(ossN.str().c_str());
ofsN << nodes.Size() << std::endl;
for (int i=0; i<nodes.Size(); i++)
{
ofsN << i
// << " " << nodes[i].vert_refc
// << " " << nodes[i].edge_refc
<< " " << nodes[i].HasVertex()
<< " " << nodes[i].HasEdge()
<< " " << nodes[i].vert_index
<< " " << nodes[i].edge_index
<< " " << nodes[i].p1
<< " " << nodes[i].p2
<< " " << nodes[i].next << std::endl;
}
ofsN.close();
NEdges = mesh->GetNEdges();
NFaces = mesh->GetNumFaces();
std::cout << "Leaving NCMesh::OnMeshUpdated" << std::endl;
}
@@ -3306,12 +3353,15 @@ const NCMesh::MeshId& NCMesh::NCList::LookUp(int index, int *type) const
void NCMesh::CollectEdgeVertices(int v0, int v1, Array<int> &indices)
{
int mid = nodes.FindId(v0, v1);
if (mid >= 0 && nodes[mid].HasVertex())
if (mid >= 0)
{
indices.Append(mid);
if (nodes[mid].HasVertex())
{
indices.Append(mid);
CollectEdgeVertices(v0, mid, indices);
CollectEdgeVertices(mid, v1, indices);
CollectEdgeVertices(v0, mid, indices);
CollectEdgeVertices(mid, v1, indices);
}
}
}
@@ -3373,6 +3423,78 @@ void NCMesh::CollectQuadFaceVertices(int v0, int v1, int v2, int v3,
}
}
void NCMesh::CollectElementVertices(int elem_id, Array<int> &indices)
{
Element &el = elements[elem_id];
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size())
{
CollectElementVertices(el.child[i], indices);
}
}
}
else
{
// This element has not been refined so add its vertices
for (int i=0; i<8; i++)
{
if (el.node[i] >= 0 && el.node[i] < nodes.Size())
{
indices.Append(el.node[i]);
}
}
}
}
void NCMesh::CollectElementEdges(int elem_id, Array<int> &indices)
{
Element &el = elements[elem_id];
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size())
{
CollectElementEdges(el.child[i], indices);
}
}
}
else
{
int* node = el.node;
GeomInfo& gi = GI[(int) el.geom];
for (int i = 0; i < gi.nv; i++)
{
if (nodes[node[i]].HasEdge())
{
indices.Append(node[i]);
}
}
for (int i = 0; i < gi.ne; i++)
{
const int* ev = gi.edges[i];
int index = nodes.FindId(node[ev[0]], node[ev[1]]);
if (index >= 0)
{
if (nodes[index].HasEdge())
{
indices.Append(index);
}
}
}
}
}
void NCMesh::BuildElementToVertexTable()
{
int nrows = leaf_elements.Size();
@@ -4874,6 +4996,107 @@ int NCMesh::GetElementDepth(int i) const
return depth;
}
void NCMesh::GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edges)
{
std::cout << "entering NCMesh::GetRefinedEdges "
<<"searching for edge with vertices: " << vn0 << " and " << vn1
<< std::endl;
int mid = nodes.FindId(vn0, vn1);
if (mid < 0) { return; }
Node &nd = nodes[mid];
// if ( nd.edge_index < 0 ) { return; }
// edges.Append(nd.edge_index);
if ( nd.HasEdge() )
{
std::cout << " found node " << mid << std::endl;
edges.Append(mid);
}
GetRefinedEdges(vn0, mid, edges);
GetRefinedEdges(mid, vn1, edges);
}
void NCMesh::GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids)
{
// Face* fa = faces.Find(vn0, vn1, vn2, vn3);
int face = faces.FindId(vn0, vn1, vn2, vn3);
/*
if (fa)
{
if ( fa->index >= 0 )
{
face_ids.Append(fa->index);
}
return;
}
*/
if (face>=0)
{
if ( faces[face].index >= 0 )
{
face_ids.Append(face);
}
return;
}
// we need to recurse deeper
int mid[4];
int split = QuadFaceSplitType(vn0, vn1, vn2, vn3, mid);
if (split == 1) // "X" split face
{
GetRefinedFaces(vn0, mid[0], mid[2], vn3, face_ids);
GetRefinedFaces(mid[0], vn1, vn2, mid[2], face_ids);
}
else if (split == 2) // "Y" split face
{
GetRefinedFaces(vn0, vn1, mid[1], mid[3], face_ids);
GetRefinedFaces(mid[3], mid[1], vn2, vn3, face_ids);
}
}
void NCMesh::GetRefinedElements(int elem_id, BlockArray<int> & elem_ids)
{
// std::cout << "entering NCMesh::GetRefinedElements searching for element id: "
// << elem_id << std::endl;
Element &el = elements[elem_id];
/*
if (el.index >= 0 && el.rank >= 0)
{
elem_ids.Append(el.index);
return;
}
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size() )
{
GetRefinedElements(el.child[i], elem_ids);
}
}
*/
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size() )
{
GetRefinedElements(el.child[i], elem_ids);
}
}
}
else
{
// This element has not been refined so add it
elem_ids.Append(elem_id);
}
}
int NCMesh::GetElementSizeReduction(int i) const
{
int elem = leaf_elements[i];
@@ -4993,6 +5216,183 @@ void NCMesh::GetBoundaryClosure(const Array<int> &bdr_attr_is_ess,
bdr_edges.Unique();
}
void NCMesh::GetEntitySetClosure(EntitySets::EntityType type,
int set_index,
Array<int> &es_vertices,
Array<int> &es_edges,
Array<int> &es_faces)
{
es_vertices.SetSize(0);
es_edges.SetSize(0);
es_faces.SetSize(0);
MFEM_VERIFY(ncent_sets != NULL, "NCMesh object contains no "
"entity set information");
if (!ncent_sets->SetExists(type, set_index))
{
std::ostringstream oss; oss << "Entity set of type \""
<< EntitySets::GetTypeName(type)
<< "\" and index " << set_index
<< " was not found.";
MFEM_VERIFY(false, oss.str().c_str());
}
int ni = ncent_sets->GetNumEntities(type ,set_index);
Array<int> inds;
Array<int> coll_inds;
switch (type)
{
case EntitySets::VERTEX:
{
/// Do nothing because vertices cannot hide
}
break;
case EntitySets::EDGE:
{
for (int i=0; i<ni; i++)
{
ncent_sets->GetEntityIndex(type, set_index, i, inds);
// collect vertices
inds.Copy(coll_inds);
this->CollectEdgeVertices(inds[0], inds[1], coll_inds);
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].vert_index;
if (index >= 0)
{
es_vertices.Append(index);
}
}
}
}
break;
case EntitySets::FACE:
{
for (int i=0; i<ni; i++)
{
ncent_sets->GetEntityIndex(type, set_index, i, inds);
// collect vertices
inds.Copy(coll_inds);
if (inds.Size() == 4)
{
this->CollectQuadFaceVertices(inds[0], inds[1], inds[2], inds[3],
coll_inds);
}
else
{
this->CollectTriFaceVertices(inds[0], inds[1], inds[2],
coll_inds);
}
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].vert_index;
if (index >= 0)
{
es_vertices.Append(index);
}
}
}
}
break;
case EntitySets::ELEMENT:
{
for (int i=0; i<ni; i++)
{
int elem_id = (*ncent_sets)(type, set_index, i);
std::cout << "examining element " << elem_id << std::endl;
// collect vertices
coll_inds.SetSize(0);
this->CollectElementVertices(elem_id, coll_inds);
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].vert_index;
if (index >= 0)
{
es_vertices.Append(index);
}
}
// collect edges
coll_inds.SetSize(0);
this->CollectElementEdges(elem_id, coll_inds);
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].edge_index;
if (index >= 0)
{
es_edges.Append(index);
}
}
}
}
break;
default:
MFEM_ABORT("GetEnitySetClosure - Unknown entity set type: \""
<< EntitySets::GetTypeName(type) << "\"");
}
/*
if (Dim == 3)
{
GetFaceList(); // make sure 'boundary_faces' is up to date
for (int i = 0; i < boundary_faces.Size(); i++)
{
int face = boundary_faces[i];
if (bdr_attr_is_ess[faces[face].attribute - 1])
{
int node[4];
FindFaceNodes(face, node);
for (int j = 0; j < 4; j++)
{
bdr_vertices.Append(nodes[node[j]].vert_index);
int enode = nodes.FindId(node[j], node[(j+1) % 4]);
MFEM_ASSERT(enode >= 0 && nodes[enode].HasEdge(), "Edge not found.");
bdr_edges.Append(nodes[enode].edge_index);
while ((enode = GetEdgeMaster(enode)) >= 0)
{
// append master edges that may not be accessible from any
// boundary element, this happens in 3D in re-entrant corners
bdr_edges.Append(nodes[enode].edge_index);
}
}
}
}
}
else if (Dim == 2)
{
GetEdgeList(); // make sure 'boundary_faces' is up to date
for (int i = 0; i < boundary_faces.Size(); i++)
{
int face = boundary_faces[i];
Face &fc = faces[face];
if (bdr_attr_is_ess[fc.attribute - 1])
{
bdr_vertices.Append(nodes[fc.p1].vert_index);
bdr_vertices.Append(nodes[fc.p3].vert_index);
}
}
}
*/
es_vertices.Sort();
es_vertices.Unique();
es_edges.Sort();
es_edges.Unique();
es_faces.Sort();
es_faces.Unique();
}
static int max4(int a, int b, int c, int d)
{
return std::max(std::max(a, b), std::max(c, d));
+35
View File
@@ -19,6 +19,7 @@
#include "../linalg/densemat.hpp"
#include "element.hpp"
#include "vertex.hpp"
#include "entsets.hpp"
#include "../fem/geom.hpp"
#include <vector>
@@ -117,6 +118,9 @@ struct MatrixMap; // for internal use
*/
class NCMesh
{
friend class EntitySets;
friend class NCEntitySets;
public:
//// Initialize with elements from an existing 'mesh'.
explicit NCMesh(const Mesh *mesh);
@@ -343,6 +347,16 @@ public:
Array<int> &bdr_vertices,
Array<int> &bdr_edges);
/** Get a list of vertices (2D/3D), edges (2D/3D), and faces (3D) that
coincide with members of the specified entity set. In 3D this function
also reveals "hidden" edges or faces. In parallel it helps identifying
vertices/edges/faces affected by non-local entities. */
virtual void GetEntitySetClosure(EntitySets::EntityType t,
int set_index,
Array<int> &es_vertices,
Array<int> &es_edges,
Array<int> &es_faces);
/// Return element geometry type. @a index is the Mesh element number.
Geometry::Type GetElementGeometry(int index) const
{ return elements[leaf_elements[index]].Geom(); }
@@ -357,6 +371,19 @@ public:
/// Return the distance of leaf 'i' from the root.
int GetElementDepth(int i) const;
/** Collect edge indices of all refined edges which are children of
the coarse edge defined by the given vertices. */
void GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edge_ids);
/** Collect face indices of all refined faces which are children of
the coarse face defined by the given vertices. */
void GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids);
/** Collect element indices of all refined elements which are children of
the coarse element defined by the given element index. */
void GetRefinedElements(int elem_id, BlockArray<int> & elem_ids);
/** Return the size reduction compared to the root element (ignoring local
stretching and curvature). */
int GetElementSizeReduction(int i) const;
@@ -501,6 +528,7 @@ protected: // implementation
Array<double> coordinates;
// secondary data
/** Apart from the primary data structure, which is the element/node/face
@@ -530,6 +558,8 @@ protected: // implementation
Table element_vertex; ///< leaf-element to vertex table, see FindSetNeighbors
// Node/edge/Face/Element sets defined on the coarse mesh
NCEntitySets * ncent_sets;
void UpdateLeafElements();
void UpdateVertices(); ///< update Vertex::index and vertex_nodeId
@@ -711,6 +741,10 @@ protected: // implementation
void CollectTriFaceVertices(int v0, int v1, int v2, Array<int> &indices);
void CollectQuadFaceVertices(int v0, int v1, int v2, int v3,
Array<int> &indices);
void CollectElementVertices(int elem_id, Array<int> &indices);
void CollectElementEdges(int elem_id, Array<int> &indices);
void BuildElementToVertexTable();
void UpdateElementToVertexTable()
@@ -926,6 +960,7 @@ public:
#endif
friend class ParNCMesh; // for ParNCMesh::ElementSet
friend class ParNCEntitySets;
friend struct MatrixMap;
friend struct PointMatrixHash;
};
+392
View File
@@ -0,0 +1,392 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../config/config.hpp"
#ifdef MFEM_USE_MPI
#include "pentsets.hpp"
#include "pmesh.hpp"
using namespace std;
namespace mfem
{
ParEntitySets::ParEntitySets(const ParEntitySets & ent_sets)
: EntitySets(ent_sets),
pmesh_(ent_sets.GetParMesh())
{
MPI_Comm_size(pmesh_->GetComm(), &NRanks_);
MPI_Comm_rank(pmesh_->GetComm(), &MyRank_);
cout << MyRank_ << ": Entering ParEntitySets copy c'tor" << endl;
cout << MyRank_ << ": Leaving ParEntitySets copy c'tor" << endl;
}
ParEntitySets::ParEntitySets(ParMesh & pmesh, const EntitySets & ent_sets,
int * partitioning,
const Array<int> & vert_global_local)
: EntitySets(ent_sets),
pmesh_(&pmesh)
{
// The copy constructor for EntitySets will initialize this object's
// data with the correct set names, and numbers of sets. However,
// the set entries themselves will need to be recomputed based on
// local numberings and the paritioning.
//
// The EntitySets object will be a copy of the serial object. This
// constructor will have to prune and renumber the data. Once this
// is done the mesh pointer stored in the EntitySets object can be
// replaced with the local portion of the parallel mesh.
MPI_Comm MyComm = pmesh_->GetComm();
MPI_Comm_size(MyComm, &NRanks_);
MPI_Comm_rank(MyComm, &MyRank_);
cout << MyRank_ << ": Entering ParEntitySets(ParMesh, EntitySets, ...) c'tor" <<
endl;
int nelem = mesh_->GetNE();
DSTable v_to_v(vert_global_local.Size());
pmesh_->GetVertexToVertexTable(v_to_v);
STable3D * faces_tbl = NULL;
const Table * serial_edge_vertex = NULL;
const Table * serial_face_vertex = NULL;
if ( ent_sets.GetNumSets(EDGE) > 0 )
{
serial_edge_vertex = ent_sets.GetEdgeVertexTable();
}
if ( ent_sets.GetNumSets(FACE) > 0 )
{
serial_face_vertex = ent_sets.GetFaceVertexTable();
faces_tbl = pmesh_->GetFacesTable();
}
Array<int> elem_global_local(nelem);
elem_global_local = -1;
int elem_counter = 0;
for (int i=0; i<nelem; i++)
{
if ( partitioning[i] == MyRank_ )
{
elem_global_local[i] = elem_counter;
elem_counter++;
}
}
EntityType t;
unsigned int ns;
t = VERTEX;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
int v0 = vert_global_local[*it];
if ( v0 >= 0 )
{
sets_[t][s].insert(v0);
}
}
}
if ( pmesh_->Dimension() > 1 )
{
t = EDGE;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
int old_edge = *it;
const int *v = serial_edge_vertex->GetRow(old_edge);
int v0 = vert_global_local[v[0]];
int v1 = vert_global_local[v[1]];
if ( v0 >= 0 && v1 >= 0 )
{
int new_edge = v_to_v(v0,v1);
if ( new_edge >= 0 )
{
sets_[t][s].insert(new_edge);
}
}
}
}
}
if ( pmesh_->Dimension() > 2 )
{
Array<int> v;
t = FACE;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
int old_face = *it;
int numv = serial_face_vertex->RowSize(old_face);
const int *v = serial_face_vertex->GetRow(old_face);
if ( vert_global_local[v[0]] >= 0 &&
vert_global_local[v[1]] >= 0 &&
vert_global_local[v[2]] >= 0 )
{
int new_face = -1;
if ( numv == 3 )
{
new_face = (*faces_tbl)(vert_global_local[v[0]],
vert_global_local[v[1]],
vert_global_local[v[2]]);
}
else
{
new_face = (*faces_tbl)(vert_global_local[v[0]],
vert_global_local[v[1]],
vert_global_local[v[2]],
vert_global_local[v[3]]);
}
if ( new_face >= 0 )
{
sets_[t][s].insert(new_face);
}
}
}
}
delete faces_tbl;
}
t = ELEMENT;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
if ( partitioning[*it] == MyRank_ )
{
sets_[t][s].insert(elem_global_local[*it]);
}
}
}
this->mesh_ = (Mesh*)this->pmesh_;
this->CopyMeshTables();
cout << MyRank_ << ": Leaving ParEntitySets(ParMesh, EntitySets, ...) c'tor" <<
endl;
}
ParEntitySets::ParEntitySets(ParMesh & pmesh, ParNCMesh &pncmesh)
: EntitySets(pmesh),
pmesh_(&pmesh)
{
MPI_Comm MyComm = pmesh_->GetComm();
MPI_Comm_size(MyComm, &NRanks_);
MPI_Comm_rank(MyComm, &MyRank_);
cout << MyRank_ << ": Entering ParEntitySets(ParMesh, ParNCMesh) c'tor" << endl;
this->BuildEntitySets(pncmesh, VERTEX);
this->BuildEntitySets(pncmesh, EDGE);
this->BuildEntitySets(pncmesh, FACE);
this->BuildEntitySets(pncmesh, ELEMENT);
cout << MyRank_ << ": Leaving ParEntitySets(ParMesh, ParNCMesh) c'tor" << endl;
}
ParEntitySets::~ParEntitySets()
{
cout << MyRank_ << ": Entering ParEntitySets d'tor" << endl;
cout << MyRank_ << ": Leaving ParEntitySets d'tor" << endl;
}
void
ParEntitySets::PrintSetInfo(std::ostream & output) const
{
if ( MyRank_ == 0 &&
( GetNumSets(VERTEX) > 0 || GetNumSets(EDGE) > 0 ||
GetNumSets(FACE) > 0 || GetNumSets(ELEMENT) > 0 ) )
{
output << "\nMFEM Parallel Entity Sets:\n";
}
this->PrintEntitySetInfo(output, VERTEX, "Vertex");
this->PrintEntitySetInfo(output, EDGE, "Edge");
this->PrintEntitySetInfo(output, FACE, "Face");
this->PrintEntitySetInfo(output, ELEMENT, "Element");
}
void
ParEntitySets::PrintEntitySetInfo(std::ostream & output, EntityType t,
const string & ent_name) const
{
if ( sets_[t].size() > 0 )
{
if ( MyRank_ == 0 )
{
output << " " << ent_name
<< " Sets (Index, Set Name, Global Size):\n";
}
for (unsigned int s=0; s<sets_[t].size(); s++)
{
int loc_size = sets_[t][s].size();
int glb_size = -1;
MPI_Reduce(&loc_size, &glb_size, 1, MPI_INT, MPI_SUM, 0,
pmesh_->GetComm());
if ( MyRank_ == 0 )
{
output << '\t' << s
<< '\t' << set_names_[t][s]
<< '\t' << glb_size
<< '\n';
}
}
if ( MyRank_ == 0 )
{
output << '\n';
}
}
}
void
ParEntitySets::BuildEntitySets(ParNCMesh &pncmesh, EntityType t)
{
cout << MyRank_ << ": BuildEntitySets for type " << GetTypeName(t) << endl;
int es = pncmesh.pncent_sets->GetEntitySize(t);
unsigned int ns = pncmesh.pncent_sets->GetNumSets(t);
cout << MyRank_ << ": num sets " << ns << endl;
Array<int> inds(es);
sets_[t].resize(ns);
set_names_[t].resize(ns);
for (unsigned int s=0; s<ns; s++)
{
int ni = pncmesh.pncent_sets->GetNumEntities(t, s);
set_names_[t][s] = pncmesh.pncent_sets->GetSetName(t, s);
set_index_by_name_[t][set_names_[t][s]] = s;
switch (t)
{
case VERTEX:
for (int i=0; i<ni; i++)
{
int node = (*pncmesh.pncent_sets)(t, s, i);
int index = pncmesh.nodes[node].vert_index;
if (!pncmesh.IsGhost(0,index))
{
sets_[t][s].insert(index);
}
}
break;
case EDGE:
for (int i=0; i<ni; i++)
{
pncmesh.pncent_sets->GetEntityIndex(t, s, i, inds);
BlockArray<int> ind_coll;
pncmesh.GetRefinedEdges(inds[0], inds[1],
ind_coll);
for (int j=0; j<ind_coll.Size(); j++)
{
int edge = ind_coll[j];
int index = pncmesh.nodes[edge].edge_index;
if (index >= 0 && !pncmesh.IsGhost(1, index))
{
sets_[t][s].insert(index);
}
}
}
break;
case FACE:
for (int i=0; i<ni; i++)
{
pncmesh.pncent_sets->GetEntityIndex(t, s, i, inds);
BlockArray<int> ind_coll;
pncmesh.GetRefinedFaces(inds[0], inds[1], inds[2], inds[3],
ind_coll);
for (int j=0; j<ind_coll.Size(); j++)
{
int face = ind_coll[j];
int index = pncmesh.faces[face].index;
if (index >= 0 && !pncmesh.IsGhost(2, index))
{
sets_[t][s].insert(index);
}
}
}
break;
case ELEMENT:
for (int i=0; i<ni; i++)
{
int elem = (*pncmesh.pncent_sets)(t, s, i);
BlockArray<int> ind_coll;
pncmesh.GetRefinedElements(elem, ind_coll);
for (int j=0; j<ind_coll.Size(); j++)
{
sets_[t][s].insert(pncmesh.elements[ind_coll[j]].index);
}
}
break;
default:
MFEM_ABORT("Unknown entity set type: \"" << GetTypeName(t) << "\"");
}
cout << MyRank_ << ": " << set_names_[t][s] << " " << s << " set size " <<
sets_[t][s].size() << "{";
for (set<int>::iterator it=sets_[t][s].begin(); it!=sets_[t][s].end(); it++)
{
cout << " " << *it;
}
cout << "}" << endl;
}
map<string,int>::iterator it;
cout << MyRank_ << ": set index by name ";
for (it=set_index_by_name_[t].begin(); it != set_index_by_name_[t].end(); it++)
{
cout << " " << it->first << "->" << it->second;
}
cout << endl;
cout << MyRank_ << ": done BuildEntitySets for type " << GetTypeName(t) << endl;
}
ParNCEntitySets::ParNCEntitySets(MPI_Comm comm, const NCMesh &ncmesh)
: NCEntitySets(*ncmesh.ncent_sets)
{
MyComm_ = comm;
MPI_Comm_size(MyComm_, &NRanks_);
MPI_Comm_rank(MyComm_, &MyRank_);
if ( MyRank_ == 0 )
{
cout << "Entering ParNCEntitySets(NCMesh) c'tor" << endl;
}
if ( MyRank_ == 0 )
{
cout << "Leaving ParNCEntitySets(NCMesh) c'tor" << endl;
}
}
} // namespace mfem
#endif // MFEM_USE_MPI
+74
View File
@@ -0,0 +1,74 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_PAR_ENTITY_SETS
#define MFEM_PAR_ENTITY_SETS
#include "../config/config.hpp"
#ifdef MFEM_USE_MPI
#include "entsets.hpp"
#include "../general/communication.hpp"
namespace mfem
{
class ParMesh;
class ParNCMesh;
class ParEntitySets : public EntitySets
{
friend class ParMesh;
public:
ParEntitySets(const ParEntitySets & ent_sets);
ParEntitySets(ParMesh & _mesh, const EntitySets & ent_sets, int * part,
const Array<int> & vert_global_local);
ParEntitySets(ParMesh & mesh, ParNCMesh &ncmesh);
virtual ~ParEntitySets();
virtual void PrintSetInfo(std::ostream &output) const;
inline ParMesh *GetParMesh() const { return pmesh_; }
private:
void PrintEntitySetInfo(std::ostream & output, EntityType t,
const std::string & ent_name) const;
void BuildEntitySets(ParNCMesh &pncmesh, EntityType t);
ParMesh * pmesh_;
int NRanks_;
int MyRank_;
};
class ParNCEntitySets : public NCEntitySets
{
public:
// ParNCEntitySets(MPI_Comm comm, EntitySets &ent_sets, NCMesh &ncmesh);
ParNCEntitySets(MPI_Comm comm, const NCMesh &ncmesh);
// ParNCEntitySets(const ParMesh & pmesh, const ParNCMesh &pncmesh);
// ParNCEntitySets(const ParNCEntitySets & pncent_sets);
private:
MPI_Comm MyComm_;
int NRanks_;
int MyRank_;
};
} // namespace mfem
#endif // MFEM_USE_MPI
#endif // MFEM_PAR_ENTITY_SETS
+37 -3
View File
@@ -91,6 +91,10 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes)
*Nodes = *pmesh.Nodes;
own_nodes = 1;
}
// Copy entity sets if present in the input mesh
ent_sets = pent_sets =
(pmesh.pent_sets) ? new ParEntitySets(*pmesh.pent_sets) : NULL;
}
ParMesh::ParMesh(ParMesh &&mesh) : ParMesh()
@@ -110,6 +114,7 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
, glob_elem_offset(-1)
, glob_offset_sequence(-1)
, gtopo(comm)
, pent_sets(NULL)
{
int *partitioning = NULL;
Array<bool> activeBdrElem;
@@ -118,6 +123,8 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
MPI_Comm_size(MyComm, &NRanks);
MPI_Comm_rank(MyComm, &MyRank);
Array<int> vert_global_local;
if (mesh.Nonconforming())
{
if (partitioning_)
@@ -148,6 +155,10 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
mesh.bdr_attributes.Copy(bdr_attributes);
GenerateNCFaceInfo();
// if (mesh.ent_sets)
// NumOfVertices = BuildLocalVertices(mesh, partitioning,
// vert_global_local);
}
else // mesh.Conforming()
{
@@ -168,7 +179,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
// re-enumerate the partitions to better map to actual processor
// interconnect topology !?
Array<int> vert_global_local;
NumOfVertices = BuildLocalVertices(mesh, partitioning, vert_global_local);
NumOfElements = BuildLocalElements(mesh, partitioning, vert_global_local);
@@ -240,6 +250,12 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
SetMeshGen();
meshgen = mesh.meshgen; // copy the global 'meshgen'
ent_sets = pent_sets =
(mesh.ent_sets) ? new ParEntitySets(*this, *mesh.ent_sets,
partitioning,
vert_global_local)
: NULL;
}
if (mesh.NURBSext)
@@ -289,7 +305,12 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
// for compatibility (e.g., Mesh::GetVertex())
SetVerticesFromNodes(Nodes);
}
/*
ent_sets = pent_sets =
(mesh.ent_sets) ? new ParEntitySets(*this, *mesh.ent_sets,
partitioning,
vert_global_local) : NULL;
*/
if (partitioning != partitioning_)
{
delete [] partitioning;
@@ -859,6 +880,7 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh)
, glob_offset_sequence(-1)
, gtopo(MyComm)
, pncmesh(NULL)
, pent_sets(NULL)
{
Mesh::InitFromNCMesh(pncmesh);
ReduceMeshGen();
@@ -925,6 +947,7 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine)
, glob_elem_offset(-1)
, glob_offset_sequence(-1)
, gtopo(comm)
, pent_sets(NULL)
{
MyComm = comm;
MPI_Comm_size(MyComm, &NRanks);
@@ -1139,7 +1162,8 @@ void ParMesh::MakeRefined_(ParMesh &orig_mesh, int ref_factor, int ref_type)
gtopo = orig_mesh.gtopo;
have_face_nbr_data = false;
pncmesh = NULL;
pent_sets = NULL;
Array<int> ref_factors(orig_mesh.GetNE());
ref_factors = ref_factor;
Mesh::MakeRefined_(orig_mesh, ref_factors, ref_type);
@@ -3768,6 +3792,13 @@ void ParMesh::NonconformingRefinement(const Array<Refinement> &refinements,
// and this mesh will be the new fine mesh
Mesh::Swap(*pmesh2, false);
// swap entity set information if present
mfem::Swap(pmesh2->pent_sets, this->pent_sets);
if (this->pent_sets)
{
this->pent_sets->pmesh_ = this;
}
delete pmesh2; // NOTE: old face neighbors destroyed here
pncmesh->GetConformingSharedStructures(*this);
@@ -6171,6 +6202,9 @@ void ParMesh::Destroy()
delete pncmesh;
ncmesh = pncmesh = NULL;
delete pent_sets;
ent_sets = pent_sets = NULL;
DeleteFaceNbrData();
for (int i = 0; i < shared_edges.Size(); i++)
+2
View File
@@ -20,6 +20,7 @@
#include "../general/globals.hpp"
#include "mesh.hpp"
#include "pncmesh.hpp"
#include "pentsets.hpp"
#include <iostream>
namespace mfem
@@ -320,6 +321,7 @@ public:
Table send_face_nbr_vertices;
ParNCMesh* pncmesh;
ParEntitySets* pent_sets;
int GetNGroups() const { return gtopo.NGroups(); }
+508
View File
@@ -20,6 +20,8 @@
#include <map>
#include <climits> // INT_MIN, INT_MAX
#include <fstream> // MLS Debugging
namespace mfem
{
@@ -27,6 +29,7 @@ using namespace bin_io;
ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part)
: NCMesh(ncmesh)
, pncent_sets(NULL)
{
MyComm = comm;
MPI_Comm_size(MyComm, &NRanks);
@@ -41,6 +44,40 @@ ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part)
Update();
std::ostringstream oss; oss << "elements_" << MyRank << ".out";
std::ofstream ofs(oss.str().c_str());
for (int i=0; i<elements.Size(); i++)
{
ofs << i
<< '\t' << elements[i].index
<< '\t' << elements[i].rank
<< '\t' << elements[i].attribute
<< '\t' << elements[i].parent;
if ( elements[i].ref_type == 0 )
{
ofs << " nodes {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].node[j];
}
ofs << "}";
}
else
{
ofs << " children {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].child[j];
}
ofs << "}";
}
ofs << std::endl;
}
ncent_sets = pncent_sets =
(ncmesh.ncent_sets) ? new ParNCEntitySets(comm, ncmesh) : NULL;
// note that at this point all processors still have all the leaf elements;
// we however may now start pruning the refinement tree to get rid of
// branches that only contain someone else's leaves (see Prune())
@@ -85,6 +122,9 @@ ParNCMesh::ParNCMesh(const ParNCMesh &other)
ParNCMesh::~ParNCMesh()
{
ClearAuxPM();
delete pncent_sets;
ncent_sets = pncent_sets = NULL;
}
void ParNCMesh::Update()
@@ -115,6 +155,386 @@ void ParNCMesh::Update()
boundary_layer.SetSize(0);
}
/*
void ParNCMesh::AssignLeafIndices()
{
// This is an override of NCMesh::AssignLeafIndices(). The difference is
// that we shift all elements we own to the beginning of the array
// 'leaf_elements' and assign all ghost elements indices >= NElements.
// Also note that the ordering of ghosts and non-ghosts is preserved here,
// which is important for ParNCMesh::GetFaceNeighbors.
// We store the original leaf ordering in 'leaf_glob_order'. This is later
// used (and deleted) in GetConformingSharedStructures
NCMesh::AssignLeafIndices(); // original numbering, for 'leaf_glob_order'
int nleafs = leaf_elements.Size();
Array<int> ghosts;
ghosts.Reserve(nleafs);
NElements = 0;
for (int i = 0; i < nleafs; i++)
{
int elem = leaf_elements[i];
if (elements[elem].rank == MyRank)
{
leaf_elements[NElements++] = elem;
}
else
{
ghosts.Append(elem);
}
}
NGhostElements = ghosts.Size();
leaf_elements.SetSize(NElements);
leaf_elements.Append(ghosts);
// store original (globally consistent) numbering in 'leaf_glob_order'
leaf_glob_order.SetSize(nleafs);
for (int i = 0; i < nleafs; i++)
{
leaf_glob_order[i] = elements[leaf_elements[i]].index;
}
// new numbering with ghost shifted to the back
NCMesh::AssignLeafIndices();
}
void ParNCMesh::UpdateVertices()
{
// This is an override of NCMesh::UpdateVertices. This version first
// assigns vert_index to vertices of elements of our rank. Only these
// vertices then make it to the Mesh in NCMesh::GetMeshComponents.
// The remaining (ghost) vertices are assigned indices greater or equal to
// Mesh::GetNV().
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasVertex()) { node->vert_index = -1; }
}
NVertices = 0;
for (int i = 0; i < leaf_elements.Size(); i++)
{
Element &el = elements[leaf_elements[i]];
if (el.rank == MyRank)
{
for (int j = 0; j < GI[el.Geom()].nv; j++)
{
int &vindex = nodes[el.node[j]].vert_index;
if (vindex < 0) { vindex = NVertices++; }
}
}
}
vertex_nodeId.SetSize(NVertices);
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasVertex() && node->vert_index >= 0)
{
vertex_nodeId[node->vert_index] = node.index();
}
}
NGhostVertices = 0;
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasVertex() && node->vert_index < 0)
{
node->vert_index = NVertices + (NGhostVertices++);
}
}
}
void ParNCMesh::OnMeshUpdated(Mesh *mesh)
{
std::cout << MyRank << ": Entering ParNCMesh::OnMeshUpdated" << std::endl;
// This is an override (or extension of) NCMesh::OnMeshUpdated().
// In addition to getting edge/face indices from 'mesh', we also
// assign indices to ghost edges/faces that don't exist in the 'mesh'.
// clear edge_index and Face::index
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasEdge()) { node->edge_index = -1; }
}
for (face_iterator face = faces.begin(); face != faces.end(); ++face)
{
face->index = -1;
}
// go assign existing edge/face indices
NCMesh::OnMeshUpdated(mesh);
std::cout << MyRank << ": NVertices = " << NVertices << std::endl;
std::ostringstream ossN;
ossN << "node_on_mesh_updated_" << MyRank << ".out";
std::ofstream ofsN(ossN.str().c_str());
ofsN << nodes.Size() << std::endl;
for (int i=0; i<nodes.Size(); i++)
{
ofsN << i
// << " " << nodes[i].vert_refc
// << " " << nodes[i].edge_refc
<< " " << nodes[i].HasVertex()
<< " " << nodes[i].HasEdge()
<< " " << nodes[i].vert_index
<< " " << nodes[i].edge_index
<< " " << nodes[i].p1
<< " " << nodes[i].p2
<< " " << nodes[i].next << std::endl;
}
ofsN.close();
// count ghost edges and assign their indices
NEdges = mesh->GetNEdges();
NGhostEdges = 0;
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasEdge() && node->edge_index < 0)
{
node->edge_index = NEdges + (NGhostEdges++);
}
}
// count ghost faces
NFaces = mesh->GetNumFaces();
NGhostFaces = 0;
for (face_iterator face = faces.begin(); face != faces.end(); ++face)
{
if (face->index < 0) { NGhostFaces++; }
}
if (Dim == 2)
{
// in 2D we have fake faces because of DG
MFEM_ASSERT(NFaces == NEdges, "");
MFEM_ASSERT(NGhostFaces == NGhostEdges, "");
}
// resize face_geom (default_geom is for slave faces beyond the ghost layer)
Geometry::Type default_geom = Geometry::SQUARE;
face_geom.SetSize(NFaces + NGhostFaces, default_geom);
// update 'face_geom' for ghost faces, assign ghost face indices
int nghosts = 0;
for (int i = 0; i < NGhostElements; i++)
{
Element &el = elements[leaf_elements[NElements + i]]; // ghost element
GeomInfo &gi = GI[el.Geom()];
for (int j = 0; j < gi.nf; j++)
{
const int *fv = gi.faces[j];
Face* face = faces.Find(el.node[fv[0]], el.node[fv[1]],
el.node[fv[2]], el.node[fv[3]]);
MFEM_ASSERT(face, "face not found!");
if (face->index < 0)
{
face->index = NFaces + (nghosts++);
// store the face geometry
static const Geometry::Type types[5] =
{
Geometry::INVALID, Geometry::INVALID,
Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::SQUARE
};
face_geom[face->index] = types[gi.nfv[j]];
}
}
}
// assign valid indices also to faces beyond the ghost layer
for (face_iterator face = faces.begin(); face != faces.end(); ++face)
{
if (face->index < 0) { face->index = NFaces + (nghosts++); }
}
MFEM_ASSERT(nghosts == NGhostFaces, "");
{
/// Debugging output
std::ostringstream oss; oss << "elements_on_mesh_updated_"
<< MyRank << ".out";
std::ofstream ofs(oss.str().c_str());
for (int i=0; i<elements.Size(); i++)
{
ofs << i
<< '\t' << elements[i].index
<< '\t' << elements[i].rank
<< '\t' << elements[i].attribute
<< '\t' << elements[i].parent;
if ( elements[i].ref_type == 0 )
{
ofs << " nodes {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].node[j];
}
ofs << "}";
}
else
{
ofs << " children {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].child[j];
}
ofs << "}";
}
ofs << std::endl;
}
if (pncent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated pncent_sets is non NULL" << std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated pncent_sets is NULL" << std::endl;
}
if (ncent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated ncent_sets is non NULL" << std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated ncent_sets is NULL" << std::endl;
}
if (mesh->ent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated mesh->ent_sets is non NULL" << std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated mesh->ent_sets is NULL" << std::endl;
}
ParMesh * pmesh = dynamic_cast<ParMesh*>(mesh);
if (pmesh)
{
std::cout << "dynamic cast succeeded: mesh is a ParMesh" << std::endl;
if (pmesh->pent_sets != NULL)
{
std::cout << "ParNCMesh::OnMeshUpdated deleting ParEntitySets object in ParMesh"
<< std::endl;
delete pmesh->pent_sets;
}
else if (pmesh->ent_sets != NULL)
{
std::cout << "ParNCMesh::OnMeshUpdated deleting EntitySets object in ParMesh" <<
std::endl;
delete pmesh->ent_sets;
}
std::cout << "ParNCMesh::OnMeshUpdated creating ParEntitySets object in ParMesh"
<< std::endl;
pmesh->ent_sets = pmesh->pent_sets =
(pncent_sets) ? new ParEntitySets(*pmesh, *this): NULL;
*/
/*
if (pmesh->ent_sets)
{
std::cout << MyRank << ": ParNCMesh::OnMeshUpdated pmesh->ent_sets is non NULL" << std::endl;
pmesh->ent_sets->PrintSetInfo(std::cout);
std::ostringstream oss; oss << "ent_sets_" << MyRank << ".out";
std::ofstream ofs(oss.str().c_str());
pmesh->ent_sets->Print(ofs);
MPI_Barrier(MyComm);
std::cout << MyRank << ": testing " << NElements << std::endl;
//pmesh->ent_sets->Prune(NElements);
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated pmesh->ent_sets is NULL" << std::endl;
}
*/
/*
if (pmesh->pent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated pmesh->pent_sets is non NULL" <<
std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated pmesh->pent_sets is NULL" << std::endl;
}
}
else
{
std::cout << "dynamic cast failed: mesh is not a ParMesh" << std::endl;
}
*/
/*
if (pncent_sets)
{
if (!pmesh->pent_sets)
{
pmesh->pent_sets = new ParEntitySets(*pmesh, *this);
}
}
*/
/*
// Prune the Entity Sets
if ( entity_sets )
{
EntitySets::EntityType t = EntitySets::INVALID;
unsigned int ns = -1;
std::cout << "Processing node sets" << std::endl;
t = EntitySets::VERTEX;
ns = entity_sets->GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
unsigned int ni = entity_sets->GetNumEntities(t, s);
int e = 0;
for (unsigned int i=0; i<ni; i++)
{
if ( (*mesh->ent_sets)(t, s, i) < NVertices )
{
(*mesh->ent_sets)(t, s, e) = (*mesh->ent_sets)(t, s, i);
e++;
}
}
(*mesh->ent_sets)(t, s).resize(e);
}
t = EntitySets::EDGE;
ns = entity_sets->GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
unsigned int ni = entity_sets->GetNumEntities(t, s);
BlockArray<int> ids;
for (unsigned int i=0; i<ni; i++)
{
if ( (*mesh->ent_sets)(t, s, i) < NEdges )
{
ids.Append((*mesh->ent_sets)(t, s, i));
}
}
(*mesh->ent_sets)(t, s).resize(ids.Size());
for (int i=0; i<ids.Size(); i++)
{
(*mesh->ent_sets)(t, s, i) = ids[i];
}
}
}
*/
/*
std::cout << MyRank << ": Leaving ParNCMesh::OnMeshUpdated" << std::endl;
}
}
*/
void ParNCMesh::ElementSharesFace(int elem, int local, int face)
{
// Analogous to ElementSharesEdge.
@@ -2732,6 +3152,94 @@ void ParNCMesh::GetDebugMesh(Mesh &debug_mesh) const
debug_mesh.ncmesh = copy;
}
void ParNCMesh::GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edges)
{
std::cout << MyRank
<< ": entering ParNCMesh::GetRefinedEdges "
<<"searching for edge with vertices: " << vn0 << " and " << vn1
<< std::endl;
return this->NCMesh::GetRefinedEdges(vn0, vn1, edges);
int mid = nodes.FindId(vn0, vn1);
if (mid < 0) { return; }
/*
Node &nd = nodes[mid];
if ( nd.edge_index < 0 ) { return; }
edges.Append(nd.edge_index);
GetRefinedEdges(vn0, mid, edges);
GetRefinedEdges(mid, vn1, edges);
*/
edges.Append(mid);
GetRefinedEdges(vn0, mid, edges);
GetRefinedEdges(mid, vn1, edges);
}
void ParNCMesh::GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids)
{
return this->NCMesh::GetRefinedFaces(vn0, vn1, vn2, vn3, face_ids);
/*
Face* fa = faces.Find(vn0, vn1, vn2, vn3);
if (fa)
{
if ( fa->index >= 0 )
{
face_ids.Append(fa->index);
}
return;
}
// we need to recurse deeper
int mid[4];
int split = FaceSplitType(vn0, vn1, vn2, vn3, mid);
if (split == 1) // "X" split face
{
GetRefinedFaces(vn0, mid[0], mid[2], vn3, face_ids);
GetRefinedFaces(mid[0], vn1, vn2, mid[2], face_ids);
}
else if (split == 2) // "Y" split face
{
GetRefinedFaces(vn0, vn1, mid[1], mid[3], face_ids);
GetRefinedFaces(mid[3], mid[1], vn2, vn3, face_ids);
}
*/
}
void ParNCMesh::GetRefinedElements(int elem_id, BlockArray<int> & elem_ids)
{
// std::cout << MyRank
// << ": entering ParNCMesh::GetRefinedElements "
// <<"searching for element id: " << elem_id << std::endl;
Element &el = elements[elem_id];
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size() )
{
GetRefinedElements(el.child[i], elem_ids);
}
}
}
else
{
// This element has not been refined so add it if it's a local element
if (el.rank == MyRank)
{
elem_ids.Append(elem_id);
}
}
}
void ParNCMesh::Trim()
{
NCMesh::Trim();
+23
View File
@@ -20,6 +20,7 @@
#include <set>
#include "ncmesh.hpp"
#include "pentsets.hpp"
#include "../general/communication.hpp"
#include "../general/sort_pairs.hpp"
@@ -248,9 +249,29 @@ public:
The debug mesh will have element attributes set to element rank + 1. */
void GetDebugMesh(Mesh &debug_mesh) const;
/** Collect edge indices of all refined edges which are children of
the coarse edge defined by the given vertices. This method
overrides a method in NCMesh and only returns locally owned
edges. */
void GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edge_ids);
/** Collect face indices of all refined faces which are children of
the coarse face defined by the given vertices. This method
overrides a method in NCMesh and only returns locally owned
faces. */
void GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids);
/** Collect element indices of all refined elements which are
children of the coarse element defined by the given element
index. This method overrides a method in NCMesh and only
returns locally owned elements. */
void GetRefinedElements(int elem_id, BlockArray<int> & elem_ids);
protected: // interface for ParMesh
friend class ParMesh;
friend class ParEntitySets;
/** For compatibility with conforming code in ParMesh and ParFESpace.
Initializes shared structures in ParMesh: gtopo, shared_*, group_s*, s*_l*.
@@ -540,6 +561,8 @@ protected: // implementation
Array<DenseMatrix*> aux_pm_store;
void ClearAuxPM();
ParNCEntitySets * pncent_sets;
long GroupsMemoryUsage() const;
friend class NeighborRowMessage;
+24 -23
View File
@@ -35,30 +35,31 @@ if (MFEM_USE_MPI)
LIBRARIES mfem mfem-common)
# Add the corresponding tests to the "test" target
add_test(NAME tesla_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:tesla> -no-vis -maxit 2 -cr "0 0 -0.2 0 0 0.2 0.2 0.4 1"
${MPIEXEC_POSTFLAGS})
if (MFEM_ENABLE_TESTING)
add_test(NAME tesla_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:tesla> -no-vis -maxit 2 -cr "0 0 -0.2 0 0 0.2 0.2 0.4 1"
${MPIEXEC_POSTFLAGS})
add_test(NAME volta_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:volta> -no-vis -maxit 2 -dbcs 1 -dbcg -ds "0.0 0.0 0.0 0.2 8.0"
${MPIEXEC_POSTFLAGS})
add_test(NAME volta_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:volta> -no-vis -maxit 2 -dbcs 1 -dbcg -ds "0.0 0.0 0.0 0.2 8.0"
${MPIEXEC_POSTFLAGS})
add_test(NAME joule_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:joule>
-no-vis -p rod -tf 3 -m ${CMAKE_CURRENT_SOURCE_DIR}/cylinder-hex.mesh
${MPIEXEC_POSTFLAGS})
add_test(NAME maxwell_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:maxwell>
-no-vis -abcs "-1" -dp "-0.3 0.0 0.0 0.3 0.0 0.0 0.1 1 .5 .5"
${MPIEXEC_POSTFLAGS})
add_test(NAME joule_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:joule>
-no-vis -p rod -tf 3 -m ${CMAKE_CURRENT_SOURCE_DIR}/cylinder-hex.mesh
${MPIEXEC_POSTFLAGS})
add_test(NAME maxwell_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:maxwell>
-no-vis -abcs "-1" -dp "-0.3 0.0 0.0 0.3 0.0 0.0 0.1 1 .5 .5"
${MPIEXEC_POSTFLAGS})
endif()
endif()
+16 -12
View File
@@ -78,10 +78,12 @@ add_mfem_miniapp(polar-nc
LIBRARIES mfem)
# Add serial tests.
add_test(NAME mesh-optimizer
COMMAND mesh-optimizer -no-vis -m ${CMAKE_CURRENT_SOURCE_DIR}/icf.mesh)
if (MFEM_ENABLE_TESTING)
add_test(NAME mesh-optimizer
COMMAND mesh-optimizer -no-vis -m ${CMAKE_CURRENT_SOURCE_DIR}/icf.mesh)
add_test(NAME minimal-surface COMMAND minimal-surface -no-vis)
add_test(NAME minimal-surface COMMAND minimal-surface -no-vis)
endif()
# Parallel apps.
if (MFEM_USE_MPI)
@@ -96,14 +98,16 @@ if (MFEM_USE_MPI)
LIBRARIES mfem)
# Add parallel tests.
add_test(NAME pmesh-optimizer_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:pmesh-optimizer> -no-vis
-m ${CMAKE_CURRENT_SOURCE_DIR}/icf.mesh
${MPIEXEC_POSTFLAGS})
if (MFEM_ENABLE_TESTING)
add_test(NAME pmesh-optimizer_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:pmesh-optimizer> -no-vis
-m ${CMAKE_CURRENT_SOURCE_DIR}/icf.mesh
${MPIEXEC_POSTFLAGS})
add_test(NAME pminimal-surface_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:pminimal-surface> -no-vis
${MPIEXEC_POSTFLAGS})
add_test(NAME pminimal-surface_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:pminimal-surface> -no-vis
${MPIEXEC_POSTFLAGS})
endif()
endif()
+60 -54
View File
@@ -13,82 +13,88 @@ add_mfem_miniapp(nurbs_ex1
MAIN nurbs_ex1.cpp
LIBRARIES mfem)
add_test(NAME nurbs_ex1_r0_o4_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis -r 0 -o 4)
if (MFEM_ENABLE_TESTING)
add_test(NAME nurbs_ex1_r0_o4_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis -r 0 -o 4)
add_test(NAME nurbs_ex1_r2_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis -r 2)
add_test(NAME nurbs_ex1_r2_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis -r 2)
add_test(NAME nurbs_ex1_per_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/beam-hex-nurbs.mesh -pm 1 -ps 2)
add_test(NAME nurbs_ex1_per_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/beam-hex-nurbs.mesh -pm 1 -ps 2)
add_test(NAME nurbs_ex1_lap_r0_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 0)
add_test(NAME nurbs_ex1_lap_r0_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 0)
add_test(NAME nurbs_ex1_lap_r2_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 2)
add_test(NAME nurbs_ex1_lap_r2_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 2)
add_test(NAME nurbs_ex1_weak_r0_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 0)
add_test(NAME nurbs_ex1_weak_r0_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 0)
add_test(NAME nurbs_ex1_weak_r2_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2)
add_test(NAME nurbs_ex1_weak_r2_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2)
add_test(NAME nurbs_ex1_weak_mp_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0)
add_test(NAME nurbs_ex1_weak_mp_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0)
add_test(NAME nurbs_ex1_weak_patch_format_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0)
add_test(NAME nurbs_ex1_weak_patch_format_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0)
add_test(NAME nurbs_ex1_weak_patch_format_r1_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1)
add_test(NAME nurbs_ex1_weak_patch_format_r1_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1)
endif()
if (MFEM_USE_MPI)
add_mfem_miniapp(nurbs_ex1p
MAIN nurbs_ex1p.cpp
LIBRARIES mfem)
add_test(NAME nurbs_ex1p_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
${MPIEXEC_POSTFLAGS})
if (MFEM_ENABLE_TESTING)
add_test(NAME nurbs_ex1p_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
${MPIEXEC_POSTFLAGS})
add_test(NAME nurbs_ex1p_lap_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis -m
${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -no-ibp
${MPIEXEC_POSTFLAGS})
add_test(NAME nurbs_ex1p_lap_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis -m
${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -no-ibp
${MPIEXEC_POSTFLAGS})
add_test(NAME nurbs_ex1p_weak_mp_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0
${MPIEXEC_POSTFLAGS})
add_test(NAME nurbs_ex1p_weak_mp_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0
${MPIEXEC_POSTFLAGS})
add_test(NAME nurbs_ex1_weak_patch_format_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0)
add_test(NAME nurbs_ex1_weak_patch_format_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0)
add_test(NAME nurbs_ex1_weak_patch_format_r1_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1)
add_test(NAME nurbs_ex1_weak_patch_format_r1_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1)
endif()
add_mfem_miniapp(nurbs_ex11p
MAIN nurbs_ex11p.cpp
LIBRARIES mfem)
add_test(NAME nurbs_ex11p_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex11p> -no-vis
${MPIEXEC_POSTFLAGS})
if (MFEM_ENABLE_TESTING)
add_test(NAME nurbs_ex11p_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex11p> -no-vis
${MPIEXEC_POSTFLAGS})
endif()
endif()
+10 -6
View File
@@ -42,8 +42,10 @@ add_mfem_miniapp(performance_ex1
LIBRARIES mfem
EXTRA_OPTIONS ${PERFORMANCE_CXX_OPTIONS})
add_test(NAME performance_ex1_ser
COMMAND performance_ex1 -no-vis -r 2)
if (MFEM_ENABLE_TESTING)
add_test(NAME performance_ex1_ser
COMMAND performance_ex1 -no-vis -r 2)
endif()
if (MFEM_USE_MPI)
add_mfem_miniapp(performance_ex1p
@@ -51,8 +53,10 @@ if (MFEM_USE_MPI)
LIBRARIES mfem
EXTRA_OPTIONS ${PERFORMANCE_CXX_OPTIONS})
add_test(NAME performance_ex1p_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:performance_ex1p> -no-vis -rs 2
${MPIEXEC_POSTFLAGS})
if (MFEM_ENABLE_TESTING)
add_test(NAME performance_ex1p_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:performance_ex1p> -no-vis -rs 2
${MPIEXEC_POSTFLAGS})
endif()
endif()
+15 -13
View File
@@ -22,20 +22,22 @@ if (MFEM_USE_MPI)
LIBRARIES mfem)
# Add the corresponding tests to the "test" target
add_test(NAME block-solvers-constant
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:block-solvers> -r 2
${MPIEXEC_POSTFLAGS})
if (MFEM_ENABLE_TESTING)
add_test(NAME block-solvers-constant
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:block-solvers> -r 2
${MPIEXEC_POSTFLAGS})
add_test(NAME block-solvers-anisotropic
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:block-solvers> -r 2
-m ${CMAKE_CURRENT_SOURCE_DIR}/anisotropic.mesh
-c ${CMAKE_CURRENT_SOURCE_DIR}/anisotropic.coeff
-eb ${CMAKE_CURRENT_SOURCE_DIR}/anisotropic.brd
${MPIEXEC_POSTFLAGS})
add_test(NAME block-solvers-anisotropic
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:block-solvers> -r 2
-m ${CMAKE_CURRENT_SOURCE_DIR}/anisotropic.mesh
-c ${CMAKE_CURRENT_SOURCE_DIR}/anisotropic.coeff
-eb ${CMAKE_CURRENT_SOURCE_DIR}/anisotropic.brd
${MPIEXEC_POSTFLAGS})
endif()
endif()
add_mfem_miniapp(lor_solvers
+1
View File
@@ -55,6 +55,7 @@ set(UNIT_TESTS_SRCS
fem/test_bilinearform.cpp
fem/test_blocknonlinearform.cpp
fem/test_calcshape.cpp
fem/test_coefficient.cpp
fem/test_datacollection.cpp
fem/test_derefine.cpp
fem/test_estimator.cpp
+308
View File
@@ -0,0 +1,308 @@
// Copyright (c) 2010-2021, 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.
#include "mfem.hpp"
#include "unit_tests.hpp"
using namespace mfem;
TEST_CASE("Piecewise Coefficient",
"[PWCoefficient]")
{
ConstantCoefficient oneCoef(1.0);
ConstantCoefficient twoCoef(2.0);
ConstantCoefficient sixCoef(6.0);
ConstantCoefficient tenCoef(10.0);
IsoparametricTransformation T;
IntegrationPoint ip;
Array<int> attr;
Array<Coefficient*> coefs;
attr.Append(1);
coefs.Append(&oneCoef);
attr.Append(6);
coefs.Append(&sixCoef);
SECTION("Default Constructor")
{
PWCoefficient pw;
// Verify value of zero for nonexistent attributes
T.Attribute = 1;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(0.0));
T.Attribute = 2;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(0.0));
// Test nonexistent coefficient removal
pw.ZeroCoefficient(2);
// Test adding individual coefficient
pw.UpdateCoefficient(2, twoCoef);
T.Attribute = 2;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(2.0));
// Test adding multiple coefficieints
pw.UpdateCoefficients(attr, coefs);
T.Attribute = 1;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(1.0));
T.Attribute = 2;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(2.0));
T.Attribute = 6;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(6.0));
// Test replacing coefficient
pw.UpdateCoefficient(2, tenCoef);
T.Attribute = 2;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(10.0));
// Test coefficient removal
pw.ZeroCoefficient(2);
T.Attribute = 2;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(0.0));
}
SECTION("Array Constructor")
{
PWCoefficient pw(attr, coefs);
// Verify predefined values
T.Attribute = 1;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(1.0));
T.Attribute = 2;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(0.0));
T.Attribute = 6;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(6.0));
// Test adding individual coefficient
pw.UpdateCoefficient(2, twoCoef);
T.Attribute = 2;
REQUIRE(pw.Eval(T, ip) == MFEM_Approx(2.0));
}
}
TEST_CASE("Piecewise Vector Coefficient",
"[PWVectorCoefficient]")
{
int d = 3;
Vector v(d); v = 0.0;
Vector oneVec(d); oneVec = 1.0;
Vector twoVec(d); twoVec = 2.0;
Vector sixVec(d); sixVec = 6.0;
Vector tenVec(d); tenVec = 10.0;
double oneNorm = oneVec.Norml2();
double twoNorm = twoVec.Norml2();
double sixNorm = sixVec.Norml2();
double tenNorm = tenVec.Norml2();
VectorConstantCoefficient oneCoef(oneVec);
VectorConstantCoefficient twoCoef(twoVec);
VectorConstantCoefficient sixCoef(sixVec);
VectorConstantCoefficient tenCoef(tenVec);
IsoparametricTransformation T;
IntegrationPoint ip;
Array<int> attr;
Array<VectorCoefficient*> coefs;
attr.Append(1);
coefs.Append(&oneCoef);
attr.Append(6);
coefs.Append(&sixCoef);
SECTION("Default Constructor")
{
PWVectorCoefficient pw(d);
// Verify value of zero for nonexistent attributes
T.Attribute = 1;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(0.0));
T.Attribute = 2;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(0.0));
// Test nonexistent coefficient removal
pw.ZeroCoefficient(2);
// Test adding individual coefficient
pw.UpdateCoefficient(2, twoCoef);
T.Attribute = 2;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(twoNorm));
// Test adding multiple coefficieints
pw.UpdateCoefficients(attr, coefs);
T.Attribute = 1;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(oneNorm));
T.Attribute = 2;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(twoNorm));
T.Attribute = 6;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(sixNorm));
// Test replacing coefficient
pw.UpdateCoefficient(2, tenCoef);
T.Attribute = 2;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(tenNorm));
// Test coefficient removal
pw.ZeroCoefficient(2);
T.Attribute = 2;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(0.0));
}
SECTION("Array Constructor")
{
PWVectorCoefficient pw(d, attr, coefs);
// Verify predefined values
T.Attribute = 1;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(oneNorm));
T.Attribute = 2;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(0.0));
T.Attribute = 6;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(sixNorm));
// Test adding individual coefficient
pw.UpdateCoefficient(2, twoCoef);
T.Attribute = 2;
pw.Eval(v, T, ip);
REQUIRE(v.Norml2() == MFEM_Approx(twoNorm));
}
}
TEST_CASE("Piecewise Matrix Coefficient",
"[PWMatrixCoefficient]")
{
int d = 3;
DenseMatrix m(d); m = 0.0;
DenseMatrix oneMat(d); oneMat = 1.0;
DenseMatrix twoMat(d); twoMat = 2.0;
DenseMatrix sixMat(d); sixMat = 6.0;
DenseMatrix tenMat(d); tenMat = 10.0;
double oneNorm = oneMat.FNorm();
double twoNorm = twoMat.FNorm();
double sixNorm = sixMat.FNorm();
double tenNorm = tenMat.FNorm();
MatrixConstantCoefficient oneCoef(oneMat);
MatrixConstantCoefficient twoCoef(twoMat);
MatrixConstantCoefficient sixCoef(sixMat);
MatrixConstantCoefficient tenCoef(tenMat);
IsoparametricTransformation T;
IntegrationPoint ip;
Array<int> attr;
Array<MatrixCoefficient*> coefs;
attr.Append(1);
coefs.Append(&oneCoef);
attr.Append(6);
coefs.Append(&sixCoef);
SECTION("Default Constructor")
{
PWMatrixCoefficient pw(d);
// Verify value of zero for nonexistent attributes
T.Attribute = 1;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(0.0));
T.Attribute = 2;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(0.0));
// Test nonexistent coefficient removal
pw.ZeroCoefficient(2);
// Test adding individual coefficient
pw.UpdateCoefficient(2, twoCoef);
T.Attribute = 2;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(twoNorm));
// Test adding multiple coefficieints
pw.UpdateCoefficients(attr, coefs);
T.Attribute = 1;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(oneNorm));
T.Attribute = 2;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(twoNorm));
T.Attribute = 6;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(sixNorm));
// Test replacing coefficient
pw.UpdateCoefficient(2, tenCoef);
T.Attribute = 2;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(tenNorm));
// Test coefficient removal
pw.ZeroCoefficient(2);
T.Attribute = 2;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(0.0));
}
SECTION("Array Constructor")
{
PWMatrixCoefficient pw(d, attr, coefs);
// Verify predefined values
T.Attribute = 1;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(oneNorm));
T.Attribute = 2;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(0.0));
T.Attribute = 6;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(sixNorm));
// Test adding individual coefficient
pw.UpdateCoefficient(2, twoCoef);
T.Attribute = 2;
pw.Eval(m, T, ip);
REQUIRE(m.FNorm() == MFEM_Approx(twoNorm));
}
}
+44
View File
@@ -60,6 +60,17 @@ TEST_CASE("DoF Transformation Classes",
REQUIRE(w.Norml2() < tol * u.Norml2());
}
SECTION("Inverse Dual DoF transformation")
{
Vector w;
ut = u; T.TransformDual(ut);
w = ut; T.InvTransformDual(w);
w -= u;
REQUIRE(w.Norml2() < tol * u.Norml2());
}
SECTION("Inner product with linear form f(v)")
{
@@ -267,6 +278,17 @@ TEST_CASE("VDoF Transformation Class",
REQUIRE(w.Norml2() < tol * v.Norml2());
}
SECTION("Inverse Dual DoF transformation")
{
Vector w;
vt = v; T.TransformDual(vt);
w = vt; T.InvTransformDual(w);
w -= v;
REQUIRE(w.Norml2() < tol * v.Norml2());
}
SECTION("Inner product with linear form f(v)")
{
vt = v; T.TransformPrimal(vt);
@@ -302,6 +324,17 @@ TEST_CASE("VDoF Transformation Class",
REQUIRE(w.Norml2() < tol * v.Norml2());
}
SECTION("Inverse Dual DoF transformation")
{
Vector w;
vt = v; T.TransformDual(vt);
w = vt; T.InvTransformDual(w);
w -= v;
REQUIRE(w.Norml2() < tol * v.Norml2());
}
SECTION("Inner product with linear form f(v)")
{
vt = v; T.TransformPrimal(vt);
@@ -327,6 +360,17 @@ TEST_CASE("VDoF Transformation Class",
REQUIRE(w.Norml2() < tol * v.Norml2());
}
SECTION("Inverse Dual DoF transformation")
{
Vector w;
vt = v; T.TransformDual(vt);
w = vt; T.InvTransformDual(w);
w -= v;
REQUIRE(w.Norml2() < tol * v.Norml2());
}
SECTION("Inner product with linear form f(v)")
{
vt = v; T.TransformPrimal(vt);
+27 -10
View File
@@ -40,7 +40,7 @@ void vectorcoeff(const Vector& x, Vector& y)
TEST_CASE("transfer")
{
for (int vectorspace = 0; vectorspace <= 1; ++vectorspace)
for (int vectorspace = 0; vectorspace <= 3; ++vectorspace)
{
for (dimension = 2; dimension <= 3; ++dimension)
{
@@ -52,7 +52,6 @@ TEST_CASE("transfer")
{
for (int geometric = 0; geometric <= 1; ++geometric)
{
int fineOrder = (geometric == 1) ? order : 2 * order;
std::cout << "Testing transfer:\n"
@@ -83,10 +82,27 @@ TEST_CASE("transfer")
}
mesh = Mesh::MakeCartesian3D(ne, ne, ne, type, 1.0, 1.0, 1.0);
}
FiniteElementCollection* c_h1_fec =
new H1_FECollection(order, dimension);
FiniteElementCollection* f_h1_fec = (geometric == 1) ? c_h1_fec : new
H1_FECollection(fineOrder, dimension);
FiniteElementCollection* c_h1_fec = nullptr;
FiniteElementCollection* f_h1_fec = nullptr;
if (vectorspace < 2)
{
c_h1_fec = new H1_FECollection(order, dimension);
f_h1_fec = (geometric == 1) ? c_h1_fec : new
H1_FECollection(fineOrder, dimension);
}
else if (vectorspace == 2)
{
c_h1_fec = new ND_FECollection(order+1, dimension);
f_h1_fec = (geometric == 1) ? c_h1_fec : new
ND_FECollection(fineOrder, dimension);
}
else
{
c_h1_fec = new RT_FECollection(order, dimension);
f_h1_fec = (geometric == 1) ? c_h1_fec : new
RT_FECollection(fineOrder, dimension);
}
Mesh fineMesh(mesh);
if (geometric)
@@ -101,10 +117,11 @@ TEST_CASE("transfer")
spaceDimension = dimension;
}
FiniteElementSpace* c_h1_fespace = new FiniteElementSpace(&mesh, c_h1_fec,
spaceDimension);
FiniteElementSpace* f_h1_fespace = new FiniteElementSpace(&fineMesh, f_h1_fec,
spaceDimension);
FiniteElementSpace* c_h1_fespace =
new FiniteElementSpace(&mesh, c_h1_fec, spaceDimension);
FiniteElementSpace* f_h1_fespace =
new FiniteElementSpace(&fineMesh, f_h1_fec,spaceDimension);
Operator* referenceOperator = nullptr;