Compare commits

...
Author SHA1 Message Date
Veselin Dobrev 33ccd307bd Include "mpi-ext.h" only if using OpenMPI. 2018-08-23 17:50:39 -07:00
Veselin Dobrev 958e0f27c4 Add an option in mfem::occa::Engine to force the use of CUDA
pointers in MPI calls, regardless of the result of the
CUDA-aware MPI check.
2018-08-23 17:21:24 -07:00
Veselin Dobrev 07d043ec77 Add a message in the ctor of OccaConformingProlongation that shows
if MPI is CUDA aware or not - this is done only when using the CUDA
OCCA mode.
2018-08-21 12:16:00 -07:00
Veselin Dobrev a61e836c4a Fix a bug in the 3D mass and diffusion GPU kernels: add barriers. 2018-08-21 05:20:31 -07:00
Veselin Dobrev aa58b549ab Include "mpi-ext.h" only when MPI_USE_MPI is defined. 2018-08-20 02:30:42 -07:00
Veselin Dobrev 87b9412e80 In class OccaConformingProlongation, check for CUDA-aware MPI. 2018-08-20 02:02:07 -07:00
Veselin Dobrev 36a9a3ac92 A few enhancements in ex1d and ex1pd - can be removed later,
before merging into master.
2018-08-18 09:40:00 -07:00
Veselin Dobrev 5bd5e169a3 Fix a bug in the class OccaConformingProlongation - need to wait for
the first copy kernel to finish before MPI communication is started.

Other small tweaks.
2018-08-15 15:47:28 -07:00
Johann Dahm a2ad9af08f Add VectorMassIntegrator 2018-08-13 10:37:58 -07:00
Veselin Dobrev c967429b2d A couple of small tweaks. 2018-08-06 17:48:13 -07:00
Johann Dahm c33e2edb72 Changes for ex16d in CUDA mode 2018-08-06 12:59:44 -07:00
Johann Dahm 7057bde885 Merge branch 'engines-dev' of github.com:mfem/mfem into engines-dev 2018-08-06 10:50:03 -07:00
Veselin Dobrev fa1f7666c4 In the OCCA backend, add support for parallel prolongation on
conforming meshes without transferring the whole vector to host
memory.

Add support for parallel AMR meshes with engines.

In class mfem::FiniteElementSpace, the conforming prolongation,
cP, and conforming restriction, cR, are no longer lazy-constructed.

In class ParFiniteElementSpace, rename the parallel versions of
the methods Construct and Destroy to ParConstruct and ParDestroy,
respectively.

In class ParFiniteElementSpace, use the field pncmesh in all
places instead of pmesh->pncmesh.

A number of small tweaks in the OCCA backend.
2018-08-06 02:25:32 -07:00
Veselin Dobrev 066c37520a Cleanup some of the code in the OCCA backend:
* Remove the method mfem::occa::Engine::GetOklDefines().
 * Switch the argument of mfem::occa::Array::OccaFill() from 'const T *'
   to 'const T'.
 * Remove unused constructors from mfem::occa::OccaSparseMatrix and make
   some of its members protected.
 * Replace 'restrict' with '@restrict' in .okl files.
 * When the prolongation is identity, initialize the occa prolongation
   and restriction operators to NULL.
2018-08-04 20:17:12 -07:00
Veselin Dobrev 61cd1aa8cd Add two new methods to the PFiniteElementSpace interface:
GetInterpolationOperator() and GetGradientOperator(), both of which map
GridFunction-size vectors (L-vectors) to QuadratureFunction-size vectors
(Q-vectors).

These new methods are not yet implemented in the OCCA backend.
2018-08-03 19:51:14 -07:00
Veselin Dobrev f87dbdc2ad Make QuadratureFunction::OwnsSpace() a const method 2018-08-03 19:49:20 -07:00
Veselin Dobrev 6c0777c0e1 Merge branch 'master' into engines-dev
Resolved conflicts:
   config/config.hpp.in
   config/config.mk.in
   config/defaults.mk
   fem/bilinearform.cpp
   makefile
2018-08-03 19:45:51 -07:00
Johann Dahm 3051b7ed11 Merge branch 'engines-dev' of github.com:mfem/mfem into engines-dev 2018-08-02 10:51:08 -07:00
Johann Dahm e77ee6a3a3 Update to latest OCCA commit and make ex16d work in GPU mode 2018-08-02 10:50:02 -07:00
Veselin Dobrev d0c90c8505 Some tweaks and cleanup in the OCCA backend.
Adjust the return types of the methods GetVLayout, GetTrueVLayout, and
Get_PFESpace in class FiniteElementSpace.

Add missing return statements in the methods mfem::Engine::As.
2018-08-01 21:52:37 -07:00
Veselin Dobrev 8ee2e444be Re-enable the engine in ex1d.
Small tweak in backends/occa/utils.okl.
2018-07-30 22:59:25 -07:00
Veselin Dobrev 7336d8ea84 Update the occa spec strings in ex1pd and ex16d. 2018-07-30 21:23:38 -07:00
Veselin Dobrev cf053cdc59 Move some methods in mfem::Engine from .hpp to .cpp.
Update the occa spec strings in ex1d to use the latest syntax.
2018-07-30 21:18:30 -07:00
Tzanio Kolev eea8eb2185 Merge pull request #528 from mfem/cubit2d-dev
2D Cubit mesh support [cubit2d-dev]
2018-07-30 13:26:51 -04:00
Tzanio Kolev 8847515e10 Merge pull request #538 from mfem/sidredc-groups-dev
Pass bp_index group instead of global group to SidreDataCollection with external DS [sidredc-groups-dev]
2018-07-30 12:46:03 -04:00
Tzanio Kolev 77e891594c Merge pull request #552 from mfem/densemat-gen-eigs-dev
Adding generalized eigenvalue solver to DenseMatrix class [densemat-gen-eigs-dev]
2018-07-30 09:28:22 -04:00
Tzanio Kolev 9e463e651f Merge pull request #553 from mfem/kronecker-prod-dev
Adding various methods mixing sparse and dense matrices [kronecker-prod-dev]
2018-07-30 09:27:50 -04:00
Tzanio Kolev 550013e3ca Merge pull request #556 from mfem/elem-center-dev
Adding Mesh::GetElementCenter method [elem-center-dev]
2018-07-30 09:26:32 -04:00
Tzanio Kolev ca3153c960 Merge pull request #551 from mfem/stable3d-print-dev
Adding a STable3D::Print method for debugging purposes [stable3d-print-dev]
2018-07-30 09:25:58 -04:00
Johann Dahm e845d83cce Example 16 working with OCCA engine
The coefficient is computed on the host and pushed to the device on
every SetParameters call.
2018-07-29 23:21:44 -07:00
Tzanio 59600de4e2 Restoring Example 1 (test version was accidently commited). 2018-07-27 16:37:44 -07:00
Tzanio 4ff1f83372 Mentioned 2D Cubit support in CHANGELOG 2018-07-27 15:29:31 -07:00
Stowell, Mark L ed24bda6ba Fixing an accidental recursion loop... 2018-07-26 08:44:06 -07:00
Veselin Dobrev df73fff427 In the CUBIT mesh reader, allow loading of meshes without side-sets. 2018-07-25 14:43:04 -07:00
Stowell, Mark L 40e07a61c3 Adding Mesh::GetElementCenter method 2018-07-25 14:24:56 -07:00
Thomas Stitt 76b79f5b0f fix doc param name 2018-07-24 14:43:19 -07:00
Tzanio 955b1a8e78 Minor 2018-07-24 04:37:00 -07:00
Tzanio e684c8d7bf Extra new line 2018-07-24 04:31:13 -07:00
Stowell, Mark L 0290cdf39f Adding various methods mixing sparse and dense matrices 2018-07-23 21:33:11 -07:00
Stowell, Mark L e785777248 Adding generalized eigenvalue solver to DenseMatrix class 2018-07-23 20:46:05 -07:00
Stowell, Mark L 577399cb45 Adding a STable3D::Print method for debugging purposes 2018-07-23 20:24:19 -07:00
Tzanio Kolev 58f8873b73 Merge pull request #541 from mfem/FixVectorRestrictedCoefficient
Fixed DenseMatrix::SetSize call argument [FixVectorRestrictedCoefficient]
2018-07-23 14:56:10 -04:00
Tzanio Kolev 5feae230e2 Merge pull request #522 from mfem/pmatrix-groups-fix
Better processor groups in P matrix construction [pmatrix-groups-fix]
2018-07-23 14:55:45 -04:00
Johann Dahm 9764593415 Make restrict compatible with current OKL format 2018-07-22 17:49:03 -07:00
Veselin Dobrev be1d6582fc Merge branch 'master' into FixVectorRestrictedCoefficient 2018-07-18 14:46:41 -07:00
Veselin Dobrev ee38e0bc9f Merge pull request #542 from mfem/revert-480-cut-mesh-groups-dev
Revert "Group communicator on (parallel) cut meshes [cut-mesh-groups-dev]"
2018-07-18 22:41:16 +01:00
Veselin Dobrev 39fd944dba Revert "Group communicator on (parallel) cut meshes [cut-mesh-groups-dev]" 2018-07-18 14:26:30 -07:00
Syun'ichi Shiraiwa 1ace21502c Fixed DenseMatrix::SetSize call argument 2018-07-18 11:10:26 -04:00
Robert Anderson f950613551 Merge pull request #480 from mfem/cut-mesh-groups-dev
Group communicator on (parallel) cut meshes [cut-mesh-groups-dev]
2018-07-13 20:32:33 -07:00
Robert W. Anderson 1dcbb71b8a Merge branch 'cut-mesh-groups-dev' of github.com:mfem/mfem into cut-mesh-groups-dev 2018-07-13 20:19:05 -07:00
Robert W. Anderson 282f35f6e0 use scalar group comm, works in nonconforming case 2018-07-13 20:17:59 -07:00
Robert W. Anderson acafb9f51a construct true dofs in nonconforming case since we now have comm groups 2018-07-13 20:17:29 -07:00
Thomas Stitt 91e027f3da When using an external sidredatacollection pass in the blueprint_index
group instead of the global group. The global group is used only
to create the blueprint index group and the global group may be shared
between multiple users; it is easier to manage if the sdc only creates
groups and views under unshared groups.
2018-07-13 17:27:58 -07:00
Tzanio Kolev 14ffb48a7f Merge pull request #521 from mfem/h1_hessian-dev
CalcHessian for H1_TriangleElement and H1_TetrahedronElement [h1_hessian-dev]
2018-07-12 07:59:47 +01:00
Tzanio Kolev adf023e004 Merge pull request #501 from mfem/visit-lod-dev
Adding a desired LOD field to the visit output [visit-lod-dev]
2018-07-12 07:59:30 +01:00
Johann Dahm 5beb85d4ce Move DontDelete() to e_layout in backend FiniteElementSpace 2018-07-05 15:03:11 -07:00
Jun Kudo 1a3e725327 Style mesh/mesh_readers.cpp 2018-07-05 09:18:44 -07:00
Jakub Cerveny 05381c7054 Simplified flagging of shared entities (removed extra 'if's). 2018-07-05 09:28:45 +02:00
Veselin Dobrev c0b2b60849 Some tweaks in VisItDataCollection.
This should fix a segfault uncovered by the internal unit tests,
which probably was due to 'mesh' being NULL leading to segfault
when accessing 'mesh->NURBSext'.
2018-07-03 16:34:05 -07:00
aschaf ff25ff7fc7 Changed the formula for the second derivative of the Chebyshev polynomials 2018-07-03 11:14:13 +02:00
Johann Dahm 7f1d0689ef Make mfem::Vertex trivially copyable 2018-07-02 22:40:38 -07:00
Jun Kudo dbabb7b0f6 Add 2D cubit mesh reader functionality 2018-07-02 13:23:40 -07:00
Tzanio Kolev e67555245b Merge pull request #519 from mfem/quad-hex-refine-fix
Fix quad/hex refinement by adding DeleteLazyTables() [quad-hex-refine-fix]
2018-07-02 16:29:03 +02:00
Tzanio Kolev e5629820e1 Merge pull request #506 from mfem/stefanozampini/fix-example
Fixes to PETSc examples [stefanozampini/fix-example]
2018-07-02 16:28:27 +02:00
Jakub Cerveny ebe26c548c One more fix of dof_owner/group init, now it runs OK on vulcan 64K cores. 2018-06-29 14:08:36 +02:00
Jakub Cerveny d8c6edeb4a Fixed initialization of dof_group/owner. 2018-06-29 11:07:35 +02:00
Tzanio 8ebd1614a3 better formating 2018-06-28 23:01:59 -07:00
Tzanio dd905c22a1 make style 2018-06-28 22:57:10 -07:00
Jakub Cerveny be0751c4d2 Merge branch 'master' into pmatrix-groups-fix 2018-06-28 16:12:08 +02:00
Jakub Cerveny 3dc412dcc0 Reverting debug stuff in ex1p.cpp. 2018-06-28 16:07:41 +02:00
Jakub Cerveny 8a82a839bb Cleaned up init of dof_group[], dof_owner[]. 2018-06-28 16:06:06 +02:00
Jakub Cerveny 22af5c49f3 Fixed two more errors, new groups are now working. 2018-06-28 15:35:03 +02:00
Tamas Horvath 0e0a2b1611 Fix quad/hex refinement by adding DeleteLazyTables() 2018-06-27 10:41:44 -04:00
Stefano Zampini 5ebce1f5e0 Merge branch 'stefanozampini/fix-example' of github.com:mfem/mfem into stefanozampini/fix-example 2018-06-26 13:37:43 +03:00
Stefano Zampini a88beec11e update PETSc options file to prevent examples from failing 2018-06-26 13:35:50 +03:00
Jakub Cerveny f46f27daac Fixed initialization of dof_group (some shared entites were skipped). 2018-06-22 14:56:32 +02:00
Veselin Dobrev 0824833e35 Update the PETSc example tests in the CMake build system. 2018-06-16 18:56:01 -07:00
aschaf f03324b804 H1_TriangleElement & H1_TetrahedronElement: added CalcHessian
I implmented CalcHessian for H1_TriangleElement and H1_TetrahedronElement. The 2nd derivatives in the Hessian are orderd "u_xx, u_xy, u_yy" and "u_xx, u_xy, u_xz, u_yy, u_yz, u_zz", respectively.

Poly_1D was expanded by a third CalcBasis function which takes an additional argument for the 2nd derivative. As only CalcChebyshev is not commented out, I just implemented the 2nd derivatives for the Chebyshev Polynomials, also with an additional argument for the 2nd derivative.
2018-06-16 12:34:36 +02:00
Jakub Cerveny 4884209327 Debugging new P matrix groups. 2018-06-15 20:38:24 +02:00
Tzanio Kolev fd809e44b5 Merge pull request #514 from mfem/doxygen-fix
Fixing a few links on the main Doxygen page [doxygen-fix]
2018-06-12 07:00:49 +02:00
Tzanio 5d466d9583 Fixing a few links on the main Doxygen page 2018-06-11 17:52:36 -07:00
Tzanio Kolev 4eb307758e Merge pull request #510 from mfem/pumi-skip-tests
Skip the PUMI tests if the PUMI data directory is not available [pumi-skip-tests]
2018-06-11 15:57:57 +02:00
Tzanio Kolev 996842cb94 Merge pull request #511 from mfem/par-mesh-read-fix
Add optional 'refine' parameter to the ParMesh constructor ... [par-mesh-read-fix]
2018-06-11 15:57:08 +02:00
Veselin Dobrev 4d3b1fab9a Add optional 'refine' parameter to the ParMesh constructor that
reads from an input stream.
2018-06-04 18:08:51 -07:00
Veselin Dobrev e50bf78531 Skip the PUMI tests if the PUMI data directory is not available. 2018-06-03 00:28:15 -07:00
Jakub Cerveny 8a87fbffde Finished better calculation of groups and shared lists, debugging. 2018-06-01 17:12:25 +02:00
Jakub Cerveny fa3ded8e1a WIP better calculation of groups and shared lists 2018-05-31 18:22:20 +02:00
Stefano Zampini d73d29508b Add nonoverlapping assembly to ex6p tests 2018-05-31 11:49:30 +03:00
Stefano Zampini b8fb486ba5 Added hybridization example (improve code coverage) 2018-05-31 11:12:53 +03:00
Stefano Zampini eb651cd3fc Change composed object name to match that used inside the PETSc library 2018-05-31 11:10:20 +03:00
Stefano Zampini 3d62128f3a PETSc examples: test local boundary specification 2018-05-31 10:54:00 +03:00
Stefano Zampini b79d47eb93 Synch PETSc rc files with PETSc 3.9 2018-05-31 10:53:38 +03:00
Stefano Zampini 30f623bdad PETSc example ex5p : added command line option to cover more library code 2018-05-31 10:52:18 +03:00
Veselin Dobrev a7e2df44c6 Merge pull request #504 from mfem/bump-to-v3.4.1
Update version to 3.4.1 -- new development version [bump-to-v3.4.1]
2018-05-30 16:10:20 -07:00
Jakub Cerveny 4a4ed4c0c3 WIP better calculation of shared groups and lists in ParNCMesh. 2018-05-30 17:36:07 +02:00
Veselin Dobrev 7b2e60490d Update version to 3.4.1 -- new development version.
In doc/CodeDocumentation.conf.in, add examples/pumi to the list of
directories searched for source files.
2018-05-29 19:14:08 -07:00
Veselin Dobrev 0715efbaf9 Merge pull request #487 from mfem/docs-dev
Improved documentation [docs-dev]
2018-05-29 16:39:33 -07:00
Tzanio 0cdd280bb4 Small change in meshing README 2018-05-29 16:36:13 -07:00
Veselin Dobrev ce12d07d38 In CONTRIBUTING.md, add the directory examples/pumi in the code overview
diagram.
2018-05-29 15:51:00 -07:00
Tzanio 37757faaae Merge branch 'master' into docs-dev 2018-05-29 06:20:43 -07:00
Tzanio Kolev ca14e8054a Merge pull request #503 from mfem/slave-faces-fix
Shared slave faces fix
2018-05-29 06:19:16 -07:00
Tzanio Kolev a0dec4d0fb Merge pull request #499 from najlkin/pr3
Improved QuadratureFunction and QuadratureSpace...
2018-05-29 06:19:03 -07:00
Tzanio Kolev 787efc1f52 Merge pull request #489 from najlkin/pr2
Added const qualifier to the solutions in the essential bc elimination methods
2018-05-29 06:18:46 -07:00
Tzanio Kolev 4a3c6794a0 Merge pull request #237 from mfem/pumi-dev
Parallel Unstructured Mesh Infrastructure (PUMI) integration [pumi-dev]
2018-05-29 06:18:09 -07:00
Jakub Cerveny c77e3318e9 After testing, turned on the temporary suboptimal version of ParNCMesh::AddMasterSlaveConnections. 2018-05-28 15:41:12 +02:00
Tzanio 59afdb57fc Updated examples/README.html 2018-05-25 17:32:11 -07:00
Tzanio b1112870d1 mfem-3.4 will be released on May 29th, 2018. 2018-05-25 16:32:50 -07:00
Tzanio 954c5b7f04 All green 2018-05-25 16:24:34 -07:00
Tzanio 7f515c1031 Typo 2018-05-25 16:08:13 -07:00
Tzanio e48992b6e3 Adding README in examples/pumi (similar to sundials, petsc) 2018-05-25 16:00:47 -07:00
Tzanio 055efbad50 Minor 2018-05-25 15:56:13 -07:00
Tzanio 81e8551911 Uniform copyright 2018-05-25 15:50:18 -07:00
Tzanio 55fc5f2536 Updated CHANGELOG 2018-05-25 15:43:40 -07:00
Tzanio 2886d5b08f Mention GLVis in INSTALL 2018-05-25 15:41:28 -07:00
Tzanio b6b5e5f53e Updated html files with 3.4 documentation from mfem/web/mfem-3.4 branch 2018-05-24 19:25:21 -07:00
Tzanio 3e4784271a Edited CONTRIBUTING.md file 2018-05-24 18:46:58 -07:00
Tzanio fb1d5b98dd Edited INSTALL file 2018-05-24 18:43:21 -07:00
Tzanio 55b058e498 Updated/fixed PUMI's Example 2 and 6p. 2018-05-24 18:32:10 -07:00
Tzanio 601f1cfbfa Styling of PUMI's Example 1/1p 2018-05-24 17:34:48 -07:00
Tzanio 1acffab78f Editorial changes in CHANGELOG and pumi.cpp. 2018-05-24 16:50:25 -07:00
Veselin Dobrev 6f2aebc7bb Update examples/pumi/makefile and 'make style'. 2018-05-24 11:25:57 -07:00
KazemKamran 66fbfd2a41 some cleaning in pumi.cpp
some cleaning in pumi.cpp
2018-05-24 14:05:40 -04:00
KazemKamran da6de9371a Adding doxygen of pumi examples 2018-05-24 12:09:58 -04:00
KazemKamran a7efad3e4a Unifying example headers, rename ex2p.cpp to ex2.cpp 2018-05-24 12:09:58 -04:00
KazemKamran 0afab1d564 Add a blurb for PUMI examples 2018-05-24 12:09:58 -04:00
Jan Nikl 401a66040c make style on the commit 48dd20d2e8 2018-05-24 15:52:04 +02:00
Tzanio Kolev 93525246b0 Merge pull request #500 from najlkin/pr4
Fixed assignment of an IntegrationRule in the constructor of NonlinearFormIntegrator
2018-05-24 06:45:11 -07:00
Ido Akkerman d0661f2302 Adding a desired LOD field to the visit output 2018-05-24 14:25:03 +02:00
Veselin Dobrev acacabd432 A few small improvements. 2018-05-23 17:37:37 -07:00
Tzanio 91615ed76b Small edits in pumi.cpp 2018-05-23 11:55:28 -07:00
Jan Nikl bd790b1996 Fixed assignment of an IntegrationRule in the constructor of NonlinearFormIntegrator. 2018-05-23 15:52:41 +02:00
Jan Nikl d501e8c9f3 Fixed the order of elements in the matrix obtained from GetElementValues of QuadratureFunction. 2018-05-23 15:40:46 +02:00
Veselin Dobrev a818788468 In mesh/pumi.cpp: more tweaks and fixed leaks. 2018-05-22 19:42:29 -07:00
Veselin Dobrev 15e3c5f821 Some tweaks in mesh/pumi.cpp; also, fixed a couple of memory leaks. 2018-05-22 14:08:17 -07:00
Veselin Dobrev 50f8519818 Fix a warning 2018-05-21 22:15:03 -07:00
Veselin Dobrev 79f2e1bd05 In mesh/pumi.cpp, restore calls that used to initialize unused
variables and still need to be called discarding the returned
value. Also, make some small formatting and coding tweaks.

All PUMI examples require MPI.

Update .gitignore.
2018-05-21 21:30:39 -07:00
Veselin Dobrev 3d052b07a6 In the makefile build system, define MFEM_USE_SIMMETRIX. 2018-05-21 18:57:57 -07:00
Veselin Dobrev 75f47a3deb Fix a few issues in the CMake build system.
Set suitable number of processors for running the PUMI parallel
examples.
2018-05-21 17:39:11 -07:00
Tzanio f91d406ce3 Silence compiler warnings in pumi.cpp 2018-05-21 17:26:09 -07:00
Veselin Dobrev d9e12f8c7e Fix examples/pumi/ex6p. 2018-05-21 15:17:49 -07:00
Tzanio f212f83a13 Merge branch 'pumi-dev' of github.com:mfem/mfem into pumi-dev 2018-05-21 15:01:14 -07:00
Tzanio 56ebcb4016 A few changes & fixes 2018-05-21 15:01:11 -07:00
Veselin Dobrev 7e89151592 Add forgotten makefile in the previous commit. 2018-05-21 15:00:11 -07:00
Veselin Dobrev 878338b1a5 Add support for building with make.
Apply astyle formatting to the PUMI examples.
2018-05-21 14:51:16 -07:00
Jan Nikl bba14e664e Added constant qualifiers to the QuadratureFunction and QuadratureSpace where applicable and added new const versions of the GetElementValues methods. 2018-05-21 22:32:48 +02:00
Jan Nikl 67da6e2d30 Added assignment operators to QuadratureFunction. 2018-05-21 22:30:33 +02:00
Tzanio 99e3fccd32 Merge branch 'master' into pumi-dev 2018-05-21 13:19:21 -07:00
Tzanio b0987500a4 make style 2018-05-21 13:18:44 -07:00
Tzanio d363dd71d4 Merge branch 'master' into docs-dev 2018-05-21 13:10:47 -07:00
Tzanio Kolev b90140c46f Merge pull request #497 from mfem/simplex-refine-fix
Fix an issue in the local refinement of simplex meshes [simplex-refine-fix]
2018-05-21 13:10:01 -07:00
Tzanio Kolev 386e342e68 Merge pull request #494 from mfem/task/2018_05_conduit_extra_boundary_topo_guard
Conduit blueprint to MFEM mesh: guard against missing boundary info
2018-05-21 13:09:25 -07:00
Tzanio Kolev 78a1b093fe Merge pull request #493 from mfem/sidre-dev
Bugfix for handling of SidreDataCollection boundary mesh blueprint index [sidre-dev]
2018-05-21 13:08:58 -07:00
Veselin Dobrev 8d1a5dfa31 Fix an issue in the local refinement of simplex meshes where the
lazy-generated Tables 'el_to_el', 'face_edge', and 'edge_vertex'
were not reset after refinement.
2018-05-18 16:19:50 -07:00
Tzanio Kolev 31ac08e6f2 Merge pull request #486 from mfem/vectorcurlcurl-fix
Bugfix for VectorCurlCurlIntegrator assemble [vectorcurlcurl-fix]
2018-05-18 14:41:59 -07:00
Jakub Cerveny 1e76ed107a After merging pmatrix-dev, at least one thing got broken: ParMesh::Print for AMR meshes.
Since in pmatrix-dev, slave faces are no longer considered shared (their P rows are not
needed by the processor owning the master face), they are also not printed when visualizing
the parallel solution. I suspect this also might have broken NC face neighbors. This branch
contains a temporary solution, a downgrade of ParNCMesh::AddMasterSlaveRanks, so that it
works the old way: slave faces are grouped with the masters. This fixes visualization and
maybe other things, but may negatively impact performance of (or even break) the P matrix
construction. I need to look more into this to find a permanent solution.
2018-05-18 22:50:19 +02:00
Cyrus Harrison e09f9d8128 guard against missing boundary info 2018-05-16 12:19:33 -07:00
Kenneth Weiss ec4fcba705 Bugfix for handling of SidreDataCollection boundary mesh blueprint index
The blueprint index was only being genererated for the boundary mesh when
rank 0 had boundary elements. We need to generate the boundary mesh
group and associated blueprint index if any of the domains have boundary
elements.
2018-05-15 20:15:26 -07:00
Veselin Dobrev e4eb8aa6df Fixed a link in CONTRIBUTING.md 2018-05-09 22:55:50 -07:00
Tzanio 1f4ead94a3 Testing docs layouts 2018-05-09 13:59:26 -07:00
Tzanio 179fc91a55 Testing docs layouts 2018-05-09 13:49:27 -07:00
Tzanio 4037e17135 Rearanged README 2018-05-09 13:38:14 -07:00
Tzanio 67e8010987 Fixed Spack URL 2018-05-09 13:35:45 -07:00
Jan Nikl 48dd20d2e8 Added const qualifier to the solution vectors in the essential bc elimination methods. 2018-05-09 10:00:12 +02:00
Tzanio 33427e3bcd Added Code Overview in CONTRIBUTING. Updated README 2018-05-07 19:08:07 -07:00
Tzanio e090a781a2 Merge branch 'master' into vectorcurlcurl-fix 2018-05-07 17:33:00 -07:00
Tzanio b62a60837a Bugfix for https://github.com/mfem/mfem/issues/467#issuecomment-380136269 2018-05-07 17:16:37 -07:00
KazemKamran c94be388e1 Resolve name conflict in adding MeshAdapt example 2018-05-04 10:00:29 -04:00
KazemKamran 37ddcfe14d Merge branch 'pumi-dev-ma' into pumi-dev 2018-05-04 09:46:17 -04:00
KazemKamran 37686b0321 Add the PUMI-MFEM MeshAdapt interface implementation and an example 2018-05-03 17:44:16 -04:00
Tzanio 293687453e Merge branch 'master' into pumi-dev 2018-05-01 11:17:34 -07:00
Tzanio 67401330d9 make style 2018-04-23 10:45:27 -07:00
Robert W. Anderson dce6ebf20d merge master 2018-03-21 15:43:32 -07:00
Cameron Smith 15b684fe21 pumi: forgot to remove config header 2018-03-14 09:12:03 -04:00
Tzanio 1bd99fd5dc Various small changes 2018-03-13 18:45:03 -07:00
KazemKamran 165dea0c66 Revert the previous commit and delete pumi addition in INSTALL, CMAKE only 2018-03-13 19:27:59 -04:00
KazemKamran 473240f1c2 Revert "Revert changes in INSTALL"
This reverts commit bb0cae0619.
2018-03-13 19:23:57 -04:00
KazemKamran bb0cae0619 Revert changes in INSTALL 2018-03-13 18:07:05 -04:00
Cameron Smith 6d1a1a19fe Revert "Update miniapps/common/CMakeLists.txt from master"
This reverts commit de5c1c376b.  It breaks the
compile.
2018-03-13 17:34:17 -04:00
Cameron Smith 6601d3757b pumi: move simmetrix define to config.hpp.in 2018-03-13 17:32:21 -04:00
KazemKamran 5252b05a79 Update miniapps/common/CMakeLists.txt from master 2018-03-13 17:15:12 -04:00
KazemKamran de5c1c376b Update miniapps/common/CMakeLists.txt from master 2018-03-13 17:10:40 -04:00
Tzanio 12c109f9e9 Update CHANGELOG 2018-03-13 13:38:51 -07:00
Tzanio 1007624ddb Update INSTALL 2018-03-13 13:32:15 -07:00
Tzanio d65e45277b make style 2018-03-13 13:19:00 -07:00
KazemKamran 4824b02b48 removing README.mfem-pumi-install, use the Spack installation 2018-03-13 16:09:59 -04:00
KazemKamran ddecdf017f change file name pumi_mesh.* to pumi.* 2018-03-12 15:07:41 -04:00
KazemKamran 25e5327b6a Make changes required after review 2018-03-12 12:04:32 -04:00
KazemKamran c4fe5bcde1 Merge branch 'pumi-dev' of github.com:mfem/mfem into pumi-dev
Making the changes required after review
2018-03-12 11:54:08 -04:00
KazemKamran dbf8797f2c Removing data/pumi 2018-03-12 11:52:34 -04:00
KazemKamran 7763533785 Make changes required after review 2018-03-12 11:49:03 -04:00
Tzanio d5874e20e5 Merge branch 'master' into pumi-dev 2018-03-12 06:17:58 -07:00
KazemKamran 56dd3dd069 resolving conflicts 2018-03-08 12:13:35 -05:00
Tzanio 4e3f26c602 Fixed merge conflict 2018-03-07 11:28:28 -08:00
Tzanio caeae60c12 Merge branch 'master' into pumi-dev
Conflicts:
	config/cmake/config.hpp.in
	config/defaults.cmake
	config/defaults.mk
	makefile
2018-03-07 11:22:44 -08:00
Robert W. Anderson 134f97c0d8 comment out the setting of master and slave faces in face_info 2018-01-23 19:36:52 -08:00
Robert W. Anderson 5caeea07a0 return faces_tbl from InitFromNCMesh for use in group construction in 3D 2018-01-23 19:36:08 -08:00
Tzanio e5c7383441 Small fixes. Should pass CI testing now... 2018-01-04 18:19:23 -08:00
Tzanio 41e6d31236 Merge branch 'master' into pumi-dev 2018-01-04 17:33:40 -08:00
Cameron Smith a22eeeab5a improve build instructions
add metis
use a toolchain on vulcan to avoid strange errors
2017-12-11 10:21:40 -08:00
Cameron Smith e60e51db39 pumi examples: remove simutil_[start|stop] 2017-12-11 10:21:40 -08:00
Cameron Smith e17ee11dc1 use mpi for serial tests
needed on ray
2017-12-11 10:21:40 -08:00
Robert W. Anderson 4f00b2d6bb Merge branch 'master' into cut-mesh-groups-dev 2017-12-05 15:34:51 -08:00
Robert W. Anderson eba6d4805b working for simple 2D cases 2017-12-05 15:32:22 -08:00
Tzanio 482378c7ec Merge branch 'master' into pumi-dev 2017-11-10 16:58:20 -08:00
KazemKamran d2cf23afde using theirs 2017-10-18 10:09:35 -04:00
KazemKamran 2b541c5e12 Merge branch 'pumi-dev' of github.com:mfem/mfem into pumi-dev
Conflicts:
	examples/pumi_atr_ex2.cpp
2017-10-17 13:15:35 -04:00
KazemKamran 9e294fc98c Add dmg model for pumi example 2017-10-12 15:05:35 -04:00
Tzanio aaa7fc536c Merge branch 'master' into pumi-dev 2017-09-22 07:35:37 -07:00
Tzanio 1d3cbc5871 Merge branch 'master' into pumi-dev 2017-09-06 19:32:15 -07:00
Tzanio 60ed92ab5a Merge branch 'master' into pumi-dev 2017-09-06 19:08:44 -07:00
Tzanio 5560d92fab make style 2017-08-29 18:18:51 -07:00
Tzanio 36650e8833 Merge branch 'master' into pumi-dev 2017-08-29 18:18:26 -07:00
KazemKamran 5dd5511fdd Add dmg model for pumi example 2017-08-08 12:43:46 -04:00
KazemKamran 7ff222b79d dmg model for attribute example 2017-08-08 12:09:59 -04:00
KazemKamran 72e42566a9 Fix a leak bug 2017-08-04 11:43:29 -04:00
KazemKamran 66e1b3641c Boundary condition classification example 2017-08-03 15:54:07 -04:00
KazemKamran c790490f91 Boundary condition classification example 2017-08-03 15:49:21 -04:00
Cameron Smith 4f34a3b696 Merge branch 'master' into pumi-dev 2017-07-20 16:12:13 -04:00
Cameron Smith 9dfe4dc6f4 cmake config header 2017-07-20 15:34:44 -04:00
Cameron Smith 7474b3deb9 restore pumi cmake option 2017-07-20 15:34:44 -04:00
Cameron Smith 325479260c gnu-make support for building without pumi 2017-07-20 15:34:40 -04:00
Cameron Smith 6ca81275dc undo some early build system changes 2017-07-20 10:48:12 -04:00
Cameron Smith 00baeb86c3 don't infect all compilation with MFEM_USE_SIMMETRIX
define a header with the preprocessor variable defined
2017-07-13 16:49:42 -04:00
Cameron Smith 54d850bbe1 use the discrete model
pumi tests pass without simmetrix
ctest -R 'pumi|Generate'
2017-07-13 13:49:00 -04:00
Cameron Smith c375afe382 missing discrete models 2017-07-13 13:41:46 -04:00
Cameron Smith 3102f164d6 gmi_sim is optional
pumi examples fail with Test project /lore/cwsmith/develop/mfem/mfem
2017-07-13 11:56:30 -04:00
Cameron Smith 04acee1f28 README: enable pumi 2017-07-12 15:31:23 -04:00
KazemKamran 71d87aa1f2 Changes to compile MFEM wo PUMI 2017-07-11 17:44:55 -04:00
KazemKamran bcfe52d498 separate pumi examples 2017-07-11 17:41:37 -04:00
Cameron Smith a8d474f3f6 instructions for installing with pumi support 2017-07-07 14:09:32 -04:00
Cameron Smith 6143572d6a miniapps/common: use pumi 2017-06-29 17:02:38 -04:00
Cameron Smith f0a41dd3d6 support serial tests with 'p' in the name 2017-06-29 16:50:16 -04:00
KazemKamran 02b65854c2 Clean unifor refinement (wo size field) 2017-06-26 14:21:10 -04:00
KazemKamran ffea082dc9 Adding PUMI examples and data 2017-06-20 18:15:11 -04:00
KazemKamran 9d79904c50 minor necessary change 2017-06-20 14:58:50 -04:00
KazemKamran eb2017b5b5 Add pumi supports for parallel and serial mesh loading 2017-06-19 11:13:29 -04:00
143 changed files with 8908 additions and 1619 deletions
+9
View File
@@ -112,6 +112,15 @@ examples/petsc/deformed.*
examples/petsc/velocity.*
examples/petsc/elastic_energy.*
examples/pumi/ex1
examples/pumi/ex[126]p
examples/pumi/refined.mesh
examples/pumi/sol.gf
examples/pumi/mesh.*
examples/pumi/sol.*
examples/pumi/displaced.mesh
miniapps/electromagnetics/volta
miniapps/electromagnetics/tesla
miniapps/electromagnetics/maxwell
+20 -3
View File
@@ -8,11 +8,23 @@
http://mfem.org
Version 3.3.3 (development)
Version 3.4.1 (development)
===========================
- Added support for reading linear and quadratic 2D quadrilateral and triangular
Cubit meshes.
Version 3.4, released on May 29, 2018
=====================================
More general and efficient mesh adaptivity
------------------------------------------
- Added support for PUMI, the Parallel Unstructured Mesh Infrastructure from
https://scorec.rpi.edu/pumi. PUMI is an unstructured, distributed mesh data
management system that is capable of handling general non-manifold models and
effectively supports automated adaptive analysis. PUMI enables for the first
time support for parallel unstructured modifications of MFEM meshes.
More efficient non-conforming adaptive mesh refinement
------------------------------------------------------
- Significantly reduced MPI communication in the construction of the parallel
prolongation matrix in ParFiniteElementSpace, for much improved parallel
scaling of non-conforming AMR on hundreds of thousands of MPI tasks. The
@@ -81,6 +93,11 @@ New and updated examples and miniapps
NURBS meshes in the miniapps/nurbs directory. Currently the directory contains
variable order NURBS versions of examples 1, 1p and 11p.
- Added PUMI versions of examples ex1, ex1p, ex2 and ex6p in a new examples/pumi
directory. The new examples demonstrate the PUMI APIs for parallel and serial
mesh loading (ex1 and ex1p), applying BCs using classification (ex2), and
performing parallel mesh adaptation (ex6p).
- Added two new miniapps related to DataCollection I/O in miniapps/tools:
load-dc.cpp can be used to visualize fields saved via DataCollection classes;
convert-dc.cpp demonstrates how to convert between MFEM's different concrete
+20 -4
View File
@@ -45,7 +45,7 @@ project(mfem NONE)
# Current version of MFEM, see also `makefile`.
# mfem_VERSION = (string)
# MFEM_VERSION = (int) [automatically derived from mfem_VERSION]
set(${PROJECT_NAME}_VERSION 3.3.3)
set(${PROJECT_NAME}_VERSION 3.4.1)
# Prohibit in-source build
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
@@ -139,7 +139,7 @@ if (MFEM_USE_MPI)
set(PETSC_INCLUDE_DIRS ${PETSC_INCLUDES})
endif()
else()
set(PKGS_NEED_MPI SUPERLU PETSC STRUMPACK)
set(PKGS_NEED_MPI SUPERLU PETSC STRUMPACK PUMI)
foreach(PKG IN LISTS PKGS_NEED_MPI)
if (MFEM_USE_${PKG})
message(STATUS "Disabling package ${PKG} - requires MPI")
@@ -246,6 +246,22 @@ if (MFEM_USE_SIDRE)
find_package(Axom REQUIRED Sidre SLIC axom_utils)
endif()
# PUMI
if (MFEM_USE_PUMI)
# If PUMI_DIR was specified, only link to that directory,
# i.e. don't link to another installation in /usr/lib by mistake
find_package(SCOREC 2.1.0 REQUIRED OPTIONAL_COMPONENTS gmi_sim
CONFIG PATHS ${PUMI_DIR} NO_DEFAULT_PATH)
if (SCOREC_FOUND)
# Define a header file with the MFEM_USE_SIMMETRIX preprocessor variable
set(MFEM_USE_SIMMETRIX ${SCOREC_gmi_sim_FOUND})
set(PUMI_FOUND ${SCOREC_FOUND})
get_target_property(PUMI_INCLUDE_DIRS
SCOREC::apf INTERFACE_INCLUDE_DIRECTORIES)
set(PUMI_LIBRARIES SCOREC::core)
endif()
endif()
# MFEM_TIMER_TYPE
if (NOT DEFINED MFEM_TIMER_TYPE)
if (APPLE)
@@ -270,8 +286,8 @@ endif()
# integers, the METIS header (with 32-bit indices, as used by mfem) needs to
# be before SuiteSparse.
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT GECKO GNUTLS NETCDF MPFR POSIXCLOCKS
MFEMBacktrace ZLIB)
MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT GECKO GNUTLS NETCDF MPFR PUMI
POSIXCLOCKS MFEMBacktrace ZLIB)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
set(TPL_INCLUDE_DIRS "")
+103 -2
View File
@@ -1,3 +1,15 @@
<p align="center">
<a href="http://mfem.org/"><img alt="mfem" src="http://mfem.org/img/logo-300.png"></a>
</p>
<p align="center">
<a href="https://github.com/mfem/mfem/blob/master/COPYRIGHT"><img alt="License" src="https://img.shields.io/badge/License-LGPL--2.1-brightgreen.svg"></a>
<a href="https://travis-ci.org/mfem/mfem"><img alt="Build Status" src="https://travis-ci.org/mfem/mfem.svg?branch=master"></a>
<a href="https://ci.appveyor.com/project/mfem/mfem"><img alt="Build Status" src="https://ci.appveyor.com/api/projects/status/19non9sqm6msi2wy?svg=true"></a>
<a href="http://mfem.github.io/doxygen/html/index.html"><img alt="Doxygen" src="https://img.shields.io/badge/code-documented-brightgreen.svg"></a>
</p>
# How to Contribute
The MFEM team welcomes contributions at all levels: bugfixes; code
@@ -16,6 +28,7 @@ See the [Quick Summary](#quick-summary) section for the main highlights of our
GitHub workflow. For more details, consult the following sections and refer
back to them before issuing pull requests:
- [Code Overview](#code-overview)
- [GitHub Workflow](#github-workflow)
- [MFEM Organization](#mfem-organization)
- [New Feature Development](#new-feature-development)
@@ -53,6 +66,94 @@ Origin](#developers-certificate-of-origin-11) at the end of this file.*
- Don't hesitate to [contact us](#contact-information) if you have any questions.
### Code Overview
- The MFEM library uses object-orient design principles which reflect, in code,
the independent mathematical concepts of meshing, linear algebra and finite
element spaces and operators.
- The MFEM source code has the following structure:
```
.
├── config
│ └── cmake
│ └── modules
├── data
├── doc
│ └── web
│ └── examples
├── examples
│ ├── petsc
│ ├── pumi
│ └── sundials
├── fem
├── general
├── linalg
├── mesh
└── miniapps
├── common
├── electromagnetics
├── meshing
├── nurbs
├── performance
└── tools
```
- The main directories are `fem/`, `mesh/` and `linalg/` containing the C++
classes implementing the finite element, mesh and linear algebra concepts
respectively.
- The main mesh classes are:
+ [`Mesh`](http://mfem.github.io/doxygen/html/classmfem_1_1Mesh.html)
+ [`NCMesh`](http://mfem.github.io/doxygen/html/classmfem_1_1NCMesh.html)
+ [`Element`](http://mfem.github.io/doxygen/html/classmfem_1_1Element.html)
+ [`ElementTransformation`](http://mfem.github.io/doxygen/html/classmfem_1_1ElementTransformation.html)
- The main finite element classes are:
+ [`FiniteElement`](http://mfem.github.io/doxygen/html/classmfem_1_1FiniteElement.html)
+ [`FiniteElementCollection`](http://mfem.github.io/doxygen/html/classmfem_1_1FiniteElement.html)
+ [`FiniteElementSpace`](http://mfem.github.io/doxygen/html/classmfem_1_1FiniteElementSpace.html)
+ [`GridFunction`](http://mfem.github.io/doxygen/html/classmfem_1_1GridFunction.html)
+ [`BilinearFormIntegrator`](http://mfem.github.io/doxygen/html/classmfem_1_1BilinearFormIntegrator.html) and [`LinearFormIntegrator`](http://mfem.github.io/doxygen/html/classmfem_1_1LinearFormIntegrator.html)
+ [`LinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1LinearFormIntegrator.html), [`BilinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1BilinearForm.html) and [`MixedBilinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1MixedBilinearForm.html)
- The main linear algebra classes and sources are
+ [`Operator`](http://mfem.github.io/doxygen/html/classmfem_1_1Operator.html) and [`BilinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1BilinearForm.html)
+ [`Vector`](http://mfem.github.io/doxygen/html/classmfem_1_1BilinearForm.html) and [`LinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1LinearForm.html)
+ [`DenseMatrix`](http://mfem.github.io/doxygen/html/classmfem_1_1DenseMatrix.html) and [`SparseMatrix`](http://mfem.github.io/doxygen/html/classmfem_1_1SparseMatrix.html)
+ Sparse [smoothers](http://mfem.github.io/doxygen/html/sparsesmoothers_8hpp.html) and linear [solvers](http://mfem.github.io/doxygen/html/solvers_8hpp.html)
- Parallel MPI objects in MFEM inherit their serial counterparts, so a parallel
mesh for example is just a serial mesh on each task plus the information on
shared geometric entities between different tasks. The parallel source files
have a `p` prefix, e.g. `pmesh.cpp` vs. the serial `mesh.cpp`.
- The main parallel classes are
+ [`ParMesh`](http://mfem.github.io/doxygen/html/solvers_8hpp.html)
+ [`ParNCMesh`](http://mfem.github.io/doxygen/html/classmfem_1_1ParMesh.html)
+ [`ParFiniteElementSpace`](http://mfem.github.io/doxygen/html/classmfem_1_1ParFiniteElementSpace.html)
+ [`ParGridFunction`](http://mfem.github.io/doxygen/html/classmfem_1_1ParGridFunction.html)
+ [`ParBilinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1ParBilinearForm.html) and [`ParLinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1ParLinearForm.html)
+ [`HypreParMatrix`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreParMatrix.html) and [`HypreParVector`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreParVector.html)
+ [`HypreSolver`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreSolver.html) and other [hypre classes](http://mfem.github.io/doxygen/html/hypre_8hpp.html)
- The `general/` directory contains C++ classes that serve as utilities for
communication, error handling, arrays, (Boolean) tables, timing, etc.
- The `config/` directory contains build-related files, both for the plain
Makefile and the CMake build options.
- The `doc/` directory contains configuration for the Doxygen code documentation
that can either be build locally, or browsed online at
http://mfem.github.io/doxygen/html/index.html.
- The `data/` directory contains a collection of small mesh files, that are used
in the simple example codes and more fully-featured mini applications in the
`examples/` and `miniapps/` directories.
- See also the [code overview](http://mfem.org/code-overview/) section on the
MFEM website.
## GitHub Workflow
The GitHub organization, https://github.com/mfem, is the main developer hub for
@@ -122,7 +223,7 @@ will allow us to reach you directly with project announcements.
# Work on "feature-dev", add local commits
# ...
# One time only) push the branch to github and setup your local
# (One time only) push the branch to github and setup your local
# branch to track the github branch (for "git pull"):
git push -u origin feature-dev
@@ -332,7 +433,7 @@ MFEM uses a `master`/`next`-branch workflow as described below:
- [ ] `CHANGELOG`
- [ ] `makefile`
- [ ] `CMakeLists.txt`
- [ ] `doc/CodeDocumentation.conf`
- [ ] `doc/CodeDocumentation.conf.in`
- [ ] (LLNL only) Make sure all `README.html` files in the source repo are up to date.
- [ ] Tag the repository:
+16
View File
@@ -32,6 +32,9 @@ following package managers:
- OpenHPC, http://openhpc.community
- Homebrew/Science, https://github.com/Homebrew/homebrew-science
We also recommend downloading and building the MFEM-based GLVis visualization
tool which can be used to visualize the meshes and solution in MFEM's examples
and miniapps. See http://glvis.org and http://mfem.org/building.
Quick start with GNU make
=========================
@@ -352,6 +355,13 @@ MFEM_USE_GZSTREAM = YES/NO
before attempting to use it with MFEM.
When enabled, this option uses the ZLIB_* library options, see below.
MFEM_USE_PUMI = YES/NO
Enable the usage of PUMI (https://scorec.rpi.edu/pumi/) in MFEM. The Parallel
Unstructured Mesh Infrastructure (PUMI) is an unstructured, distributed mesh
data management system that is capable of handling general non-manifold
models and effectively supports automated adaptive analysis. PUMI enables
support for parallel unstructured mesh modifications in MFEM.
MFEM_BUILD_TAG = (any value)
An optional tag to characterize the build. Exported to config/config.mk.
Can be used to identify the MFEM build from other makefiles.
@@ -461,6 +471,10 @@ The specific libraries and their options are:
https://support.hdfgroup.org/HDF5 (HDF5)
Options: CONDUIT_OPT, CONDUIT_LIB.
- PUMI, used when MFEM_USE_PUMI = YES.
URL: https://scorec.rpi.edu/pumi
Options: PUMI_OPT, PUMI_LIB.
- MPFR (optional), used when MFEM_USE_MPFR = YES.
URL: http://mpfr.org, it depends on the GMP library: https://gmplib.org
Options: MPFR_OPT, MPFR_LIB.
@@ -593,6 +607,7 @@ MFEM_USE_GNUTLS
MFEM_USE_NETCDF
MFEM_USE_MPFR
MFEM_USE_GZSTREAM
MFEM_USE_PUMI
The following options are CMake specific:
@@ -638,6 +653,7 @@ The CMake build system adds auto-detection for the following packages/libraries:
- MPFR
- LIBUNWIND
- POSIXCLOCKS
- PUMI
The following built-in CMake packages are also used:
+10 -6
View File
@@ -12,11 +12,15 @@ to enable the research and development of scalable finite element discretization
and solver algorithms through general finite element abstractions, accurate and
flexible visualization, and tight integration with the hypre library.
For building instructions, see the file INSTALL, or type "make help". Copyright
information and licensing restrictions can be found in the file COPYRIGHT.
* For building instructions, see the file INSTALL, or type "make help".
The best starting point for new users interested in MFEM's features is the
interactive documentation in examples/README.html.
* Copyright and licensing information can be found in the file COPYRIGHT.
* The best starting point for new users interested in MFEM's features is the
interactive documentation in examples/README.html.
* Developers interested in contributing to the library, should read the
instructions and documentation in the CONTRIBUTING.md file.
Conceptually, MFEM can be viewed as a finite element toolbox that provides the
building blocks for developing finite element algorithms in a manner similar to
@@ -56,8 +60,8 @@ time integrators, etc.
For examples of using MFEM, see the examples/ and miniapps/ directories, as well
as the OpenGL visualization tool GLVis which is available at http://glvis.org.
This project is released under the LGPL v2.1 license. See LICENSE file for full
details.
This project is released under the LGPL v2.1 license with static linking
exception. See files COPYRIGHT and LICENSE file for full details.
LLNL Release Number: LLNL-CODE-443211
DOI: 10.11578/dc.20171025.1248
+2
View File
@@ -109,10 +109,12 @@ public:
PLayout &GetLayout() const { return *layout; }
/// TODO
/// Note: we cannot use static_cast for class PArray.
template <typename derived_t>
derived_t &As() { return dynamic_cast<derived_t&>(*this); }
/// TODO
/// Note: we cannot use static_cast for class PArray.
template <typename derived_t>
const derived_t &As() const { return dynamic_cast<const derived_t&>(*this); }
+22 -2
View File
@@ -19,9 +19,29 @@
namespace mfem
{
DFiniteElementSpace Engine::MakeFESpace(FiniteElementSpace &fes) const
Engine::Engine(Backend *b, int n_mem, int n_workers)
: backend(b),
#ifdef MFEM_USE_MPI
comm(MPI_COMM_NULL),
#endif
num_mem_res(n_mem),
num_workers(n_workers),
memory_resources(new MemoryResource*[num_mem_res]()),
workers_weights(new double[num_workers]()),
workers_mem_res(new int[num_workers]())
{
return DFiniteElementSpace(new PFiniteElementSpace(*this, fes));
// Note: all arrays are value-initialized with zeros.
}
Engine::~Engine()
{
delete [] workers_mem_res;
delete [] workers_weights;
for (int i = 0; i < num_mem_res; i++)
{
delete memory_resources[i];
}
delete [] memory_resources;
}
} // namespace mfem
+9 -28
View File
@@ -65,29 +65,10 @@ protected:
public:
/// TODO: doxygen
Engine(Backend *b, int n_mem, int n_workers)
: backend(b),
#ifdef MFEM_USE_MPI
comm(MPI_COMM_NULL),
#endif
num_mem_res(n_mem),
num_workers(n_workers),
memory_resources(new MemoryResource*[num_mem_res]()),
workers_weights(new double[num_workers]()),
workers_mem_res(new int[num_workers]())
{ /* Note: all arrays are value-initialized with zeros. */ }
Engine(Backend *b, int n_mem, int n_workers);
/// TODO: doxygen
virtual ~Engine()
{
delete [] workers_mem_res;
delete [] workers_weights;
for (int i = 0; i < num_mem_res; i++)
{
delete memory_resources[i];
}
delete [] memory_resources;
}
virtual ~Engine();
/**
@@ -120,11 +101,11 @@ public:
/// TODO
template <typename derived_t>
derived_t &As() { *util::As<derived_t>(this); }
derived_t &As() { return *util::As<derived_t>(this); }
/// TODO
template <typename derived_t>
const derived_t &As() const { *util::As<const derived_t>(this); }
const derived_t &As() const { return *util::As<const derived_t>(this); }
// TODO: Error handling ... handle errors at the Engine level, at the class
@@ -139,10 +120,10 @@ public:
// TODO: Asynchronous execution in this class ...
/// Allocate and return a new layout for the given @a size.
/** The layout decomposition is determined automatically by the Engine using
a deterministic algorithm: calls to this method with the same @a size
will produce the same result, as long as the Engine remains unmodified
between the calls.
/** The layout decomposition (in the case of multiple workers) is determined
automatically by the Engine using a deterministic algorithm: calls to
this method with the same @a size will produce the same result, as long
as the Engine remains unmodified between the calls.
The returned object is allocated with operator new and must be
deallocated by the caller.
@@ -180,7 +161,7 @@ public:
int type_id = ScalarId<double>::value) const = 0;
/// TODO: doxygen
virtual DFiniteElementSpace MakeFESpace(FiniteElementSpace &fes) const;
virtual DFiniteElementSpace MakeFESpace(FiniteElementSpace &fes) const = 0;
/// TODO: doxygen
virtual DBilinearForm MakeBilinearForm(BilinearForm &bf) const = 0;
+40 -3
View File
@@ -22,6 +22,7 @@ namespace mfem
{
class FiniteElementSpace;
class QuadratureSpace;
/// TODO: doxygen
class PFiniteElementSpace : public RefCounted
@@ -30,11 +31,11 @@ protected:
/// Engine with shared ownership
SharedPtr<const Engine> engine;
/// Not owned.
FiniteElementSpace *fes;
mfem::FiniteElementSpace *fes;
public:
/// TODO: doxygen
PFiniteElementSpace(const Engine &e, FiniteElementSpace &fespace)
PFiniteElementSpace(const Engine &e, mfem::FiniteElementSpace &fespace)
: engine(&e), fes(&fespace) { }
/// Virtual destructor
@@ -43,7 +44,8 @@ public:
/// Get the associated engine
const Engine &GetEngine() const { return *engine; }
mfem::FiniteElementSpace* GetFESpace() const { return fes; }
/// Return the associated mfem::FiniteElementSpace
mfem::FiniteElementSpace *GetFESpace() const { return fes; }
/// TODO
template <typename derived_t>
@@ -52,6 +54,41 @@ public:
/// TODO
template <typename derived_t>
const derived_t &As() const { return *util::As<const derived_t>(this); }
/**
@name Virtual interface: finite element space functionality
*/
///@{
/// TODO
/** Return the operator mapping T-vectors to L-vectors. If a NULL pointer is
returned then the mapping is the idenity. */
virtual const mfem::Operator *GetProlongationOperator() const = 0;
/// TODO
/** Return the operator mapping L-vectors to T-vectors that extracts the
subset of all true dofs, i.e. no assembly is performed. If a NULL pointer
is returned then the mapping is the idenity. */
virtual const mfem::Operator *GetRestrictionOperator() const = 0;
/// TODO
/** Return the operator mapping L-vectors to Q-vectors that evaluates the
values of a GridFunction as a QuadratureFunction on the given
QuadratureSpace. If the returned pointer is NULL, then the mapping is the
identity. */
virtual const mfem::Operator *GetInterpolationOperator(
const mfem::QuadratureSpace &qspace) const = 0;
/// TODO
/** Return the operator mapping L-vectors to Q-vectors that evaluates the
_reference element_ gradients of a GridFunction as a QuadratureFunction
on the given QuadratureSpace. */
virtual const mfem::Operator *GetGradientOperator(
const mfem::QuadratureSpace &qspace) const = 0;
///@}
// End: Virtual interface
};
} // namespace mfem
+6
View File
@@ -69,10 +69,16 @@ public:
std::size_t Size() const { return size; }
/// TODO
/** Useful in backends for down-casting to a backend-specific layout type.
When MFEM_DEBUG=YES, performs a type check using dynamic_cast. */
template <typename derived_t>
derived_t &As() { return *util::As<derived_t>(this); }
/// TODO
/** Useful in backends for down-casting to a backend-specific layout type.
When MFEM_DEBUG=YES, performs a type check using dynamic_cast. */
template <typename derived_t>
const derived_t &As() const { return *util::As<const derived_t>(this); }
+3 -2
View File
@@ -160,11 +160,12 @@ public:
template <typename U>
bool operator==(const SharedPtr<U> &other) const
{ return ptr == other.Ptr(); }
{ return ptr == other.Get(); }
template <typename U>
bool operator!=(const SharedPtr<U> &other) const
{ return ptr != other.Ptr(); }
{ return ptr != other.Get(); }
// Comparison to any type convertible to void *, e.g. the type of NULL.
template <typename U>
bool operator==(const U &p) const { return ptr == (void*) p; }
template <typename U>
+66
View File
@@ -0,0 +1,66 @@
// 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.
/*
---[ Defines Known At Compile-Time ]------------
ELEMENT_BATCH : How many elements are in each
. computation batch
NUM_DOFS_1D : Dofs in the 1D segments
NUM_DOFS_2D : Dofs in the 2D faces
NUM_DOFS_3D : Dofs in the 3D domain
NUM_QUAD_1D : Dofs in the 1D segments
NUM_QUAD_2D : Dofs in the 2D faces
NUM_QUAD_3D : Dofs in the 3D domain
NUM_MAX_1D : max(NUM_QUAD_1D, NUM_DOFS_1D)
NUM_QUAD_DOFS_1D: NUM_QUAD_1D * NUM_DOFS_1D
COEFF_ARGS : Code that passes required arguments to the kernel
COEFF : Code that computes the coefficient
================================================
[MISSING]
- Add support to auto-pick @dim and use @idxOrder on stack arrays
| double a[2][2];
| a[0][1]; <-- regular index
| a(0,1); <-- uses @idxOrder a[0][1] or a[1][0]
- Add support for @idxOrder to change indexing order after allocation
| double a[2][2] @idxOrder(0,1);
| a(0,1) -> a[1][0]
| @set(a, idxOrder(1,0));
| a(0,1) -> a[0][1]
- Add support to iterate over loop depending on mode
| for(i; @inner) {
| for(0 < j < N) {} <-- ++j or j += block?
| }
*/
#include "mfem-occa://defines.okl"
#if USING_TENSOR_OPS
# ifdef OCCA_USING_GPU
# if USING_LOW_ORDER
# include "mfem-occa://mass/tensor/gpuHighOrder.okl"
# else
# include "mfem-occa://mass/tensor/gpuHighOrder.okl"
# endif
# else
# include "mfem-occa://mass/tensor/cpu.okl"
# endif
#else
# ifdef OCCA_USING_GPU
# if USING_LOW_ORDER
# include "mfem-occa://mass/simplex/gpuHighOrder.okl"
# else
# include "mfem-occa://mass/simplex/gpuHighOrder.okl"
# endif
# else
# include "mfem-occa://mass/simplex/cpu.okl"
# endif
#endif
+38
View File
@@ -0,0 +1,38 @@
// 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.
/*
---[ Defines Known At Compile-Time ]------------
ELEMENT_BATCH : How many elements are in each
. computation batch
NUM_DOFS_1D : Dofs in the 1D segments
NUM_DOFS_2D : Dofs in the 2D faces
NUM_DOFS_3D : Dofs in the 3D domain
NUM_QUAD_1D : Dofs in the 1D segments
NUM_QUAD_2D : Dofs in the 2D faces
NUM_QUAD_3D : Dofs in the 3D domain
NUM_MAX_1D : max(NUM_QUAD_1D, NUM_DOFS_1D)
NUM_QUAD_DOFS_1D: NUM_QUAD_1D * NUM_DOFS_1D
CONST_COEFF : If the coefficient is constant, pass it
. as a define
================================================
[MISSING]
See kernels/DiffusionIntegrator.okl
*/
#include "mfem-occa://defines.okl"
#if USING_TENSOR_OPS
# ifndef OCCA_USING_GPU
# include "mfem-occa://vmass/tensor/cpu.okl"
# endif
#endif
+8 -10
View File
@@ -41,8 +41,7 @@ int Array::DoResize(PLayout &new_layout, void **buffer,
MFEM_ASSERT(dynamic_cast<Layout *>(&new_layout) != NULL,
"new_layout is not an OCCA Layout");
Layout *lt = static_cast<Layout *>(&new_layout);
layout.Reset(lt); // Reset() checks if the pointer is the same
int err = ResizeData(lt, item_size);
int err = OccaResize(lt, item_size);
if (!err && buffer)
{
*buffer = GetBuffer();
@@ -72,22 +71,22 @@ void Array::DoFill(const void *value_ptr, std::size_t item_size)
switch (item_size)
{
case sizeof(int8_t):
OccaFill((const int8_t *)value_ptr);
OccaFill(*(const int8_t *)value_ptr);
break;
case sizeof(int16_t):
OccaFill((const int16_t *)value_ptr);
OccaFill(*(const int16_t *)value_ptr);
break;
case sizeof(int32_t):
OccaFill((const int32_t *)value_ptr);
OccaFill(*(const int32_t *)value_ptr);
break;
// case sizeof(int64_t):
// OccaFill((const int64_t *)value_ptr);
// OccaFill(*(const int64_t *)value_ptr);
// break;
case sizeof(double):
OccaFill((const double *)value_ptr);
OccaFill(*(const double *)value_ptr);
break;
// case sizeof(::occa::double2):
// OccaFill((const ::occa::double2 *)value_ptr);
// OccaFill(*(const ::occa::double2 *)value_ptr);
// break;
default:
MFEM_ABORT("item_size = " << item_size << " is not supported");
@@ -112,8 +111,7 @@ void Array::DoAssign(const PArray &src, std::size_t item_size)
// class.
const Array *source = dynamic_cast<const Array *>(&src);
MFEM_ASSERT(source != NULL, "invalid source Array type");
MFEM_ASSERT(Size() == source->Size(), "");
slice.copyFrom(source->slice);
OccaAssign(*source);
}
} // namespace mfem::occa
+56 -12
View File
@@ -60,16 +60,16 @@ protected:
inline void *GetBuffer() const;
inline int ResizeData(const Layout *lt, std::size_t item_size);
template <typename T>
inline void OccaFill(const T *val_ptr)
{ ::occa::linalg::operator_eq<T>(slice, *val_ptr); }
public:
Array(const Engine &e)
: PArray(*(new Layout(e, 0))),
data(e.Alloc(0)),
slice(data)
{ }
Array(Layout &lt, std::size_t item_size)
: PArray(lt),
data(lt.Alloc(lt.Size()*item_size)),
data(lt.OccaEngine().Alloc(lt.Size()*item_size)),
slice(data)
{ }
@@ -77,11 +77,23 @@ public:
inline void MakeRef(Array &master);
Layout &OccaLayout() const
{ return *static_cast<Layout *>(layout.Get()); }
Layout &OccaLayout() const { return layout->As<Layout>(); }
const Engine &OccaEngine() const { return OccaLayout().OccaEngine(); }
::occa::memory &OccaMem() { return slice; }
const ::occa::memory &OccaMem() const { return slice; }
inline int OccaResize(Layout *lt, std::size_t item_size);
inline int OccaResize(std::size_t new_size, std::size_t item_size);
template <typename T>
inline void OccaFill(const T val);
inline void OccaAssign(const Array &src);
inline void OccaPush(const void *src);
};
@@ -98,13 +110,14 @@ inline void *Array::GetBuffer() const
return NULL;
}
inline int Array::ResizeData(const Layout *lt, std::size_t item_size)
inline int Array::OccaResize(Layout *lt, std::size_t item_size)
{
layout.Reset(lt); // Reset() checks if the pointer is the same
const std::size_t new_bytes = lt->Size()*item_size;
if (data.size() < new_bytes ||
data.getDHandle() != lt->OccaEngine().GetDevice().getDHandle())
data.getDevice() != lt->OccaEngine().GetDevice())
{
data = lt->Alloc(new_bytes);
data = lt->OccaEngine().Alloc(new_bytes);
slice = data;
// If memory allocation fails - an exception is thrown.
}
@@ -122,6 +135,37 @@ inline void Array::MakeRef(Array &master)
slice = master.slice;
}
inline int Array::OccaResize(std::size_t new_size, std::size_t item_size)
{
Layout &ol = OccaLayout();
ol.OccaResize(new_size);
return OccaResize(&ol, item_size);
}
template <typename T>
inline void Array::OccaFill(const T val)
{
::occa::linalg::operator_eq<T>(slice, val);
}
inline void Array::OccaAssign(const Array &src)
{
if (slice != src.slice && slice.size() != 0)
{
MFEM_ASSERT(slice.size() == src.slice.size(), "");
slice.copyFrom(src.slice);
}
}
inline void Array::OccaPush(const void *src)
{
if (slice.size() != 0)
{
slice.copyFrom(src);
}
}
} // namespace mfem::occa
} // namespace mfem
+41 -17
View File
@@ -24,8 +24,8 @@ namespace occa
OccaBilinearForm::OccaBilinearForm(FiniteElementSpace *ofespace_) :
Operator(ofespace_->OccaVLayout()),
localX((ofespace_->OccaEVLayout().DontDelete(), ofespace_->OccaEVLayout())),
localY((ofespace_->OccaEVLayout().DontDelete(), ofespace_->OccaEVLayout()))
localX(ofespace_->OccaEVLayout()),
localY(ofespace_->OccaEVLayout())
{
Init(ofespace_->OccaEngine(), ofespace_, ofespace_);
}
@@ -34,8 +34,8 @@ OccaBilinearForm::OccaBilinearForm(FiniteElementSpace *otrialFESpace_,
FiniteElementSpace *otestFESpace_) :
Operator(otrialFESpace_->OccaVLayout(),
otestFESpace_->OccaVLayout()),
localX((otrialFESpace_->OccaEVLayout().DontDelete(), otrialFESpace_->OccaEVLayout())),
localY((otestFESpace_->OccaEVLayout().DontDelete(), otestFESpace_->OccaEVLayout()))
localX(otrialFESpace_->OccaEVLayout()),
localY(otestFESpace_->OccaEVLayout())
{
Init(otrialFESpace_->OccaEngine(), otrialFESpace_, otestFESpace_);
}
@@ -65,11 +65,9 @@ void OccaBilinearForm::Init(const Engine &e,
if (GetDevice().mode() == "OpenMP")
{
const std::string &okl_path = OccaEngine().GetOklPath();
const std::string &okl_defines = OccaEngine().GetOklDefines();
::occa::kernel initLocalKernel =
GetDevice().buildKernel(okl_path + "utils.okl",
"InitLocalVector",
okl_defines);
"InitLocalVector");
const std::size_t sd = sizeof(double);
const uint64_t trialEntries = sd * (elements * trialLocalDofs);
@@ -273,8 +271,6 @@ void OccaBilinearForm::InitRHS(const mfem::Array<int> &constraintList,
mfem::Vector &X, mfem::Vector &B,
int copy_interior)
{
const std::string okl_defines = OccaEngine().GetOklDefines();
// FIXME: move these kernels to the Backend?
static ::occa::kernelBuilder get_subvector_builder =
::occa::linalg::customLinearMethod(
@@ -288,7 +284,7 @@ void OccaBilinearForm::InitRHS(const mfem::Array<int> &constraintList,
" VTYPE1: 'double',"
" VTYPE2: 'int',"
" TILESIZE: 128,"
"}" + okl_defines);
"}");
static ::occa::kernelBuilder set_subvector_builder =
::occa::linalg::customLinearMethod(
@@ -302,7 +298,7 @@ void OccaBilinearForm::InitRHS(const mfem::Array<int> &constraintList,
" VTYPE1: 'double',"
" VTYPE2: 'int',"
" TILESIZE: 128,"
"}" + okl_defines);
"}");
const mfem::Operator *P = GetTrialProlongation();
const mfem::Operator *R = GetTrialRestriction();
@@ -345,6 +341,7 @@ void OccaBilinearForm::InitRHS(const mfem::Array<int> &constraintList,
constrList.OccaMem());
}
// FIXME: add case for HypreParMatrix here
OccaConstrainedOperator *cA = dynamic_cast<OccaConstrainedOperator*>(A);
if (cA)
{
@@ -361,7 +358,7 @@ void OccaBilinearForm::InitRHS(const mfem::Array<int> &constraintList,
void OccaBilinearForm::Mult_(const Vector &x, Vector &y) const
{
otrialFESpace->GlobalToLocal(x, localX);
localY.Fill<double>(0.0);
localY.OccaFill<double>(0.0);
const int integratorCount = (int) integrators.size();
for (int i = 0; i < integratorCount; ++i)
@@ -376,7 +373,7 @@ void OccaBilinearForm::Mult_(const Vector &x, Vector &y) const
void OccaBilinearForm::MultTranspose_(const Vector &x, Vector &y) const
{
otestFESpace->GlobalToLocal(x, localX);
localY.Fill<double>(0.0);
localY.OccaFill<double>(0.0);
const int integratorCount = (int) integrators.size();
for (int i = 0; i < integratorCount; ++i)
@@ -432,19 +429,42 @@ void BilinearForm::InitOccaBilinearForm()
Coefficient *scal_coeff = dbfi[i]->GetScalarCoefficient();
ConstantCoefficient *const_coeff =
dynamic_cast<ConstantCoefficient*>(scal_coeff);
GridFunctionCoefficient *gridfunc_coeff =
dynamic_cast<GridFunctionCoefficient*>(scal_coeff);
// TODO: other types of coefficients ...
double val = const_coeff ? const_coeff->constant : 1.0;
OccaCoefficient ocoeff(obform->OccaEngine(), val);
OccaCoefficient *ocoeff = NULL;
if (const_coeff)
{
ocoeff = new OccaCoefficient(obform->OccaEngine(),
const_coeff->constant);
}
else if (gridfunc_coeff)
{
ocoeff = new OccaCoefficient(obform->OccaEngine(),
*gridfunc_coeff->GetGridFunction(), true);
}
else if (!scal_coeff)
{
ocoeff = new OccaCoefficient(obform->OccaEngine(), 1.0);
}
else
{
MFEM_ABORT("Coefficient type not supported");
}
OccaIntegrator *ointeg = NULL;
if (integ_name == "(undefined)")
{
MFEM_ABORT("BilinearFormIntegrator does not define Name()");
}
else if (integ_name == "mass")
{
ointeg = new OccaMassIntegrator(*ocoeff);
}
else if (integ_name == "diffusion")
{
ointeg = new OccaDiffusionIntegrator(ocoeff);
ointeg = new OccaDiffusionIntegrator(*ocoeff);
}
else
{
@@ -452,6 +472,10 @@ void BilinearForm::InitOccaBilinearForm()
<< "] is not supported");
}
// NOTE: The integrators copy ocoeff, so it can be deleted here so there
// is no memory leak.
delete ocoeff;
const mfem::IntegrationRule *ir = dbfi[i]->GetIntRule();
if (ir) { ointeg->SetIntegrationRule(*ir); }
+4 -6
View File
@@ -107,11 +107,10 @@ OccaGeometry OccaGeometry::Get(::occa::device device,
props["defines/STORE_JACOBIAN_DET"] = (flags & JacobianDet);
const std::string &okl_path = ofespace.OccaEngine().GetOklPath();
const std::string &okl_defines = ofespace.OccaEngine().GetOklDefines();
::occa::kernel init = device.buildKernel(okl_path + "geometry.okl",
stringWithDim("InitGeometryInfo",
fe.GetDim()),
props + okl_defines);
props);
init(elements,
maps.dofToQuadD,
geom.meshNodes,
@@ -730,10 +729,9 @@ OccaGeometry OccaIntegrator::GetGeometry(const int flags)
{
const std::string filename = GetName() + ".okl";
const std::string &okl_path = OccaEngine().GetOklPath();
const std::string &okl_defines = OccaEngine().GetOklDefines();
return GetDevice().buildKernel(okl_path + filename,
kernelName,
props + okl_defines);
props);
}
//====================================
@@ -786,8 +784,8 @@ void OccaDiffusionIntegrator::Assemble()
OccaGeometry geom = GetGeometry(OccaGeometry::Jacobian);
assembledOperator.Resize<double>(symmDims * quadraturePoints * elements,
NULL);
assembledOperator.OccaResize(symmDims * quadraturePoints * elements,
sizeof(double));
assembleKernel((int) mesh->GetNE(),
maps.quadWeights,
+24 -11
View File
@@ -119,17 +119,18 @@ void OccaVectorParameter::Setup(OccaIntegrator &integ,
//---[ GridFunction Parameter ]-------
OccaGridFunctionParameter::OccaGridFunctionParameter(const std::string &name_,
OccaGridFunction &gf_,
const Engine &e,
mfem::GridFunction &gf_,
const bool useRestrict_)
: name(name_),
gf(gf_),
gfQuad(*(new Layout(gf_.OccaLayout().OccaEngine(), 0))),
gfQuad(e),
useRestrict(useRestrict_) {}
OccaParameter* OccaGridFunctionParameter::Clone()
{
OccaGridFunctionParameter *param =
new OccaGridFunctionParameter(name, gf, useRestrict);
new OccaGridFunctionParameter(name, gfQuad.OccaEngine(), gf, useRestrict);
param->gfQuad.MakeRef(gfQuad);
return param;
}
@@ -141,15 +142,16 @@ void OccaGridFunctionParameter::Setup(OccaIntegrator &integ,
std::string &args = (props["defines/COEFF_ARGS"]
.asString()
.string());
args += "const double *";
if (useRestrict)
{
args += " restrict ";
args += "@restrict ";
}
args += "const double *";
args += name;
args += " @dim(NUM_QUAD, numElements),\n";
gf.ToQuad(integ.GetIntegrationRule(), gfQuad);
FiniteElementSpace &f = gf.FESpace()->Get_PFESpace()->As<FiniteElementSpace>();
ToQuad(integ.GetIntegrationRule(), f, gf.Get_PVector()->As<Vector>(), gfQuad);
}
::occa::kernelArg OccaGridFunctionParameter::KernelArgs()
@@ -168,6 +170,16 @@ OccaCoefficient::OccaCoefficient(const Engine &e, const double value) :
coeffValue = value;
}
OccaCoefficient::OccaCoefficient(const Engine &e, mfem::GridFunction &gf,
const bool useRestrict) :
engine(&e),
integ(NULL),
name("COEFF")
{
coeffValue = "(u(q, e))";
AddGridFunction("u", gf, useRestrict);
}
OccaCoefficient::OccaCoefficient(const Engine &e, const std::string &source) :
engine(&e),
integ(NULL),
@@ -261,10 +273,13 @@ OccaCoefficient& OccaCoefficient::AddVector(const std::string &name_,
}
OccaCoefficient& OccaCoefficient::AddGridFunction(const std::string &name_,
OccaGridFunction &gf,
mfem::GridFunction &gf,
const bool useRestrict)
{
return Add(new OccaGridFunctionParameter(name_, gf, useRestrict));
MFEM_ASSERT(engine->CheckVector(gf.Get_PVector()) &&
engine->CheckFESpace(gf.FESpace()->Get_PFESpace()),
"invalid device GridFunction");
return Add(new OccaGridFunctionParameter(name_, *engine, gf, useRestrict));
}
bool OccaCoefficient::IsConstant()
@@ -302,10 +317,9 @@ Vector OccaCoefficient::Eval()
void OccaCoefficient::Eval(Vector &quadCoeff)
{
const std::string &okl_path = OccaEngine().GetOklPath();
const std::string &okl_defines = OccaEngine().GetOklDefines();
static ::occa::kernelBuilder builder =
::occa::kernelBuilder::fromFile(okl_path + "coefficient.okl",
"CoefficientEval", okl_defines);
"CoefficientEval");
if (integ == NULL)
{
@@ -320,7 +334,6 @@ void OccaCoefficient::Eval(Vector &quadCoeff)
kernelProps["defines/COEFF"] = name;
kernelProps["defines/COEFF_ARGS"] = name + "_ARGS";
}
kernelProps += okl_defines;
::occa::kernel evalKernel = builder.build(GetDevice(), kernelProps);
evalKernel(elements, *this, quadCoeff.OccaMem());
+6 -3
View File
@@ -178,13 +178,14 @@ class OccaGridFunctionParameter : public OccaParameter
{
private:
const std::string name;
OccaGridFunction &gf;
mfem::GridFunction &gf;
Vector gfQuad;
bool useRestrict;
public:
OccaGridFunctionParameter(const std::string &name_,
OccaGridFunction &gf_,
const Engine &e,
mfem::GridFunction &gf_,
const bool useRestrict_ = false);
virtual OccaParameter* Clone();
@@ -219,6 +220,8 @@ private:
public:
OccaCoefficient(const Engine &e, const double value = 1.0);
OccaCoefficient(const Engine &e, mfem::GridFunction &gf,
const bool useRestrict = false);
OccaCoefficient(const Engine &e, const std::string &source);
OccaCoefficient(const Engine &e, const char *source);
~OccaCoefficient();
@@ -263,7 +266,7 @@ public:
const bool useRestrict = false);
OccaCoefficient& AddGridFunction(const std::string &name_,
OccaGridFunction &gf,
mfem::GridFunction &gf,
const bool useRestrict = false);
bool IsConstant();
+20 -20
View File
@@ -13,10 +13,10 @@
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
const double * restrict quadWeights,
const Jacobian2D_t restrict J,
@restrict const double *quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
SymmOperator2D_t restrict oper) {
@restrict SymmOperator2D_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
@@ -32,13 +32,13 @@
}
@kernel void MultAdd2D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DofToQuadD2D_t restrict dofToQuadD,
const QuadToDof_t restrict quadToDof,
const QuadToDofD2D_t restrict quadToDofD,
const SymmOperator2D_t restrict oper,
const DLocal_t restrict solIn,
DLocal_t restrict solOut) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD2D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD2D_t quadToDofD,
@restrict const SymmOperator2D_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
@@ -78,10 +78,10 @@
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
const double * restrict quadWeights,
const Jacobian3D_t restrict J,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
SymmOperator3D_t restrict oper) {
@restrict SymmOperator3D_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
@@ -118,13 +118,13 @@
}
@kernel void MultAdd3D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DofToQuadD3D_t restrict dofToQuadD,
const QuadToDof_t restrict quadToDof,
const QuadToDofD3D_t restrict quadToDofD,
const SymmOperator3D_t restrict oper,
const DLocal_t restrict solIn,
DLocal_t restrict solOut) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD3D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD3D_t quadToDofD,
@restrict const SymmOperator3D_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
@@ -38,13 +38,13 @@
}
@kernel void MultAdd2D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DofToQuadD2D_t restrict dofToQuadD,
const QuadToDof_t restrict quadToDof,
const QuadToDofD2D_t restrict quadToDofD,
const SymmOperator2D_t restrict oper,
const DLocal_t restrict solIn,
DLocal_t restrict solOut) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD2D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD2D_t quadToDofD,
@restrict const SymmOperator2D_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_gradX[NUM_QUAD];
@@ -131,13 +131,13 @@
}
@kernel void MultAdd3D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DofToQuadD3D_t restrict dofToQuadD,
const QuadToDof_t restrict quadToDof,
const QuadToDofD3D_t restrict quadToDofD,
const SymmOperator3D_t restrict oper,
const DLocal_t restrict solIn,
DLocal_t restrict solOut) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD3D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD3D_t quadToDofD,
@restrict const SymmOperator3D_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_gradX[NUM_QUAD];
+30 -30
View File
@@ -13,10 +13,10 @@
//---[ 1D ]-----------------------------
@kernel void Assemble1D(const int numElements,
const double * restrict quadWeights,
const Jacobian1D_t restrict J,
@restrict const double * quadWeights,
@restrict const Jacobian1D_t J,
COEFF_ARGS
SymmOperator1D_t restrict oper) {
@restrict SymmOperator1D_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_1D; ++q; @inner) {
oper(q, e) = quadWeights[q] * COEFF / J(q, e);
@@ -25,13 +25,13 @@
}
@kernel void MultAdd1D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DofToQuad_t restrict dofToQuadD,
const QuadToDof_t restrict quadToDof,
const QuadToDof_t restrict quadToDofD,
const SymmOperator1D_t restrict oper,
const DLocal1D_t restrict solIn,
DLocal1D_t restrict solOut) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator1D_t oper,
@restrict const DLocal1D_t solIn,
@restrict DLocal1D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
@@ -62,10 +62,10 @@
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
const double * restrict quadWeights,
const Jacobian2D_t restrict J,
@restrict const double * quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
SymmOperator2D_t restrict oper) {
@restrict SymmOperator2D_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_2D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
@@ -81,13 +81,13 @@
}
@kernel void MultAdd2D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DofToQuad_t restrict dofToQuadD,
const QuadToDof_t restrict quadToDof,
const QuadToDof_t restrict quadToDofD,
const SymmOperator2D_t restrict oper,
const DLocal2D_t restrict solIn,
DLocal2D_t restrict solOut) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator2D_t oper,
@restrict const DLocal2D_t solIn,
@restrict DLocal2D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
@@ -175,10 +175,10 @@
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
const double * restrict quadWeights,
const Jacobian3D_t restrict J,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
SymmOperator3D_t restrict oper) {
@restrict SymmOperator3D_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_3D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
@@ -215,13 +215,13 @@
}
@kernel void MultAdd3D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DofToQuad_t restrict dofToQuadD,
const QuadToDof_t restrict quadToDof,
const QuadToDof_t restrict quadToDofD,
const SymmOperator3D_t restrict oper,
const DLocal3D_t restrict solIn,
DLocal3D_t restrict solOut) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator3D_t oper,
@restrict const DLocal3D_t solIn,
@restrict DLocal3D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
+23 -21
View File
@@ -29,13 +29,13 @@
}
@kernel void MultAdd1D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DofToQuad_t restrict dofToQuadD,
const QuadToDof_t restrict quadToDof,
const QuadToDof_t restrict quadToDofD,
const SymmOperator1D_t restrict oper,
const DLocal1D_t restrict solIn,
DLocal1D_t restrict solOut) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator1D_t oper,
@restrict const DLocal1D_t solIn,
@restrict DLocal1D_t solOut) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M1_ELEMENT_BATCHES; @outer) {
@shared double s_dofToQuadD[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@@ -108,13 +108,13 @@
}
@kernel void MultAdd2D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DofToQuad_t restrict dofToQuadD,
const QuadToDof_t restrict quadToDof,
const QuadToDof_t restrict quadToDofD,
const SymmOperator2D_t restrict oper,
const DLocal2D_t restrict solIn,
DLocal2D_t restrict solOut) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator2D_t oper,
@restrict const DLocal2D_t solIn,
@restrict DLocal2D_t solOut) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M2_ELEMENT_BATCH; @outer) {
// Store dof <--> quad mappings
@@ -272,13 +272,13 @@
}
@kernel void MultAdd3D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DofToQuad_t restrict dofToQuadD,
const QuadToDof_t restrict quadToDof,
const QuadToDof_t restrict quadToDofD,
const SymmOperator3D_t restrict oper,
const DLocal3D_t restrict solIn,
DLocal3D_t restrict solOut) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator3D_t oper,
@restrict const DLocal3D_t solIn,
@restrict DLocal3D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
// Store dof <--> quad mappings
@@ -391,6 +391,7 @@
}
}
}
@barrier("s_z_s_Dz_sync_1");
}
// Iterate over xy planes to compute solution
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
@@ -427,6 +428,7 @@
}
}
}
@barrier("s_z_s_Dz_s_xyDz_sync_1");
}
}
}
+37 -10
View File
@@ -42,7 +42,6 @@ void Engine::Init(const std::string &engine_spec)
device[0].setup(props);
okl_path = "mfem-occa://";
// okl_defines = "...";
if (!fileOpenerRegistered)
{
// The directories from "MFEM_OCCA_OKL_PATH", if any, have the highest
@@ -57,6 +56,9 @@ void Engine::Init(const std::string &engine_spec)
::occa::io::fileOpener::add(fo);
fileOpenerRegistered = true;
}
// std::cout << "OCCA device properties:\n" << device[0].properties();
force_cuda_aware_mpi = false;
}
Engine::Engine(const std::string &engine_spec)
@@ -74,6 +76,36 @@ Engine::Engine(MPI_Comm _comm, const std::string &engine_spec)
}
#endif
bool Engine::CheckEngine(const mfem::Engine *engine) const
{
return (engine != NULL && util::Is<const Engine>(engine) != NULL &&
*util::As<const Engine>(engine) == *this);
}
bool Engine::CheckLayout(const PLayout *layout) const
{
return (layout != NULL && util::Is<const Layout>(layout) != NULL &&
layout->As<Layout>().OccaEngine() == *this);
}
bool Engine::CheckArray(const PArray *array) const
{
return (array != NULL && util::Is<const Array>(array) != NULL &&
array->As<Array>().OccaEngine() == *this);
}
bool Engine::CheckVector(const PVector *vector) const
{
return (vector != NULL && util::Is<const Vector>(vector) != NULL &&
vector->As<Vector>().OccaEngine() == *this);
}
bool Engine::CheckFESpace(const PFiniteElementSpace *fes) const
{
return (fes != NULL && util::Is<const FiniteElementSpace>(fes) != NULL &&
fes->As<FiniteElementSpace>().OccaEngine() == *this);
}
DLayout Engine::MakeLayout(std::size_t size) const
{
return DLayout(new Layout(*this, size));
@@ -88,19 +120,14 @@ DLayout Engine::MakeLayout(const mfem::Array<std::size_t> &offsets) const
DArray Engine::MakeArray(PLayout &layout, std::size_t item_size) const
{
MFEM_ASSERT(dynamic_cast<Layout *>(&layout) != NULL,
"invalid input layout");
Layout *lt = static_cast<Layout *>(&layout);
return DArray(new Array(*lt, item_size));
return DArray(new Array(layout.As<Layout>(), item_size));
}
DVector Engine::MakeVector(PLayout &layout, int type_id) const
{
MFEM_ASSERT(type_id == ScalarId<double>::value, "invalid type_id");
MFEM_ASSERT(dynamic_cast<Layout *>(&layout) != NULL,
"invalid input layout");
Layout *lt = static_cast<Layout *>(&layout);
return DVector(new Vector(*lt));
MFEM_ASSERT(type_id == ScalarId<double>::value, "type_id " << type_id
<< " is not supported");
return DVector(new Vector(layout.As<Layout>()));
}
DFiniteElementSpace Engine::MakeFESpace(mfem::FiniteElementSpace &fespace) const
+36 -3
View File
@@ -41,18 +41,23 @@ protected:
// int *workers_mem_res;
static bool fileOpenerRegistered;
::occa::device *device; // An array of OCCA devices
std::string okl_path, okl_defines;
/// An array of OCCA devices. Currently only a single device is supported.
::occa::device *device;
std::string okl_path;
bool force_cuda_aware_mpi;
void Init(const std::string &engine_spec);
public:
/// TODO: doxygen
Engine(const std::string &engine_spec);
#ifdef MFEM_USE_MPI
/// TODO: doxygen
Engine(MPI_Comm comm, const std::string &engine_spec);
#endif
/// TODO: doxygen
virtual ~Engine() { delete [] device; }
/**
@@ -60,13 +65,41 @@ public:
*/
///@{
/// Get the associated OCCA device.
::occa::device GetDevice(int idx = 0) const { return device[idx]; }
/// TODO: doxygen
const std::string &GetOklPath() const { return okl_path; }
/// OCCA device memory allocation.
::occa::memory Alloc(std::size_t bytes) const
{ return GetDevice().malloc(bytes); }
/// Two mfem::occa::Engine%s are equal if they use the same OCCA device.
bool operator==(const Engine &other) const
{ return GetDevice() == other.GetDevice(); }
/// TODO: doxygen
const std::string &GetOklDefines() const { return okl_defines; }
bool CheckEngine(const mfem::Engine *e) const;
/// TODO: doxygen
bool CheckLayout(const PLayout *layout) const;
/// TODO: doxygen
bool CheckArray(const PArray *array) const;
/// TODO: doxygen
bool CheckVector(const PVector *vector) const;
/// TODO: doxygen
bool CheckFESpace(const PFiniteElementSpace *fes) const;
#ifdef MFEM_USE_MPI
void SetForceCudaAwareMPI(bool force = true)
{ force_cuda_aware_mpi = force; }
bool GetForceCudaAwareMPI() const { return force_cuda_aware_mpi; }
#endif
///@}
// End: OCCA specific interface
+379 -21
View File
@@ -16,6 +16,12 @@
#include "fespace.hpp"
#include "interpolation.hpp"
#ifdef MFEM_USE_MPI
#ifdef OMPI_RELEASE_VERSION
#include <mpi-ext.h> // Check for cuda support
#endif
#endif
namespace mfem
{
@@ -25,41 +31,42 @@ namespace occa
FiniteElementSpace::FiniteElementSpace(const Engine &e,
mfem::FiniteElementSpace &fespace)
: PFiniteElementSpace(e, fespace),
e_layout(e, 0) // resized in SetupLocalGlobalMaps()
e_layout(new Layout(e, 0)) // resized in SetupLocalGlobalMaps()
{
vdim = fespace.GetVDim();
ordering = fespace.GetOrdering();
SetupLocalGlobalMaps();
SetupOperators();
SetupOperators(); // calls virtual methods of 'fes'
SetupKernels();
}
FiniteElementSpace::~FiniteElementSpace()
{
delete [] elementDofMap;
delete [] elementDofMapInverse;
delete restrictionOp;
delete prolongationOp;
}
void FiniteElementSpace::SetupLocalGlobalMaps()
{
const mfem::FiniteElement &fe = *(fes->GetFE(0));
const int elements = fes->GetNE();
if (elements == 0) { return; }
// Assuming of finite elements are the same.
const mfem::FiniteElement &fe = *fes->GetFE(0);
const mfem::TensorBasisElement *el =
dynamic_cast<const mfem::TensorBasisElement*>(&fe);
const mfem::Table &e2dTable = fes->GetElementToDofTable();
const int *elementMap = e2dTable.GetJ();
const int elements = fes->GetNE();
globalDofs = fes->GetNDofs();
localDofs = fe.GetDof();
e_layout.Resize(localDofs * elements * fes->GetVDim());
e_layout->OccaResize(e2dTable.Size_of_connections());
elementDofMap = new int[localDofs];
elementDofMapInverse = new int[localDofs];
int *elementDofMap = new int[localDofs];
if (el)
{
::memcpy(elementDofMap,
@@ -73,10 +80,6 @@ void FiniteElementSpace::SetupLocalGlobalMaps()
elementDofMap[i] = i;
}
}
for (int i = 0; i < localDofs; ++i)
{
elementDofMapInverse[elementDofMap[i]] = i;
}
// Allocate device offsets and indices
globalToLocalOffsets.allocate(GetDevice(),
@@ -99,6 +102,7 @@ void FiniteElementSpace::SetupLocalGlobalMaps()
for (int e = 0; e < elements; ++e)
{
MFEM_ASSERT(e2dTable.RowSize(e) == localDofs, "");
for (int d = 0; d < localDofs; ++d)
{
const int gid = elementMap[localDofs*e + d];
@@ -130,19 +134,64 @@ void FiniteElementSpace::SetupLocalGlobalMaps()
}
offsets[0] = 0;
delete [] elementDofMap;
globalToLocalOffsets.keepInDevice();
globalToLocalIndices.keepInDevice();
localToGlobalMap.keepInDevice();
}
void FiniteElementSpace::SetupOperators()
void FiniteElementSpace::SetupOperators() const
{
// Construct 'restrictionOp' and 'prolongationOp'.
prolongationOp = restrictionOp = NULL;
const mfem::SparseMatrix *R = fes->GetRestrictionMatrix();
const mfem::Operator *P = fes->GetProlongationMatrix();
CreateRPOperators(OccaVLayout(), OccaTrueVLayout(),
R, P,
restrictionOp,
prolongationOp);
if (!P) { return; }
Layout &v_layout = OccaVLayout();
Layout &t_layout = OccaTrueVLayout();
// Assuming R has one entry per row equal to 1.
MFEM_ASSERT(R->Finalized(), "");
const int tdofs = R->Height();
MFEM_ASSERT(tdofs == (int)t_layout.Size(), "");
MFEM_ASSERT(tdofs == R->GetI()[tdofs], "");
::occa::array<int> ltdof_ldof(GetDevice(), tdofs, R->GetJ());
ltdof_ldof.keepInDevice();
restrictionOp = new RestrictionOperator(v_layout, t_layout, ltdof_ldof);
const mfem::SparseMatrix *pmat = dynamic_cast<const mfem::SparseMatrix*>(P);
if (pmat)
{
const mfem::SparseMatrix *pmatT = Transpose(*pmat);
OccaSparseMatrix *occaP =
CreateMappedSparseMatrix(t_layout, v_layout, *pmat);
OccaSparseMatrix *occaPT =
CreateMappedSparseMatrix(v_layout, t_layout, *pmatT);
prolongationOp = new ProlongationOperator(*occaP, *occaPT);
delete occaPT;
delete occaP;
}
#ifdef MFEM_USE_MPI
else if (fes->Conforming() && dynamic_cast<ParFiniteElementSpace*>(fes))
{
ParFiniteElementSpace *pfes = static_cast<ParFiniteElementSpace*>(fes);
prolongationOp = new OccaConformingProlongation(*this, *pfes,
ltdof_ldof.memory());
}
#endif
else
{
prolongationOp = new ProlongationOperator(t_layout, v_layout, P);
}
}
void FiniteElementSpace::SetupKernels()
@@ -158,15 +207,324 @@ void FiniteElementSpace::SetupKernels()
::occa::device device = GetDevice();
const std::string &okl_path = OccaEngine().GetOklPath();
const std::string &okl_defines = OccaEngine().GetOklDefines();
globalToLocalKernel = device.buildKernel(okl_path + "fespace.okl",
"GlobalToLocal",
props + okl_defines);
props);
localToGlobalKernel = device.buildKernel(okl_path + "fespace.okl",
"LocalToGlobal",
props + okl_defines);
props);
}
#ifdef MFEM_USE_MPI
OccaConformingProlongation::OccaConformingProlongation(
const FiniteElementSpace &ofes, const mfem::ParFiniteElementSpace &pfes,
::occa::memory ltdof_ldof_)
: Operator(ofes.OccaTrueVLayout(), ofes.OccaVLayout()),
shr_ltdof(ofes.OccaEngine()),
ext_ldof(ofes.OccaEngine()),
shr_buf(shr_ltdof.OccaLayout(), sizeof(double)),
ext_buf(ext_ldof.OccaLayout(), sizeof(double)),
shr_buf_offsets(NULL), ext_buf_offsets(NULL),
ltdof_ldof(ltdof_ldof_),
gc(pfes.GroupComm())
{
MFEM_ASSERT(pfes.Conforming(), "internal error");
const Engine &engine = ofes.OccaEngine();
const std::string &okl_path = engine.GetOklPath();
::occa::device device = engine.GetDevice();
{
Table nbr_ltdof;
gc.GetNeighborLTDofTable(nbr_ltdof);
shr_ltdof.OccaResize(nbr_ltdof.Size_of_connections(), sizeof(int));
shr_ltdof.OccaPush(nbr_ltdof.GetJ());
shr_buf.OccaResize(&shr_ltdof.OccaLayout(), sizeof(double));
shr_buf_offsets = nbr_ltdof.GetI();
{
mfem::Array<int> shr_ltdof(nbr_ltdof.GetJ(),
nbr_ltdof.Size_of_connections());
mfem::Array<int> unique_ltdof(shr_ltdof);
unique_ltdof.Sort();
unique_ltdof.Unique();
// Note: the next loop modifies the J array of nbr_ltdof
for (int i = 0; i < shr_ltdof.Size(); i++)
{
shr_ltdof[i] = unique_ltdof.FindSorted(shr_ltdof[i]);
MFEM_ASSERT(shr_ltdof[i] != -1, "internal error");
}
Table unique_shr;
Transpose(shr_ltdof, unique_shr, unique_ltdof.Size());
unq_ltdof = device.malloc(unique_ltdof.Size()*sizeof(int),
unique_ltdof.GetData());
unq_shr_i = device.malloc((unique_shr.Size()+1)*sizeof(int),
unique_shr.GetI());
unq_shr_j = device.malloc(unique_shr.Size_of_connections()*sizeof(int),
unique_shr.GetJ());
}
delete [] nbr_ltdof.GetJ();
nbr_ltdof.LoseData();
}
{
Table nbr_ldof;
gc.GetNeighborLDofTable(nbr_ldof);
ext_ldof.OccaResize(nbr_ldof.Size_of_connections(), sizeof(int));
ext_ldof.OccaPush(nbr_ldof.GetJ());
ext_buf.OccaResize(&ext_ldof.OccaLayout(), sizeof(double));
ext_buf_offsets = nbr_ldof.GetI();
delete [] nbr_ldof.GetJ();
nbr_ldof.LoseData();
}
host_shr_buf = NULL;
host_ext_buf = NULL;
// If the device has a separate memory space (e.g. CUDA device) and the MPI
// library does not support buffers in that separate memory space, we
// allocate separate host buffers to use for MPI communication.
if (device.hasSeparateMemorySpace())
{
bool need_host_buf = true;
if (device.mode() == "CUDA")
{
#ifdef MPIX_CUDA_AWARE_SUPPORT
need_host_buf = !MPIX_Query_cuda_support();
#endif
if (engine.GetForceCudaAwareMPI()) { need_host_buf = false; }
if (gc.GetGroupTopology().MyRank() == 0)
{
mfem::out << "\nOccaConformingProlongation: CUDA-aware MPI: "
<< (need_host_buf ? "NO" : "YES") << "\n\n";
}
}
if (need_host_buf)
{
host_shr_buf = new char[shr_buf.OccaMem().size()];
host_ext_buf = new char[ext_buf.OccaMem().size()];
}
}
ExtractSubVector = device.buildKernel(okl_path + "mappings.okl",
"ExtractSubVector",
"defines: { TILESIZE: 256 }");
SetSubVector = device.buildKernel(okl_path + "mappings.okl",
"SetSubVector",
"defines: { TILESIZE: 256 }");
AddSubVector = device.buildKernel(okl_path + "mappings.okl",
"AddSubVector",
"defines: { TILESIZE: 256 }");
const GroupTopology &gtopo = gc.GetGroupTopology();
int req_counter = 0;
for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++)
{
const int send_offset = shr_buf_offsets[nbr];
const int send_size = shr_buf_offsets[nbr+1] - send_offset;
if (send_size > 0) { req_counter++; }
const int recv_offset = ext_buf_offsets[nbr];
const int recv_size = ext_buf_offsets[nbr+1] - recv_offset;
if (recv_size > 0) { req_counter++; }
}
requests = new MPI_Request[req_counter];
}
OccaConformingProlongation::~OccaConformingProlongation()
{
delete [] requests;
delete [] host_ext_buf;
delete [] host_shr_buf;
delete [] ext_buf_offsets;
delete [] shr_buf_offsets;
}
void OccaConformingProlongation::BcastBeginCopy(const ::occa::memory &src,
std::size_t item_size) const
{
// shr_buf[i] = src[shr_ltdof[i]]
MFEM_ASSERT(item_size == sizeof(double), "");
if (shr_ltdof.Size() == 0) { return; }
ExtractSubVector((int)shr_ltdof.Size(), shr_ltdof.OccaMem(), src,
shr_buf.OccaMem());
// If the above kernel is executed asynchronously, wait for it to complete:
shr_buf.OccaMem().getDevice().finish();
if (host_shr_buf)
{
shr_buf.OccaMem().copyTo(host_shr_buf);
}
}
void OccaConformingProlongation::BcastLocalCopy(const ::occa::memory &src,
::occa::memory &dst,
std::size_t item_size) const
{
// dst[ltdof_ldof[i]] = src[i]
MFEM_ASSERT(item_size == sizeof(double), "");
if (ltdof_ldof.size<int>() == 0) { return; }
SetSubVector((int)ltdof_ldof.size<int>(), ltdof_ldof, src, dst);
}
void OccaConformingProlongation::BcastEndCopy(::occa::memory &dst,
std::size_t item_size) const
{
// dst[ext_ldof[i]] = ext_buf[i]
MFEM_ASSERT(item_size == sizeof(double), "");
if (ext_ldof.Size() == 0) { return; }
if (host_ext_buf)
{
ext_buf.OccaMem().copyFrom(host_ext_buf);
}
SetSubVector((int)ext_ldof.Size(), ext_ldof.OccaMem(),
ext_buf.OccaMem(), dst);
}
void OccaConformingProlongation::ReduceBeginCopy(const ::occa::memory &src,
std::size_t item_size) const
{
// ext_buf[i] = src[ext_ldof[i]]
MFEM_ASSERT(item_size == sizeof(double), "");
if (ext_ldof.Size() == 0) { return; }
ExtractSubVector((int)ext_ldof.Size(), ext_ldof.OccaMem(), src,
ext_buf.OccaMem());
// If the above kernel is executed asynchronously, wait for it to complete:
ext_buf.OccaMem().getDevice().finish();
if (host_ext_buf)
{
ext_buf.OccaMem().copyTo(host_ext_buf);
}
}
void OccaConformingProlongation::ReduceLocalCopy(const ::occa::memory &src,
::occa::memory &dst,
std::size_t item_size) const
{
// dst[i] = src[ltdof_ldof[i]]
MFEM_ASSERT(item_size == sizeof(double), "");
if (ltdof_ldof.size<int>() == 0) { return; }
ExtractSubVector((int)ltdof_ldof.size<int>(), ltdof_ldof, src, dst);
}
void OccaConformingProlongation::ReduceEndAssemble(::occa::memory &dst,
std::size_t item_size) const
{
// dst[shr_ltdof[i]] += shr_buf[i]
MFEM_ASSERT(item_size == sizeof(double), "");
if (unq_ltdof.size<int>() == 0) { return; }
if (host_shr_buf)
{
shr_buf.OccaMem().copyFrom(host_shr_buf);
}
AddSubVector((int)unq_ltdof.size<int>(), unq_ltdof, unq_shr_i, unq_shr_j,
shr_buf.OccaMem(), dst);
}
void OccaConformingProlongation::Mult_(const Vector &x, Vector &y) const
{
const GroupTopology &gtopo = gc.GetGroupTopology();
BcastBeginCopy(x.OccaMem(), sizeof(double)); // copy to 'shr_buf'
int req_counter = 0;
for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++)
{
const int send_offset = shr_buf_offsets[nbr];
const int send_size = shr_buf_offsets[nbr+1] - send_offset;
if (send_size > 0)
{
void *send_buf;
if (host_shr_buf)
{
send_buf = host_shr_buf + send_offset*sizeof(double);
}
else
{
send_buf = (shr_buf.OccaMem() + send_offset*sizeof(double)).ptr();
}
MPI_Isend(send_buf, send_size, MPI_DOUBLE, gtopo.GetNeighborRank(nbr),
41822, gtopo.GetComm(), &requests[req_counter++]);
}
const int recv_offset = ext_buf_offsets[nbr];
const int recv_size = ext_buf_offsets[nbr+1] - recv_offset;
if (recv_size > 0)
{
void *recv_buf;
if (host_ext_buf)
{
recv_buf = host_ext_buf + recv_offset*sizeof(double);
}
else
{
recv_buf = (ext_buf.OccaMem() + recv_offset*sizeof(double)).ptr();
}
MPI_Irecv(recv_buf, recv_size, MPI_DOUBLE, gtopo.GetNeighborRank(nbr),
41822, gtopo.GetComm(), &requests[req_counter++]);
}
}
BcastLocalCopy(x.OccaMem(), y.OccaMem(), sizeof(double));
MPI_Waitall(req_counter, requests, MPI_STATUSES_IGNORE);
BcastEndCopy(y.OccaMem(), sizeof(double)); // copy from 'ext_buf'
}
void OccaConformingProlongation::MultTranspose_(const Vector &x,
Vector &y) const
{
const GroupTopology &gtopo = gc.GetGroupTopology();
ReduceBeginCopy(x.OccaMem(), sizeof(double)); // copy to 'ext_buf'
int req_counter = 0;
for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++)
{
const int send_offset = ext_buf_offsets[nbr];
const int send_size = ext_buf_offsets[nbr+1] - send_offset;
if (send_size > 0)
{
void *send_buf;
if (host_ext_buf)
{
send_buf = host_ext_buf + send_offset*sizeof(double);
}
else
{
send_buf = (ext_buf.OccaMem() + send_offset*sizeof(double)).ptr();
}
MPI_Isend(send_buf, send_size, MPI_DOUBLE, gtopo.GetNeighborRank(nbr),
41823, gtopo.GetComm(), &requests[req_counter++]);
}
const int recv_offset = shr_buf_offsets[nbr];
const int recv_size = shr_buf_offsets[nbr+1] - recv_offset;
if (recv_size > 0)
{
void *recv_buf;
if (host_shr_buf)
{
recv_buf = host_shr_buf + recv_offset*sizeof(double);
}
else
{
recv_buf = (shr_buf.OccaMem() + recv_offset*sizeof(double)).ptr();
}
MPI_Irecv(recv_buf, recv_size, MPI_DOUBLE, gtopo.GetNeighborRank(nbr),
41823, gtopo.GetComm(), &requests[req_counter++]);
}
}
ReduceLocalCopy(x.OccaMem(), y.OccaMem(), sizeof(double));
MPI_Waitall(req_counter, requests, MPI_STATUSES_IGNORE);
ReduceEndAssemble(y.OccaMem(), sizeof(double)); // assemble from 'shr_buf'
}
#endif // MFEM_USE_MPI
} // namespace mfem::occa
} // namespace mfem
+85 -21
View File
@@ -35,10 +35,7 @@ protected:
// SharedPtr<const mfem::Engine> engine;
// mfem::FiniteElementSpace *fes;
Layout e_layout;
int *elementDofMap;
int *elementDofMapInverse;
SharedPtr<Layout> e_layout;
::occa::array<int> globalToLocalOffsets;
::occa::array<int> globalToLocalIndices;
@@ -50,10 +47,10 @@ protected:
int globalDofs, localDofs;
int vdim;
mfem::Operator *restrictionOp, *prolongationOp;
mutable Operator *prolongationOp, *restrictionOp;
void SetupLocalGlobalMaps();
void SetupOperators();
void SetupOperators() const; // calls virtual methods of 'fes' !!!
void SetupKernels();
public:
@@ -64,8 +61,7 @@ public:
virtual ~FiniteElementSpace();
/// TODO: doxygen
const Engine &OccaEngine() const
{ return *static_cast<const Engine *>(engine.Get()); }
const Engine &OccaEngine() const { return engine->As<Engine>(); }
/// TODO: doxygen
::occa::device GetDevice(int idx = 0) const
@@ -79,13 +75,7 @@ public:
Layout &OccaTrueVLayout() const
{ return *fes->GetTrueVLayout().As<Layout>(); }
Layout &OccaEVLayout() { return e_layout; }
#ifdef MFEM_USE_MPI
bool isDistributed() const { return (OccaEngine().GetComm() != MPI_COMM_NULL); }
#else
bool isDistributed() const { return false; }
#endif
Layout &OccaEVLayout() { return *e_layout; }
bool hasTensorBasis() const
{ return dynamic_cast<const mfem::TensorBasisElement*>(fes->GetFE(0)); }
@@ -105,20 +95,29 @@ public:
int GetNE() const { return fes->GetNE(); }
const mfem::FiniteElementCollection* FEColl() const
const mfem::FiniteElementCollection *FEColl() const
{ return fes->FEColl(); }
const mfem::FiniteElement* GetFE(const int idx) const
const mfem::FiniteElement *GetFE(const int idx) const
{ return fes->GetFE(idx); }
const int* GetElementDofMap() const { return elementDofMap; }
const int* GetElementDofMapInverse() const { return elementDofMapInverse; }
virtual const mfem::Operator *GetProlongationOperator() const
{ return prolongationOp; }
const mfem::Operator* GetRestrictionOperator() { return restrictionOp; }
const mfem::Operator* GetProlongationOperator() { return prolongationOp; }
virtual const mfem::Operator *GetRestrictionOperator() const
{ return restrictionOp; }
virtual const mfem::Operator *GetInterpolationOperator(
const mfem::QuadratureSpace &qspace) const
{ return NULL; /* FIXME */ }
virtual const mfem::Operator *GetGradientOperator(
const mfem::QuadratureSpace &qspace) const
{ return NULL; /* FIXME */ }
const ::occa::array<int> GetLocalToGlobalMap() const
{ return localToGlobalMap; }
/// L-vector to E-vector
void GlobalToLocal(const Vector &globalVec, Vector &localVec) const
{
globalToLocalKernel(globalDofs,
@@ -127,6 +126,8 @@ public:
globalToLocalIndices,
globalVec.OccaMem(), localVec.OccaMem());
}
/// E-vector to L-vector, transpose of GlobalToLocal
void LocalToGlobal(const Vector &localVec, Vector &globalVec) const
{
localToGlobalKernel(globalDofs,
@@ -137,6 +138,69 @@ public:
}
};
#ifdef MFEM_USE_MPI
/// OCCA version of mfem::ConformingProlongationOperator
class OccaConformingProlongation : public Operator
{
protected:
// size(shr_buf)=size(shr_ltdof)
// size(ext_buf)=size(ext_ldof)
Array shr_ltdof, ext_ldof;
mutable Array shr_buf, ext_buf;
mutable char *host_shr_buf, *host_ext_buf;
// Offsets into {shr,ext}_buf; size is num. neighbors, i.e.
// gc.GetGroupTopology().GetNumNeighbors():
int *shr_buf_offsets, *ext_buf_offsets;
::occa::memory ltdof_ldof; // shared with the restriction operator
::occa::memory unq_ltdof; // enumeration of the unique ltdofs in shr_ltdof
::occa::memory unq_shr_i, unq_shr_j;
::occa::kernel ExtractSubVector, SetSubVector, AddSubVector;
MPI_Request *requests;
const GroupCommunicator &gc;
// Kernel: copy ltdofs from 'src' to 'shr_buf' - prepare for send.
// shr_buf[i] = src[shr_ltdof[i]]
void BcastBeginCopy(const ::occa::memory &src, std::size_t item_size) const;
// Kernel: copy ltdofs from 'src' to ldofs in 'dst'.
// dst[ltdof_ldof[i]] = src[i]
void BcastLocalCopy(const ::occa::memory &src, ::occa::memory &dst,
std::size_t item_size) const;
// Kernel: copy ext. dofs from 'ext_buf' to 'dst' - after recv.
// dst[ext_ldof[i]] = ext_buf[i]
void BcastEndCopy(::occa::memory &dst, std::size_t item_size) const;
// Kernel: copy ext. dofs from 'src' to 'ext_buf' - prepare for send.
// ext_buf[i] = src[ext_ldof[i]]
void ReduceBeginCopy(const ::occa::memory &src, std::size_t item_size) const;
// Kernel: copy owned ldofs from 'src' to ltdofs in 'dst'.
// dst[i] = src[ltdof_ldof[i]]
void ReduceLocalCopy(const ::occa::memory &src, ::occa::memory &dst,
std::size_t item_size) const;
// Kernel: assemble dofs from 'shr_buf' into to 'dst' - after recv.
// dst[shr_ltdof[i]] += shr_buf[i]
void ReduceEndAssemble(::occa::memory &dst, std::size_t item_size) const;
public:
OccaConformingProlongation(const FiniteElementSpace &ofes,
const mfem::ParFiniteElementSpace &pfes,
::occa::memory ltdof_ldof_);
virtual ~OccaConformingProlongation();
// overrides
virtual void Mult_(const Vector &x, Vector &y) const;
virtual void MultTranspose_(const Vector &x, Vector &y) const;
};
#endif // MFEM_USE_MPI
} // namespace mfem::occa
} // namespace mfem
+8 -8
View File
@@ -25,10 +25,10 @@ typedef double *Local_t @dim(NUM_VDIM, localEntries) @dimOrder(1, 0);
@kernel void GlobalToLocal(const int globalEntries,
const int localEntries,
const int * restrict offsets,
const int * restrict indices,
const Global_t restrict globalX,
Local_t restrict localX) {
@restrict const int * offsets,
@restrict const int * indices,
@restrict const Global_t globalX,
@restrict Local_t localX) {
for (int i = 0; i < globalEntries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < globalEntries) {
@@ -46,10 +46,10 @@ typedef double *Local_t @dim(NUM_VDIM, localEntries) @dimOrder(1, 0);
@kernel void LocalToGlobal(const int globalEntries,
const int localEntries,
const int * restrict offsets,
const int * restrict indices,
const Local_t restrict localX,
Global_t restrict globalX) {
@restrict const int * offsets,
@restrict const int * indices,
@restrict const Local_t localX,
@restrict Global_t globalX) {
for (int i = 0; i < globalEntries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < globalEntries) {
+15 -15
View File
@@ -36,11 +36,11 @@ typedef double* Jacobian2D_t @dim(2, 2, NUM_QUAD, numElements);
typedef double* Jacobian3D_t @dim(3, 3, NUM_QUAD, numElements);
@kernel void InitGeometryInfo1D(const int numElements,
const DofToQuadD1D_t restrict dofToQuadD,
const Local1D_t restrict nodes,
Jacobian1D_t restrict J,
Jacobian1D_t restrict invJ,
QLocal_t restrict detJ) {
@restrict const DofToQuadD1D_t dofToQuadD,
@restrict const Local1D_t nodes,
@restrict Jacobian1D_t J,
@restrict Jacobian1D_t invJ,
@restrict QLocal_t detJ) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_nodes[NUM_DOFS];
@@ -70,11 +70,11 @@ typedef double* Jacobian3D_t @dim(3, 3, NUM_QUAD, numElements);
}
@kernel void InitGeometryInfo2D(const int numElements,
const DofToQuadD2D_t restrict dofToQuadD,
const Local2D_t restrict nodes,
Jacobian2D_t restrict J,
Jacobian2D_t restrict invJ,
QLocal_t restrict detJ) {
@restrict const DofToQuadD2D_t dofToQuadD,
@restrict const Local2D_t nodes,
@restrict Jacobian2D_t J,
@restrict Jacobian2D_t invJ,
@restrict QLocal_t detJ) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_nodes[2 * NUM_DOFS] @dim(2, NUM_DOFS);
@@ -119,11 +119,11 @@ typedef double* Jacobian3D_t @dim(3, 3, NUM_QUAD, numElements);
}
@kernel void InitGeometryInfo3D(const int numElements,
const DofToQuadD3D_t restrict dofToQuadD,
const Local3D_t restrict nodes,
Jacobian3D_t restrict J,
Jacobian3D_t restrict invJ,
QLocal_t restrict detJ) {
@restrict const DofToQuadD3D_t dofToQuadD,
@restrict const Local3D_t nodes,
@restrict Jacobian3D_t J,
@restrict Jacobian3D_t invJ,
@restrict QLocal_t detJ) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_nodes[3 * NUM_DOFS] @dim(3, NUM_DOFS);
+9 -118
View File
@@ -59,135 +59,26 @@ std::map<std::string, ::occa::kernel> gridFunctionKernels;
return kernel;
}
// OccaGridFunction::OccaGridFunction() :
// Vector(),
// ofespace(NULL),
// sequence(0) {}
OccaGridFunction::OccaGridFunction(FiniteElementSpace *ofespace_)
: PArray(ofespace_->OccaVLayout()),
Array(ofespace_->OccaVLayout(), sizeof(double)),
Vector(ofespace_->OccaVLayout()),
ofespace(ofespace_),
sequence(0) {}
// OccaGridFunction::OccaGridFunction(OccaFiniteElementSpace *ofespace_,
// OccaVectorRef ref) :
// OccaVector(ref),
// ofespace(ofespace_),
// sequence(0) {}
OccaGridFunction::OccaGridFunction(const OccaGridFunction &v)
: PArray(v),
Array(v),
Vector(v),
ofespace(v.ofespace),
sequence(v.sequence) {}
OccaGridFunction& OccaGridFunction::operator = (double value)
void ToQuad(const IntegrationRule &ir, FiniteElementSpace &fespace, Vector &gf,
Vector &quadValues)
{
Fill(value);
return *this;
}
OccaGridFunction& OccaGridFunction::operator = (const Vector &v)
{
Assign<double>(v);
return *this;
}
// OccaGridFunction& OccaGridFunction::operator = (const OccaVectorRef &v)
// {
// OccaVector::operator = (v);
// return *this;
// }
OccaGridFunction& OccaGridFunction::operator = (const OccaGridFunction &v)
{
Assign<double>(v);
return *this;
}
// void OccaGridFunction::SetGridFunction(mfem::GridFunction &gf)
// {
// Vector v = *this;
// gf.MakeRef(ofespace->GetFESpace(), v, 0);
// // Make gf the owner of the data
// v.Swap(gf);
// }
void OccaGridFunction::GetTrueDofs(Vector &v)
{
const mfem::Operator *R = ofespace->GetRestrictionOperator();
if (!R)
{
v.MakeRef(*this);
}
else
{
v.Resize<double>(R->OutLayout(), NULL);
mfem::Vector mfem_v(v);
R->Mult(this->Wrap(), mfem_v);
}
}
void OccaGridFunction::SetFromTrueDofs(Vector &v)
{
const mfem::Operator *P = ofespace->GetProlongationOperator();
if (!P)
{
MakeRef(v);
}
else
{
Resize<double>(P->OutLayout(), NULL);
mfem::Vector mfem_this(*this);
P->Mult(v.Wrap(), mfem_this);
}
}
mfem::FiniteElementSpace* OccaGridFunction::GetFESpace()
{
return ofespace->GetFESpace();
}
const mfem::FiniteElementSpace* OccaGridFunction::GetFESpace() const
{
return ofespace->GetFESpace();
}
void OccaGridFunction::ToQuad(const IntegrationRule &ir, Vector &quadValues)
{
const Engine &engine = OccaLayout().OccaEngine();
const Engine &engine = fespace.OccaEngine();
::occa::device device = engine.GetDevice();
OccaDofQuadMaps &maps = OccaDofQuadMaps::Get(device, *ofespace, ir);
OccaDofQuadMaps &maps = OccaDofQuadMaps::Get(device, fespace, ir);
const int elements = ofespace->GetNE();
const int elements = fespace.GetNE();
const int numQuad = ir.GetNPoints();
quadValues.Resize<double>(*(new Layout(engine, numQuad * elements)), NULL);
quadValues.OccaResize(numQuad * elements, sizeof(double));
::occa::kernel g2qKernel = GetGridFunctionKernel(device, *ofespace, ir);
::occa::kernel g2qKernel = GetGridFunctionKernel(device, fespace, ir);
g2qKernel(elements,
maps.dofToQuad,
ofespace->GetLocalToGlobalMap(),
this->OccaMem(),
fespace.GetLocalToGlobalMap(),
gf.OccaMem(),
quadValues.OccaMem());
}
void OccaGridFunction::Distribute(const Vector &v)
{
if (ofespace->isDistributed())
{
mfem::Vector mfem_this(*this);
ofespace->GetProlongationOperator()->Mult(v.Wrap(), mfem_this);
}
else
{
*this = v;
}
}
} // namespace mfem::occa
} // namespace mfem
+11 -39
View File
@@ -22,14 +22,10 @@ namespace mfem
{
class IntegrationRule;
class GridFunction;
namespace occa
{
class OccaIntegrator;
class OccaDofQuadMaps;
// TODO: make this object part of the backend or the engine.
extern std::map<std::string, ::occa::kernel> gridFunctionKernels;
@@ -38,41 +34,17 @@ extern std::map<std::string, ::occa::kernel> gridFunctionKernels;
FiniteElementSpace &fespace,
const mfem::IntegrationRule &ir);
class OccaGridFunction : public Vector
{
protected:
FiniteElementSpace *ofespace;
long sequence;
::occa::kernel gridFuncToQuad[3];
public:
// OccaGridFunction();
OccaGridFunction(FiniteElementSpace *ofespace_);
// OccaGridFunction(FiniteElementSpace *ofespace_,
// OccaVectorRef ref);
OccaGridFunction(const OccaGridFunction &gf);
OccaGridFunction& operator = (double value);
OccaGridFunction& operator = (const Vector &v);
// OccaGridFunction& operator = (const OccaVectorRef &v);
OccaGridFunction& operator = (const OccaGridFunction &gf);
// void SetGridFunction(mfem::GridFunction &gf);
void GetTrueDofs(Vector &v);
void SetFromTrueDofs(Vector &v);
mfem::FiniteElementSpace* GetFESpace();
const mfem::FiniteElementSpace* GetFESpace() const;
void ToQuad(const mfem::IntegrationRule &ir, Vector &quadValues);
void Distribute(const Vector &v);
};
// ToQuad version without the deprecated class.
//
// FIXME: This is the action of a global B matrix, mapping L-vector to Q-vector,
// so it should be made into an operator that can be constructed by the
// FE space class. A batched version, where only a subset of the elements
// are processed should be defined as well.
//
// The abstract operator construction method in the FE space class is:
// PFiniteElementSpace::GetInterpolationOperator(...)
void ToQuad(const IntegrationRule &ir, FiniteElementSpace &ofespace, Vector &gf,
Vector &quadValues);
} // namespace mfem::occa
+3 -3
View File
@@ -11,14 +11,14 @@
#include "mfem-occa://defines.okl"
#if USING_TENSOR_OPS
# if OCCA_USING_CPU
#ifdef USING_TENSOR_OPS
# ifdef OCCA_USING_CPU
# include "mfem-occa://gridfunc/tensor/cpu.okl"
# else
# include "mfem-occa://gridfunc/tensor/gpuHighOrder.okl"
# endif
#else
# if OCCA_USING_CPU
# ifdef OCCA_USING_CPU
# include "mfem-occa://gridfunc/simplex/cpu.okl"
# else
# include "mfem-occa://gridfunc/simplex/gpuHighOrder.okl"
+8 -8
View File
@@ -13,10 +13,10 @@
//---[ 2D ]-----------------------------
@kernel void GridFuncToQuad2D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DLocalMap_t restrict l2gMap,
const double * restrict gf,
QVLocal_t restrict out) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap_t l2gMap,
@restrict const double * gf,
@restrict QVLocal_t out) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
@@ -39,10 +39,10 @@
//---[ 3D ]-----------------------------
@kernel void GridFuncToQuad3D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DLocalMap_t restrict l2gMap,
const double * restrict gf,
QVLocal_t restrict out) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap_t l2gMap,
@restrict const double * gf,
@restrict QVLocal_t out) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
@@ -13,10 +13,10 @@
//---[ 2D ]-----------------------------
@kernel void GridFuncToQuad2D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DLocalMap_t restrict l2gMap,
const double * restrict gf,
QVLocal_t restrict out) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap_t l2gMap,
@restrict const double * gf,
@restrict QVLocal_t out) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_gf[NUM_VDIM][NUM_DOFS];
@@ -47,10 +47,10 @@
//---[ 3D ]-----------------------------
@kernel void GridFuncToQuad3D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DLocalMap_t restrict l2gMap,
const double * restrict gf,
QVLocal_t restrict out) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap_t l2gMap,
@restrict const double * gf,
@restrict QVLocal_t out) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_gf[NUM_VDIM][NUM_DOFS];
+12 -12
View File
@@ -13,10 +13,10 @@
//---[ 1D ]-----------------------------
@kernel void GridFuncToQuad1D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DLocalMap1D_t restrict l2gMap,
const double * restrict gf,
QVLocal1D_t restrict out) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap1D_t l2gMap,
@restrict const double * gf,
@restrict QVLocal1D_t out) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double r_out[NUM_VDIM][NUM_QUAD_1D];
@@ -47,10 +47,10 @@
//---[ 2D ]-----------------------------
@kernel void GridFuncToQuad2D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DLocalMap2D_t restrict l2gMap,
const double * restrict gf,
QVLocal2D_t restrict out) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap2D_t l2gMap,
@restrict const double * gf,
@restrict QVLocal2D_t out) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
@@ -106,10 +106,10 @@
//---[ 3D ]-----------------------------
@kernel void GridFuncToQuad3D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DLocalMap3D_t restrict l2gMap,
const double * restrict gf,
QVLocal3D_t restrict out) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap3D_t l2gMap,
@restrict const double * gf,
@restrict QVLocal3D_t out) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double out_xyz[NUM_VDIM][NUM_QUAD_1D][NUM_QUAD_1D][NUM_QUAD_1D];
+12 -12
View File
@@ -13,10 +13,10 @@
//---[ 1D ]-----------------------------
@kernel void GridFuncToQuad1D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DLocalMap1D_t restrict l2gMap,
const double * restrict gf,
QLocal1D_t restrict out) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap1D_t l2gMap,
@restrict const double * gf,
@restrict QLocal1D_t out) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M1_ELEMENT_BATCHES; @outer) {
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@@ -54,10 +54,10 @@
//---[ 2D ]-----------------------------
@kernel void GridFuncToQuad2D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DLocalMap2D_t restrict l2gMap,
const double * restrict gf,
QLocal2D_t restrict out) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap2D_t l2gMap,
@restrict const double * gf,
@restrict QLocal2D_t out) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M2_ELEMENT_BATCH; @outer) {
// Store dof <--> quad mappings
@@ -109,10 +109,10 @@
//---[ 3D ]-----------------------------
@kernel void GridFuncToQuad3D(const int numElements,
const DofToQuad_t restrict dofToQuad,
const DLocalMap3D_t restrict l2gMap,
const double * restrict gf,
QLocal3D_t restrict out) {
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap3D_t l2gMap,
@restrict const double * gf,
@restrict QLocal3D_t out) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
// Store dof <--> quad mappings
+20 -63
View File
@@ -20,94 +20,51 @@ namespace mfem
namespace occa
{
void CreateRPOperators(Layout &v_layout, Layout &t_layout,
const mfem::SparseMatrix *R, const mfem::Operator *P,
mfem::Operator *&OccaR, mfem::Operator *&OccaP)
{
if (!P)
{
OccaR = new IdentityOperator(t_layout);
OccaP = new IdentityOperator(t_layout);
return;
}
const mfem::SparseMatrix *pmat = dynamic_cast<const mfem::SparseMatrix*>(P);
::occa::device device = v_layout.OccaEngine().GetDevice();
if (R)
{
OccaSparseMatrix *occaR =
CreateMappedSparseMatrix(v_layout, t_layout, *R);
::occa::array<int> reorderIndices = occaR->reorderIndices;
delete occaR;
OccaR = new RestrictionOperator(v_layout, t_layout, reorderIndices);
}
if (pmat)
{
const mfem::SparseMatrix *pmatT = Transpose(*pmat);
OccaSparseMatrix *occaP =
CreateMappedSparseMatrix(t_layout, v_layout, *pmat);
OccaSparseMatrix *occaPT =
CreateMappedSparseMatrix(v_layout, t_layout, *pmatT);
OccaP = new ProlongationOperator(*occaP, *occaPT);
}
else
{
OccaP = new ProlongationOperator(t_layout, v_layout, P);
}
}
RestrictionOperator::RestrictionOperator(Layout &in_layout, Layout &out_layout,
::occa::array<int> indices) :
Operator(in_layout, out_layout)
::occa::array<int> indices)
: Operator(in_layout, out_layout)
{
entries = indices.size() / 2;
trueIndices = indices;
// FIXME: paths ...
::occa::device device = in_layout.OccaEngine().GetDevice();
const std::string &okl_path = in_layout.OccaEngine().GetOklPath();
const std::string &okl_defines = in_layout.OccaEngine().GetOklDefines();
multOp = device.buildKernel(okl_path + "mappings.okl",
"ExtractSubVector",
"defines: { TILESIZE: 256 }" + okl_defines);
"defines: { TILESIZE: 256 }");
multTransposeOp = device.buildKernel(okl_path + "mappings.okl",
"SetSubVector",
"defines: { TILESIZE: 256 }" +
okl_defines);
"defines: { TILESIZE: 256 }");
}
void RestrictionOperator::Mult_(const Vector &x, Vector &y) const
{
multOp(entries, trueIndices, x.OccaMem(), y.OccaMem());
// y[i] = x[trueIndices[i]]
multOp(height, trueIndices, x.OccaMem(), y.OccaMem());
}
void RestrictionOperator::MultTranspose_(const Vector &x, Vector &y) const
{
y.Fill<double>(0.0);
multTransposeOp(entries, trueIndices, x.OccaMem(), y.OccaMem());
y.OccaFill<double>(0.0);
// y[trueIndices[i]] = x[i]
multTransposeOp(height, trueIndices, x.OccaMem(), y.OccaMem());
}
ProlongationOperator::ProlongationOperator(OccaSparseMatrix &multOp_,
OccaSparseMatrix &multTransposeOp_) :
Operator(multOp_),
pmat(NULL),
multOp(multOp_),
multTransposeOp(multTransposeOp_) {}
OccaSparseMatrix &multTransposeOp_)
: Operator(multOp_),
pmat(NULL),
multOp(multOp_),
multTransposeOp(multTransposeOp_)
{ }
ProlongationOperator::ProlongationOperator(Layout &in_layout,
Layout &out_layout,
const mfem::Operator *pmat_) :
Operator(in_layout, out_layout),
pmat(pmat_),
multOp(*this),
multTransposeOp(*this)
const mfem::Operator *pmat_)
: Operator(in_layout, out_layout),
pmat(pmat_),
multOp(*this),
multTransposeOp(*this)
{ }
void ProlongationOperator::Mult_(const Vector &x, Vector &y) const
+1 -7
View File
@@ -27,16 +27,10 @@ namespace mfem
namespace occa
{
// [MISSING] Proper destructors
void CreateRPOperators(Layout &v_layout, Layout &t_layout,
const mfem::SparseMatrix *R, const mfem::Operator *P,
mfem::Operator *&OccaR, mfem::Operator *&OccaP);
class RestrictionOperator : public Operator
{
protected:
int entries;
::occa::array<int> trueIndices;
::occa::array<int> trueIndices; // ldof = trueIndices[ltdof]
::occa::kernel multOp, multTransposeOp;
public:
+1 -2
View File
@@ -39,8 +39,7 @@ public:
const Engine &OccaEngine() const
{ return *static_cast<const Engine *>(engine.Get()); }
::occa::memory Alloc(std::size_t bytes) const
{ return OccaEngine().GetDevice().malloc(bytes); }
void OccaResize(std::size_t new_size) { size = new_size; }
virtual ~Layout() { }
+35 -13
View File
@@ -16,38 +16,60 @@
*/
@kernel void ExtractSubVector(const int entries,
const int * restrict indices,
const double * restrict in,
double * restrict out) {
@restrict const int *indices,
@restrict const double *in,
@restrict double *out) {
for (int i = 0; i < entries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < entries) {
out[i] = in[indices[i]];
out[i] = in[indices[i]]; // indices can be repeated
}
}
}
@kernel void SetSubVector(const int entries,
const int * restrict indices,
const double * restrict in,
double * restrict out) {
@restrict const int *indices,
@restrict const double *in,
@restrict double *out) {
for (int i = 0; i < entries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < entries) {
out[indices[i]] = in[i];
out[indices[i]] = in[i]; // indices CANNOT be repeated
}
}
}
@kernel void AddSubVector(const int num_unique_dst_indices,
@restrict const int *unique_dst_indices,
@restrict const int *unique_to_src_offsets,
@restrict const int *unique_to_src_indices,
@restrict const double *src,
@restrict double *dst) {
for (int i = 0; i < num_unique_dst_indices; ++i;
@tile(TILESIZE, @outer, @inner)) {
if (i < num_unique_dst_indices) {
const int dst_idx = unique_dst_indices[i];
double sum = dst[dst_idx];
const int end = unique_to_src_offsets[i+1];
for (int j = unique_to_src_offsets[i]; j != end; ++j) {
sum += src[unique_to_src_indices[j]];
}
dst[dst_idx] = sum;
}
}
}
@kernel void MapSubVector(const int entries,
const int * restrict indices,
const double * restrict in,
double * restrict out) {
@restrict const int *indices,
@restrict const double *in,
@restrict double *out) {
for (int i = 0; i < entries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < entries) {
const int fromIdx = indices[2*i + 0];
const int toIdx = indices[2*i + 1];
const int fromIdx = indices[2*i + 0]; // fromIdx indices can be repeated
const int toIdx = indices[2*i + 1]; // toIdx indices CANNOT be repeated
out[toIdx] = in[fromIdx];
}
}
+122
View File
@@ -0,0 +1,122 @@
// 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 "mfem-occa://defines.okl"
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
oper(q, e) = quadWeights[q] * COEFF * ((J11 * J22) - (J21 * J12));
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD2D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD2D_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double r_sol[NUM_DOFS];
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] = 0;
}
for (int q = 0; q < NUM_QUAD; ++q) {
double s = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
s += solIn(d, e) * quadToDof(d, q);
}
s *= oper(q, e);
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] += (s * quadToDof(d, q));
}
}
for (int d = 0; d < NUM_DOFS; ++d) {
solOut(d, e) += r_sol[d];
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD3D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD3D_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double r_sol[NUM_DOFS];
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] = 0;
}
for (int q = 0; q < NUM_QUAD; ++q) {
double s = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
s += solIn(d, e) * quadToDof(d, q);
}
s *= oper(q, e);
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] += (s * quadToDof(d, q));
}
}
for (int d = 0; d < NUM_DOFS; ++d) {
solOut(d, e) += r_sol[d];
}
}
}
}
//======================================
+129
View File
@@ -0,0 +1,129 @@
// 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 "mfem-occa://defines.okl"
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A2_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A2_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A2_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += A2_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
oper(q, e) = quadWeights[q] * COEFF * ((J11 * J22) - (J21 * J12));
}
}
}
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD2D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD2D_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_sol[NUM_QUAD];
for (int qOff = 0; qOff < M2_INNER_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += M2_INNER_BATCH) {
double s = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
s += solIn(d, e) * dofToQuad(d, q);
}
s_sol[q] = s * oper(q, e);
}
}
for (int dOff = 0; dOff < M2_INNER_BATCH; ++dOff) {
for (int d = dOff; d < NUM_DOFS; d += M2_INNER_BATCH) {
double r_sol = 0;
for (int q = 0; q < NUM_QUAD; ++q) {
r_sol += (s_sol[q] * quadToDof(d, q));
}
solOut(d, e) += r_sol;
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A3_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A3_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A3_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += A3_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD3D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD3D_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_sol[NUM_QUAD];
for (int qOff = 0; qOff < M3_INNER_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += M3_INNER_BATCH) {
double s = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
s += solIn(d, e) * dofToQuad(d, q);
}
s_sol[q] = s * oper(q, e);
}
}
for (int dOff = 0; dOff < M3_INNER_BATCH; ++dOff) {
for (int d = dOff; d < NUM_DOFS; d += M3_INNER_BATCH) {
double r_sol = 0;
for (int q = 0; q < NUM_QUAD; ++q) {
r_sol += (s_sol[q] * quadToDof(d, q));
}
solOut(d, e) += r_sol;
}
}
}
}
//======================================
+281
View File
@@ -0,0 +1,281 @@
// 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 "mfem-occa://defines.okl"
//---[ 1D ]-----------------------------
@kernel void Assemble1D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian1D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_1D; ++q; @inner) {
const double detJ = J(q, e);
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
@kernel void MultAdd1D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal1D_t oper,
@restrict const DLocal1D_t solIn,
@restrict DLocal1D_t solOut) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double sol_x[NUM_QUAD_1D];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] = 0;
}
// sol_x{qx} = dofToQuad{qx,dx} * sol{dx}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] += s * dofToQuad(qx, dx);
}
}
// sol_x{q} *= oper{q}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] *= oper(qx, e);
}
// sol{dx} = quadToDof{dx,qx} * sol_x{qx}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(dx, e) += sol_x[qx] * quadToDof(dx, qx);
}
}
}
}
}
//======================================
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_2D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
const double detJ = ((J11 * J22) - (J21 * J12));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal2D_t oper,
@restrict const DLocal2D_t solIn,
@restrict DLocal2D_t solOut) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double sol_xy[NUM_QUAD_1D][NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[qy][qx] = 0;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double sol_x[NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
sol_x[qy] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, dy, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] += dofToQuad(qx, dx) * s;
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double d2q = dofToQuad(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[qy][qx] += d2q * sol_x[qx];
}
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[qy][qx] *= oper(qx, qy, e);
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double sol_x[NUM_DOFS_1D];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[dx] = 0;
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double s = sol_xy[qy][qx];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[dx] += quadToDof(dx, qx) * s;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double q2d = quadToDof(dy, qy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(dx, dy, e) += q2d * sol_x[dx];
}
}
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_3D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal3D_t oper,
@restrict const DLocal3D_t solIn,
@restrict DLocal3D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double sol_xyz[NUM_QUAD_1D][NUM_QUAD_1D][NUM_QUAD_1D];
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xyz[qz][qy][qx] = 0;
}
}
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
double sol_xy[NUM_QUAD_1D][NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[qy][qx] = 0;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double sol_x[NUM_QUAD_1D];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, dy, dz, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] += dofToQuad(qx, dx) * s;
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double wy = dofToQuad(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[qy][qx] += wy * sol_x[qx];
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
const double wz = dofToQuad(qz, dz);
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xyz[qz][qy][qx] += wz * sol_xy[qy][qx];
}
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xyz[qz][qy][qx] *= oper(qx, qy, qz, e);
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
double sol_xy[NUM_DOFS_1D][NUM_DOFS_1D];
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_xy[dy][dx] = 0;
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double sol_x[NUM_DOFS_1D];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[dx] = 0;
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double s = sol_xyz[qz][qy][qx];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[dx] += quadToDof(dx, qx) * s;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double wy = quadToDof(dy, qy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_xy[dy][dx] += wy * sol_x[dx];
}
}
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double wz = quadToDof(dz, qz);
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(dx, dy, dz, e) += wz * sol_xy[dy][dx];
}
}
}
}
}
}
}
//======================================
+341
View File
@@ -0,0 +1,341 @@
// 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 "mfem-occa://defines.okl"
//---[ 1D ]-----------------------------
@kernel void Assemble1D(const int numElements,
const double *quadWeights,
const Jacobian1D_t J,
COEFF_ARGS
QLocal_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A1_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A1_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int q = 0; q < NUM_QUAD_1D; ++q; @inner) {
oper(q, e) = quadWeights[q] * COEFF * J(q, e);
}
}
}
}
}
@kernel void MultAdd1D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal1D_t oper,
@restrict const DLocal1D_t solIn,
@restrict DLocal1D_t solOut) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M1_ELEMENT_BATCHES; @outer) {
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_quadToDof[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
@exclusive double r_sol[NUM_QUAD_1D];
for (int el = 0; el < M1_INNER_ELEMENT_BATCH; ++el; @inner) {
for (int i = el; i < NUM_QUAD_DOFS_1D; i += M1_INNER_ELEMENT_BATCH) {
s_dofToQuad[i] = dofToQuad[i];
s_quadToDof[i] = quadToDof[i];
}
}
for (int b = 0; b < M1_OUTER_ELEMENT_BATCH; ++b) {
for (int el = 0; el < M1_INNER_ELEMENT_BATCH; ++el; @inner) {
const int e = eOff + b*M1_INNER_ELEMENT_BATCH + el;
if (e < numElements) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
r_sol[qx] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
r_sol[qx] += s * s_dofToQuad(qx, dx);
}
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
r_sol[qx] *= oper(qx, e);
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
double s = 0;
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
s += r_sol[qx] * s_quadToDof(dx, qx);
}
solOut(dx, e) += s;
}
}
}
}
}
}
//======================================
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
const double *quadWeights,
const Jacobian2D_t J,
COEFF_ARGS
QLocal_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A2_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A2_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A2_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD_2D; q += A2_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
oper(q, e) = quadWeights[q] * COEFF * ((J11 * J22) - (J21 * J12));
}
}
}
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal2D_t oper,
@restrict const DLocal2D_t solIn,
@restrict DLocal2D_t solOut) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M2_ELEMENT_BATCH; @outer) {
// Store dof <--> quad mappings
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_quadToDof[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
// Store xy planes in @shared memory
@shared double s_xy[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
@shared double s_xy2[NUM_QUAD_2D] @dim(NUM_QUAD_1D, NUM_QUAD_1D);
@exclusive double r_x[NUM_MAX_1D];
for (int x = 0; x < NUM_MAX_1D; ++x; @inner) {
for (int id = x; id < NUM_QUAD_DOFS_1D; id += NUM_MAX_1D) {
s_dofToQuad[id] = dofToQuad[id];
s_quadToDof[id] = quadToDof[id];
}
}
for (int e = eOff; e < (eOff + M2_ELEMENT_BATCH); ++e) {
if (e < numElements) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if (dx < NUM_DOFS_1D) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
s_xy(dx, qy) = 0;
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
r_x[dy] = solIn(dx, dy, e);
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double xy = 0;
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
xy += r_x[dy] * s_dofToQuad(qy, dy);
}
s_xy(dx, qy) = xy;
}
}
}
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
if (qy < NUM_QUAD_1D) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
double s = 0;
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
s += s_xy(dx, qy) * s_dofToQuad(qx, dx);
}
s_xy2(qx, qy) = s * oper(qx, qy, e);
}
}
}
for (int qx = 0; qx < NUM_MAX_1D; ++qx; @inner) {
if (qx < NUM_QUAD_1D) {
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
s_xy(dy, qx) = 0;
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
r_x[qy] = s_xy2(qx, qy);
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double s = 0;
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
s += r_x[qy] * s_quadToDof(dy, qy);
}
s_xy(dy, qx) = s;
}
}
}
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if (dx < NUM_DOFS_1D) {
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double s = 0;
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
s += (s_xy(dy, qx) * s_quadToDof(dx, qx));
}
solOut(dx, dy, e) += s;
}
}
}
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
const double *quadWeights,
const Jacobian3D_t J,
COEFF_ARGS
QLocal_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A3_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A3_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A3_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD_3D; q += A3_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal3D_t oper,
@restrict const DLocal3D_t solIn,
@restrict DLocal3D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
// Store dof <--> quad mappings
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_quadToDof[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
// Store xy planes in @shared memory
@shared double s_xy[NUM_MAX_2D] @dim(NUM_MAX_1D, NUM_MAX_1D);
// Store z axis as registers
@exclusive double r_z[NUM_QUAD_1D];
@exclusive double r_z2[NUM_DOFS_1D];
for (int y = 0; y < NUM_MAX_1D; ++y; @inner) {
for (int x = 0; x < NUM_MAX_1D; ++x; @inner) {
const int id = (y * NUM_MAX_1D) + x;
// Fetch Q <--> D maps
if (id < NUM_QUAD_DOFS_1D) {
s_dofToQuad[id] = dofToQuad[id];
s_quadToDof[id] = quadToDof[id];
}
// Initialize our Z axis
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
r_z[qz] = 0;
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
r_z2[dz] = 0;
}
}
}
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double s = solIn(dx, dy, dz, e);
// Calculate D -> Q in the Z axis
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
r_z[qz] += s * s_dofToQuad(qz, dz);
}
}
}
}
}
// For each xy plane
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
// Fill xy plane at given z position
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
s_xy(dx, dy) = r_z[qz];
}
}
}
// Calculate Dxyz, xDyz, xyDz in plane
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
for (int qx = 0; qx < NUM_MAX_1D; ++qx; @inner) {
if ((qx < NUM_QUAD_1D) && (qy < NUM_QUAD_1D)) {
double s = 0;
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double wy = s_dofToQuad(qy, dy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double wx = s_dofToQuad(qx, dx);
s += wx * wy * s_xy(dx, dy);
}
}
s *= oper(qx, qy, qz, e);
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double wz = s_quadToDof(dz, qz);
r_z2[dz] += wz * s;
}
}
}
}
@barrier("s_xy_sync_1");
}
// Iterate over xy planes to compute solution
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
// Place xy plane in @shared memory
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
for (int qx = 0; qx < NUM_MAX_1D; ++qx; @inner) {
if ((qx < NUM_QUAD_1D) && (qy < NUM_QUAD_1D)) {
s_xy(qx, qy) = r_z2[dz];
}
}
}
// Finalize solution in xy plane
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
double solZ = 0;
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double wy = s_quadToDof(dy, qy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double wx = s_quadToDof(dx, qx);
solZ += wx * wy * s_xy(qx, qy);
}
}
solOut(dx, dy, dz, e) += solZ;
}
}
}
@barrier("s_xy_sync_2");
}
}
}
//======================================
+15 -8
View File
@@ -73,15 +73,21 @@ void OccaConstrainedOperator::Setup(::occa::device device_,
own_A = own_A_;
constraintIndices = constraintList_.Size();
constraintList = constraintList_.Get_PArray()->As<Array>().OccaMem();
if (constraintList_.Size() > 0)
{
constraintList = constraintList_.Get_PArray()->As<Array>().OccaMem();
}
else
{
// constraintList is not used
}
}
void OccaConstrainedOperator::EliminateRHS(const Vector &x, Vector &b) const
{
const std::string &okl_defines = InLayout_().OccaEngine().GetOklDefines();
::occa::kernel mapDofs = mapDofBuilder.build(device, okl_defines);
::occa::kernel mapDofs = mapDofBuilder.build(device);
w.Fill<double>(0.0);
w.OccaFill(0.0);
if (constraintIndices)
{
@@ -107,11 +113,12 @@ void OccaConstrainedOperator::Mult_(const Vector &x, Vector &y) const
return;
}
const std::string &okl_defines = InLayout_().OccaEngine().GetOklDefines();
::occa::kernel mapDofs = mapDofBuilder.build(device, okl_defines);
::occa::kernel clearDofs = clearDofBuilder.build(device, okl_defines);
::occa::kernel mapDofs = mapDofBuilder.build(device);
::occa::kernel clearDofs = clearDofBuilder.build(device);
z.Assign<double>(x); // z = x
// z.OccaAssign(x); // z = x
// Is Axpy faster than DtoD copy on Volta?
z.Axpby(1.0, x, 0.0, x);
clearDofs(constraintIndices, z.OccaMem(), constraintList);
+2 -4
View File
@@ -37,11 +37,9 @@ public:
Operator(Layout &in_layout, Layout &out_layout)
: mfem::Operator(in_layout, out_layout) { }
Layout &InLayout_() const
{ return *static_cast<Layout*>(in_layout.Get()); }
Layout &InLayout_() const { return in_layout->As<Layout>(); }
Layout &OutLayout_() const
{ return *static_cast<Layout*>(out_layout.Get()); }
Layout &OutLayout_() const { return out_layout->As<Layout>(); }
virtual void Mult_(const Vector &x, Vector &y) const = 0;
+11 -11
View File
@@ -16,11 +16,11 @@
*/
@kernel void Mult(const int entries,
const int * restrict offsets,
const int * restrict indices,
const double * restrict weights,
const double * restrict in,
double * restrict out) {
@restrict const int *offsets,
@restrict const int *indices,
@restrict const double *weights,
@restrict const double *in,
@restrict double *out) {
for (int i = 0; i < entries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < entries) {
@@ -36,12 +36,12 @@
}
@kernel void MappedMult(const int entries,
const int * restrict offsets,
const int * restrict indices,
const double * restrict weights,
const int * restrict outIndices,
const double * restrict in,
double * restrict out) {
@restrict const int *offsets,
@restrict const int *indices,
@restrict const double *weights,
@restrict const int *outIndices,
@restrict const double *in,
@restrict double *out) {
for (int i = 0; i < entries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < entries) {
+14 -41
View File
@@ -22,54 +22,26 @@ namespace occa
OccaSparseMatrix::OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
const mfem::SparseMatrix &m,
const ::occa::properties &props) :
Operator(in_layout, out_layout)
const ::occa::properties &props)
: Operator(in_layout, out_layout)
{
Setup(in_layout.OccaEngine().GetDevice(), m, props);
}
OccaSparseMatrix::OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
const mfem::SparseMatrix &m,
::occa::array<int> reorderIndices_,
::occa::array<int> mappedIndices_,
const ::occa::properties &props) :
Operator(in_layout, out_layout)
{
Setup(in_layout.OccaEngine().GetDevice(), m,
reorderIndices, mappedIndices_, props);
}
OccaSparseMatrix::OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
::occa::array<int> offsets_,
::occa::array<int> indices_,
::occa::array<double> weights_,
const ::occa::properties &props) :
Operator(in_layout, out_layout),
offsets(offsets_),
indices(indices_),
weights(weights_)
{
SetupKernel(in_layout.OccaEngine().GetDevice(), props);
}
OccaSparseMatrix::OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
::occa::array<int> offsets_,
::occa::array<int> indices_,
::occa::array<double> weights_,
::occa::array<int> reorderIndices_,
::occa::array<int> mappedIndices_,
const ::occa::properties &props) :
Operator(in_layout, out_layout),
offsets(offsets_),
indices(indices_),
weights(weights_),
reorderIndices(reorderIndices_),
mappedIndices(mappedIndices_)
const ::occa::properties &props)
: Operator(in_layout, out_layout),
offsets(offsets_),
indices(indices_),
weights(weights_),
reorderIndices(reorderIndices_),
mappedIndices(mappedIndices_)
{
SetupKernel(in_layout.OccaEngine().GetDevice(), props);
}
@@ -84,6 +56,9 @@ void OccaSparseMatrix::Setup(::occa::device device, const SparseMatrix &m,
::occa::array<int> mappedIndices_,
const ::occa::properties &props)
{
MFEM_ASSERT(m.Finalized(), "");
MFEM_ASSERT(m.Height() == height, "");
MFEM_ASSERT(m.Width() == width, "");
const int nnz = m.GetI()[height];
offsets.allocate(device,
@@ -106,7 +81,6 @@ void OccaSparseMatrix::Setup(::occa::device device, const SparseMatrix &m,
void OccaSparseMatrix::SetupKernel(::occa::device device,
const ::occa::properties &props)
{
const bool hasOutIndices = mappedIndices.isInitialized();
const ::occa::properties defaultProps("defines: {"
@@ -114,14 +88,13 @@ void OccaSparseMatrix::SetupKernel(::occa::device device,
"}");
const std::string &okl_path = InLayout_().OccaEngine().GetOklPath();
const std::string &okl_defines = InLayout_().OccaEngine().GetOklDefines();
mapKernel = device.buildKernel(okl_path + "mappings.okl",
"MapSubVector",
defaultProps + props + okl_defines);
defaultProps + props);
multKernel = device.buildKernel(okl_path + "sparse.okl",
hasOutIndices ? "MappedMult" : "Mult",
defaultProps + props + okl_defines);
defaultProps + props);
}
void OccaSparseMatrix::Mult_(const Vector &x, Vector &y) const
+23 -29
View File
@@ -30,40 +30,12 @@ namespace occa
/// TODO: doxygen
class OccaSparseMatrix : public Operator
{
public:
protected:
::occa::array<int> offsets, indices;
::occa::array<double> weights;
::occa::array<int> reorderIndices, mappedIndices;
::occa::kernel mapKernel, multKernel;
/// Construct an empty OccaSparseMatrix.
OccaSparseMatrix(const Operator &orig)
: Operator(orig) { }
OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
const mfem::SparseMatrix &m,
const ::occa::properties &props = ::occa::properties());
OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
const mfem::SparseMatrix &m,
::occa::array<int> reorderIndices_,
::occa::array<int> mappedIndices_,
const ::occa::properties &props = ::occa::properties());
OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
::occa::array<int> offsets_,
::occa::array<int> indices_,
::occa::array<double> weights_,
const ::occa::properties &props = ::occa::properties());
OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
::occa::array<int> offsets_,
::occa::array<int> indices_,
::occa::array<double> weights_,
::occa::array<int> reorderIndices_,
::occa::array<int> mappedIndices_,
const ::occa::properties &props = ::occa::properties());
void Setup(::occa::device device, const mfem::SparseMatrix &m,
const ::occa::properties &props);
@@ -75,6 +47,28 @@ public:
void SetupKernel(::occa::device device,
const ::occa::properties &props);
public:
/// Construct an empty OccaSparseMatrix.
OccaSparseMatrix(const Operator &orig)
: Operator(orig) { }
// Implicitly defined copy constructor.
OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
const mfem::SparseMatrix &m,
const ::occa::properties &props = ::occa::properties());
OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
::occa::array<int> offsets_,
::occa::array<int> indices_,
::occa::array<double> weights_,
::occa::array<int> reorderIndices_,
::occa::array<int> mappedIndices_,
const ::occa::properties &props = ::occa::properties());
const ::occa::array<int> &GetReorderIndices() const
{ return reorderIndices; }
// override
virtual void Mult_(const Vector &x, Vector &y) const;
};
+1 -1
View File
@@ -13,7 +13,7 @@ typedef double* Local_t @dim(numDofs, numElements);
@kernel void InitLocalVector(const int numElements,
const int numDofs,
Local_t restrict sol) {
@restrict Local_t sol) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int d = 0; d < numDofs; ++d; @inner) {
sol(d, e) = 0;
+10 -18
View File
@@ -45,17 +45,16 @@ void Vector::DoDotProduct(const PVector &x, void *result,
MFEM_ASSERT(result_type_id == ScalarId<double>::value, "");
double *res = (double *)result;
MFEM_ASSERT(dynamic_cast<const Vector *>(&x) != NULL, "invalid Vector type");
const Vector *xp = static_cast<const Vector *>(&x);
MFEM_ASSERT(this->Size() == xp->Size(), "");
*res = ::occa::linalg::dot<double, double, double>(this->slice, xp->slice);
const Vector &xp = x.As<Vector>();
MFEM_ASSERT(this->Size() == xp.Size(), "");
*res = ::occa::linalg::dot<double, double, double>(this->slice, xp.slice);
#ifdef MFEM_USE_MPI
double local_dot = *res;
if (IsParallel())
{
MPI_Allreduce(&local_dot, res, 1, MPI_DOUBLE, MPI_SUM,
OccaLayout().OccaEngine().GetComm());
OccaEngine().GetComm());
}
#endif
}
@@ -64,8 +63,6 @@ void Vector::DoAxpby(const void *a, const PVector &x,
const void *b, const PVector &y,
int ab_type_id)
{
const std::string &okl_defines = OccaLayout().OccaEngine().GetOklDefines();
//
// TODO: move all kernel builders to class mfem::occa::Backend
//
@@ -124,7 +121,7 @@ void Vector::DoAxpby(const void *a, const PVector &x,
{
if (db == 0.0)
{
OccaFill(&da);
OccaFill(da);
}
else
{
@@ -136,8 +133,7 @@ void Vector::DoAxpby(const void *a, const PVector &x,
else
{
// *this = db * y
::occa::kernel kernel = axpby1_builder.build(slice.getDevice(),
okl_defines);
::occa::kernel kernel = axpby1_builder.build(slice.getDevice());
kernel((int)Size(), db, slice, yp->slice);
}
}
@@ -154,8 +150,7 @@ void Vector::DoAxpby(const void *a, const PVector &x,
else
{
// *this = da * x
::occa::kernel kernel = axpby1_builder.build(slice.getDevice(),
okl_defines);
::occa::kernel kernel = axpby1_builder.build(slice.getDevice());
kernel((int)Size(), da, slice, xp->slice);
}
}
@@ -165,22 +160,19 @@ void Vector::DoAxpby(const void *a, const PVector &x,
if (this->slice == xp->slice)
{
// *this = da * (*this) + db * y
::occa::kernel kernel = axpby2_builder.build(slice.getDevice(),
okl_defines);
::occa::kernel kernel = axpby2_builder.build(slice.getDevice());
kernel((int)Size(), da, db, slice, yp->slice);
}
else if (this->slice == yp->slice)
{
// *this = da * x + db * (*this)
::occa::kernel kernel = axpby2_builder.build(slice.getDevice(),
okl_defines);
::occa::kernel kernel = axpby2_builder.build(slice.getDevice());
kernel((int)Size(), db, da, slice, xp->slice);
}
else
{
// *this = da * x + db * y
::occa::kernel kernel = axpby3_builder.build(slice.getDevice(),
okl_defines);
::occa::kernel kernel = axpby3_builder.build(slice.getDevice());
kernel((int)Size(), da, db, slice, xp->slice, yp->slice);
}
}
+10 -1
View File
@@ -25,7 +25,12 @@ namespace mfem
namespace occa
{
// FIXME: Once XL fixes this code quirk we can remove this #ifdef switch
#ifdef __ibmxl__
class Vector : public Array, public PVector
#else
class Vector : virtual public Array, public PVector
#endif
{
protected:
//
@@ -52,6 +57,10 @@ protected:
// End: Virtual interface
public:
Vector(const Engine &e)
: PArray(*(new Layout(e, 0))), Array(e), PVector(*layout)
{ }
Vector(Layout &lt)
: PArray(lt), Array(lt, sizeof(double)), PVector(lt)
{ }
@@ -61,7 +70,7 @@ public:
const mfem::Vector Wrap() const;
#if defined(MFEM_USE_MPI)
bool IsParallel() const { return (OccaLayout().OccaEngine().GetComm() != MPI_COMM_NULL); }
bool IsParallel() const { return (OccaEngine().GetComm() != MPI_COMM_NULL); }
#endif
};
+321
View File
@@ -0,0 +1,321 @@
// 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 "mfem-occa://defines.okl"
//---[ 1D ]-----------------------------
@kernel void Assemble1D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian1D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_1D; ++q; @inner) {
oper(q, e) = quadWeights[q] * COEFF * J(q, e);
}
}
}
@kernel void MultAdd1D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DVLocal1D_t solIn,
@restrict DVLocal1D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double sol_x[1][NUM_QUAD_1D];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[0][qx] = 0;
}
// sol_x{qx} = dofToQuad{qx,dx} * sol{dx}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[0][qx] += dofToQuad(qx, dx) * solIn(0, dx, e);
}
}
// sol_x{q} *= oper{q}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[0][qx] *= oper(qx, e);
}
// sol{dx} = quadToDof{dx,qx} * sol_x{qx}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(0, dx, e) += sol_x[0][qx] * quadToDof(dx, qx);
}
}
}
}
}
//======================================
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_2D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
oper(q, e) = quadWeights[q] * COEFF * ((J11 * J22) - (J21 * J12));
}
} // e
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DVLocal2D_t solIn,
@restrict DVLocal2D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy=0; dummy<1; ++dummy; @inner) {
double sol_xy[2][NUM_QUAD_1D][NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[0][qx][qy] = 0;
sol_xy[1][qx][qy] = 0;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double sol_x[2][NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
sol_x[0][qy] = 0;
sol_x[1][qy] = 0;
}
// sol_x{vd, dx, qy} = dofToQuad{qy, dy} * sol{vd, dx, dy}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
sol_x[0][qy] += dofToQuad(qy, dx) * solIn(0, dx, dy, e);
sol_x[1][qy] += dofToQuad(qy, dx) * solIn(1, dx, dy, e);
}
}
// sol_xy{qx, qy} = dofToQuad{qx, dx} * sol_x{dx, qy}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double d2q = dofToQuad(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[0][qx][qy] += d2q * sol_x[0][qx];
sol_xy[1][qx][qy] += d2q * sol_x[1][qx];
}
}
} // dy
// sol_xy{qx, qy} = sol_xy{q} *= oper{q, e}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const int q = QUAD_2D_ID(qx, qy);
sol_xy[0][qx][qy] *= oper(q, e);
sol_xy[1][qx][qy] *= oper(q, e);
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double sol_x[2][NUM_DOFS_1D];
for (int dx = 0; dx < NUM_QUAD_1D; ++dx) {
sol_x[0][dx] = 0;
sol_x[1][dx] = 0;
}
// sol_x{qx, dy} = quadToDof{dy, qy} * sol_xy{qx, qy}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[0][dx] += quadToDof(dx, qx) * sol_xy[0][qx][qy];
sol_x[1][dx] += quadToDof(dx, qx) * sol_xy[1][qx][qy];
}
}
// sol{dx, dy, e} = quadToDof{dx, qx} * sol_x{qx, dy}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double q2d = quadToDof(dy, qy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(0, dx, dy, e) += q2d * sol_x[0][dx];
solOut(1, dx, dy, e) += q2d * sol_x[1][dx];
}
}
}
} // dummy
} // e
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_3D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DVLocal3D_t solIn,
@restrict DVLocal3D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double sol_xyz[3][NUM_QUAD_1D][NUM_QUAD_1D][NUM_QUAD_1D];
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xyz[0][qz][qy][qx] = 0;
sol_xyz[1][qz][qy][qx] = 0;
sol_xyz[2][qz][qy][qx] = 0;
}
}
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
double sol_xy[3][NUM_QUAD_1D][NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[0][qy][qx] = 0;
sol_xy[1][qy][qx] = 0;
sol_xy[2][qy][qx] = 0;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double sol_x[3][NUM_QUAD_1D];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[0][qx] = 0;
sol_x[1][qx] = 0;
sol_x[2][qx] = 0;
}
// sol_x{qx} = dofToQuad{qx, dx} * sol{dx, dy, dz, e}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[0][qx] += dofToQuad(qx, dx) * solIn(0, dx, dy, dz, e);
sol_x[1][qx] += dofToQuad(qx, dx) * solIn(1, dx, dy, dz, e);
sol_x[2][qx] += dofToQuad(qx, dx) * solIn(2, dx, dy, dz, e);
}
}
// sol_xy{qx, qy} = dofToQuad{qy, dy} * sol_x{dx}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double wy = dofToQuad(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[0][qy][qx] += wy * sol_x[0][qx];
sol_xy[1][qy][qx] += wy * sol_x[1][qx];
sol_xy[2][qy][qx] += wy * sol_x[2][qx];
}
}
} // dy
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
const double wz = dofToQuad(qz, dz);
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xyz[0][qz][qy][qx] += wz * sol_xy[0][qy][qx];
sol_xyz[1][qz][qy][qx] += wz * sol_xy[1][qy][qx];
sol_xyz[2][qz][qy][qx] += wz * sol_xy[2][qy][qx];
}
}
}
} // dz
// sol_xyz{qz, qy, qx} *= oper{q, e}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const int q = QUAD_3D_ID(qx, qy, qz);
sol_xyz[0][qz][qy][qx] *= oper(q, e);
sol_xyz[1][qz][qy][qx] *= oper(q, e);
sol_xyz[2][qz][qy][qx] *= oper(q, e);
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
double sol_xy[3][NUM_DOFS_1D][NUM_DOFS_1D];
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_xy[0][dy][dx] = 0;
sol_xy[1][dy][dx] = 0;
sol_xy[2][dy][dx] = 0;
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double sol_x[3][NUM_DOFS_1D];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[0][dx] = 0;
sol_x[1][dx] = 0;
sol_x[2][dx] = 0;
}
// sol_x{dx} = quadToDof{dx, qx} * sol_xyz{qz, qy, qx}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[0][dx] += quadToDof(dx, qx) * sol_xyz[0][qz][qy][qx];
sol_x[1][dx] += quadToDof(dx, qx) * sol_xyz[1][qz][qy][qx];
sol_x[2][dx] += quadToDof(dx, qx) * sol_xyz[2][qz][qy][qx];
}
}
// sol_xy{dy, dx} = quadToDof{dy, qy} * sol_x{dx}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double wy = quadToDof(dy, qy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_xy[0][dy][dx] += wy * sol_x[0][dx];
sol_xy[1][dy][dx] += wy * sol_x[1][dx];
sol_xy[2][dy][dx] += wy * sol_x[2][dx];
}
}
} // qy
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double wz = quadToDof(dz, qz);
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(0, dx, dy, dz, e) += wz * sol_xy[0][dy][dx];
solOut(1, dx, dy, dz, e) += wz * sol_xy[1][dy][dx];
solOut(2, dx, dy, dz, e) += wz * sol_xy[2][dy][dx];
}
}
}
} // qz
} // dummy
} // e
}
//======================================
+1
View File
@@ -39,6 +39,7 @@ set(MFEM_USE_PETSC @MFEM_USE_PETSC@)
set(MFEM_USE_MPFR @MFEM_USE_MPFR@)
set(MFEM_USE_SIDRE @MFEM_USE_SIDRE@)
set(MFEM_USE_CONDUIT @MFEM_USE_CONDUIT@)
set(MFEM_USE_PUMI @MFEM_USE_PUMI@)
set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
set(MFEM_CXX_FLAGS "@CMAKE_CXX_FLAGS@")
+7
View File
@@ -98,6 +98,9 @@
// Enable MFEM functionality based on Conduit
#cmakedefine MFEM_USE_CONDUIT
// Enable MFEM functionality based on the PUMI library
#cmakedefine MFEM_USE_PUMI
// Which library functions to use in class StopWatch for measuring time.
// For a list of the available options, see INSTALL.
// If not defined, an option is selected automatically.
@@ -113,4 +116,8 @@
// Version of HYPRE used for building MFEM.
#cmakedefine MFEM_HYPRE_VERSION @MFEM_HYPRE_VERSION@
// Macro defined when PUMI is built with support for the Simmetrix SimModSuite
// library.
#cmakedefine MFEM_USE_SIMMETRIX
#endif // MFEM_CONFIG_HEADER
+5 -2
View File
@@ -36,12 +36,15 @@
#ifdef MFEM_USE_PETSC
#error Building with PETSc (MFEM_USE_PETSC=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
#ifdef MFEM_USE_PUMI
#error Building with PUMI (MFEM_USE_PUMI=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
#endif // MFEM_USE_MPI not defined
// Macro that returns its first arg when MFEM_USE_BACKENDS is defined, and its
// second arg if it is not defined.
#ifdef MFEM_USE_BACKENDS
#define MFEM_IF_BACKENDS(x,y) (x)
#define MFEM_IF_BACKENDS(x,y) x
#else
#define MFEM_IF_BACKENDS(x,y) (y)
#define MFEM_IF_BACKENDS(x,y) y
#endif
+7
View File
@@ -115,6 +115,9 @@
// Enable functionality based on the MPFR library.
// #define MFEM_USE_MPFR
// Enable MFEM functionality based on the PUMI library
// #define MFEM_USE_PUMI
// Enable the use of MFEM backends.
// #define MFEM_USE_BACKENDS
@@ -130,4 +133,8 @@
// Version of HYPRE used for building MFEM.
// #define MFEM_HYPRE_VERSION @MFEM_HYPRE_VERSION@
// Macro defined when PUMI is built with support for the Simmetrix SimModSuite
// library.
// #define MFEM_USE_SIMMETRIX
#endif // MFEM_CONFIG_HEADER
+1
View File
@@ -39,6 +39,7 @@ MFEM_USE_PETSC = @MFEM_USE_PETSC@
MFEM_USE_MPFR = @MFEM_USE_MPFR@
MFEM_USE_SIDRE = @MFEM_USE_SIDRE@
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
MFEM_USE_PUMI = @MFEM_USE_PUMI@
MFEM_USE_BACKENDS = @MFEM_USE_BACKENDS@
MFEM_USE_OCCA = @MFEM_USE_OCCA@
+4
View File
@@ -40,6 +40,7 @@ option(MFEM_USE_PETSC "Enable PETSc support." OFF)
option(MFEM_USE_MPFR "Enable MPFR usage." OFF)
option(MFEM_USE_SIDRE "Enable Axom/Sidre usage" OFF)
option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF)
option(MFEM_USE_PUMI "Enable PUMI" OFF)
# Allow a user to disable testing, examples, and/or miniapps at CONFIGURE TIME
# if they don't want/need them (e.g. if MFEM is "just a dependency" and all they
@@ -145,6 +146,9 @@ set(AXOM_DIR "${MFEM_DIR}/../axom" CACHE PATH "Path to the Axom library.")
set(Axom_REQUIRED_PACKAGES "Conduit/relay" CACHE STRING
"Additional packages required by Axom.")
set(PUMI_DIR "${MFEM_DIR}/../pumi-2.1.0" CACHE STRING
"Directory where PUMI is installed")
set(BLAS_INCLUDE_DIRS "" CACHE STRING "Path to BLAS headers.")
set(BLAS_LIBRARIES "" CACHE STRING "The BLAS library.")
set(LAPACK_INCLUDE_DIRS "" CACHE STRING "Path to LAPACK headers.")
+8
View File
@@ -109,6 +109,7 @@ MFEM_USE_PETSC = NO
MFEM_USE_MPFR = NO
MFEM_USE_SIDRE = NO
MFEM_USE_CONDUIT = NO
MFEM_USE_PUMI = NO
# Compile and link options for zlib.
ZLIB_DIR =
@@ -274,6 +275,13 @@ SIDRE_LIB = \
-Wl,-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib \
-lsidre -lslic -laxom_utils -lconduit -lconduit_relay -lhdf5 $(ZLIB_LIB) -ldl
# PUMI
# Note that PUMI_DIR is needed -- it is used to check for gmi_sim.h
PUMI_DIR = @MFEM_DIR@/../pumi-2.1.0
PUMI_OPT = -I$(PUMI_DIR)/include
PUMI_LIB = -L$(PUMI_DIR)/lib -lpumi -lcrv -lma -lmds -lapf -lpcu -lgmi -lparma\
-llion -lmth -lapf_zoltan -lspr
OCCA_DIR = @MFEM_DIR@/../occa
OCCA_OPT = -I$(OCCA_DIR)/include
OCCA_LIB = -Wl,-rpath,$(OCCA_DIR)/lib -L$(OCCA_DIR)/lib -locca
+11 -2
View File
@@ -38,6 +38,9 @@ all: header config-mk
MPI = $(MFEM_USE_MPI:NO=)
GHV = get_hypre_version
GHV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(HYPRE_OPT))
SMX = $(if $(MFEM_USE_PUMI:NO=),MFEM_USE_SIMMETRIX)
SMX_PATH = $(PUMI_DIR)/include/gmi_sim.h
SMX_FILE = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(SMX_PATH))
$(GHV): $(SRC)$(GHV).cpp
$(call mfem-info, Determining HYPRE version ...)
@@ -52,10 +55,16 @@ get-hypre-version: $(GHV).out
$(info HYPRE version: $(MFEM_HYPRE_VERSION)),\
$(error Unable to determine HYPRE version))
header: $(if $(MPI),get-hypre-version,)
check-smx:
$(call mfem-info, Checking for Simmetrix header [$(SMX_FILE)] ...)
$(eval MFEM_USE_SIMMETRIX:=$(if $(wildcard $(SMX_FILE)),YES,NO))
$(call mfem-info, MFEM_USE_SIMMETRIX = $(MFEM_USE_SIMMETRIX))
$(eval export MFEM_USE_SIMMETRIX)
header: $(if $(MPI),get-hypre-version,) $(if $(SMX),check-smx)
$(call mfem-info, Writing $(CONFIG_HPP) ...)
@set -- && \
for def in $${MFEM_DEFINES} $(if $(MPI),MFEM_HYPRE_VERSION,); do \
for def in $${MFEM_DEFINES} $(if $(MPI),MFEM_HYPRE_VERSION) $(SMX); do \
eval var=\$$$$def && \
if [ "NO" != "$${var}" ]; then \
set -- "$$@" -e "s|// \(#define $${def} \)|\1|" && \
+2
View File
@@ -14,11 +14,13 @@
# Colors used below:
# green '\033[0;32m'
# red '\033[0;31m'
# yellow '\033[0;33m'
# no color '\033[0m'
COLOR_PRINT = if [ -t 1 ]; then \
printf $(1)$(2)'\033[0m'$(3); else printf $(2)$(3); fi
PRINT_OK = $(call COLOR_PRINT,'\033[0;32m',OK," ($$1 $$2)\n")
PRINT_FAILED = $(call COLOR_PRINT,'\033[0;31m',FAILED," ($$1 $$2)\n")
PRINT_SKIP = $(call COLOR_PRINT,'\033[0;33m',SKIP,"\n")
# Timing support
define TIMECMD_detect
+3 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = "MFEM"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = v3.3.3
PROJECT_NUMBER = v3.4.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -761,6 +761,7 @@ WARN_LOGFILE =
INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/mfem.hpp \
@MFEM_SOURCE_DIR@/backends/base \
@MFEM_SOURCE_DIR@/backends/occa \
@MFEM_SOURCE_DIR@/config \
@MFEM_SOURCE_DIR@/general \
@MFEM_SOURCE_DIR@/linalg \
@@ -768,6 +769,7 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/fem \
@MFEM_SOURCE_DIR@/examples \
@MFEM_SOURCE_DIR@/examples/petsc \
@MFEM_SOURCE_DIR@/examples/pumi \
@MFEM_SOURCE_DIR@/examples/sundials \
@MFEM_SOURCE_DIR@/miniapps/common \
@MFEM_SOURCE_DIR@/miniapps/meshing \
+12 -3
View File
@@ -36,8 +36,8 @@ namespace mfem {
* - HypreSolver and other \link hypre.hpp hypre classes\endlink
*
* <H3>Example codes</H3>
* - <a class="el" href="ex1_8cpp_source.html">Example 1</a>: nodal H1 FEM for the Laplace problem
* - <a class="el" href="ex1p_8cpp_source.html">Example 1p</a>: parallel nodal H1 FEM for the Laplace problem
* - <a class="el" href="examples_2ex1_8cpp_source.html">Example 1</a>: nodal H1 FEM for the Laplace problem
* - <a class="el" href="examples_2ex1p_8cpp_source.html">Example 1p</a>: parallel nodal H1 FEM for the Laplace problem
* - <a class="el" href="ex2_8cpp_source.html">Example 2</a>: vector FEM for linear elasticity
* - <a class="el" href="ex2p_8cpp_source.html">Example 2p</a>: parallel vector FEM for linear elasticity
* - <a class="el" href="ex3_8cpp_source.html">Example 3</a>: Nedelec H(curl) FEM for the definite Maxwell problem
@@ -56,7 +56,7 @@ namespace mfem {
* - <a class="el" href="ex9p_8cpp_source.html">Example 9p</a>: parallel Discontinuous Galerkin (DG) time-dependent advection
* - <a class="el" href="ex10_8cpp_source.html">Example 10</a>: time-dependent implicit nonlinear elasticity
* - <a class="el" href="ex10p_8cpp_source.html">Example 10p</a>: parallel time-dependent implicit nonlinear elasticity
* - <a class="el" href="ex11p_8cpp_source.html">Example 11p</a>: parallel Laplace eigensolver
* - <a class="el" href="examples_2ex11p_8cpp_source.html">Example 11p</a>: parallel Laplace eigensolver
* - <a class="el" href="ex12p_8cpp_source.html">Example 12p</a>: parallel linear elasticity eigensolver
* - <a class="el" href="ex13p_8cpp_source.html">Example 13p</a>: parallel Maxwell eigensolver
* - <a class="el" href="ex14_8cpp_source.html">Example 14</a>: Discontinuous Galerkin (DG) for the Laplace problem
@@ -96,6 +96,15 @@ namespace mfem {
* <a class="el" href="petsc_2ex10p_8cpp_source.html">10p</a>
* demonstrating the use of MFEM's \link petsc.hpp PETSc classes\endlink
*
* <H4>PUMI Examples</H4>
* - Variants of Examples
* <a class="el" href="examples_2pumi_2ex1_8cpp_source.html">1</a>,
* <a class="el" href="examples_2pumi_2ex1p_8cpp_source.html">1p</a>,
* <a class="el" href="pumi_2ex2_8cpp_source.html">2</a>,
* and
* <a class="el" href="pumi_2ex6p_8cpp_source.html">6p</a>
* demonstrating the use of MFEM's \link pumi.hpp PUMI classes\endlink
*
* <H3>Miniapps</H3>
* - <a class="el" href="volta_8cpp_source.html">Volta</a>: simple electrostatics simulation code
* - <a class="el" href="tesla_8cpp_source.html">Tesla</a>: simple magnetostatics simulation code
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

+8 -3
View File
@@ -25,6 +25,7 @@ list(APPEND ALL_EXE_SRCS
ex16.cpp
ex17.cpp
ex18.cpp
ex19.cpp
)
if (MFEM_USE_MPI)
@@ -47,6 +48,7 @@ if (MFEM_USE_MPI)
ex16p.cpp
ex17p.cpp
ex18p.cpp
ex19p.cpp
)
endif()
@@ -61,8 +63,6 @@ foreach(SRC_FILE ${ALL_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(FIND ${TEST_NAME} "p" is_parallel_test)
set(THIS_TEST_OPTIONS "-no-vis")
if (${TEST_NAME} MATCHES "ex10p*")
list(APPEND THIS_TEST_OPTIONS "-tf" "5")
@@ -70,7 +70,7 @@ foreach(SRC_FILE ${ALL_EXE_SRCS})
list(APPEND THIS_TEST_OPTIONS "-e" "1")
endif()
if (is_parallel_test EQUAL -1)
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
@@ -91,3 +91,8 @@ endif()
if (MFEM_USE_PETSC)
add_subdirectory(petsc)
endif()
# Include the examples/pumi directory if PUMI is enabled
if (MFEM_USE_PUMI)
add_subdirectory(pumi)
endif()
+160 -77
View File
File diff suppressed because one or more lines are too long
+441
View File
@@ -0,0 +1,441 @@
// MFEM Example 16
//
// Compile with: make ex16
//
// Sample runs: ex16
// ex16 -m ../data/inline-tri.mesh
// ex16 -m ../data/disc-nurbs.mesh -tf 2
// ex16 -s 1 -a 0.0 -k 1.0
// ex16 -s 2 -a 1.0 -k 0.0
// ex16 -s 3 -a 0.5 -k 0.5 -o 4
// ex16 -s 14 -dt 1.0e-4 -tf 4.0e-2 -vs 40
// ex16 -m ../data/fichera-q2.mesh
// ex16 -m ../data/escher.mesh
// ex16 -m ../data/beam-tet.mesh -tf 10 -dt 0.1
// ex16 -m ../data/amr-quad.mesh -o 4 -r 0
// ex16 -m ../data/amr-hex.mesh -o 2 -r 0
//
// Description: This example solves a time dependent nonlinear heat equation
// problem of the form du/dt = C(u), with a non-linear diffusion
// operator C(u) = \nabla \cdot (\kappa + \alpha u) \nabla u.
//
// The example demonstrates the use of nonlinear operators (the
// class ConductionOperator defining C(u)), as well as their
// implicit time integration. Note that implementing the method
// ConductionOperator::ImplicitSolve is the only requirement for
// high-order implicit (SDIRK) time integration.
//
// We recommend viewing examples 2, 9 and 10 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
/** After spatial discretization, the conduction model can be written as:
*
* du/dt = M^{-1}(-Ku)
*
* where u is the vector representing the temperature, M is the mass matrix,
* and K is the diffusion operator with diffusivity depending on u:
* (\kappa + \alpha u).
*
* Class ConductionOperator represents the right-hand side of the above ODE.
*/
class ConductionOperator : public TimeDependentOperator
{
protected:
FiniteElementSpace &fespace;
Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
BilinearForm M;
BilinearForm K;
GridFunction u_alpha_gf;
GridFunctionCoefficient u_coeff;
OperatorHandle Moper, Koper;
Operator *T; // T = M + dt K
double current_dt;
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
// FIXME: add the preconditioner
// DSmoother M_prec; // Preconditioner for the mass matrix M
CGSolver T_solver; // Implicit solver for T = M + dt K
// FIXME: add the preconditioner
// DSmoother T_prec; // Preconditioner for the implicit solver
double alpha, kappa;
mutable Vector z; // auxiliary vector
public:
ConductionOperator(FiniteElementSpace &f, const char *oper_spec,
double alpha, double kappa, const Vector &u);
virtual void Mult(const Vector &u, Vector &du_dt) const;
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
This is the only requirement for high-order SDIRK implicit integration.*/
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
void SetParameters(const Vector &u);
virtual ~ConductionOperator();
};
class TimeDerivativeOperator : public Operator
{
Operator *Moper;
Operator *Koper;
mutable Vector Kdu;
const double dt;
public:
// FIXME: Sparse matrices should be changed to have PLayouts
// allocated so that this constructor works even when Moper and
// Koper were not created from engines.
TimeDerivativeOperator(Operator *_Moper, const double _dt, Operator *_Koper)
: Operator(*_Koper->InLayout(), *_Moper->OutLayout()),
Moper(_Moper),
Koper(_Koper),
Kdu(_Moper->OutLayout()),
dt(_dt) { }
virtual void Mult(const Vector &x, Vector &y) const
{
Moper->Mult(x, y);
Koper->Mult(x, Kdu);
y.Axpby(1.0, y, dt, Kdu);
}
};
double InitialTemperature(const Vector &x);
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int ref_levels = 2;
int order = 2;
int ode_solver_type = 3;
double t_final = 0.5;
double dt = 1.0e-2;
double alpha = 1.0e-2;
double kappa = 0.5;
bool visualization = true;
bool visit = false;
int vis_steps = 5;
const char *oper_spec = "representation: 'partial'";
const char *occa_spec = "mode: 'Serial'";
int precision = 8;
cout.precision(precision);
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
"\t 11 - Forward Euler, 12 - RK2, 13 - RK3 SSP, 14 - RK4.");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
"Time step.");
args.AddOption(&alpha, "-a", "--alpha",
"Alpha coefficient.");
args.AddOption(&kappa, "-k", "--kappa",
"Kappa coefficient offset.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&visit, "-visit", "--visit-datafiles", "-no-visit",
"--no-visit-datafiles",
"Save data files for VisIt (visit.llnl.gov) visualization.");
args.AddOption(&vis_steps, "-vs", "--visualization-steps",
"Visualize every n-th timestep.");
args.AddOption(&oper_spec, "-s", "--oper-spec", "Operator specification");
args.AddOption(&occa_spec, "-os", "--occa-spec", "OCCA engine specification");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// Examples for OCCA specifications:
// - CPU (serial): "mode: 'Serial'"
// - CUDA GPU: "mode: 'CUDA', device_id: 0"
// - OpenMP on CPUs: "mode: 'OpenMP', threads: 4"
// - OpenCL on device 0: "mode: 'OpenCL', device_id: 0, platform_id: 0"
SharedPtr<Engine> engine(new mfem::occa::Engine(occa_spec));
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral and hexahedral meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
mesh->SetEngine(*engine);
int dim = mesh->Dimension();
// 3. Define the ODE solver used for time integration. Several implicit
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
// explicit Runge-Kutta methods are available.
ODESolver *ode_solver;
switch (ode_solver_type)
{
// Implicit L-stable methods
case 1: ode_solver = new BackwardEulerSolver; break;
case 2: ode_solver = new SDIRK23Solver(2); break;
case 3: ode_solver = new SDIRK33Solver; break;
// Explicit methods
case 11: ode_solver = new ForwardEulerSolver; break;
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 13: ode_solver = new RK3SSPSolver; break;
case 14: ode_solver = new RK4Solver; break;
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
case 24: ode_solver = new SDIRK34Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
delete mesh;
return 3;
}
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
// command-line parameter.
for (int lev = 0; lev < ref_levels; lev++)
{
mesh->UniformRefinement();
}
// 5. Define the vector finite element space representing the current and the
// initial temperature, u_ref.
H1_FECollection fe_coll(order, dim);
FiniteElementSpace fespace(mesh, &fe_coll);
int fe_size = fespace.GetTrueVSize();
cout << "Number of temperature unknowns: " << fe_size << endl;
GridFunction u_gf(&fespace);
// 6. Set the initial conditions for u. All boundaries are considered
// natural. This computes this on the host, so pull/push is needed.
u_gf.Pull();
FunctionCoefficient u_0(InitialTemperature);
u_gf.ProjectCoefficient(u_0);
u_gf.Push();
Vector u;
u_gf.GetTrueDofs(u);
// 7. Initialize the conduction operator and the visualization.
ConductionOperator oper(fespace, oper_spec, alpha, kappa, u);
u_gf.SetFromTrueDofs(u);
{
ofstream omesh("ex16.mesh");
omesh.precision(precision);
mesh->Print(omesh);
ofstream osol("ex16-init.gf");
osol.precision(precision);
u_gf.Pull(); // pull back to host before saving
u_gf.Save(osol);
}
VisItDataCollection visit_dc("Example16", mesh);
visit_dc.RegisterField("temperature", &u_gf);
if (visit)
{
visit_dc.SetCycle(0);
visit_dc.SetTime(0.0);
visit_dc.Save();
}
socketstream sout;
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
sout.open(vishost, visport);
if (!sout)
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
visualization = false;
cout << "GLVis visualization disabled.\n";
}
else
{
sout.precision(precision);
sout << "solution\n" << *mesh << u_gf;
sout << "pause\n";
sout << flush;
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
}
}
// 8. Perform time-integration (looping over the time iterations, ti, with a
// time-step dt).
ode_solver->Init(oper);
double t = 0.0;
bool last_step = false;
for (int ti = 1; !last_step; ti++)
{
if (t + dt >= t_final - dt/2)
{
last_step = true;
}
ode_solver->Step(u, t, dt);
if (last_step || (ti % vis_steps) == 0)
{
cout << "step " << ti << ", t = " << t << endl;
// u_gf and u are both on the device at this point.
u_gf.SetFromTrueDofs(u);
if (visualization)
{
u_gf.Pull(); // pull back to host before saving
sout << "solution\n" << *mesh << u_gf << flush;
}
if (visit)
{
visit_dc.SetCycle(ti);
visit_dc.SetTime(t);
visit_dc.Save();
}
}
oper.SetParameters(u);
}
// 9. Save the final solution. This output can be viewed later using GLVis:
// "glvis -m ex16.mesh -g ex16-final.gf".
{
ofstream osol("ex16-final.gf");
osol.precision(precision);
u_gf.Pull(); // pull back to host before saving
u_gf.Save(osol);
}
// 10. Free the used memory.
delete ode_solver;
delete mesh;
return 0;
}
ConductionOperator::ConductionOperator(FiniteElementSpace &f,
const char *oper_spec, double al,
double kap, const Vector &u)
: TimeDependentOperator(*f.GetTrueVLayout()), fespace(f), M(&fespace),
K(&fespace), u_alpha_gf(&f), u_coeff(&u_alpha_gf), Moper(oper_spec),
Koper(oper_spec), T(NULL), current_dt(0.0), z(f.GetTrueVLayout())
{
const double rel_tol = 1e-8;
M.AddDomainIntegrator(new MassIntegrator());
M.Assemble();
M.FormSystemMatrix(ess_tdof_list, Moper);
K.AddDomainIntegrator(new DiffusionIntegrator(u_coeff));
M_solver.iterative_mode = false;
M_solver.SetRelTol(rel_tol);
M_solver.SetAbsTol(0.0);
M_solver.SetMaxIter(200);
M_solver.SetPrintLevel(0);
// M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(*Moper.Ptr());
alpha = al;
kappa = kap;
T_solver.iterative_mode = false;
T_solver.SetRelTol(rel_tol);
T_solver.SetAbsTol(0.0);
T_solver.SetMaxIter(200);
T_solver.SetPrintLevel(0);
// T_solver.SetPreconditioner(T_prec);
SetParameters(u);
}
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
{
// Compute:
// du_dt = M^{-1}*-K(u)
// for du_dt
Koper.Ptr()->Mult(u, z);
z.Axpby(-1.0, z, 0.0, z);
M_solver.Mult(z, du_dt);
}
void ConductionOperator::ImplicitSolve(const double dt,
const Vector &u, Vector &du_dt)
{
// Solve the equation:
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
// for du_dt
if (!T)
{
T = new TimeDerivativeOperator(Moper.Ptr(), dt, Koper.Ptr());
current_dt = dt;
T_solver.SetOperator(*T);
}
MFEM_VERIFY(dt == current_dt, ""); // SDIRK methods use the same dt
Koper.Ptr()->Mult(u, z);
z.Axpby(-1.0, z, 0.0, z);
T_solver.Mult(z, du_dt);
}
void ConductionOperator::SetParameters(const Vector &u)
{
u_alpha_gf.SetFromTrueDofs(u);
u_alpha_gf.Pull();
for (int i = 0; i < u_alpha_gf.Size(); i++)
{
u_alpha_gf(i) = kappa + alpha*u_alpha_gf(i);
}
u_alpha_gf.Push();
// Reassemble after changing u_alpha_gf (and hence u_coeff)...
K.Assemble();
K.FormSystemMatrix(ess_tdof_list, Koper);
delete T;
T = NULL; // re-compute T on the next ImplicitSolve
}
ConductionOperator::~ConductionOperator()
{
delete T;
}
double InitialTemperature(const Vector &x)
{
if (x.Norml2() < 0.5)
{
return 2.0;
}
else
{
return 1.0;
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ using namespace mfem;
//
// and K^-1 is an approximation of the inverse of the displacement part of the
// Jacobian and S^-1 is an approximation of the inverse of the Schur
// complement S = B K^-1 B^T. The Schur complement is approximiated using
// complement S = B K^-1 B^T. The Schur complement is approximated using
// a mass matrix of the pressure variables.
class JacobianPreconditioner : public Solver
{
+1 -1
View File
@@ -50,7 +50,7 @@ using namespace mfem;
//
// and K^-1 is an approximation of the inverse of the displacement part of the
// Jacobian and S^-1 is an approximation of the inverse of the Schur
// complement S = B K^-1 B^T. The Schur complement is approximiated using
// complement S = B K^-1 B^T. The Schur complement is approximated using
// a mass matrix of the pressure variables.
class JacobianPreconditioner : public Solver
{
+23 -6
View File
@@ -12,17 +12,20 @@ int main(int argc, char *argv[])
const char *spec = "cpu";
const char *mesh_file = "../data/star.mesh";
int order = 1;
int ref_levels = -1;
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&spec, "-s", "--spec",
"Compute resurce specification.");
"Compute resource specification.");
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(&ref_levels, "-r", "--refine-levels",
"Number of uniform refinements to apply to the mesh.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
@@ -36,20 +39,29 @@ int main(int argc, char *argv[])
}
args.PrintOptions(cout);
#ifdef MFEM_USE_BACKENDS
/// Engine *engine = EngineDepot.Select(spec);
string occa_spec("mode: 'Serial'");
// string occa_spec("mode: 'CUDA', deviceID: 0");
// string occa_spec("mode: 'Serial'");
string occa_spec("mode: 'CUDA', device_id: 0");
// string occa_spec("mode: 'OpenMP', threads: 4");
// string occa_spec("mode: 'OpenCL', deviceID: 0, platformID: 0");
// string occa_spec("mode: 'OpenCL', device_id: 0, platform_id: 0");
// The following flag affects only 'Serial' and 'OpenMP' modes.
// In 'CUDA' mode, '-O3' affects only host code.
// In 'OpenCL' mode, adding '-O3' breaks compilation.
// occa_spec += ", kernel: { compiler_flags: '-O3' }";
SharedPtr<Engine> engine(new mfem::occa::Engine(occa_spec));
#endif
// 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);
#ifdef MFEM_USE_BACKENDS
mesh->SetEngine(*engine);
#endif
int dim = mesh->Dimension();
// 3. Refine the mesh to increase the resolution. In this example we do
@@ -57,7 +69,7 @@ int main(int argc, char *argv[])
// largest number that gives a final mesh with no more than 50,000
// elements.
{
int ref_levels =
ref_levels = ref_levels >= 0 ? ref_levels :
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
@@ -132,7 +144,12 @@ int main(int argc, char *argv[])
cout << "Size of linear system: " << A.Ptr()->Height() << endl;
// 10. Solve the system A X = B with CG.
CG(*A.Ptr(), B, X, 3, 1000, 1e-12, 0.0);
tic_toc.Clear();
tic_toc.Start();
const int print_level = 3;
CG(*A.Ptr(), B, X, print_level, 1000, 1e-12, 0.0);
tic_toc.Stop();
cout << "CG time: " << tic_toc.RealTime() << " sec." << endl;
// 11. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
+67 -6
View File
@@ -16,6 +16,8 @@ int main(int argc, char *argv[])
// 2. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int ser_ref_levels = -1;
int par_ref_levels = -1;
int order = 1;
bool static_cond = false;
bool visualization = 1;
@@ -23,6 +25,10 @@ int main(int argc, char *argv[])
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
@@ -46,20 +52,31 @@ int main(int argc, char *argv[])
args.PrintOptions(cout);
}
#ifdef MFEM_USE_BACKENDS
/// Engine *engine = EngineDepot.Select(spec);
string occa_spec("mode: 'Serial'");
// string occa_spec("mode: 'CUDA', deviceID: 0");
// string occa_spec("mode: 'Serial'");
string occa_spec;
{
stringstream occa_spec_ss;
occa_spec_ss << "mode: 'CUDA', device_id: 0";
// const int nGPUs = 4;
// occa_spec_ss << "mode: 'CUDA', device_id: " << (myid % nGPUs);
occa_spec = occa_spec_ss.str();
}
// string occa_spec("mode: 'OpenMP', threads: 4");
// string occa_spec("mode: 'OpenCL', deviceID: 0, platformID: 0");
// string occa_spec("mode: 'OpenCL', device_id: 0, platform_id: 0");
SharedPtr<Engine> engine(new mfem::occa::Engine(MPI_COMM_WORLD, occa_spec));
#endif
// 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);
#ifdef MFEM_USE_BACKENDS
mesh->SetEngine(*engine);
#endif
int dim = mesh->Dimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
@@ -67,8 +84,12 @@ int main(int argc, char *argv[])
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 10,000 elements.
{
int ref_levels =
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
int ref_levels = (int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
ref_levels = ser_ref_levels >= 0 ? ser_ref_levels : ref_levels;
if (myid == 0)
{
cout << "Serial refinement levels: " << ref_levels << endl;
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
@@ -81,12 +102,18 @@ int main(int argc, char *argv[])
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
int par_ref_levels = 2;
par_ref_levels = par_ref_levels >= 0 ? par_ref_levels : 2;
if (myid == 0)
{
cout << "Parallel refinement levels: " << par_ref_levels << endl;
}
for (int l = 0; l < par_ref_levels; l++)
{
pmesh->UniformRefinement();
}
}
pmesh->PrintInfo(cout);
if (myid == 0) { cout << endl; }
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
@@ -164,7 +191,41 @@ int main(int argc, char *argv[])
pcg->SetMaxIter(1000);
pcg->SetPrintLevel(3);
pcg->SetOperator(*A.Ptr());
// Run one CG iteration to make sure all kernels are loaded before measuring
// time.
if (myid == 0)
{
cout << "Running 1 CG iteration to load all kernels ..." << flush;
}
{
Vector X2(X);
pcg->SetMaxIter(1);
pcg->SetPrintLevel(-1);
pcg->Mult(B, X2);
pcg->SetMaxIter(1000);
pcg->SetPrintLevel(3);
}
if (myid == 0)
{
cout << " done." << endl;
}
double start_time = MPI_Wtime();
pcg->Mult(B, X);
double end_time = MPI_Wtime();
double loc_time = end_time - start_time;
double max_time, min_time;
MPI_Allreduce(&loc_time, &max_time, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
MPI_Allreduce(&loc_time, &min_time, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
if (myid == 0)
{
cout << "CG time: " << max_time << " sec (min: " << min_time << " sec)\n"
<< "DOFs/sec in CG: "
<< 1e-6*size*pcg->GetNumIterations()/max_time << " ("
<< 1e-6*size*pcg->GetNumIterations()/min_time << ") million.\n"
<< endl;
}
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
+3
View File
@@ -38,6 +38,9 @@ endif
ifeq ($(MFEM_USE_PETSC),YES)
SUBDIRS += petsc
endif
ifeq ($(MFEM_USE_PUMI),YES)
SUBDIRS += pumi
endif
SUBDIRS_ALL = $(addsuffix /all,$(SUBDIRS))
SUBDIRS_TEST = $(addsuffix /test,$(SUBDIRS))
SUBDIRS_CLEAN = $(addsuffix /clean,$(SUBDIRS))
+19 -21
View File
@@ -63,31 +63,29 @@ add_mfem_examples(PETSC_EXAMPLES_SRCS ${PFX} copy_petsc_rc_files test_petsc)
# ctest -R petsc
# Command line options for the tests.
set(EX1P_ARGS -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p)
set(EX2P_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p)
set(EX3P_ARGS -m ../../data/klein-bottle.mesh
-o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping)
set(EX4P_ARGS -m ../../data/klein-bottle.mesh
-o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping)
set(EX5P_BDDC_ARGS -m ../../data/star.mesh
--usepetsc --petscopts rc_ex5p_bddc --nonoverlapping)
set(EX5P_FSPL_ARGS -m ../../data/beam-tet.mesh
--usepetsc --petscopts rc_ex5p_fieldsplit)
set(EX6P_ARGS -m ../../data/amr-quad.mesh --usepetsc)
set(EX9P_E_ARGS -m ../../data/periodic-hexagon.mesh
--usepetsc --petscopts rc_ex9p_expl -dt 0.1)
set(EX9P_ES_ARGS -m ../../data/periodic-hexagon.mesh
--usepetsc --petscopts rc_ex9p_expl --no-step)
set(EX9P_IS_ARGS -m ../../data/periodic-hexagon.mesh
--usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5)
set(EX10P_ARGS -m ../../data/beam-quad.mesh
-tf 30 -s 3 -rs 2 -dt 3 --usepetsc --petscopts rc_ex10p)
set(EX1_ARGS_W -m ../../data/amr-quad.mesh --usepetsc)
set(EX1_ARGS_P -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p)
set(EX2_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p)
set(EX3_ARGS -m ../../data/klein-bottle.mesh -o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping)
set(EX4_ARGS -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping)
set(EX4_HYB_ARGS -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping --hybridization)
set(EX5_BDDC_LB_ARGS -m ../../data/star.mesh --usepetsc -o 0 --petscopts rc_ex5p_bddc --nonoverlapping --local-bdr)
set(EX5_BDDC_GB_ARGS -m ../../data/star.mesh --usepetsc -o 0 --petscopts rc_ex5p_bddc --nonoverlapping)
set(EX5_FSPL_ARGS -m ../../data/beam-tet.mesh --usepetsc -o 0 --petscopts rc_ex5p_fieldsplit)
set(EX6_ARGS -m ../../data/amr-quad.mesh --usepetsc)
set(EX6_NONOVL_ARGS -m ../../data/amr-quad.mesh --usepetsc --nonoverlapping)
set(EX9_E_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl -dt 0.1)
set(EX9_ES_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step)
set(EX9_IS_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5)
set(EX10_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3)
# Add the tests: one test per command-line-variable.
foreach(TEST_OPTIONS_VAR
EX1P_ARGS EX2P_ARGS EX3P_ARGS EX4P_ARGS EX5P_BDDC_ARGS EX5P_FSPL_ARGS
EX6P_ARGS EX9P_E_ARGS EX9P_ES_ARGS EX9P_IS_ARGS EX10P_ARGS)
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)
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})
+20 -11
View File
@@ -64,6 +64,7 @@ int main(int argc, char *argv[])
bool visualization = 1;
bool use_petsc = true;
bool use_nonoverlapping = false;
bool local_bdr_spec = false;
const char *petscrc_file = "";
OptionsParser args(argc, argv);
@@ -86,6 +87,9 @@ int main(int argc, char *argv[])
"-no-nonoverlapping", "--no-nonoverlapping",
"Use or not the block diagonal PETSc's matrix format "
"for non-overlapping domain decomposition.");
args.AddOption(&local_bdr_spec, "-local-bdr", "--local-bdr", "-no-local-bdr",
"--no-local-bdr",
"Specify boundary dofs in local (Vdofs) ordering.");
args.Parse();
if (!args.Good())
{
@@ -306,33 +310,38 @@ int main(int argc, char *argv[])
{
if (use_nonoverlapping)
{
PetscBDDCSolverParams opts;
// For saddle point problems, we need to provide BDDC the list of
// boundary dofs either essential or natural.
// Since R_space is the only space that may have boundary dofs and it
// is ordered first then W_space, we don't need any local offset when
// specifying the dofs.
Array<int> bdr_tdof_list;
bool local = false;
if (pmesh->bdr_attributes.Size())
{
Array<int> bdr(pmesh->bdr_attributes.Max());
bdr = 1;
R_space->GetEssentialTrueDofs(bdr, bdr_tdof_list);
local = false;
// Alternatively, you can also provide the list of dofs in local
// ordering:
// R_space->GetEssentialVDofs(bdr, bdr_tdof_list);
// bdr_tdof_list.SetSize(R_space->GetVSize()+W_space->GetVSize(),0);
// local = true;
if (!local_bdr_spec)
{
// Essential dofs in global ordering
R_space->GetEssentialTrueDofs(bdr, bdr_tdof_list);
}
else
{
// Alternatively, you can also provide the list of dofs in local
// ordering
R_space->GetEssentialVDofs(bdr, bdr_tdof_list);
bdr_tdof_list.SetSize(R_space->GetVSize()+W_space->GetVSize(),0);
}
opts.SetNatBdrDofs(&bdr_tdof_list,local_bdr_spec);
}
else
{
MFEM_ABORT("Need to know the boundary dofs");
MFEM_WARNING("Missing boundary dofs. This may cause solver failures.");
}
PetscBDDCSolverParams opts;
opts.SetNatBdrDofs(&bdr_tdof_list,local);
// See also command line options rc_ex5p_bddc
pdarcyPr = new PetscBDDCSolver(MPI_COMM_WORLD,*darcyOp,opts,"prec_");
}
+19 -13
View File
@@ -69,18 +69,21 @@ TESTNAME = Parallel PETSc example
# Testing PETSc execution options.
EX1_ARGS_W := -m ../../data/amr-quad.mesh --usepetsc
EX1_ARGS_P := -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p
EX2_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p
EX3_ARGS := -m ../../data/klein-bottle.mesh -o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping
EX4_ARGS := -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping
EX5_BDDC_ARGS := -m ../../data/star.mesh --usepetsc -o 0 --petscopts rc_ex5p_bddc --nonoverlapping
EX5_FSPL_ARGS := -m ../../data/beam-tet.mesh --usepetsc -o 0 --petscopts rc_ex5p_fieldsplit
EX6_ARGS := -m ../../data/amr-quad.mesh --usepetsc
EX9_E_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl -dt 0.1
EX9_ES_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step
EX9_IS_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5
EX10_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3
EX1_ARGS_W := -m ../../data/amr-quad.mesh --usepetsc
EX1_ARGS_P := -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p
EX2_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p
EX3_ARGS := -m ../../data/klein-bottle.mesh -o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping
EX4_ARGS := -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping
EX4_HYB_ARGS := -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping --hybridization
EX5_BDDC_LB_ARGS := -m ../../data/star.mesh --usepetsc -o 0 --petscopts rc_ex5p_bddc --nonoverlapping --local-bdr
EX5_BDDC_GB_ARGS := -m ../../data/star.mesh --usepetsc -o 0 --petscopts rc_ex5p_bddc --nonoverlapping
EX5_FSPL_ARGS := -m ../../data/beam-tet.mesh --usepetsc -o 0 --petscopts rc_ex5p_fieldsplit
EX6_ARGS := -m ../../data/amr-quad.mesh --usepetsc
EX6_NONOVL_ARGS := -m ../../data/amr-quad.mesh --usepetsc --nonoverlapping
EX9_E_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl -dt 0.1
EX9_ES_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step
EX9_IS_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5
EX10_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3
ex1p-test-par: ex1p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_W))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_P))
@@ -90,11 +93,14 @@ ex3p-test-par: ex3p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX3_ARGS))
ex4p-test-par: ex4p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX4_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX4_HYB_ARGS))
ex5p-test-par: ex5p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX5_BDDC_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX5_BDDC_LB_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX5_BDDC_GB_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX5_FSPL_ARGS))
ex6p-test-par: ex6p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX6_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX6_NONOVL_ARGS))
ex9p-test-par: ex9p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_E_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_ES_ARGS))
+3
View File
@@ -6,4 +6,7 @@
# it needs PETSc configured with MUMPS
-solver_pc_type cholesky
# Petsc 3.9
-solver_pc_factor_mat_solver_type mumps
# Older versions of PETSc
-solver_pc_factor_mat_solver_package mumps
+6 -3
View File
@@ -16,7 +16,10 @@
#-pc_bddc_adaptive_threshold 10
# Customization of the local solvers
#-pc_bddc_neumann_pc_factor_mat_solver_package mumps
#-pc_bddc_dirichlet_pc_factor_mat_solver_package mumps
# With PETSc versions older than 3.9
# use "mat_solver_package" instead of "mat_solver_type"
#
#-pc_bddc_neumann_pc_factor_mat_solver_type mumps
#-pc_bddc_dirichlet_pc_factor_mat_solver_type mumps
#-pc_bddc_coarse_pc_type cholesky
#-pc_bddc_coarse_pc_factor_mat_solver_package mumps
#-pc_bddc_coarse_pc_factor_mat_solver_type mumps
+3
View File
@@ -2,4 +2,7 @@
# it needs PETSc configured with MUMPS
-solver_pc_type cholesky
# Petsc 3.9
-solver_pc_factor_mat_solver_type mumps
# Older versions of PETSc
-solver_pc_factor_mat_solver_package mumps
+6 -3
View File
@@ -13,7 +13,10 @@
#-pc_bddc_adaptive_threshold 10
# Customization of the local solvers
#-pc_bddc_neumann_pc_factor_mat_solver_package mumps
#-pc_bddc_dirichlet_pc_factor_mat_solver_package mumps
# With PETSc versions older than 3.9
# use "mat_solver_package" instead of "mat_solver_type"
#
#-pc_bddc_neumann_pc_factor_mat_solver_type mumps
#-pc_bddc_dirichlet_pc_factor_mat_solver_type mumps
#-pc_bddc_coarse_pc_type cholesky
#-pc_bddc_coarse_pc_factor_mat_solver_package mumps
#-pc_bddc_coarse_pc_factor_mat_solver_type mumps
+18 -4
View File
@@ -25,15 +25,29 @@
# verbose output
#-prec_pc_bddc_check_level 1
# local solvers (needs PETSc compiled with support for SuiteSparse)
# default solvers will fail
# local solvers (default "petsc" solvers will fail)
# needs PETSc compiled with support for MUMPS or SuiteSparse
# use "umfpack" in place of "mumps" if you want to use
# SuiteSparse solvers
#
# With PETSc versions older than 3.9
# use "mat_solver_package" instead of "mat_solver_type"
#
-prec_pc_bddc_neumann_pc_type lu
-prec_pc_bddc_neumann_pc_factor_mat_solver_package umfpack
-prec_pc_bddc_neumann_pc_factor_mat_solver_type mumps
-prec_pc_bddc_neumann_pc_factor_mat_solver_package mumps
-prec_pc_bddc_dirichlet_pc_type lu
-prec_pc_bddc_dirichlet_pc_factor_mat_solver_package umfpack
-prec_pc_bddc_dirichlet_pc_factor_mat_solver_type mumps
-prec_pc_bddc_dirichlet_pc_factor_mat_solver_package mumps
# MUMPS sometimes fails with a very annoying error
-mat_mumps_icntl_14 500
-prec_pc_bddc_dirichlet_mat_mumps_icntl_14 500
-prec_pc_bddc_neumann_mat_mumps_icntl_14 500
# coarse solver (needs PETSc compiled with support for MUMPS)
# default solver may fail
-prec_pc_bddc_coarse_pc_factor_mat_solver_type mumps
-prec_pc_bddc_coarse_pc_factor_mat_solver_package mumps
-prec_pc_bddc_coarse_pc_type cholesky
+72
View File
@@ -0,0 +1,72 @@
# 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.
set(PUMI_EXAMPLES_SRCS)
# All PUMI examples require MPI
if (MFEM_USE_MPI)
list(APPEND PUMI_EXAMPLES_SRCS
ex1.cpp
ex1p.cpp
ex2.cpp
ex6p.cpp
)
endif()
# Include the source directory where mfem.hpp and mfem-performance.hpp are.
include_directories(BEFORE ${PROJECT_BINARY_DIR})
# Add "test_pumi" target, see below.
add_custom_target(test_pumi
${CMAKE_CTEST_COMMAND} -R pumi USES_TERMINAL)
# Add one executable per cpp file, adding "pumi_" as prefix. Sets
# "test_pumi" as a target that depends on the given examples.
set(PFX pumi_)
add_mfem_examples(PUMI_EXAMPLES_SRCS ${PFX} "" test_pumi)
# Testing.
# The PUMI tests can be run separately using the target "test_pumi"
# which builds the examples and runs:
# ctest -R pumi
# Command line options for the tests.
# TODO...
# Set the number of processors for the parallel examples.
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})
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()
+18
View File
@@ -0,0 +1,18 @@
Finite Element Discretization Library
__
_ __ ___ / _| ___ _ __ ___
| '_ ` _ \ | |_ / _ \| '_ ` _ \
| | | | | || _|| __/| | | | | |
|_| |_| |_||_| \___||_| |_| |_|
http://mfem.org
This directory contains modifications of the example codes that illustrate the
use of MFEM features based on the Parallel Unstructured Mesh Infrastructure,
PUMI, from https://scorec.rpi.edu/pumi.
To build these examples, make sure that MFEM is configured with the option
"MFEM_USE_PUMI = YES", see the top-level INSTALL file for details.
We recommend comparing the original example codes with the corresponding files
in the current directory.
+262
View File
@@ -0,0 +1,262 @@
// MFEM Example 1
// PUMI Modification
//
// Compile with: make ex1
//
// Sample runs:
// ex1 -m ../../data/pumi/serial/Kova.smb -p ../../data/pumi/geom/Kova.dmg
//
// Note: Example models + meshes for the PUMI examples can be downloaded
// from github.com/mfem/data/pumi. After downloading we recommend
// creating a symbolic link to the above directory in ../../data.
//
// 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.
//
// This PUMI modification demonstrates how PUMI's API can be used
// to load a PUMI mesh classified on a geometric model and then
// convert it to the MFEM mesh format. The inputs are a Parasolid
// model, "*.xmt_txt" and a SCOREC mesh "*.smb". The option "-o"
// is used for the Finite Element order and "-go" is used for the
// geometry order. Note that they can be used independently, i.e.
// "-o 8 -go 3" solves for 8th order FE on a third order geometry.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#ifdef MFEM_USE_SIMMETRIX
#include <SimUtil.h>
#include <gmi_sim.h>
#endif
#include <apfMDS.h>
#include <gmi_null.h>
#include <PCU.h>
#include <apfConvert.h>
#include <gmi_mesh.h>
#include <crv.h>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI).
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/pumi/serial/Kova.smb";
#ifdef MFEM_USE_SIMMETRIX
const char *model_file = "../../data/pumi/geom/Kova.x_t";
#else
const char *model_file = "../../data/pumi/geom/Kova.dmg";
#endif
int order = 1;
bool static_cond = false;
bool visualization = 1;
int geom_order = 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(&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.AddOption(&model_file, "-p", "--parasolid",
"Parasolid model to use.");
args.AddOption(&geom_order, "-go", "--geometry_order",
"Geometric order of the model");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the SCOREC Mesh.
PCU_Comm_Init();
#ifdef MFEM_USE_SIMMETRIX
Sim_readLicenseFile(0);
gmi_sim_start();
gmi_register_sim();
#endif
gmi_register_mesh();
apf::Mesh2* pumi_mesh;
pumi_mesh = apf::loadMdsMesh(model_file, mesh_file);
// 4. Increase the geometry order if necessary.
if (geom_order > 1)
{
crv::BezierCurver bc(pumi_mesh, geom_order, 2);
bc.run();
}
pumi_mesh->verify();
// 5. Create the MFEM mesh object from the PUMI mesh. We can handle
// triangular and tetrahedral meshes. Other inputs are the same as the
// MFEM default constructor.
Mesh *mesh = new PumiMesh(pumi_mesh, 1, 1);
int dim = mesh->Dimension();
// 6. 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 =
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 7. 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;
// 8. 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 (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 9. 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();
// 10. 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;
// 11. 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));
// 12. 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
// 13. 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
// 13. 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
// 14. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 15. 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);
// 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.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 17. Free the used memory.
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete mesh;
pumi_mesh->destroyNative();
apf::destroyMesh(pumi_mesh);
PCU_Comm_Free();
#ifdef MFEM_USE_SIMMETRIX
gmi_sim_stop();
Sim_unregisterAllKeys();
#endif
MPI_Finalize();
return 0;
}
+292
View File
@@ -0,0 +1,292 @@
// MFEM Example 1 - Parallel Version
// PUMI Modification
//
// Compile with: make ex1p
//
// Sample runs:
// mpirun -np 8 ex1p -m ../../data/pumi/parallel/Kova/Kova100k_8.smb
// -p ../../data/pumi/geom/Kova.dmg -o 1 -go 2
//
// Note: Example models + meshes for the PUMI examples can be downloaded
// from github.com/mfem/data/pumi. After downloading we recommend
// creating a symbolic link to the above directory in ../../data.
//
// 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.
//
// This PUMI modification demonstrates how PUMI's API can be used
// to load a parallel PUMI mesh classified on a geometric model
// and then generate the corresponding parallel MFEM mesh. The
// example also performs a "uniform" refinement, similar to the
// MFEM examples, for coarse meshes. However, the refinement is
// performed using the PUMI API. The inputs are a Parasolid
// model, "*.xmt_txt" and SCOREC parallel meshes "*.smb". The
// option "-o" is used for the Finite Element order and "-go" for
// the geometry order. Note that they can be used independently:
// "-o 8 -go 3" solves for 8th order FE on third order geometry.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#ifdef MFEM_USE_SIMMETRIX
#include <SimUtil.h>
#include <gmi_sim.h>
#endif
#include <apfMDS.h>
#include <gmi_null.h>
#include <PCU.h>
#include <apfConvert.h>
#include <gmi_mesh.h>
#include <crv.h>
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 = "../../data/pumi/parallel/Kova/Kova100k_8.smb";
#ifdef MFEM_USE_SIMMETRIX
const char *model_file = "../../data/pumi/geom/Kova.x_t";
#else
const char *model_file = "../../data/pumi/geom/Kova.dmg";
#endif
int order = 1;
bool static_cond = false;
bool visualization = 1;
int geom_order = 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(&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.AddOption(&model_file, "-p", "--parasolid",
"Parasolid model to use.");
args.AddOption(&geom_order, "-go", "--geometry_order",
"Geometric order of the model");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the SCOREC Mesh
PCU_Comm_Init();
#ifdef MFEM_USE_SIMMETRIX
Sim_readLicenseFile(0);
gmi_sim_start();
gmi_register_sim();
#endif
gmi_register_mesh();
apf::Mesh2* pumi_mesh;
pumi_mesh = apf::loadMdsMesh(model_file, mesh_file);
// 4. Increase the geometry order and refine the mesh if necessary. Parallel
// uniform refinement is performed if the total number of elements is less
// than 10,000.
int dim = pumi_mesh->getDimension();
int nEle = pumi_mesh->count(dim);
int ref_levels = (int)floor(log(10000./nEle)/log(2.)/dim);
if (geom_order > 1)
{
crv::BezierCurver bc(pumi_mesh, geom_order, 2);
bc.run();
}
// Perform Uniform refinement
if (ref_levels > 1)
{
ma::Input* uniInput = ma::configureUniformRefine(pumi_mesh, ref_levels);
if (geom_order > 1)
{
crv::adapt(uniInput);
}
else
{
ma::adapt(uniInput);
}
}
pumi_mesh->verify();
// 5. Create the parallel MFEM mesh object from the parallel PUMI mesh.
// We can handle triangular and tetrahedral meshes. Note that the
// mesh resolution is performed on the PUMI mesh.
ParMesh *pmesh = new ParPumiMesh(MPI_COMM_WORLD, pumi_mesh);
// 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 (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 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;
pumi_mesh->destroyNative();
apf::destroyMesh(pumi_mesh);
PCU_Comm_Free();
#ifdef MFEM_USE_SIMMETRIX
gmi_sim_stop();
Sim_unregisterAllKeys();
#endif
MPI_Finalize();
return 0;
}
+413
View File
@@ -0,0 +1,413 @@
// MFEM Example 2
// PUMI Modification
//
// Compile with: make ex2
//
// Sample runs:
// ex2 -m ../../data/pumi/serial/pillbox.smb -p ../../data/pumi/geom/pillbox.dmg
// -bf ../../data/pumi/serial/boundary.mesh
//
// Note: Example models + meshes for the PUMI examples can be downloaded
// from github.com/mfem/data/pumi. After downloading we recommend
// creating a symbolic link to the above directory in ../../data.
//
// Description: This example code solves a simple linear elasticity problem
// describing a multi-material cantilever beam.
//
// Specifically, we approximate the weak form of -div(sigma(u))=0
// where sigma(u)=lambda*div(u)*I+mu*(grad*u+u*grad) is the stress
// tensor corresponding to displacement field u, and lambda and mu
// are the material Lame constants. The boundary conditions are
// u=0 on the fixed part of the boundary with attribute 1, and
// sigma(u).n=f on the remainder with f being a constant pull down
// vector on boundary elements with attribute 2, and zero
// otherwise. The geometry of the domain is assumed to be as
// follows:
// boundary
// attribute 2
// (push down)
// ||
// \/
// +----------+
// | |
// | |
// +---------| material |----------+
// boundary --->| material| 2 | material |<--- boundary
// attribute 1 | 1 | | 3 | attribute 1
// (fixed) +---------+----------+----------+ (fixed)
//
// The example demonstrates the use of high-order and NURBS vector
// finite element spaces with the linear elasticity bilinear form,
// meshes with curved elements, and the definition of piece-wise
// constant and vector coefficient objects. Static condensation is
// also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "../../general/text.hpp"
#ifdef MFEM_USE_SIMMETRIX
#include <SimUtil.h>
#include <gmi_sim.h>
#endif
#include <apfMDS.h>
#include <gmi_null.h>
#include <PCU.h>
#include <apfConvert.h>
#include <gmi_mesh.h>
#include <crv.h>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI).
int num_proc, myId;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_proc);
MPI_Comm_rank(MPI_COMM_WORLD, &myId);
// 2. Parse command-line options.
const char *mesh_file = "../../data/pumi/serial/pillbox.smb";
const char *boundary_file = "../../data/pumi/serial/boundary.mesh";
#ifdef MFEM_USE_SIMMETRIX
const char *model_file = "../../data/pumi/geom/pillbox.smd";
#else
const char *model_file = "../../data/pumi/geom/pillbox.dmg";
#endif
int order = 1;
bool static_cond = false;
bool visualization = 1;
int geom_order = 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(&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.AddOption(&model_file, "-p", "--parasolid",
"Parasolid model to use.");
args.AddOption(&geom_order, "-go", "--geometry_order",
"Geometric order of the model");
args.AddOption(&boundary_file, "-bf", "--txt",
"txt file containing boundary tags");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 3. Read the SCOREC Mesh.
PCU_Comm_Init();
#ifdef MFEM_USE_SIMMETRIX
Sim_readLicenseFile(0);
gmi_sim_start();
gmi_register_sim();
#endif
gmi_register_mesh();
apf::Mesh2* pumi_mesh;
pumi_mesh = apf::loadMdsMesh(model_file, mesh_file);
// 4. Increase the geometry order if necessary.
if (geom_order > 1)
{
crv::BezierCurver bc(pumi_mesh, geom_order, 0);
bc.run();
}
pumi_mesh->verify();
// Read boundary
string bdr_tags;
named_ifgzstream input_bdr(boundary_file);
input_bdr >> ws;
getline(input_bdr, bdr_tags);
filter_dos(bdr_tags);
cout << " the boundary tag is : " << bdr_tags << endl;
Array<int> Dirichlet;
int numOfent;
if (bdr_tags == "Dirichlet")
{
input_bdr >> numOfent;
cout << " num of Dirichlet bdr conditions : " << numOfent << endl;
Dirichlet.SetSize(numOfent);
for (int kk = 0; kk < numOfent; kk++)
{
input_bdr >> Dirichlet[kk];
}
}
Dirichlet.Print();
Array<int> load_bdr;
skip_comment_lines(input_bdr, '#');
input_bdr >> bdr_tags;
filter_dos(bdr_tags);
cout << " the boundary tag is : " << bdr_tags << endl;
if (bdr_tags == "Load")
{
input_bdr >> numOfent;
load_bdr.SetSize(numOfent);
cout << " num of load bdr conditions : " << numOfent << endl;
for (int kk = 0; kk < numOfent; kk++)
{
input_bdr >> load_bdr[kk];
}
}
load_bdr.Print();
// 5. Create the MFEM mesh object from the PUMI mesh. We can handle triangular
// and tetrahedral meshes. Other inputs are the same as MFEM default
// constructor.
Mesh *mesh = new PumiMesh(pumi_mesh, 1, 1);
int dim = mesh->Dimension();
// Boundary conditions hack.
apf::MeshIterator* itr = pumi_mesh->begin(dim-1);
apf::MeshEntity* ent ;
int bdr_cnt = 0;
while ((ent = pumi_mesh->iterate(itr)))
{
apf::ModelEntity *me = pumi_mesh->toModel(ent);
if (pumi_mesh->getModelType(me) == (dim-1))
{
// Everywhere 3 as initial
(mesh->GetBdrElement(bdr_cnt))->SetAttribute(3);
int tag = pumi_mesh->getModelTag(me);
if (Dirichlet.Find(tag) != -1)
{
// Dirichlet attr -> 1
(mesh->GetBdrElement(bdr_cnt))->SetAttribute(1);
}
else if (load_bdr.Find(tag) != -1)
{
// Load attr -> 2
(mesh->GetBdrElement(bdr_cnt))->SetAttribute(2);
}
bdr_cnt++;
}
}
pumi_mesh->end(itr);
// Assign attributes for elements.
double ppt[3];
Vector cent(ppt, dim);
for (int el = 0; el < mesh->GetNE(); el++)
{
(mesh->GetElementTransformation(el))->
Transform(Geometries.GetCenter(mesh->GetElementBaseGeometry(el)),cent);
if (cent(0) <= -0.05)
{
mesh->SetAttribute(el , 1);
}
else if (cent(0) >= 0.05)
{
mesh->SetAttribute(el , 2);
}
else
{
mesh->SetAttribute(el , 3);
}
}
mesh->SetAttributes();
if (mesh->attributes.Max() < 2 || mesh->bdr_attributes.Max() < 2)
{
cerr << "\nInput mesh should have at least two materials and "
<< "two boundary attributes! (See schematic in ex2.cpp)\n"
<< endl;
return 3;
}
// 6. 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 5,000
// elements.
{
int ref_levels =
(int)floor(log(5000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 7. Define a finite element space on the mesh. Here we use vector finite
// elements, i.e. dim copies of a scalar finite element space. The vector
// dimension is specified by the last argument of the FiniteElementSpace
// constructor. For NURBS meshes, we use the (degree elevated) NURBS space
// associated with the mesh nodes.
FiniteElementCollection *fec;
FiniteElementSpace *fespace;
if (mesh->NURBSext)
{
fec = NULL;
fespace = mesh->GetNodes()->FESpace();
}
else
{
fec = new H1_FECollection(order, dim);
fespace = new FiniteElementSpace(mesh, fec, dim);
}
cout << "Number of finite element unknowns: " << fespace->GetTrueVSize()
<< endl << "Assembling: " << flush;
// 8. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking only
// boundary attribute 1 from the mesh as essential and converting it to a
// list of true dofs.
Array<int> ess_tdof_list, ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 0;
ess_bdr[0] = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
// 9. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system. In this case, b_i equals the boundary integral
// of f*phi_i where f represents a "pull down" force on the Neumann part
// of the boundary and phi_i are the basis functions in the finite element
// fespace. The force is defined by the VectorArrayCoefficient object f,
// which is a vector of Coefficient objects. The fact that f is non-zero
// on boundary attribute 2 is indicated by the use of piece-wise constants
// coefficient for its last component.
VectorArrayCoefficient f(dim);
for (int i = 0; i < dim-1; i++)
{
f.Set(i, new ConstantCoefficient(0.0));
}
{
Vector pull_force(mesh->bdr_attributes.Max());
pull_force = 0.0;
pull_force(1) = -3.0e-2;
f.Set(dim-1, new PWConstCoefficient(pull_force));
f.Set(dim-2, new PWConstCoefficient(pull_force));
}
LinearForm *b = new LinearForm(fespace);
b->AddBoundaryIntegrator(new VectorBoundaryLFIntegrator(f));
cout << "r.h.s. ... " << flush;
b->Assemble();
// 10. 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;
// 11. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the linear elasticity integrator with piece-wise
// constants coefficient lambda and mu.
Vector lambda(mesh->attributes.Max());
lambda = 1.0;
lambda(0) = lambda(1)*10;
lambda(1) = lambda(1)*100;
PWConstCoefficient lambda_func(lambda);
Vector mu(mesh->attributes.Max());
mu = 1.0;
mu(0) = mu(1)*10;
mu(1) = mu(1)*100;
PWConstCoefficient mu_func(mu);
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new ElasticityIntegrator(lambda_func,mu_func));
// 12. 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.
cout << "matrix ... " << flush;
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "done." << endl;
cout << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 13. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system Ax=b with PCG.
GSSmoother M(A);
PCG(A, M, B, X, 1, 500, 1e-8, 0.0);
#else
// 13. 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
// 14. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 15. For non-NURBS meshes, make the mesh curved based on the finite element
// space. This means that we define the mesh elements through a fespace
// based transformation of the reference element. This allows us to save
// the displaced mesh as a curved mesh when using high-order finite
// element displacement field. We assume that the initial mesh (read from
// the file) is not higher order curved mesh compared to the chosen FE
// space.
if (!mesh->NURBSext)
{
mesh->SetNodalFESpace(fespace);
}
// 16. Save the displaced mesh and the inverted solution (which gives the
// backward displacements to the original grid). This output can be
// viewed later using GLVis: "glvis -m displaced.mesh -g sol.gf".
{
GridFunction *nodes = mesh->GetNodes();
*nodes += x;
x *= -1;
ofstream mesh_ofs("displaced.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 17. Send the above data by socket to a GLVis server. Use the "n" and "b"
// keys in GLVis to visualize the displacements.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 18. Free the used memory.
delete a;
delete b;
if (fec)
{
delete fespace;
delete fec;
}
delete mesh;
pumi_mesh->destroyNative();
apf::destroyMesh(pumi_mesh);
PCU_Comm_Free();
#ifdef MFEM_USE_SIMMETRIX
gmi_sim_stop();
Sim_unregisterAllKeys();
#endif
MPI_Finalize();
return 0;
}
+387
View File
@@ -0,0 +1,387 @@
// MFEM Example 6 - Parallel Version
// PUMI Modification
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 8 ex6p
//
// 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 adapted in a conforming (tetrahedrons) manner according
// to a simple SPR ZZ error estimator.
//
// This PUMI variation also performs a "uniform" refinement,
// similar to MFEM examples, for coarse meshes. However, the
// refinement is performed using the PUMI API. A new option "-ar"
// is added to modify the "adapt_ratio" which is the fraction of
// allowable error that scales the output size field of the error
// estimator.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#ifdef MFEM_USE_SIMMETRIX
#include <SimUtil.h>
#include <gmi_sim.h>
#endif
#include <apfMDS.h>
#include <gmi_null.h>
#include <PCU.h>
#include <spr.h>
#include <apfConvert.h>
#include <gmi_mesh.h>
#include <crv.h>
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 = "../../data/pumi/parallel/Kova/Kova100k_8.smb";
#ifdef MFEM_USE_SIMMETRIX
const char *model_file = "../../data/pumi/geom/Kova.x_t";
const char *smd_file = NULL;
#else
const char *model_file = "../../data/pumi/geom/Kova.dmg";
#endif
int order = 1;
bool static_cond = false;
bool visualization = 1;
int geom_order = 1;
double adapt_ratio = 0.05;
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(&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.AddOption(&model_file, "-p", "--model",
"parasolid or .dmg model to use.");
#ifdef MFEM_USE_SIMMETRIX
args.AddOption(&smd_file, "-sm", "--smd_model",
"smd model file to use.");
#endif
args.AddOption(&geom_order, "-go", "--geometry_order",
"Geometric order of the model");
args.AddOption(&adapt_ratio, "-ar", "--adapt_ratio",
"adaptation factor used in MeshAdapt");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the SCOREC Mesh.
PCU_Comm_Init();
#ifdef MFEM_USE_SIMMETRIX
Sim_readLicenseFile(0);
gmi_sim_start();
gmi_register_sim();
#endif
gmi_register_mesh();
apf::Mesh2* pumi_mesh;
#ifdef MFEM_USE_SIMMETRIX
if (smd_file)
{
gmi_model *mixed_model = gmi_sim_load(model_file, smd_file);
pumi_mesh = apf::loadMdsMesh(mixed_model, mesh_file);
}
else
#endif
{
pumi_mesh = apf::loadMdsMesh(model_file, mesh_file);
}
// 4. Increase the geometry order and refine the mesh if necessary. Parallel
// uniform refinement is performed if the total number of elements is less
// than 100,000.
int dim = pumi_mesh->getDimension();
int nEle = pumi_mesh->count(dim);
int ref_levels = (int)floor(log(100000./nEle)/log(2.)/dim);
if (geom_order > 1)
{
crv::BezierCurver bc(pumi_mesh, geom_order, 2);
bc.run();
}
// Perform Uniform refinement
if (myid == 1)
{
std::cout << " ref level : " << ref_levels << std::endl;
}
if (ref_levels > 1)
{
ma::Input* uniInput = ma::configureUniformRefine(pumi_mesh, ref_levels);
if ( geom_order > 1)
{
crv::adapt(uniInput);
}
else
{
ma::adapt(uniInput);
}
}
pumi_mesh->verify();
// 5. Create the parallel MFEM mesh object from the parallel PUMI mesh. We
// can handle triangular and tetrahedral meshes. Note that the mesh
// resolution is performed on the PUMI mesh.
ParMesh *pmesh = new ParPumiMesh(MPI_COMM_WORLD, pumi_mesh);
// 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 == 1)
{
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 == 1)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. 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));
// 8. 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;
// 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 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(); }
// 12. The main AMR loop. In each iteration we solve the problem on the
// current mesh, visualize the solution, and adapt the mesh.
apf::Field* Tmag_field = 0;
apf::Field* temp_field = 0;
apf::Field* ipfield = 0;
apf::Field* sizefield = 0;
int max_iter = 3;
for (int Itr = 0; Itr < max_iter; Itr++)
{
HYPRE_Int global_dofs = fespace->GlobalTrueVSize();
if (myid == 1)
{
cout << "\nAMR iteration " << Itr << endl;
cout << "Number of unknowns: " << global_dofs << endl;
}
// Assemble.
a->Assemble();
b->Assemble();
// Essential boundary condition.
Array<int> ess_tdof_list;
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// Form linear system.
HypreParMatrix A;
Vector B, X;
const int copy_interior = 1;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B, copy_interior);
// 13. 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);
// 14. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 15. Save in parallel the displaced mesh and the inverted solution (which
// gives the backward displacements to the original grid). 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 above data by socket to a GLVis server. Use the "n" and "b"
// keys in GLVis to visualize the displacements.
if (visualization)
{
sout << "parallel " << num_procs << " " << myid << "\n";
sout << "solution\n" << *pmesh << x << flush;
}
// 17. Field transfer. Scalar solution field and magnitude field for error
// estimation are created the PUMI mesh.
if (order > geom_order)
{
Tmag_field = apf::createField(pumi_mesh, "field_mag",
apf::SCALAR, apf::getLagrange(order));
temp_field = apf::createField(pumi_mesh, "T_field",
apf::SCALAR, apf::getLagrange(order));
}
else
{
Tmag_field = apf::createFieldOn(pumi_mesh, "field_mag",apf::SCALAR);
temp_field = apf::createFieldOn(pumi_mesh, "T_field", apf::SCALAR);
}
ParPumiMesh* pPPmesh = dynamic_cast<ParPumiMesh*>(pmesh);
pPPmesh->FieldMFEMtoPUMI(pumi_mesh, &x, temp_field, Tmag_field);
ipfield= spr::getGradIPField(Tmag_field, "MFEM_gradip", 2);
sizefield = spr::getSPRSizeField(ipfield, adapt_ratio);
apf::destroyField(Tmag_field);
apf::destroyField(ipfield);
apf::destroyNumbering(pumi_mesh->findNumbering("LocalVertexNumbering"));
// 18. Perform MesAdapt.
ma::Input* erinput = ma::configure(pumi_mesh, sizefield);
erinput->shouldFixShape = true;
erinput->maximumIterations = 2;
if ( geom_order > 1)
{
crv::adapt(erinput);
}
else
{
ma::adapt(erinput);
}
ParMesh* Adapmesh = new ParPumiMesh(MPI_COMM_WORLD, pumi_mesh);
pPPmesh->UpdateMesh(Adapmesh);
delete Adapmesh;
// 19. Update the FiniteElementSpace, GridFunction, and bilinear form.
fespace->Update();
x.Update();
x = 0.0;
pPPmesh->FieldPUMItoMFEM(pumi_mesh, temp_field, &x);
a->Update();
b->Update();
// Destroy fields.
apf::destroyField(temp_field);
apf::destroyField(sizefield);
}
// 20. Free the used memory.
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete pmesh;
pumi_mesh->destroyNative();
apf::destroyMesh(pumi_mesh);
PCU_Comm_Free();
#ifdef MFEM_USE_SIMMETRIX
gmi_sim_stop();
Sim_unregisterAllKeys();
#endif
MPI_Finalize();
return 0;
}
+94
View File
@@ -0,0 +1,94 @@
# 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.
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/pumi/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
# All PUMI examples require MPI
SEQ_EXAMPLES =
PAR_EXAMPLES = ex1 ex1p ex2 ex6p
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
else
EXAMPLES = $(PAR_EXAMPLES) $(SEQ_EXAMPLES)
endif
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
# Remove built-in rule
%: %.cpp
# Replace the default implicit rule for *.cpp files
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
all: $(EXAMPLES)
ifeq ($(MFEM_USE_PUMI),NO)
$(EXAMPLES):
$(error MFEM is not configured with PUMI)
endif
MFEM_TESTS = EXAMPLES
include $(MFEM_TEST_MK)
ifneq (,$(filter test%,$(MAKECMDGOALS)))
ifeq (,$(wildcard ../../data/pumi))
$(info PUMI data directory not found. The PUMI tests will be SKIPPED.)
mfem-test = printf " $(3) [$(2) $(1) ... ]: "; $(PRINT_SKIP)
endif
endif
# Testing: Parallel vs. serial runs
RUN_MPI_NP = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP)
RUN_MPI = $(RUN_MPI_NP) $(MFEM_MPI_NP)
SERIAL_NAME := Serial PUMI example
PARALLEL_NAME := Parallel PUMI example
%-test-par: %
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME))
%-test-seq: %
@$(call mfem-test,$<,, $(SERIAL_NAME))
# Testing: Example-specific execution options:
ex1-test-par: ex1
@$(call mfem-test,$<, $(RUN_MPI_NP) 1, $(PARALLEL_NAME))
ex1p-test-par: ex1p
@$(call mfem-test,$<, $(RUN_MPI_NP) 8, $(PARALLEL_NAME))
ex2-test-par: ex2
@$(call mfem-test,$<, $(RUN_MPI_NP) 1, $(PARALLEL_NAME))
ex6p-test-par: ex6p
@$(call mfem-test,$<, $(RUN_MPI_NP) 8, $(PARALLEL_NAME))
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
# Generate an error message if the MFEM library is not built and exit
$(MFEM_LIB_FILE):
$(error The MFEM library is not built)
clean: clean-build clean-exec
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f refined.mesh sol.gf mesh.* sol.* displaced.mesh
+8 -7
View File
@@ -688,7 +688,7 @@ void BilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
else
#endif
{
if (A.Type() == Operator::MFEM_SPARSEMAT)
if (A.Type() == Operator::MFEM_SPARSEMAT || A.Type() == Operator::ANY_TYPE)
{
SparseMatrix A_sm;
FormLinearSystem(ess_tdof_list, x, b, A_sm, X, B, copy_interior);
@@ -724,7 +724,7 @@ void BilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
else
#endif
{
if (A.Type() == Operator::MFEM_SPARSEMAT)
if (A.Type() == Operator::MFEM_SPARSEMAT || A.Type() == Operator::ANY_TYPE)
{
SparseMatrix A_sm;
FormSystemMatrix(ess_tdof_list, A_sm);
@@ -847,7 +847,7 @@ void BilinearForm::ComputeElementMatrices()
}
void BilinearForm::EliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
Vector &sol, Vector &rhs,
const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy)
{
Array<int> ess_dofs, conf_ess_dofs;
@@ -899,7 +899,7 @@ void BilinearForm::EliminateEssentialBCDiag (const Array<int> &bdr_attr_is_ess,
}
void BilinearForm::EliminateVDofs(const Array<int> &vdofs,
Vector &sol, Vector &rhs,
const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy)
{
for (int i = 0; i < vdofs.Size(); i++)
@@ -939,7 +939,8 @@ void BilinearForm::EliminateVDofs(const Array<int> &vdofs,
}
void BilinearForm::EliminateEssentialBCFromDofs(
const Array<int> &ess_dofs, Vector &sol, Vector &rhs, DiagonalPolicy dpolicy)
const Array<int> &ess_dofs, const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy)
{
MFEM_ASSERT(ess_dofs.Size() == height, "incorrect dof Array size");
MFEM_ASSERT(sol.Size() == height, "incorrect sol Vector size");
@@ -1232,7 +1233,7 @@ void MixedBilinearForm::ConformingAssemble()
}
void MixedBilinearForm::EliminateTrialDofs (
Array<int> &bdr_attr_is_ess, Vector &sol, Vector &rhs )
Array<int> &bdr_attr_is_ess, const Vector &sol, Vector &rhs )
{
int i, j, k;
Array<int> tr_vdofs, cols_marker (trial_fes -> GetVSize());
@@ -1255,7 +1256,7 @@ void MixedBilinearForm::EliminateTrialDofs (
}
void MixedBilinearForm::EliminateEssentialBCFromTrialDofs (
Array<int> &marked_vdofs, Vector &sol, Vector &rhs)
Array<int> &marked_vdofs, const Vector &sol, Vector &rhs)
{
mat -> EliminateCols (marked_vdofs, &sol, &rhs);
}
+6 -6
View File
@@ -347,7 +347,7 @@ public:
essential DOFs is set to 1.0. This behavior is controlled by the argument
@a dpolicy. */
void EliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
Vector &sol, Vector &rhs,
const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy = DIAG_ONE);
/// Eliminate essential boundary DOFs from the system matrix.
@@ -358,7 +358,7 @@ public:
double value);
/// Eliminate the given @a vdofs. NOTE: here, @a vdofs is a list of DOFs.
void EliminateVDofs(const Array<int> &vdofs, Vector &sol, Vector &rhs,
void EliminateVDofs(const Array<int> &vdofs, const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy = DIAG_ONE);
/// Eliminate the given @a vdofs, storing the eliminated part internally.
@@ -369,10 +369,10 @@ public:
DiagonalPolicy dpolicy = DIAG_ONE);
/** @brief Similar to
EliminateVDofs(const Array<int> &, Vector &, Vector &, DiagonalPolicy)
EliminateVDofs(const Array<int> &, const Vector &, Vector &, DiagonalPolicy)
but here @a ess_dofs is a marker (boolean) array on all vector-dofs
(@a ess_dofs[i] < 0 is true). */
void EliminateEssentialBCFromDofs(const Array<int> &ess_dofs, Vector &sol,
void EliminateEssentialBCFromDofs(const Array<int> &ess_dofs, const Vector &sol,
Vector &rhs, DiagonalPolicy dpolicy = DIAG_ONE);
/** @brief Similar to EliminateVDofs(const Array<int> &, DiagonalPolicy) but
@@ -496,10 +496,10 @@ public:
void ConformingAssemble();
void EliminateTrialDofs(Array<int> &bdr_attr_is_ess,
Vector &sol, Vector &rhs);
const Vector &sol, Vector &rhs);
void EliminateEssentialBCFromTrialDofs(Array<int> &marked_vdofs,
Vector &sol, Vector &rhs);
const Vector &sol, Vector &rhs);
virtual void EliminateTestDofs(Array<int> &bdr_attr_is_ess);
+1
View File
@@ -1598,6 +1598,7 @@ void VectorCurlCurlIntegrator::AssembleElementMatrix(
ir = &IntRules.Get(el.GetGeomType(), order);
}
elmat.SetSize(dof*dim);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
+1 -1
View File
@@ -209,7 +209,7 @@ void VectorRestrictedCoefficient::Eval(
}
else
{
M.SetSize(vdim);
M.SetSize(vdim, ir.GetNPoints());
M = 0.0;
}
}
+32 -21
View File
@@ -304,32 +304,43 @@ ConduitDataCollection::BlueprintMeshToMesh(const Node &n_mesh,
if ( n_mesh_topo.has_child("boundary_topology") )
{
std::string bndry_topo_name = n_mesh_topo["boundary_topology"].as_string();
const Node &n_bndry_topo = n_mesh["topologies"][bndry_topo_name];
std::string bndry_ele_shape = n_bndry_topo["elements/shape"].as_string();
bndry_geo = ShapeNameToGeomType(bndry_ele_shape);
int num_idxs_per_bndry_ele = Geometry::NumVerts[mesh_geo];
// In VisIt, we encountered a case were a mesh specified a boundary
// topology, but the boundary topology was omitted from the blueprint
// index, so it's data could not be obtained.
//
// This guard prevents an error in that case, allowing the mesh to be
// created without boundary info
const Node &n_bndry_conn = n_bndry_topo["elements/connectivity"];
// mfem requires ints, we could have int64s, etc convert if necessary
if ( n_bndry_conn.dtype().is_int() &&
n_bndry_conn.is_compact())
if (n_mesh["topologies"].has_child(bndry_topo_name))
{
bndry_indices = n_bndry_conn.value();
}
else
{
Node &(n_bndry_conn_conv) =
n_conv["topologies"][bndry_topo_name]["elements/connectivity"];
n_bndry_conn.to_int_array(n_bndry_conn_conv);
bndry_indices = (n_bndry_conn_conv).value();
const Node &n_bndry_topo = n_mesh["topologies"][bndry_topo_name];
std::string bndry_ele_shape = n_bndry_topo["elements/shape"].as_string();
}
bndry_geo = ShapeNameToGeomType(bndry_ele_shape);
int num_idxs_per_bndry_ele = Geometry::NumVerts[mesh_geo];
num_bndry_ele =
n_bndry_topo["elements/connectivity"].dtype().number_of_elements();
num_bndry_ele = num_bndry_ele / num_idxs_per_bndry_ele;
const Node &n_bndry_conn = n_bndry_topo["elements/connectivity"];
// mfem requires ints, we could have int64s, etc convert if necessary
if ( n_bndry_conn.dtype().is_int() &&
n_bndry_conn.is_compact())
{
bndry_indices = n_bndry_conn.value();
}
else
{
Node &(n_bndry_conn_conv) =
n_conv["topologies"][bndry_topo_name]["elements/connectivity"];
n_bndry_conn.to_int_array(n_bndry_conn_conv);
bndry_indices = (n_bndry_conn_conv).value();
}
num_bndry_ele =
n_bndry_topo["elements/connectivity"].dtype().number_of_elements();
num_bndry_ele = num_bndry_ele / num_idxs_per_bndry_ele;
}
}
else
{
+49 -14
View File
@@ -10,6 +10,7 @@
// Software Foundation) version 2.1 dated February 1999.
#include "fem.hpp"
#include "../mesh/nurbs.hpp"
#include "../general/text.hpp"
#include "picojson.h"
@@ -331,6 +332,25 @@ DataCollection::~DataCollection()
// class VisItDataCollection implementation
void VisItDataCollection::UpdateMeshInfo()
{
if (mesh)
{
spatial_dim = mesh->SpaceDimension();
topo_dim = mesh->Dimension();
if (mesh->NURBSext)
{
visit_levels_of_detail =
std::max(visit_levels_of_detail, mesh->NURBSext->GetOrder());
}
}
else
{
spatial_dim = 0;
topo_dim = 0;
}
}
VisItDataCollection::VisItDataCollection(const std::string& collection_name,
Mesh *mesh)
: DataCollection(collection_name, mesh)
@@ -338,17 +358,10 @@ VisItDataCollection::VisItDataCollection(const std::string& collection_name,
appendRankToFileName = true; // always include rank in file names
cycle = 0; // always include cycle in directory names
if (mesh)
{
spatial_dim = mesh->SpaceDimension();
topo_dim = mesh->Dimension();
}
else
{
spatial_dim = 0;
topo_dim = 0;
}
visit_levels_of_detail = 1;
visit_max_levels_of_detail = 32;
UpdateMeshInfo();
}
#ifdef MFEM_USE_MPI
@@ -362,9 +375,11 @@ VisItDataCollection::VisItDataCollection(MPI_Comm comm,
MPI_Comm_size(comm, &num_procs);
appendRankToFileName = true; // always include rank in file names
cycle = 0; // always include cycle in directory names
spatial_dim = 0;
topo_dim = 0;
visit_levels_of_detail = 1;
visit_max_levels_of_detail = 32;
UpdateMeshInfo();
}
#endif
@@ -372,8 +387,7 @@ void VisItDataCollection::SetMesh(Mesh *new_mesh)
{
DataCollection::SetMesh(new_mesh);
appendRankToFileName = true;
spatial_dim = mesh->SpaceDimension();
topo_dim = mesh->Dimension();
UpdateMeshInfo();
}
#ifdef MFEM_USE_MPI
@@ -392,6 +406,26 @@ void VisItDataCollection::RegisterField(const std::string& name,
{
DataCollection::RegisterField(name, gf);
field_info_map[name] = VisItFieldInfo("nodes", gf->VectorDim());
int LOD = 1;
if (gf->FESpace()->GetNURBSext())
{
LOD = gf->FESpace()->GetNURBSext()->GetOrder();
}
else
{
for (int e=0; e<gf->FESpace()->GetNE() ; e++)
{
LOD = std::max(LOD,gf->FESpace()->GetFE(e)->GetOrder());
}
}
visit_levels_of_detail = std::max(visit_levels_of_detail, LOD);
}
void VisItDataCollection::SetLevelsOfDetail(int levels_of_detail)
{
visit_levels_of_detail = levels_of_detail;
}
void VisItDataCollection::SetMaxLevelsOfDetail(int max_levels_of_detail)
@@ -595,6 +629,7 @@ std::string VisItDataCollection::GetVisItRootString()
{
ftags["assoc"] = picojson::value((it->second).association);
ftags["comps"] = picojson::value(to_string((it->second).num_components));
ftags["lod"] = picojson::value(to_string(visit_levels_of_detail));
field["path"] = picojson::value(path_str + it->first + file_ext_format);
field["tags"] = picojson::value(ftags);
fields[it->first] = picojson::value(field);
+6
View File
@@ -398,6 +398,7 @@ protected:
// Additional data needed in the VisIt root file, which describes the mesh
// and all the fields in the collection
int spatial_dim, topo_dim;
int visit_levels_of_detail;
int visit_max_levels_of_detail;
std::map<std::string, VisItFieldInfo> field_info_map;
typedef std::map<std::string, VisItFieldInfo>::iterator FieldInfoMapIterator;
@@ -407,6 +408,8 @@ protected:
/// Read in a VisIt root file in JSON format
void ParseVisItRootString(const std::string& json);
void UpdateMeshInfo();
// Helper functions for Load()
void LoadVisItRootFile(const std::string& root_name);
void LoadMesh();
@@ -437,6 +440,9 @@ public:
/// Add a grid function to the collection and update the root file
virtual void RegisterField(const std::string& field_name, GridFunction *gf);
/// Set VisIt parameter: default levels of detail for the MultiresControl
void SetLevelsOfDetail(int levels_of_detail);
/// Set VisIt parameter: maximum levels of detail for the MultiresControl
void SetMaxLevelsOfDetail(int max_levels_of_detail);
+114
View File
@@ -6598,6 +6598,34 @@ void Poly_1D::CalcChebyshev(const int p, const double x, double *u, double *d)
}
}
void Poly_1D::CalcChebyshev(const int p, const double x, double *u, double *d,
double *dd)
{
// recursive definition, z in [-1,1]
// T_0(z) = 1, T_1(z) = z
// T_{n+1}(z) = 2*z*T_n(z) - T_{n-1}(z)
// T'_n(z) = n*U_{n-1}(z)
// U_0(z) = 1 U_1(z) = 2*z
// U_{n+1}(z) = 2*z*U_n(z) - U_{n-1}(z)
// U_n(z) = z*U_{n-1}(z) + T_n(z) = z*T'_n(z)/n + T_n(z)
// T'_{n+1}(z) = (n + 1)*(z*T'_n(z)/n + T_n(z))
// T''_{n+1}(z) = (n + 1)*(2*(n + 1)*T'_n(z) + z*T''_n(z)) / n
double z;
u[0] = 1.;
d[0] = 0.;
dd[0]= 0.;
if (p == 0) { return; }
u[1] = z = 2.*x - 1.;
d[1] = 2.;
dd[1] = 0;
for (int n = 1; n < p; n++)
{
u[n+1] = 2*z*u[n] - u[n-1];
d[n+1] = (n + 1)*(z*d[n]/n + 2*u[n]);
dd[n+1] = (n + 1)*(2.*(n + 1)*d[n] + z*dd[n])/n;
}
}
const double *Poly_1D::GetPoints(const int p, const int btype)
{
BasisType::Check(btype);
@@ -7463,8 +7491,12 @@ H1_TriangleElement::H1_TriangleElement(const int p, const int btype)
dshape_x.SetSize(p + 1);
dshape_y.SetSize(p + 1);
dshape_l.SetSize(p + 1);
ddshape_x.SetSize(p + 1);
ddshape_y.SetSize(p + 1);
ddshape_l.SetSize(p + 1);
u.SetSize(Dof);
du.SetSize(Dof, Dim);
ddu.SetSize(Dof, (Dim * (Dim + 1)) / 2 );
#else
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
#endif
@@ -7568,6 +7600,38 @@ void H1_TriangleElement::CalcDShape(const IntegrationPoint &ip,
Ti.Mult(du, dshape);
}
void H1_TriangleElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &ddshape) const
{
const int p = Order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1);
Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_l(p + 1);
DenseMatrix ddu(Dof, Dim);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x);
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y, ddshape_y);
poly1d.CalcBasis(p, 1. - ip.x - ip.y, shape_l, dshape_l, ddshape_l);
for (int o = 0, j = 0; j <= p; j++)
for (int i = 0; i + j <= p; i++)
{
int k = p - i - j;
// u_xx, u_xy, u_yy
ddu(o,0) = ((ddshape_x(i) * shape_l(k)) - 2. * (dshape_x(i) * dshape_l(k)) +
(shape_x(i) * ddshape_l(k))) * shape_y(j);
ddu(o,1) = (((shape_x(i) * ddshape_l(k)) - dshape_x(i) * dshape_l(k)) * shape_y(
j)) + (((dshape_x(i) * shape_l(k)) - (shape_x(i) * dshape_l(k))) * dshape_y(j));
ddu(o,2) = ((ddshape_y(j) * shape_l(k)) - 2. * (dshape_y(j) * dshape_l(k)) +
(shape_y(j) * ddshape_l(k))) * shape_x(i);
o++;
}
Ti.Mult(ddu, ddshape);
}
H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype)
: NodalFiniteElement(3, Geometry::TETRAHEDRON, ((p + 1)*(p + 2)*(p + 3))/6,
@@ -7584,8 +7648,13 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype)
dshape_y.SetSize(p + 1);
dshape_z.SetSize(p + 1);
dshape_l.SetSize(p + 1);
ddshape_x.SetSize(p + 1);
ddshape_y.SetSize(p + 1);
ddshape_z.SetSize(p + 1);
ddshape_l.SetSize(p + 1);
u.SetSize(Dof);
du.SetSize(Dof, Dim);
ddu.SetSize(Dof, (Dim * (Dim + 1)) / 2);
#else
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
#endif
@@ -7738,6 +7807,51 @@ void H1_TetrahedronElement::CalcDShape(const IntegrationPoint &ip,
Ti.Mult(du, dshape);
}
void H1_TetrahedronElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &ddshape) const
{
const int p = Order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1);
Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_z(p + 1), ddshape_l(p + 1);
DenseMatrix ddu(Dof, ((Dim + 1) * Dim) / 2);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x);
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y, ddshape_y);
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z, ddshape_z);
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z, shape_l, dshape_l, ddshape_l);
for (int o = 0, k = 0; k <= p; k++)
for (int j = 0; j + k <= p; j++)
for (int i = 0; i + j + k <= p; i++)
{
// u_xx, u_xy, u_xz, u_yy, u_yz, u_zz
int l = p - i - j - k;
ddu(o,0) = ((ddshape_x(i) * shape_l(l)) - 2. * (dshape_x(i) * dshape_l(l)) +
(shape_x(i) * ddshape_l(l))) * shape_y(j) * shape_z(k);
ddu(o,1) = ((dshape_y(j) * ((dshape_x(i) * shape_l(l)) -
(shape_x(i) * dshape_l(l)))) +
(shape_y(j) * ((ddshape_l(l) * shape_x(i)) -
(dshape_x(i) * dshape_l(l)))))* shape_z(k);
ddu(o,2) = ((dshape_z(k) * ((dshape_x(i) * shape_l(l)) -
(shape_x(i) * dshape_l(l)))) +
(shape_z(k) * ((ddshape_l(l) * shape_x(i)) -
(dshape_x(i) * dshape_l(l)))))* shape_y(j);
ddu(o,3) = ((ddshape_y(j) * shape_l(l)) - 2. * (dshape_y(j) * dshape_l(l)) +
(shape_y(j) * ddshape_l(l))) * shape_x(i) * shape_z(k);
ddu(o,4) = ((dshape_z(k) * ((dshape_y(j) * shape_l(l)) -
(shape_y(j)*dshape_l(l))) ) +
(shape_z(k)* ((ddshape_l(l)*shape_y(j)) -
(dshape_y(j) * dshape_l(l)) ) ) )* shape_x(i);
ddu(o,5) = ((ddshape_z(k) * shape_l(l)) - 2. * (dshape_z(k) * dshape_l(l)) +
(shape_z(k) * ddshape_l(l))) * shape_y(j) * shape_x(i);
o++;
}
Ti.Mult(ddu, ddshape);
}
H1Pos_TriangleElement::H1Pos_TriangleElement(const int p)
: PositiveFiniteElement(2, Geometry::TRIANGLE, ((p + 1)*(p + 2))/2, p,
+18 -2
View File
@@ -1564,6 +1564,8 @@ private:
static void CalcChebyshev(const int p, const double x, double *u);
static void CalcChebyshev(const int p, const double x, double *u, double *d);
static void CalcChebyshev(const int p, const double x, double *u, double *d,
double *dd);
QuadratureFunctions1D quad_func;
@@ -1618,6 +1620,14 @@ public:
// { CalcLegendre(p, x, u, d); }
{ CalcChebyshev(p, x, u, d); }
// Evaluate the values, derivatives and second derivatives of a hierarchical 1D basis at point x
static void CalcBasis(const int p, const double x, double *u, double *d,
double *dd)
// { CalcMono(p, x, u, d); }
// { CalcBernstein(p, x, u, d); }
// { CalcLegendre(p, x, u, d); }
{ CalcChebyshev(p, x, u, d, dd); }
// Evaluate a representation of a Delta function at point x
static double CalcDelta(const int p, const double x)
{ return pow(x, (double) p); }
@@ -1820,7 +1830,8 @@ class H1_TriangleElement : public NodalFiniteElement
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_l, dshape_x, dshape_y, dshape_l, u;
mutable DenseMatrix du;
mutable Vector ddshape_x, ddshape_y, ddshape_l;
mutable DenseMatrix du, ddu;
#endif
DenseMatrixInverse Ti;
@@ -1829,6 +1840,8 @@ public:
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &ddshape) const;
};
@@ -1838,7 +1851,8 @@ private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_z, shape_l;
mutable Vector dshape_x, dshape_y, dshape_z, dshape_l, u;
mutable DenseMatrix du;
mutable Vector ddshape_x, ddshape_y, ddshape_z, ddshape_l;
mutable DenseMatrix du, ddu;
#endif
DenseMatrixInverse Ti;
@@ -1848,6 +1862,8 @@ public:
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &ddshape) const;
};

Some files were not shown because too many files have changed in this diff Show More