Compare commits

..
Author SHA1 Message Date
camierjs 934f2b94e0 Merge branch 'master' into mdspan 2024-11-20 07:53:22 -08:00
Tzanio Kolev 302be130d1 Merge pull request #4592 from mfem/stale-action-update
Update to stale.yml to enable cache, on-demand dispatch, and higher rate limit
2024-11-15 15:24:57 -08:00
Mittal, Ketan 9d7696d803 update to stale.yml 2024-11-15 13:36:10 -08:00
Tzanio Kolev 1e0bb496e8 Merge pull request #4476 from mfem/hughcars/ncsubmesh-dev
SubMesh support for nonconformal AMR
2024-11-15 13:01:18 -08:00
Tzanio Kolev 81ee483d2a Merge pull request #4579 from mfem/fix-nvcc-warnings
Fix nvcc warnings
2024-11-13 10:01:07 -08:00
Tzanio Kolev 6eb86d9fbb Merge pull request #4588 from mfem/stale-action
Add stale.yml
2024-11-12 18:16:14 -08:00
Ketan Mittal 59f8bb30ef Merge branch 'master' into stale-action 2024-11-12 18:08:08 -08:00
Ketan MittalandTzanio Kolev 561b172a8b Update .github/workflows/stale.yml
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2024-11-12 18:03:46 -08:00
Tzanio Kolev b8547cb430 Merge pull request #4538 from mfem/cutint-1d-bug
Cutint 1d bug
2024-11-12 17:51:11 -08:00
Tzanio Kolev caf98db468 Merge pull request #4528 from mfem/sundials-v7-support
Add support for SUNDIALS v7
2024-11-12 17:11:49 -08:00
Mittal, Ketan 20cd0b2a9f remove old stale 2024-11-12 16:04:17 -08:00
Mittal, Ketan a2bbf76926 Merge branch 'master' of https://github.com/mfem/mfem into stale-action 2024-11-12 12:21:11 -08:00
Mittal, Ketan 109baa5448 update days-before-close 2024-11-12 12:20:17 -08:00
Will Pazner e6fb9d0ff9 Merge pull request #4548 from mfem/ParMatrixFrobeniusNorm
HypreParMatrix Frobenius Norm
2024-11-12 11:39:54 -08:00
Ketan Mittal 6a167c938f Add stale.yml 2024-11-12 11:04:23 -08:00
Tzanio Kolev a24370a2ed Merge pull request #4469 from mfem/setownership-arraycoeffs-dev
Add ownership getters + setters for Array-type coefficients
2024-11-10 15:19:28 -08:00
Tzanio Kolev 9a28ca5e6b Merge pull request #4539 from mfem/ncmesh-attr
Set NCMesh attributes
2024-11-10 15:18:21 -08:00
Tzanio Kolev 5a1d69837d Merge branch 'master' into hughcars/ncsubmesh-dev 2024-11-10 14:00:25 -08:00
Vladimir Z Tomov 7876439a7d Merge branch 'master' into cutint-1d-bug 2024-11-09 22:12:51 -08:00
Vladimir Z Tomov 64907e2ab1 Rearranged if-statements to avoid segfault. 2024-11-09 22:00:56 -08:00
Veselin Dobrev ee3f9fe97b Fix nvcc warnings 2024-11-09 16:47:12 -08:00
Veselin Dobrev 564e2ff58e Re-write a statement to work around an issue with gcc 8.3.1 2024-11-08 17:32:59 -08:00
Will Pazner 6105a4e1fa Merge pull request #4560 from mfem/vector-identity-interpolator
Vector identity interpolator
2024-11-05 10:45:42 -08:00
Tzanio Kolev 759ca48add Merge pull request #4408 from mfem/device-ho-lor-H1
Device HO to LOR Transfer
2024-11-04 15:59:50 -08:00
Arturo Vargas c214533826 mention device LOR-HO transfer capability in changelog 2024-11-04 14:52:54 -08:00
Hugh Carson 199f3616b6 Merge remote-tracking branch 'origin/master' into hughcars/ncsubmesh-dev 2024-11-04 10:28:45 -05:00
Hugh Carson 3b4825675b Updated CHANGELOG 2024-11-04 10:28:39 -05:00
Tzanio Kolev 8b8abfb611 Merge pull request #4436 from mfem/algoim_cut_integration_port
Algoim cut integration port
2024-11-03 10:21:57 -08:00
Tzanio Kolev 8989feda0d Merge pull request #4466 from mfem/col-der-kernel
Kernels to compute derivatives of gridfunctions with Lagrange interpolants on collocated points
2024-11-03 10:20:55 -08:00
Tzanio Kolev 784b74e1b3 Merge pull request #4523 from helloworld922/hip_uvm
Fixed support for HIP managed memory allocation/deallocation in the memory manager
2024-11-03 10:20:31 -08:00
Veselin Dobrev cea760b1e6 Fix a potential memory leak in class IdentityInterpolator
Reported-by: Will Pazner <pazner@users.noreply.github.com>
2024-11-01 19:11:43 -07:00
Veselin Dobrev 4b6e48e915 Merge branch 'master' into vector-identity-interpolator
Resolved conflicts and related edits:
   fem/bilininteg.hpp
2024-11-01 14:57:02 -07:00
Tucker Hartland 73efadce18 adding comment indicating that matrix data on host for the indicated hypre version 2024-11-01 14:47:40 -07:00
Veselin Dobrev ba9de3252b In class IdentityInterpolator, add support for vector dimension
(number of components) greater than 1. The case of PA is not
supported yet.

Class VectorIdentityInterpolator simply inherits from
IdentityInterpolator while requiring the vector dimension to
be set at construction.
2024-11-01 14:35:55 -07:00
Tucker HartlandandWill Pazner 9dc7331d9c Style update
Updating style as suggested by Will.

Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2024-11-01 10:25:04 -07:00
Tucker Hartland d5d2cbba19 computing FNorm without making use of the expensive hypre_MergeDiagAndOffd call. Summing local Frobenius norms of diag/offd components before a single all-to-all communication. 2024-11-01 08:57:07 -07:00
Veselin Dobrev db92a8950b In sundials.cpp, use a macro to switch between the prefixes ARKStep
and ARKode used in different SUNDIALS versions.
2024-10-31 18:31:13 -07:00
Tucker Hartland 2464a9d1ca adding a means to compute Frobenius norms when mfem is built with hypre version < 2.19.0 2024-10-31 15:21:55 -07:00
Veselin DobrevandChris Vogl f6db201a39 Apply reviewer suggestion
Co-authored-by: Chris Vogl <vogl2@llnl.gov>
2024-10-31 14:45:45 -07:00
Veselin Dobrev def4df1313 Merge branch 'master' into sundials-v7-support
Resolved conflicts:
   linalg/sundials.hpp
2024-10-31 14:31:54 -07:00
Veselin DobrevandWill Pazner c3ac1e2222 Apply reviewer suggestion
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2024-10-30 18:05:22 -07:00
Arturo Vargas 031f8ad04a convert more multi-dim loops to 1d loops 2024-10-30 14:15:22 -07:00
Hugh Carson 2cb4f5fd65 Merge remote-tracking branch 'origin/master' into hughcars/ncsubmesh-dev 2024-10-30 14:10:26 -04:00
Hugh Carson 9f708051da Address PR feedback
- Rename RemoveBoundaryElementToEdge to DeleteBoundaryElementToEdge
- Remove unneeded member variables `from` and `attributes` from NCSubMesh and ParNCSubMesh
2024-10-30 14:09:09 -04:00
Arturo Vargas 3a64973722 use 1D index instead of 3D to avoid thread block limits 2024-10-30 10:36:59 -07:00
Will Pazner 6cedf73dd5 Small style adjustments to HypreParMatrix::FNorm 2024-10-30 09:21:01 -07:00
Will Pazner bd6c2ab61a Change 3D thread block to 1D threading in EA LOR transfer
This kernel was requesting too many threads per block.

Since it doesn't use shared memory, there is no problem using a flat threading
strategy.
2024-10-29 21:30:12 -07:00
Will Pazner 1c90b1fd4f Ensure proper alias synchronization in EA LOR transfer 2024-10-29 21:16:37 -07:00
Will Pazner 41cc480ba8 Merge pull request #4555 from mfem/batched-mult-transpose
Batched mult transpose in LOR transfer
2024-10-29 15:10:21 -07:00
Will Pazner b1fc0a039f Use batched linear algebra in LOR transfer 2024-10-29 13:07:33 -07:00
Will Pazner a714c4e881 Fix signature of MixedMassEA 2024-10-29 12:55:48 -07:00
Will Pazner 8d189be921 Add DenseTensor::NewMemoryAndSize 2024-10-29 12:55:30 -07:00
Will Pazner 82b0035ba2 Add MultTranspose in batched linear algebra 2024-10-29 12:36:00 -07:00
Arturo Vargas a8db9de5a3 make memory type is now a method 2024-10-29 09:52:50 -07:00
Arturo Vargas c086d8362d removed unused var 2024-10-29 09:08:03 -07:00
Arturo Vargas cf78d5d9f5 clean up 2024-10-28 22:36:08 -07:00
Arturo Vargas 447d2ccd52 remove unused var 2024-10-28 22:27:59 -07:00
Arturo Vargas 323cd8a2ae clean up 2024-10-28 22:25:09 -07:00
Arturo Vargas cbb95d2a8e clean up pass and driver config 2024-10-28 22:08:51 -07:00
Arturo Vargas 1767d82a92 drivers 2024-10-28 21:54:05 -07:00
Arturo Vargas 4c33502069 remove error checking and introduce ea switch 2024-10-28 21:01:31 -07:00
blaz a74eed1083 Merge branch 'master' into algoim_cut_integration_port 2024-10-28 20:50:38 -07:00
Arturo Vargas 3de18c65ab ready to remove error checking routines 2024-10-28 20:12:35 -07:00
Arturo Vargas 8451125d53 remove dead code 2024-10-28 18:00:58 -07:00
Arturo Vargas d9c65990d2 Merge branch 'master' into device-ho-lor-H1 2024-10-28 17:54:20 -07:00
Arturo Vargas c1a796c60f decrease tol for testing 2024-10-28 17:54:06 -07:00
Arturo Vargas d7d0e802a0 remove coefficient usage 2024-10-28 17:41:40 -07:00
Vladimir Z Tomov dee95c1d72 improved the download / build / setup instructions. 2024-10-28 15:14:11 -07:00
Arturo Vargas 5099277778 increase solve tol 2024-10-28 14:28:06 -07:00
Arturo Vargas 3a9a131967 Merge branch 'device-ho-lor-H1' of github.com:mfem/mfem into device-ho-lor-H1 2024-10-28 14:26:46 -07:00
Arturo Vargas 4491140db5 reduce quad point calculation 2024-10-28 14:25:50 -07:00
Veselin Dobrev 17955e1140 Merge pull request #3480 from mfem/ab-am-refactor
New ode solver selection mechanism[ab-am-refactor]
2024-10-28 14:08:56 -07:00
Arturo VargasandAndrew Ho 89eb2213fc Update fem/transfer.cpp
Co-authored-by: Andrew Ho <ho37@llnl.gov>
2024-10-28 10:23:24 -07:00
Joseph Signorelli f4675033a9 Merge branch 'master' into setownership-arraycoeffs-dev 2024-10-28 11:01:55 -05:00
Joseph Signorelli 1662cbb045 remove ; 2024-10-28 11:01:31 -05:00
Tzanio Kolev d703c8c7a4 Merge branch 'master' into hip_uvm 2024-10-27 14:45:23 -07:00
Tzanio Kolev 2bac83dc34 Merge branch 'master' into ncmesh-attr 2024-10-26 18:30:21 -07:00
Veselin Dobrev e3c0420c09 In the CMake build system, skip the 'pmesh-fitting' test when
HYPRE is built with GPU support -- in that case the miniapp
returns MFEM_SKIP_RETURN_VALUE.
2024-10-25 16:07:17 -07:00
Tucker Hartland e46a3dc294 NormFro --> FNorm for consistency with DenseMatrix::FNorm 2024-10-25 11:20:17 -07:00
Tucker Hartland 7f2ee0b7c9 minor update 2024-10-25 10:10:09 -07:00
Tucker Hartland 324a86d4e7 adding a NormFro method to the HypreParMatrix class which is a wrapper of the hypre function hypre_PARCSRMatrixNormFro 2024-10-25 09:56:02 -07:00
Hugh Carson d7c3190a68 Restore public access of FindFaceNodes. Wrap another long method 2024-10-25 11:04:15 -04:00
Hugh Carson d98eb5b5a0 Fix long line not caught by ReWrap 2024-10-25 10:39:47 -04:00
Hugh Carson 14e5114039 Address PR feedback
- Fix doc typos: long line, extra spaces, apostrophes.
- Make FindFaceNodes protected again.
- Add doxygen descriptors to IntegerSet default constructors.
2024-10-25 10:36:23 -04:00
Arturo Vargas 235ab39d4a fix variable shadow issues 2024-10-24 12:56:06 -07:00
Arturo Vargas 55efebfa00 protected -> public when methods have kernels 2024-10-24 12:41:02 -07:00
Arturo Vargas fc13ff8f6c bug fixes 2024-10-23 16:22:31 -07:00
Arturo Vargas 08cf03fc7f need to to revisit batch linear alg usage 2024-10-23 14:58:33 -07:00
Arturo Vargas 3bb7ea788f use batch mult in more places 2024-10-23 13:57:22 -07:00
Arturo Vargas f1146c13b9 introduce make ref for dense tensor 2024-10-23 13:29:33 -07:00
Arturo Vargas 81fc677483 use CoefficientVector 2024-10-23 13:04:28 -07:00
Arturo Vargas 28f9bc4dd7 clean up 2024-10-22 15:54:37 -07:00
Arturo Vargas 1886e25382 clean up pass 2024-10-22 15:40:34 -07:00
Arturo Vargas e5cd8378dc clean up pass 2024-10-22 15:33:08 -07:00
Arturo Vargas be35149113 remove old function 2024-10-22 15:31:33 -07:00
Arturo Vargas 808560ba72 add documentation for UseDevice and VerifySolution 2024-10-22 12:57:04 -07:00
Arturo Vargas 30164b2db9 remove duplicate variables 2024-10-22 10:29:17 -07:00
Arturo Vargas feeebaacc1 clean up pass 2024-10-22 09:51:38 -07:00
Arturo Vargas ad46b5217f remove duplicate variables 2024-10-22 09:20:52 -07:00
Hugh Carson 854b2c5ed8 Merge remote-tracking branch 'origin/master' into hughcars/ncsubmesh-dev 2024-10-22 12:03:40 -04:00
Hugh Carson de70ec68cf Add MFEM_DEPRECATED to some backwards compatible methods 2024-10-22 12:03:22 -04:00
Arturo Vargas 7c37e06cd5 set tol through methods 2024-10-21 15:57:27 -07:00
Arturo VargasandVeselin Dobrev 0cdfebca48 Update fem/transfer.cpp
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2024-10-21 15:50:16 -07:00
Arturo Vargas 78ddcfee78 clean up 2024-10-21 15:48:45 -07:00
Arturo Vargas a92dc14745 revert public to protected 2024-10-21 15:19:25 -07:00
Arturo Vargas 718204a3c3 clean up pass 2024-10-21 15:16:01 -07:00
Arturo Vargas 569a756b11 clean up pass 2024-10-21 15:12:40 -07:00
Arturo Vargas 56381a3706 Merge branch 'device-ho-lor-H1' of github.com:mfem/mfem into device-ho-lor-H1 2024-10-21 15:01:18 -07:00
Arturo Vargas 645bf01441 clean up 2024-10-21 15:01:06 -07:00
Arturo VargasandWill Pazner 4eaa589c1f Update fem/transfer.hpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2024-10-21 14:59:41 -07:00
Arturo Vargas 6205ec2b12 use Reciprocal 2024-10-21 14:43:14 -07:00
Arturo Vargas 027681ff54 clean up pass 2024-10-21 14:28:09 -07:00
Arturo VargasandWill Pazner 4acd812daa Update linalg/batched/native.cpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2024-10-21 14:24:20 -07:00
Arturo VargasandWill Pazner a1024d3645 Update linalg/batched/native.cpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2024-10-21 14:13:25 -07:00
Arturo VargasandAndrew Ho 6df6f1f199 Update miniapps/tools/lor-transfer-p.cpp
Co-authored-by: Andrew Ho <ho37@llnl.gov>
2024-10-21 14:12:22 -07:00
Arturo VargasandWill Pazner 29d97f356e Update linalg/batched/native.cpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2024-10-21 14:09:30 -07:00
Arturo Vargas e91f98c2c1 Merge branch 'master' into device-ho-lor-H1 2024-10-21 14:08:38 -07:00
Arturo Vargas af9695d8f2 remove redundant namespace 2024-10-21 14:06:33 -07:00
Arturo Vargas f2f0b17d91 clean up pass 2024-10-21 13:58:57 -07:00
Veselin Dobrev 36f15e5784 Fix one more test failure when using HYPRE built with GPU + UVM
The fix uses a newly added constructor for HypreParVector that creates
an alias to existing Vector + offset.

Also, fix some doxygen comments.

This commit shouls also address issue #4351 (not tested yet).
2024-10-20 12:36:53 -07:00
Tzanio Kolev db1cb03562 Merge pull request #4510 from lindsayad/hypre-mixed-int
Compare PETSc 64bit int also with HYPRE_MIXEDINT
2024-10-19 15:52:00 -07:00
Tzanio Kolev b0cfba73ff Merge pull request #4461 from mfem/gslib-custom-interpolation-fix
bug-fix for custom interpolation utility with FindPointsGSLIB
2024-10-19 15:51:39 -07:00
Arturo Vargas 8ebcd5b6d3 fix precondioner 2024-10-18 17:12:36 -07:00
Veselin Dobrev 5c1d4f24a3 Fix test failures when using HYPRE built with GPU + UVM 2024-10-17 18:48:39 -07:00
Veselin Dobrev cf4e79b0e5 Bugfixes in MemoryManager::Copy* methods for the case of alias memory 2024-10-17 16:07:13 -07:00
Will Pazner d8a9621dd5 Fix sample runs with new ODE type integers
Also add type 6 for RK6
2024-10-16 21:59:22 -07:00
Arturo VargasandAndrew Ho 0c42c16022 Update miniapps/tools/lor-transfer-p.cpp
Co-authored-by: Andrew Ho <ho37@llnl.gov>
2024-10-16 17:00:20 -07:00
Arturo VargasandAndrew Ho 81f936aad5 Update miniapps/tools/lor-transfer-p.cpp
Co-authored-by: Andrew Ho <ho37@llnl.gov>
2024-10-15 16:39:08 -07:00
Arturo Vargas 5faf1e83bb Merge branch 'master' into device-ho-lor-H1 2024-10-15 09:11:57 -07:00
Dylan Copeland b0acea4560 Set NCMesh element attribute from Mesh::SetAttribute. 2024-10-14 18:42:37 -07:00
Tzanio Kolev 540c21c9e5 Merge pull request #4123 from mfem/najlkin/mixed-DG
D(P)G elements support in MixedBilinearForm
2024-10-14 18:03:19 -07:00
Tzanio Kolev 829af3b6d4 Merge branch 'master' into hip_uvm 2024-10-14 17:23:19 -07:00
Jan-Phillip Baecker:MAIL:TERMINAL:CLOUD dc142f33b4 Removed old code lines 2024-10-14 12:17:33 +02:00
J-Pi b9c143a3fe Merge branch 'master' into cutint-1d-bug 2024-10-14 10:47:12 +02:00
Jan-Phillip Baecker:MAIL:TERMINAL:CLOUD e15a3fabfc Fixed style 2024-10-14 10:34:49 +02:00
Jan-Phillip Baecker:MAIL:TERMINAL:CLOUD 7249c9dd22 fixed 1d bug 2024-10-14 10:05:05 +02:00
Hugh Carson bb1f48cc06 make style 2024-10-11 13:48:14 -04:00
Ketan Mittal bc13b805da Merge branch 'master' into gslib-custom-interpolation-fix 2024-10-11 10:42:59 -07:00
Hugh Carson b42f27fe48 Move another debug only variables inside of assert 2024-10-11 13:25:40 -04:00
Hugh Carson ee59eb5cc0 Move debug only variable inside of assert 2024-10-11 11:31:38 -04:00
Hugh Carson 6672424982 Unused variable warnings 2024-10-11 11:06:33 -04:00
Hugh Carson 449ae5e8c3 Fix bug where ncmesh would not discover new boundary attribute group 2024-10-11 10:56:28 -04:00
Will Pazner 7f962b0ee6 Remove need to call Opt<> when adding kernel specializations
If called without specifying optional template parameters (e.g. NBZ), they will
be default-constructed. This means kernels should handle the case of T_NBZ = 0
(and replace with NBZ = 1 or other suitable default value in that case).
2024-10-10 19:27:13 -07:00
Mittal, Ketan f0ca6327cc add kernel specialization to unit test 2024-10-10 17:20:40 -07:00
Will Pazner 82b0b3c9e5 Merge remote-tracking branch 'origin/master' into col-der-kernel
# Conflicts:
#	fem/qinterp/dispatch.hpp
#	fem/qinterp/grad_by_nodes.cpp
#	fem/qinterp/grad_by_vdim.cpp
#	fem/qinterp/grad_phys_by_nodes.cpp
#	fem/qinterp/grad_phys_by_vdim.cpp
2024-10-10 17:02:26 -07:00
Hugh Carson a130d17bc9 Merge remote-tracking branch 'origin/master' into hughcars/ncsubmesh-dev 2024-10-10 17:25:29 -04:00
Hugh Carson 445e41bb77 Tidy up and style fix 2024-10-10 17:24:51 -04:00
Hugh Carson 6c17447045 Fix triangle ambiguity by only labeling children after tree is finished. 2024-10-10 17:19:22 -04:00
Hugh Carson ada0e37801 Fix by only labeling non-ambiguous or central children 2024-10-09 17:00:52 -04:00
Hugh Carson 4cf617347f Handle the nodes in the case of center -> corner -> root. Non ambiguous paths now have the ability to reorganize all faces discovered. Not handling child reallocation correctly yet 2024-10-09 15:38:23 -04:00
Arturo Vargas a854669092 Merge branch 'master' into device-ho-lor-H1 2024-10-08 09:39:31 -07:00
Ido Akkerman 77f2bcb3af Also change the parallel case 2024-10-07 12:32:13 +02:00
Vladimir Z Tomov e58ec7d6e9 macro 2024-10-04 17:14:13 -07:00
Vladimir Z Tomov 7b5497868d minor 2024-10-04 16:51:47 -07:00
Vladimir Z Tomov f5e5f62194 style 2024-10-04 16:43:14 -07:00
Vladimir Z Tomov 8d6557fa59 minor 2024-10-04 16:23:33 -07:00
Vladimir Z Tomov 2c7f088dc7 surface Algoim integration in ex38. 2024-10-04 16:12:29 -07:00
Tzanio Kolev 11030265e2 Merge pull request #4480 from mfem/kinsol-options
Add Anderson acceleration and fixed point/Picard options
2024-10-04 15:52:48 -07:00
Vladimir Z Tomov 22a7948a1b volumetric Algoim in ex38. 2024-10-04 15:39:13 -07:00
Ido Akkerman 2aa283d3ec Correct default time integrator -- numbering changed 2024-10-04 18:19:25 +02:00
Ido Akkerman a6d067bc86 Try to fix ex10 bug 2024-10-04 17:20:20 +02:00
Ido Akkerman 9ddb323911 Make style 2024-10-04 16:27:36 +02:00
Ido Akkerman 3fba6c6c64 Add different mechanism for nuber of stages in ODE & Add a get function to statedata to accept blockvectors 2024-10-04 16:25:48 +02:00
Veselin Dobrev 2bbf2a757f Support SUNDIALS v7 when using CUDA or HIP 2024-10-03 05:28:56 -07:00
Veselin Dobrev 970521a17a To link properly with SUNDIALS v7, check for, and link with
libsundials_core.* when the file is present in the SUNDIALS lib
directory.
2024-10-03 03:24:24 -07:00
Vladimir Z Tomov a42ef2644e Added algoim as option in ex38. 2024-10-02 12:23:21 -07:00
Vladimir Z Tomov 4f69b9bca4 Merge branch 'master' into algoim_cut_integration_port 2024-10-02 11:28:30 -07:00
Veselin Dobrev 0a00d9f69b Doxygen fix 2024-10-01 13:15:15 -07:00
Veselin Dobrev 87298ef8e4 Fix for SUNDIALS < v6 2024-10-01 13:10:28 -07:00
Veselin Dobrev c9a11a7a5b Added support for SUNDIALS v7 2024-09-30 21:49:31 -07:00
Arturo Vargas 5d6d96b5b1 merge with master and fix conflicts 2024-09-28 20:47:49 -07:00
Andrew Ho 676a94dcc5 Added support for HIP managed memory to the memory manager 2024-09-27 14:04:45 -07:00
Jan Nikl 635026fc5f Fixed override in TransposeIntegrator. 2024-09-26 08:35:55 -07:00
Jan Nikl 2a85a72d19 Merge branch 'master' into najlkin/mixed-DG 2024-09-26 08:30:20 -07:00
Tzanio Kolev 8ed11a5c9a Merge pull request #4356 from mfem/najlkin/mixed-form-elim-dofs
Elimination of essential DOFs/BCs in MixedBilinearForm
2024-09-25 18:43:03 -07:00
Tzanio Kolev 0739640110 Merge pull request #3138 from mfem/dispatch-map
Runtime dispatch for SMEM GPU kernels
2024-09-25 18:42:12 -07:00
Tzanio Kolev 96ac1d9444 Merge pull request #4500 from mfem/vector-move
Fix memory leak in Vector move assignment
2024-09-25 18:41:38 -07:00
Tzanio Kolev 1e29890736 Merge pull request #4399 from mfem/override
Override specifier in virtual functions
2024-09-21 16:57:22 -07:00
Tzanio Kolev ecf167ca37 Merge branch 'master' into hughcars/ncsubmesh-dev 2024-09-21 16:22:15 -07:00
Tzanio Kolev 6c22a3a1ef Merge branch 'master' into override 2024-09-21 14:28:02 -07:00
Christopher vogl d6ae740c12 addressed style issues 2024-09-19 18:50:22 -07:00
cjvogl 8dc00bd3d0 added ex options check to avoid soft failures 2024-09-19 18:47:19 -07:00
cjvogl c9d87590fc refactored SUNDIALS examples to address bugs
- combined nls and nls-type for unified solver selection
- refactored HyperelasticOperator constructor with optional values for
  damping and AA
- avoiding setting JFNK for Picard iteration
- avoiding setting AA with 0 subspace
- avoiding setting damping unless user specified
2024-09-19 18:36:12 -07:00
cjvogl 04368ef95a propagated changed from SUNDIALS ex10p to ex10 2024-09-19 15:31:15 -07:00
Tzanio Kolev cfebb493c0 Merge pull request #4493 from mfem/stefanozampini/petsc-examples-init-device
Update petsc examples with missing device initializations
2024-09-19 07:41:53 -07:00
Tzanio Kolev af6cc43ad8 Merge pull request #4489 from mfem/print-mathematica-dev2
Adding PrintMathematica to dense linear algebra objects [print-mathematica-dev2]
2024-09-19 07:41:26 -07:00
Tzanio Kolev 3303e58921 Merge pull request #4448 from adam-sim-dev/remove-mesquitesmooth
Remove MesquiteSmooth which is not implemented
2024-09-19 07:41:03 -07:00
Alex Lindsay ea8fd50995 Compare PETSc 64bit int also with HYPRE_MIXEDINT 2024-09-16 21:37:22 -07:00
Arturo Vargas 24ed3a7fe2 Merge branch 'master' into device-ho-lor-H1 2024-09-16 09:14:48 -07:00
adam-sim-dev 192c4eeeea Merge branch 'master' into remove-mesquitesmooth 2024-09-16 20:25:31 +08:00
Arturo Vargas 3cedb47e7c fix style 2024-09-15 18:55:56 -07:00
Arturo Vargas c24baff0b9 use 2D for instead of 3D 2024-09-15 18:54:54 -07:00
Arturo Vargas 8bdd414658 true changes 2024-09-15 18:09:27 -07:00
Arturo Vargas d4b0014407 minor name change 2024-09-15 15:15:04 -07:00
Arturo Vargas e822520d5d revert back to master version 2024-09-15 15:11:23 -07:00
Arturo Vargas 4c952181c9 remove cout 2024-09-15 15:09:24 -07:00
Arturo Vargas 6d4f7570ad add timers to parallel driver 2024-09-15 15:07:46 -07:00
Tzanio Kolev 30bf4cae58 Merge pull request #4487 from mfem/cubit-reader-fix
Make reader comply with CUBIT output
2024-09-15 14:21:49 -07:00
Arturo Vargas 5d27d4c77f add timers to driver 2024-09-13 10:54:45 -07:00
Arturo Vargas e8a7f2136a build fixes and add helper methods 2024-09-13 10:01:44 -07:00
Hugh Carson 0432b1c47c Check for == -1 rather than < 0, rename variables 2024-09-13 10:25:30 -04:00
Arturo Vargas 167b591d01 remove old batch linear algebra header 2024-09-12 14:27:01 -07:00
Arturo Vargas 75452f6e30 remove intro example 2024-09-12 14:14:34 -07:00
Arturo Vargas 58bd809f87 integrate new batchlinear alg code 2024-09-12 14:12:46 -07:00
Hugh Carson 708a8d92f8 Fix Rewrap error + compile error from method definition 2024-09-12 15:17:42 -04:00
Hugh Carson f3add08ae3 Address MR feedback:
- Rewrapping to 80
- Forward some base methods to public access
- Restore some old implementation methods in terms of new versions
- Doyxgen and comment fixes
2024-09-12 14:14:07 -04:00
Will Pazner 542a72402c Fix memory leak in Vector move assignment 2024-09-11 20:32:16 -07:00
Arturo Vargas 96860ce2a6 Merge branch 'master' into device-ho-lor-H1 2024-09-11 10:25:56 -07:00
adam-sim-dev 344c72ad98 Merge branch 'master' into remove-mesquitesmooth 2024-09-11 15:17:27 +08:00
Tzanio Kolev cf530e9029 Merge branch 'master' into hughcars/ncsubmesh-dev 2024-09-10 12:23:40 -07:00
Will Pazner fb1a587206 Update CHANGELOG 2024-09-10 11:59:39 -07:00
Chris Vogl bd11106166 Revert changes to CVODESSolver::StepB 2024-09-10 11:55:49 -07:00
Will Pazner b2c53715e9 Runtime enable or disable fallback kernel reporting 2024-09-10 11:54:10 -07:00
Tzanio Kolev 957ca0d500 Merge pull request #4416 from mfem/build-bdr-dof-arr-dev
Add `FiniteElementSpace::BuildDofToBdrArrays()` and Minor Doc Clarification
2024-09-10 11:53:35 -07:00
dylan-copeland 20d8f980a5 Merge branch 'master' of github.com:mfem/mfem into override 2024-09-09 20:49:17 -07:00
dylan-copeland aeeddcb11e Fix a function in sundials. 2024-09-09 20:48:53 -07:00
Hugh Carson 2f6871e449 CI Fixes:
- Unused variables
- Memory leak
- Initialization order
- Remove std::vector usage
- Fix char index into arrays
- Early exit if an empty ncsubmesh is constructed
- Array list initalizer was hardcoded to int
- Remove anonynmous namespace from ncmesh_tables.hpp, use static and
  constexpr instead
- Remove unneeded table includes in ncsubmesh.cpp and pncsubmesh.cpp
- Move trivial type assertion of Array to class body from constructor
- Fix warning about use of abs over std::abs in batched linalg
- Add parent hashtable accessors to bypass access controls in parent
  classes.
- Change loop condition to avoid need for ncmesh_tables.hpp include
- Change [ParSubMesh] to [SubMesh] for Catch2 category, the parallel
  is implicit in [Parallel] label
- Missing include in mesh_test_utils.cpp
- Fix bug for array access with empty ncmesh
2024-09-09 15:10:25 -04:00
Hugh Carson 8a2ef8aa36 Refactor volume ncsubmesh to use same code on serial and parallel paths. Also fix documentation issues 2024-09-09 15:10:25 -04:00
Hugh Carson f0bc536820 Revert back to master some unneeded changes 2024-09-09 15:10:25 -04:00
Hugh Carson f052af3d6b Make style 2024-09-09 15:10:25 -04:00
Hugh Carson a3be873907 Make serial unit test copies of the parallel versions 2024-09-09 15:10:25 -04:00
Hugh Carson d0c358ab48 Refactor serial to use the same code branches as parallel for surface 2024-09-09 15:10:25 -04:00
Hugh Carson 982f7a1729 Refactor the surface submesh into a templated utils method. 2024-09-09 15:10:24 -04:00
Hugh Carson 96ef25817c Convenience addElement method 2024-09-09 15:10:24 -04:00
Hugh Carson 7f0e9c8801 Delete alternative older implementation 2024-09-09 15:10:24 -04:00
Hugh Carson f96f8af545 Upgrade the internal face boundary attribute test for NC refinement of the volume submesh 2024-09-09 15:10:24 -04:00
Hugh Carson 4edd730ce7 ghost boundary attributes mean volume tests are passsing 2024-09-09 15:10:24 -04:00
Hugh Carson 06955c17d9 Fix the boundary attributes of subvolume issue without using an RT space 2024-09-09 15:10:24 -04:00
Hugh Carson 06a8b35570 Comment out a lot of printing, will need to delete properly. Fix up VolumeSubMesh test to be more succinct 2024-09-09 15:10:24 -04:00
Hugh Carson 92ff8c744f Reprotect some members of NCMesh, make exposed derived for testing, make hex nonconformal volume testing ok 2024-09-09 15:10:24 -04:00
Hugh Carson c269b1ea54 More bug fixes and testing
- Fix bug for higher order meshes
- Fix bug with missing fields in NCMesh copy ctor.
- Fix test_array double -> int casting.
- Add test for Hex volume submesh
2024-09-09 15:10:24 -04:00
Hugh Carson cc70734bc0 Add initializer_list constructor to Array, and fix some more edge cases from testing 2024-09-09 15:10:24 -04:00
Hugh Carson 013eace8a6 Fix issue where parent triangular faces discovered by child 3 might disagree with child 0,1,2. If an outer child rediscovers the face the parent face will be reordered. 2024-09-09 15:10:24 -04:00
Hugh Carson 8237b9212d Abandoning interior surfaces, the resulting spaces are too ambiguous and the results don't warrant the extra effort 2024-09-09 15:10:24 -04:00
Hugh Carson 009837f4c8 Collection of bug fixes:
- Fix to permute children if a grandchild discovers a different face node ordering. Running out of tests
- Fix bug for triangle faces where central face parent nodes were not being identified correctly.
- Fix bug in ParentFaceNodes where a central triangle face would discover parent nodes with a different orientation to the surrounding faces.
- Fix bug where check was on parent_nodes rather than face_nodes for a second node hit
2024-09-09 15:10:24 -04:00
Hugh Carson b991cb755e Rewrite of the parallel data structure, complete ncmesh is now built doing a leaf to root tree traversal. The ordering is inherited from the parent ncmesh, ensuring all ranks build the correct ncmesh structure. Can handle external nc boundaries, can't handle internal yet due to face instability. 2024-09-09 15:10:24 -04:00
Hugh Carson 5e3359a805 Preliminary work on developing NCSubMesh
Many small features and a lot of really quite dirty code, print statements etc. This comes from squashing a large number of commits together.
A few different strategies were tried and failed (partially building the NC structure, having ranks have different NC etc.) before arriving at
the final reverse tree traversal algorithm.
2024-09-09 15:10:24 -04:00
Tzanio Kolev 596b76cee2 Merge branch 'master' into cubit-reader-fix 2024-09-09 11:55:15 -07:00
adam-sim-dev f8f04c9328 Merge branch 'master' into remove-mesquitesmooth 2024-09-09 08:22:01 +08:00
Tzanio Kolev 8555207d7b Merge pull request #4474 from tsokar/fix_tmop_fitting_bug
Fix uninitialized variables in pmesh-fitting
2024-09-08 15:36:09 -07:00
Stefano Zampini df87b22266 PETSc: Initialize device in examples
otherwise there will be mismatches in HYPRE and PETSc default devices for CUDA installs of MFEM
2024-09-08 14:19:48 +03:00
Stefano Zampini f57aa5a808 PETSc: fix Operator type conversion for device matrices
Add MATGENERIC to the supported operators for some operations
2024-09-08 09:56:58 +03:00
Stowell, Mark L ed256ff9a3 Removing special character from suggested Mathematica code 2024-09-05 18:03:27 -07:00
Stowell, Mark L dd127b07b5 Adding PrintMathematica to dense linear algebra objects 2024-09-05 18:02:15 -07:00
blaz df0c066e43 ALGOIM cut integration rules changes 2024-09-05 15:40:36 -07:00
Ketan Mittal 608ec13913 Merge branch 'master' into fix_tmop_fitting_bug 2024-09-05 12:29:00 -07:00
Ketan Mittal 8d01267e28 Merge branch 'master' into col-der-kernel 2024-09-05 12:26:44 -07:00
Julian Andrej b69059e79b fix sidesets too 2024-09-04 13:59:31 -07:00
Julian Andrej d6a4f0ae6c bug for bug implementation 2024-09-04 13:47:21 -07:00
Julian Andrej 0a9a48a9fc typo 2024-09-03 11:15:02 -07:00
Julian Andrej e0935aa66f remove rogue header include 2024-09-03 11:14:11 -07:00
Julian Andrej f56ef541cd remove comment 2024-09-03 11:09:51 -07:00
adam-sim-dev c5e02ba0cc Merge branch 'master' into remove-mesquitesmooth 2024-09-03 08:55:21 +08:00
Tzanio Kolev 3d43371e9d Merge pull request #4442 from mfem/bowen/miniapp-port
feature: make GLVis socket user-configurable in miniapps
2024-09-01 11:27:56 -07:00
Joseph SignorelliandJan Nikl 9c13b53522 Remove bdr attribute unnecessary setting
Co-authored-by: Jan Nikl <nikl1@llnl.gov>
2024-08-30 16:10:15 -05:00
Joseph Signorelli 83bd5a2f6c Correctly call base class function 2024-08-30 16:08:16 -05:00
Will Pazner 47de3415cf Internal namespace for Occa PA functions 2024-08-30 10:36:37 -07:00
Arturo Vargas 8130e46a06 merge with develop 2024-08-30 08:47:09 -07:00
Joseph Signorelli a80d35b387 Explicitly call FiniteElementSpace::GetEssentialVDofs 2024-08-29 11:33:50 -05:00
Joseph Signorelli b21b24b4cf Revert "debug commit"
This reverts commit 7a9ccc5dad.
2024-08-29 11:33:03 -05:00
Julian Andrej d13d2f0f7a add anderson acceleration and fixed point/picard options 2024-08-29 08:35:17 -07:00
Tzanio Kolev 5574298f29 Reverted commit_max_files_changed back to 50 2024-08-28 11:46:11 -07:00
Tzanio Kolev 8c09d9109c Adjusted CHANGELOG 2024-08-28 11:45:08 -07:00
john bowen 9cbb59b742 Formatting 2024-08-28 11:10:08 -07:00
Tzanio Kolev e5bbc170d3 Merge branch 'master' into dispatch-map 2024-08-28 10:51:40 -07:00
Joseph Signorelli 47ddbc4f67 Merge branch 'build-bdr-dof-arr-dev' of github.com:mfem/mfem into build-bdr-dof-arr-dev 2024-08-28 08:55:58 -05:00
Joseph Signorelli 4044514851 style 2024-08-28 08:55:52 -05:00
Joseph Signorelli 7a9ccc5dad debug commit 2024-08-28 08:55:34 -05:00
adam-sim-dev 60fc13dcaf Merge branch 'master' into remove-mesquitesmooth 2024-08-28 10:07:15 +08:00
Tzanio Kolev 20cb653eb3 Merge branch 'master' into build-bdr-dof-arr-dev 2024-08-27 17:04:18 -07:00
john bowen da8b01bcf1 Merge branch 'master' into bowen/miniapp-port 2024-08-27 14:44:04 -07:00
john bowen e4cfbc56d7 Add visport to declarations 2024-08-27 14:43:20 -07:00
Tzanio Kolev e50e54e090 Merge pull request #4283 from mfem/trigger-pymfem-ci
Add workflow for triggering pymfem CI
2024-08-27 13:00:45 -07:00
dylan-copeland db7072a5c4 Merge branch 'master' of github.com:mfem/mfem into override 2024-08-27 11:28:27 -07:00
Mittal, Ketan b82b7dc1a2 Merge branch 'master' of https://github.com/mfem/mfem into gslib-custom-interpolation-fix 2024-08-27 09:36:13 -07:00
Mittal, Ketan bb055a83c1 minor fix for L2 functions with points on faces 2024-08-27 09:35:52 -07:00
Tsokar 411ee5b1cf Update master 2024-08-27 17:29:16 +02:00
Tsokar fcc353b30c Initialize surf_fit_marker and surf_fit_mat_gf earlier 2024-08-27 17:25:44 +02:00
Tzanio Kolev b33a8d24ab Merge pull request #4453 from mfem/use-correct-bind
use ::bind instead of bind
2024-08-27 07:45:00 -07:00
Tsokar f1f98dd735 Fix uninitialized variables in pmesh-fitting 2024-08-27 08:46:37 +02:00
john bowen cc9885695b Merge branch 'master' into bowen/miniapp-port 2024-08-26 14:42:55 -07:00
john bowen d3a66a5887 Fix build issues 2024-08-26 14:39:23 -07:00
Tzanio Kolev e77d74aeef Merge branch 'master' into build-bdr-dof-arr-dev 2024-08-25 17:39:59 -07:00
Tzanio Kolev 723e8e656e Merge branch 'master' into remove-mesquitesmooth 2024-08-25 17:34:21 -07:00
Joseph Signorelli 93225fa096 Add ownership getters + setters for array coefficients 2024-08-23 10:57:18 -05:00
Mittal, Ketan 95c7b8b692 Merge branch 'master' of https://github.com/mfem/mfem into col-der-kernel 2024-08-22 15:57:28 -07:00
Joseph Signorelli fb1d72e453 style 2024-08-22 17:24:46 -05:00
Joseph SignorelliandJan Nikl af1bc97a77 Fix forgotten reference
Co-authored-by: Jan Nikl <nikl1@llnl.gov>
2024-08-22 17:23:17 -05:00
Joseph Signorelli 4fac872989 style 2024-08-22 17:07:55 -05:00
Joseph Signorelli 76e7693235 Compare against boundary LDofs with associated BE on its own rank only 2024-08-22 17:06:50 -05:00
Joseph Signorelli 39fd1c5dee Loop over all the LDofs, not the TDofs! 2024-08-22 15:21:43 -05:00
Joseph Signorelli fc802cbd6d Add continue to prevent segfaults. Separate element + bdr element checks. 2024-08-22 11:18:27 -05:00
Joseph Signorelli 61a49b8ca0 Fix MeshType::SEGMENT improperly setting bdr_attributes
Previous code used `Mesh::GenerateBoundaryElements()` followed by `Mesh::FinalizeTopology()`. This was preventing the ability to SetBdrAttributes for MeshType::SEGMENT
Fix is to instead just call `Mesh::FinalizeTopology(true)`.
2024-08-22 11:13:09 -05:00
Tzanio Kolev 0713dd34f0 Merge branch 'master' into build-bdr-dof-arr-dev 2024-08-21 08:28:51 -07:00
justinlaughlin 7d448fec3d undo change to bind on general/socketstream.cpp 2024-08-20 21:39:34 -07:00
justinlaughlin 88c0b0321c update isockstream.cpp to not use namespace std 2024-08-20 21:38:53 -07:00
Mittal, Ketan dddfd64c04 update unit test 2024-08-20 09:19:27 -07:00
Mittal, Ketan 3a03d25d8a fix for case when points_cnt = 0 2024-08-20 09:14:10 -07:00
Joseph Signorelli d303e35976 minor - fix failing test 2024-08-20 11:11:06 -05:00
Joseph Signorelli c34fc00644 style 2024-08-20 11:03:23 -05:00
Joseph Signorelli e71352e90e Implement parallel test 2024-08-20 11:03:01 -05:00
Joseph Signorelli 1d4f49acfb Include bdr dof check for serial. Renamed ldof variable to elemdof 2024-08-20 10:40:23 -05:00
john bowen ababf1aab3 Fix duplicated line 2024-08-19 10:53:41 -07:00
john bowen 0971513c89 Bump max number of files per branch 2024-08-19 10:45:28 -07:00
john bowen cef0828362 update changelog 2024-08-19 10:15:27 -07:00
john bowen 46cde14697 Merge branch 'master' into bowen/miniapp-port 2024-08-19 10:13:39 -07:00
justinlaughlin dd5963bd21 use ::bind instead of bind 2024-08-15 14:12:18 -07:00
Justin Laughlin e992d41a38 Merge branch 'master' into trigger-pymfem-ci 2024-08-14 15:27:22 -07:00
adam-sim-dev 2fad6d25b9 Remove MesquiteSmooth which is not implemented 2024-08-14 10:59:20 +08:00
dylan-copeland 898367b198 Merge branch 'master' of github.com:mfem/mfem into override 2024-08-13 19:24:59 -07:00
Joseph SignorelliandJan Nikl 104da453ed Update fem/fespace.hpp
Co-authored-by: Jan Nikl <nikl1@llnl.gov>
2024-08-13 13:22:52 -05:00
Mittal, Ketan 644e0540b1 Merge branch 'master' of https://github.com/mfem/mfem into col-der-kernel 2024-08-13 09:35:41 -07:00
Mittal, Ketan 4cbc97ae6b move permutation method to test 2024-08-13 09:35:13 -07:00
john bowen c82ce947d6 Reorder args 2024-08-12 16:14:48 -07:00
john bowen c8644c4b13 Reorder args 2024-08-12 15:56:29 -07:00
john bowen e680558010 Add command line args for glvis 2024-08-12 13:04:12 -07:00
john bowen 0c12c9298b Make visport user configurable for miniapps 2024-08-12 13:01:37 -07:00
Mittal, Ketan 00cccf157f minor fix and update unit test 2024-08-11 14:39:42 -07:00
Mittal, Ketan da8efca267 derivative kernels for Lagrange polynomials on collocated nodes 2024-08-11 12:35:57 -07:00
Justin Laughlin 16fc316ee6 Update trigger-pymfem-ci.yml - remove pull-request from triggers 2024-08-08 15:44:23 -07:00
Justin Laughlin fd195a0e8a Merge branch 'master' into trigger-pymfem-ci 2024-08-08 15:23:54 -07:00
Justin Laughlin 45f5d4bd72 Update trigger-pymfem-ci.yml
update target for POST, change input, and add trigger on push to master
2024-08-08 15:23:21 -07:00
bslazarov 347d5f3861 final before changes :-) 2024-08-08 15:06:14 -07:00
Joseph SignorelliandWill Pazner 3c886d0c76 Update fem/fespace.hpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2024-08-08 14:42:36 -05:00
Joseph Signorelli 4877bf12d1 Deprecate BuildDofToArrays, make build array fxns protected + automatic 2024-08-08 10:45:19 -05:00
Arturo Vargas 4a022b3393 Merge branch 'master' into device-ho-lor-H1 2024-08-07 11:44:30 -07:00
bslazarov db8304e311 algoim port 2024-08-06 16:21:24 -07:00
Joseph Signorelli 70941f93f0 Automatically build arrays on Get calls
- `Build` array fxns made const
- arrays declared as mutable
2024-08-06 17:04:19 -05:00
Joseph Signorelli f49ffcb99b Merge branch 'build-bdr-dof-arr-dev' of github.com:mfem/mfem into build-bdr-dof-arr-dev 2024-08-06 15:37:50 -05:00
Joseph Signorelli a076bd04cb Delete bdr dof arrays 2024-08-06 15:33:06 -05:00
Joseph Signorelli 095893d224 Merge branch 'master' into build-bdr-dof-arr-dev 2024-08-06 15:31:37 -05:00
blaz cf49036582 updated constructor 2024-08-05 23:03:15 -07:00
blaz 69b9e48cd6 port of Algoim Integration Rules 2024-08-05 22:51:05 -07:00
Will Pazner b023416c47 Use override specifier in more places
Identified using clang-tidy check 'modernize-use-override'
2024-08-05 09:45:46 -07:00
Arturo Vargas c786caef28 Merge branch 'master' into device-ho-lor-H1 2024-07-30 09:24:03 -07:00
Arturo Vargas 4abe31b237 clean up example 2024-07-29 17:00:31 -07:00
Arturo Vargas 2c723d8a21 fixup example 2024-07-29 16:56:40 -07:00
Arturo Vargas 9a742299b5 clean up code and fix error checking bug 2024-07-29 16:49:25 -07:00
Arturo Vargas 2b2b141281 remove dead code 2024-07-29 15:52:47 -07:00
Arturo Vargas e554d15416 delete old blas example 2024-07-29 15:46:41 -07:00
Arturo Vargas 1e19cc58d4 double -> real_t 2024-07-29 14:52:13 -07:00
Arturo Vargas 937390c63b clean up pass 2024-07-29 14:45:21 -07:00
Arturo Vargas 74f8617a9e remove variable shadowing 2024-07-29 14:42:14 -07:00
Arturo Vargas 77ee552475 remove shadow variable 2024-07-29 14:35:47 -07:00
Arturo Vargas efa4308b0c remove variable shadowing 2024-07-29 14:31:10 -07:00
Arturo Vargas 84caff9dd6 double -> real_t 2024-07-29 14:16:20 -07:00
Arturo Vargas 0d663eb13f remove variable shadowing 2024-07-29 14:12:20 -07:00
Arturo Vargas c1261461c5 double -> real_t 2024-07-29 14:03:49 -07:00
Arturo Vargas 256e513b02 double -> real_t 2024-07-29 14:01:03 -07:00
Arturo Vargas 9bf8f03d47 clean up pass 2024-07-29 13:52:22 -07:00
Arturo Vargas 45716da3e8 merge master and make style 2024-07-29 13:36:13 -07:00
Arturo Vargas 093be3733b make style 2024-07-29 13:16:43 -07:00
Arturo Vargas 7c6e4c48ae add missing header 2024-07-29 13:15:11 -07:00
Veselin Dobrev ac36c05f4b Fix typo 2024-07-26 16:10:45 -07:00
Veselin Dobrev 065c7dfd2b Add class VectorIdentityInterpolator 2024-07-26 15:08:46 -07:00
Arturo Vargas e8d76b6887 fix transfer fem spaces 2024-07-24 15:59:50 -07:00
Arturo Vargas f69981012a remove output 2024-07-24 15:55:20 -07:00
Arturo Vargas 2ebbe59aee revert cuda integration 2024-07-23 18:46:00 -07:00
Arturo Vargas bd7218a2e4 make style fixes 2024-07-23 15:14:43 -07:00
Arturo Vargas 8726340bc1 cuda cublas call not supported with 11.2 2024-07-23 13:09:35 -07:00
Arturo Vargas f0de5ade98 make function with lambda public 2024-07-23 12:47:35 -07:00
Arturo Vargas 77b88173b4 optimization pass for MPI version 2024-07-23 12:06:23 -07:00
Arturo Vargas bff6755a36 use mfem::out 2024-07-22 14:53:42 -07:00
Arturo Vargas b914196334 Merge branch 'master' into device-ho-lor-H1 2024-07-22 14:16:21 -07:00
dylan-copeland 661e2d3d2b Fixing some mistakes. 2024-07-19 17:14:46 -07:00
dylan-copeland 1c71292d7c Merge branch 'master' of github.com:mfem/mfem into override 2024-07-19 16:44:39 -07:00
dylan-copeland 0e7dc57fe5 A couple more files. 2024-07-19 16:43:50 -07:00
dylan-copeland 337ab968e1 Override for more header files, miniapps, and examples. 2024-07-19 16:38:03 -07:00
Joseph Signorelli 88f731cf32 Update docs 2024-07-19 15:02:16 -05:00
Joseph Signorelli f89885905c style 2024-07-19 14:49:58 -05:00
dylan-copeland 3bf5c6adad Override for files in linalg. 2024-07-19 12:19:56 -07:00
Joseph Signorelli def84fdd86 Add doftobdr arrays + minor documentation rephrase 2024-07-19 13:57:06 -05:00
dylan-copeland 565c2b800d Override for the remaining files in fem. 2024-07-19 11:10:00 -07:00
Christine Tseng 1b484707ab attempt of MassIntegrator replacement for lumped M_L and M_H build 2024-07-18 16:59:50 -07:00
Christine Tseng 72a520df8b clean up style, clean out unnecessary files 2024-07-18 13:57:17 -07:00
chrissytseng e44d7cdea7 Merge branch 'master' into device-ho-lor-H1 2024-07-18 13:12:26 -07:00
Christine Tseng 423edcc540 make style 2024-07-18 13:11:32 -07:00
Christine Tseng 9e71343031 commit backends.hpp 2024-07-17 15:32:36 -07:00
Christine Tseng 02194f6ecb made L2Projection public for mfem::forall; fixed dimension issue by initializing operator with scalar FES 2024-07-17 13:51:05 -07:00
Christine Tseng 09b0b3eacc edit coeff == nullptr case to set coeff = 1 2024-07-17 11:53:26 -07:00
Jan Nikl 0c91dba1bd Added verifies for SpMat(Elim)(). 2024-07-16 14:51:17 -07:00
Jan Nikl fce85e66a9 Removed virtual and added override in the whole DGTraceIntegrator. 2024-07-16 14:42:02 -07:00
Jan Nikl 6d5381cdd2 Removed virtualand added override to DGTraceIntegrator. 2024-07-16 14:33:46 -07:00
Christine Tseng 8bbf7a87c2 cleaned for intuitive naming; coeff set default to nullptr 2024-07-16 13:17:08 -07:00
Christine Tseng 432d290af5 fixed cases for building R in device H1Space; cleaned up 2024-07-15 16:50:51 -07:00
Christine Tseng a2ffe892c8 fixes for device H1Space parallel, including parallel driver 2024-07-15 16:03:43 -07:00
Christine Tseng ab8e18be26 added device H1Space parallel 2024-07-15 16:00:18 -07:00
dylan-copeland 5d6ca8b560 Fix for -Winconsistent-missing-override. 2024-07-12 21:10:43 -07:00
Dylan Copeland cc22712539 Override for some files in fem. 2024-07-12 19:49:00 -07:00
Dylan Copeland 6fbe2c2280 Override for remaining files in fem/fe. 2024-07-12 18:51:09 -07:00
Dylan Copeland 65b3cb157a Adding override specifier to virtual functions. 2024-07-12 12:05:29 -07:00
Christine Tseng 84b49f507a added compatibility for MFEM_USE_MPI for rank 1 2024-07-11 09:16:17 -07:00
Christine Tseng 7aa36f82d9 added H1Space device Restriction Operator class 2024-07-03 15:49:05 -07:00
Christine Tseng 5032ec9d7d cleaned up for less memory and computation 2024-07-02 15:33:20 -07:00
Christine Tseng 1c655cbdc5 Added preconditioner for H1Space Device prolongation operator - significant reductions to CGsolver iterations 2024-07-02 14:52:50 -07:00
Christine Tseng 170ebdc372 Added H1Space Device Prolong and Prolong Transpose 2024-07-01 16:45:46 -07:00
Christine Tseng b2c45912f7 added preliminary set up of P operator 2024-06-28 16:17:06 -07:00
Christine Tseng b758c68930 added H1 MultTranspose; cleaned up classes; R is ready for merge 2024-06-27 13:36:32 -07:00
Christine Tseng 5067891393 Added QuadCoeffFunc on inv(lumped M_L) and mixed mass element assembly for device 2024-06-27 12:15:28 -07:00
Will Pazner ffce41001e Suppress Doxygen warnings 2024-06-27 09:27:58 -07:00
Will Pazner 5724e4f274 Improve kernel dispatch mechanism and workaround MSVC issues
Introduce some workarounds for MSVC:

- Need to expand variadic macros explicitly
- Adjacent parameter packs in function templates not supported; use nested
  structs instead
- Can't use default parameters in template definition if not present in
  declaration

Some improvements to the kernel dispatch:

- Run is now a static member function (don't need to call Get)
- DIM is not treated differently from the other parameters
2024-06-27 09:27:58 -07:00
Will Pazner e189b0b0f0 Fix deprecated implicit cast warning 2024-06-26 16:12:42 -07:00
Will Pazner 11badb5d2f Workaround for gcc bug with variadic template parameter packs 2024-06-26 16:09:07 -07:00
Will Pazner 39e3854585 Remove extra semicolon, include <cstddef> 2024-06-26 15:57:55 -07:00
Will Pazner c271ac1eda Fix MFEM_REGISTER_KERNELS macro warnings
Fixes the warnings:

must specify at least one argument for '...' parameter of variadic macro
[-Werror,-Wgnu-zero-variadic-macro-arguments]

and

extra ';' inside a class [-Werror,-Wextra-semi]
2024-06-26 15:27:29 -07:00
Will Pazner ed8ce36e96 Use regular comments instead of Doxygen for MFEM_REGISTER_KERNELS macro 2024-06-26 15:26:46 -07:00
john bowen 66c71dd4f2 Merge branch 'dispatch-map-v2' into dispatch-map 2024-06-26 14:42:27 -07:00
Will Pazner 635c487665 Simplify kernel dispatch macro 2024-06-26 11:42:24 -07:00
Will Pazner 90c995f0e6 Add mechanism for reporting kernel fallbacks 2024-06-26 11:25:47 -07:00
Will Pazner 9d3ce2c394 Add headers to fem/CMakeLists.txt 2024-06-26 11:25:04 -07:00
Jan Nikl 6fd27950ed Revert "Added support of mixed elements to the non-linear form integrator."
This reverts commit 736f0aca8a.
2024-06-26 08:46:33 -07:00
Will Pazner 185b2bba58 Kernel dispatch for non-tensor eval kernels 2024-06-25 22:12:54 -07:00
Christine Tseng 297877bbef including transfer docs for Device Mult for H1 2024-06-25 16:35:07 -07:00
Christine Tseng f0e9b0b55f Added DeviceMult for H1 Space, missing QuadCoeffFunction ability on lumped(inv M_L) 2024-06-25 16:22:09 -07:00
Will Pazner 93e6be67d3 Doxygen documentation for dispatch map 2024-06-25 15:24:17 -07:00
Will Pazner 7a4ab004c2 Add Det kernel specializations 2024-06-25 15:11:11 -07:00
Will Pazner 467cc941f3 Fix to QuadratureInterpolator in H(div) linear solver 2024-06-25 15:06:22 -07:00
Will Pazner 5a5d9cfe77 Split QuadratureInterpolator kernel instantiations into multiple translation units 2024-06-25 15:05:48 -07:00
Will Pazner 998b531fe5 Rework NBZ kernel dispatch, add Det QuadratureInterpolator kernels 2024-06-25 14:39:00 -07:00
Will Pazner c33327f234 Bring back NBZ in QuadratureInterpolator 2024-06-25 13:29:56 -07:00
Will Pazner e60145110d QuadratureInterpolator kernel specializations 2024-06-25 13:03:04 -07:00
Will Pazner 5f04684f17 Bring back NBZ in mass and diffusion kernels 2024-06-25 12:48:48 -07:00
Will Pazner a3065a05dc Rename MFEM_DECLARE_KERNELS to MFEM_REGISTER_KERNELS 2024-06-25 11:06:21 -07:00
Will Pazner ede448d783 Unify kernel dispatch with and without fallback parameters 2024-06-25 11:05:36 -07:00
Will Pazner 2e0df87cd6 Use dispatch mechanism in QuadratureInterpolator 2024-06-24 21:57:07 -07:00
Will Pazner 5ec854e9e4 Rearrange parameters in kernel dispatch 2024-06-24 21:48:07 -07:00
Will Pazner 842c68b0b5 Proof of concept for dispatch with QuadratureInterpolator 2024-06-24 16:38:43 -07:00
Will Pazner c3806304d4 More simplifications 2024-06-24 15:50:12 -07:00
Will Pazner a092f9cad0 Small adjustments 2024-06-24 14:38:41 -07:00
Will Pazner 17eb65d619 Some suggestions for dispatch map 2024-06-24 13:47:01 -07:00
john bowen 75567ae1ef remove NBZ as a kernel parameter 2024-06-21 11:22:07 -07:00
john bowen c18e27aeac Merge branch 'master' into dispatch-map 2024-06-20 10:06:08 -07:00
john bowen 3d84777b69 Simplify kernel specialization class boilerplate using a macro. 2024-06-20 10:03:05 -07:00
Christine Tseng 69bfdf44c7 fix use_device if-statement under L2Space MultTranspose from DeviceMult to DeviceMultTranspose 2024-06-18 11:03:22 -07:00
Christine Tseng acd07bc6bd added QuadratureFunctionCoefficient; examples of coefficient implementation in lor-transfer.cpp driver 2024-06-18 10:32:35 -07:00
Christine Tseng 6a21cb7eba added QuadratureFunctionCoefficient for weighted integrals 2024-06-18 09:59:51 -07:00
john bowen cb6d48f499 Simplify Run method in kernel dispatch 2024-06-13 15:18:33 -07:00
Jan Nikl f135f662e7 Replaced depracated method MixedBilinearForm::EliminateTrialDofs(). 2024-06-13 11:40:41 -07:00
Jan Nikl 9ca87d3ecf Fixed shadowing in MixedBilinearForm. 2024-06-13 11:27:33 -07:00
Jan Nikl 10b9503528 Removed some extra spaces in MixedBilinearForm. 2024-06-13 11:03:10 -07:00
Jan Nikl 0572181086 Improved docstring in MixedBilinearForm. 2024-06-13 10:58:38 -07:00
Jan Nikl 8c58872ec8 Fixed math in bilinearform. 2024-06-13 10:39:28 -07:00
Jan Nikl df5b718f16 Added dof/bc elimination methods to MixedBilinearForm. 2024-06-13 10:39:15 -07:00
john bowen 01dfecd67e Fix unit test failures 2024-06-13 09:40:43 -07:00
john bowen f387244e57 Update kernel dispatch to support QuadratureInterpolator 2024-06-12 13:21:20 -07:00
Jan Nikl ce0d89397b Changed the allocation of empty matrices in BilinearForm::Compute*Matrix(). 2024-06-10 15:18:28 -07:00
Jan Nikl c2cc36e559 Changed the allocation of empty matrices in MixedBilinearForm::Compute*Matrix(). 2024-06-10 15:12:50 -07:00
Jan Nikl 305124eaaf Removed extra space in TransposeIntegrator. 2024-06-10 14:47:58 -07:00
Jan Nikl e30950f349 Fixed 'a' to 'an' in docstring of BilinearForm::AddInteriorFaceIntegrator(). 2024-06-10 14:22:49 -07:00
Jan Nikl 254ade218b Removed some extra spaces in bilinearform.cpp. 2024-06-10 14:17:41 -07:00
Christine Tseng 8d78dcaf9e vendor calls on batched mult in batchlinalg.cpp done; driver blas.cpp is for checks 2024-06-07 14:01:16 -07:00
IdoAkkerman a69e1c69ef Fix unittest 2024-05-31 17:31:18 +02:00
IdoAkkerman 4bafc17358 Rename out -> os 2024-05-31 16:54:30 +02:00
IdoAkkerman dfcb153e52 Remove unnecessary Get routine 2024-05-31 16:49:30 +02:00
IdoAkkerman eea4386fcf Merge branch 'master' into ab-am-refactor 2024-05-31 13:48:41 +02:00
john bowen 7b84f6ddc6 Merge branch 'master' into dispatch-map 2024-05-30 08:19:05 -07:00
Jan Nikl 22653aaf6e Revert "Fixed short circruiting."
This reverts commit 43dd9549f4.
2024-05-24 09:15:26 -07:00
Jan Nikl c6a3ccba0b Renamed Compute*FaceElementMatrix() methods to just Compute*FaceMatrix() to be more consistent. 2024-05-23 10:31:57 -07:00
Jan Nikl 755206a2d3 Added a note about ignored integrators. 2024-05-23 10:28:29 -07:00
Jan Nikl 43dd9549f4 Fixed short circruiting. 2024-05-23 10:19:40 -07:00
Ido Akkerman ebc27b9511 Merge branch 'master' into ab-am-refactor 2024-05-21 11:02:36 +02:00
Jan Nikl 1c17415be3 Changed double to real_t in DGTraceIntegrator::AssembleFaceMatrix(). 2024-05-20 09:38:33 -07:00
Jan Nikl eaed96dae0 Merge branch 'master' into najlkin/mixed-DG 2024-05-20 09:34:44 -07:00
Arturo Vargas da07b29b6d add missing cmake files 2024-05-14 16:38:50 -07:00
Arturo Vargas 0942a818ca Merge branch 'master' into artv3/device-ho-lor 2024-05-14 16:05:22 -07:00
tomov2 959b07ce39 wip 1D bug moments-based integration. 2024-05-09 11:59:17 -07:00
Justin Laughlin badd444b9f add pull_request to triggers so it will show up 2024-05-07 17:55:33 -07:00
Justin Laughlin a3ce8974f6 add input to workflow_dispatch 2024-05-07 17:53:19 -07:00
Justin Laughlin f33a4ced53 Merge remote-tracking branch 'origin/master' into trigger-pymfem-ci 2024-05-07 17:48:16 -07:00
Arturo Vargas ddb518df90 clean up pass 2024-05-07 16:50:17 -07:00
Arturo Vargas 84575c6423 remove unused variables 2024-05-07 10:44:46 -07:00
Arturo Vargas 5e6727225b make style 2024-05-07 10:02:21 -07:00
Arturo Vargas 5c8dae8e8e fix constructor ordering 2024-05-07 10:00:01 -07:00
Arturo Vargas aa9886365f minor clean up 2024-05-06 13:25:23 -07:00
Arturo Vargas 38e48d89b1 fix name space issue 2024-05-06 13:14:30 -07:00
Arturo Vargas 64e2b26824 double -> real_t 2024-05-06 10:23:35 -07:00
Arturo Vargas 3137379e1d clean up pass 2024-05-06 10:16:13 -07:00
Arturo Vargas 901a85abf2 minor 2024-05-06 10:13:04 -07:00
Justin Laughlin 78fff76695 change ref to master, and remove inputs for now (until pymfem workflow is updated) 2024-05-03 21:06:26 -07:00
Justin Laughlin 947310138e refresh action 2024-05-03 21:02:54 -07:00
Justin Laughlin 1d939a207a change target repo to pymfem 2024-05-03 20:27:45 -07:00
Justin Laughlin 3a5d89a6fb need to add pull_request to triggers so it will show up as an action 2024-05-03 20:19:16 -07:00
Justin Laughlin c0cc3eb976 add workflow for triggering pymfem CI 2024-05-03 18:45:19 -07:00
Arturo Vargas aaf861460e transition by calling use device 2024-05-01 14:47:15 -07:00
Arturo Vargas 19500f3c0b Merge branch 'artv3/device-ho-lor' of github.com:mfem/mfem into artv3/device-ho-lor 2024-05-01 13:45:04 -07:00
Arturo Vargas 3f359156ed add temporary type 2024-05-01 13:44:53 -07:00
Arturo VargasandTom Stitt 67372245c4 Update linalg/batchlinalg.cpp
Co-authored-by: Tom Stitt <stitt4@llnl.gov>
2024-05-01 13:30:15 -07:00
Arturo Vargas 074f28ccba move macros to backends.hpp 2024-05-01 13:26:59 -07:00
Arturo Vargas 76cbcfd3be clean up pass 2024-04-30 11:40:03 -07:00
Arturo Vargas 48a170c57d NE -> len / general clean up 2024-04-30 11:37:01 -07:00
Arturo Vargas 782b0266f2 name change DeleteDevice_ ->ReleaseDeviceMemory 2024-04-04 15:59:26 -07:00
Arturo Vargas 7bd7f08fe9 LibBatchSolver -> BatchSolver 2024-04-04 14:59:51 -07:00
IdoAkkerman c2dc013de5 Fix merge error 2024-04-04 22:09:41 +02:00
Arturo VargasandTom Stitt 208f36f354 Update linalg/densemat.cpp
Co-authored-by: Tom Stitt <stitt4@llnl.gov>
2024-04-04 09:54:36 -07:00
Arturo VargasandTom Stitt 3a4fe0bfe7 Update linalg/batchlinalg.cpp
Co-authored-by: Tom Stitt <stitt4@llnl.gov>
2024-04-04 09:54:28 -07:00
IdoAkkerman 4230779792 Merge branch 'master' into ab-am-refactor 2024-04-04 14:05:24 +02:00
IdoAkkerman 7a4bd3fb51 Non-const Get and rename Append 2024-04-04 13:59:49 +02:00
IdoAkkerman 9e0f9cabc0 Merge branch 'master' into ab-am-refactor 2024-04-03 12:17:41 +02:00
IdoAkkerman b8a5c6e1a6 Fix 2 lines between class implementation 2024-04-03 12:06:08 +02:00
IdoAkkerman d168ea86ec Correct typo 2024-04-03 12:02:15 +02:00
IdoAkkerman 60b4414fd9 Added changes/additions to changelog 2024-04-03 11:54:56 +02:00
IdoAkkerman 59ec6ace17 Default Get implemented in ODEstate base class 2024-04-03 11:13:38 +02:00
IdoAkkerman 521b044d61 formatting ode2 message 2024-04-03 11:00:31 +02:00
IdoAkkerman 852da98c50 Changed ASSERT to range macro 2024-04-03 10:47:04 +02:00
IdoAkkerman 03904a8bb0 change argument name 2024-04-03 10:46:31 +02:00
IdoAkkerman 3cf792a66b Add dox to headerfile 2024-04-03 10:42:21 +02:00
IdoAkkerman 6bdaa12c88 Remove explicit function name from assert 2024-04-03 10:41:58 +02:00
IdoAkkerman 6787428ae8 Remove dox -- correct error messages 2024-04-03 10:40:52 +02:00
Ido AkkermanandVeselin Dobrev 68a9a070a5 Update linalg/ode.cpp
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2024-04-03 10:34:24 +02:00
IdoAkkerman 12927b36f0 Make style 2024-04-02 17:00:45 +02:00
IdoAkkerman 43533b51d5 Merge branch 'master' into ab-am-refactor 2024-04-02 16:58:57 +02:00
john bowen 5f083cea48 Remove ubuntu cmake build error 2024-03-27 16:56:25 -07:00
john bowen 80e29c8950 Delete use of sizeof... due to msvc incompatability. 2024-03-27 16:34:34 -07:00
john bowen 7264091c6f Fix mac build 2024-03-27 16:12:12 -07:00
john bowen 33c0df349d fix makefile build 2024-03-27 14:59:13 -07:00
john bowen d3015edb40 Delete double usage 2024-03-27 14:18:55 -07:00
john bowen 927c7f82be Merge branch 'master' into dispatch-map 2024-03-27 14:13:17 -07:00
john bowen 008dda250b Fix unit tests 2024-03-27 14:08:54 -07:00
john bowen a6b00aacbf Merge branch 'master' into dispatch-map 2024-03-21 12:23:59 -07:00
john bowen 504ae95915 fix ld error 2024-03-21 12:23:26 -07:00
Arturo Vargas cfbedc494a fix formatting 2024-03-19 13:40:42 -07:00
john bowen 5d28b67295 copyright 2024-03-19 13:06:20 -07:00
john bowen b19800f1a7 Workaround for GCC limitation on class method non-type variadic pack deduction 2024-03-19 13:04:44 -07:00
Arturo Vargas 1b1d9ca272 clean up pass 2024-03-19 10:52:05 -07:00
john bowen e96dc7e4aa copyright 2024-03-07 10:59:20 -08:00
john bowen 3a113dcdd6 Merge branch 'master' into dispatch-map 2024-03-07 10:44:09 -08:00
john bowen 6a6d7eb83c Astyle 2024-03-07 10:43:50 -08:00
john bowen 8a0e295691 Delete occa merge artifact 2024-03-05 09:57:20 -08:00
john bowen 3386418737 Fixing build issues 2024-03-01 13:03:51 -08:00
john bowen 2f09777b17 tmp 2024-02-29 12:35:06 -08:00
john bowen 12842aa9e1 Tmp: Add non type parameter packs to generalize AddSpecialization API 2024-02-15 10:02:44 -08:00
Jan Nikl 3388132bc3 Added const qualifiers to the Compute(Bdr)FaceElementMatrix() methods of MixedBilinearForm. 2024-02-08 11:52:54 -08:00
Jan Nikl 1dedc55a42 Added MixedBilinearForm::Get(B)FBFI methods. 2024-02-08 11:43:16 -08:00
Jan Nikl fd6ac545fa Added MixedBilinearForm::Compute(Bdr)FaceElementMatrix(). 2024-02-08 11:42:06 -08:00
Jan Nikl 736f0aca8a Added support of mixed elements to the non-linear form integrator. 2024-02-08 11:38:24 -08:00
Jan Nikl cdc9127ed6 Added mixed boundary face integrators to MixedBilinearForm. 2024-02-08 11:37:26 -08:00
Jan Nikl cdbca8beb2 Added support of integral finite elements to DGTraceIntegrator for the mixed form. 2024-02-08 11:36:07 -08:00
Jan Nikl bffd75c0da Added mixed DG support to DGTraceIntegrator. 2024-02-08 11:35:34 -08:00
Jan Nikl 1b5ae7461b Added interior face integrators for mixed forms. 2024-02-08 11:33:42 -08:00
john bowen b07ff3f5db Merge branch 'master' into dispatch-map 2024-02-08 09:34:15 -08:00
john bowen b86fdfb46c Add clangd files to gitignore 2024-01-30 10:56:05 -08:00
john bowen 50905e0dcb Copyright 2024-01-30 10:55:15 -08:00
john bowen 9702811d72 Fix linker errors 2024-01-16 17:28:47 -08:00
john bowen 955fe9f9df Merge branch 'master' into dispatch-map 2024-01-16 14:44:06 -08:00
john bowen 97e4f45be3 astyle format 2024-01-16 14:43:30 -08:00
john bowen 60242d41bd Fix makefile build error 2024-01-16 14:33:40 -08:00
john bowen 1fb47dab6b Cleanup following rebase 2024-01-16 13:35:46 -08:00
john bowen cd671cae3e tmp 2024-01-03 13:58:12 -08:00
john bowen c2154f95fe Merge branch 'master' into dispatch-map 2024-01-02 13:14:48 -08:00
Ido Akkerman b48574391e Merge pull request #4041 from mfem/ab-am-refactor-unique-ptr
Use unique_ptr in PR #3480
2023-12-21 09:25:07 +01:00
Will Pazner cd6919ce29 Return unique_ptr from ODESolver::Select (and others) 2023-12-19 12:24:34 -08:00
Will Pazner 15f7f9dd1a Merge remote-tracking branch 'origin/master' into ab-am-refactor 2023-12-19 12:24:18 -08:00
Ido AkkermanandWill Pazner 2305d501db Apply suggestions from code review
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2023-12-11 13:34:23 +01:00
IdoAkkerman e125207781 Merge branch 'master' into ab-am-refactor 2023-12-04 14:26:50 +01:00
IdoAkkerman 8701290a72 Small compile fix -- unusaed variable 2023-12-04 14:26:17 +01:00
IdoAkkerman 35e3930fd7 Refactor ode test -- split with and without restart 2023-12-04 13:15:25 +01:00
IdoAkkerman f5cf13076b Merge branch 'master' into ab-am-refactor 2023-11-29 11:33:55 +01:00
IdoAkkerman 2bb6c55d66 Move object and add comments 2023-11-29 11:33:22 +01:00
IdoAkkerman 08085843db Merge remote-tracking branch 'origin/ab-am-refactor-suggestion' into ab-am-refactor 2023-11-29 11:05:34 +01:00
IdoAkkerman 3123099784 Remove superfluous nullptr init 2023-11-29 10:35:08 +01:00
Christopher vogl 4e3df5a144 indentation adjustment for code style 2023-11-21 19:33:23 -08:00
Christopher vogl 6baa0e29db added missing 'override' discovered by clang 2023-11-21 19:31:29 -08:00
Christopher vogl 612b7aa4f7 added curly brackets to appease code style 2023-11-21 19:27:37 -08:00
Christopher vogl 80702006f2 updated test_ode to use new ODESolverWithStates class 2023-11-21 19:25:30 -08:00
Christopher vogl 6ac7f61224 introduced ODESolverWithStates interface and moved GetState from ODESolver 2023-11-21 19:24:49 -08:00
Christopher vogl 098063f588 introduced ODEStateData interface and renamed ODEStateData to ODEStateDataVector 2023-11-21 19:23:52 -08:00
IdoAkkerman c76b58fb12 Merge branch 'ab-am-refactor' of https://github.com/mfem/mfem into ab-am-refactor 2023-11-21 11:10:40 +01:00
IdoAkkerman 4849471dc2 Changed ABORT comment 2023-11-21 10:52:31 +01:00
Ido Akkerman 4c57ba72a6 Merge branch 'master' into ab-am-refactor 2023-11-21 10:01:56 +01:00
IdoAkkerman 0a44db4850 Add clang include 2023-11-20 17:15:07 +01:00
IdoAkkerman 04691f4c16 Add comments 2023-11-20 17:11:17 +01:00
IdoAkkerman 3e1aec8bf8 Rename data and members of ODEStateData, also different access from ODESolver 2023-11-20 16:51:58 +01:00
IdoAkkerman ab71be1272 Make style 2023-11-20 15:43:02 +01:00
IdoAkkerman d7352fbfd4 Merge branch 'ab-am-refactor' of https://github.com/mfem/mfem into ab-am-refactor 2023-11-20 15:41:08 +01:00
IdoAkkerman ab7028ed7e Use ABORT instead of error 2 2023-11-20 15:25:27 +01:00
IdoAkkerman 793dd5e4c2 Use ABORT instead of error 2023-11-20 15:24:41 +01:00
IdoAkkerman 3920872a08 Rename State, add const and use 2023-11-20 15:22:35 +01:00
IdoAkkerman 94fd002fab Rename StateData, add ODE 2023-11-20 14:53:08 +01:00
Ido Akkerman 282e5b1a3d Merge branch 'master' into ab-am-refactor 2023-11-06 09:36:14 +01:00
IdoAkkerman f49f007eda Small ubuntu fix 2023-11-03 10:13:39 +01:00
IdoAkkerman a2943f213f Make style 2023-11-03 09:59:04 +01:00
IdoAkkerman 9c35bfbfda Mem leak fix 2023-11-03 09:53:03 +01:00
IdoAkkerman e488fc158d Small macos fixes 2023-11-03 09:39:14 +01:00
IdoAkkerman 1d194da30d Merge branch 'master' into ab-am-refactor 2023-11-02 16:16:28 +01:00
Ido Akkerman 77d3c64a0d Add state to ODE2 2023-11-02 14:21:50 +01:00
Ido Akkerman cd0ef98f79 Fix potential sequence error 2023-11-02 13:55:03 +01:00
Ido Akkerman fcb853fd6c Add memtype statement 2023-11-02 13:50:10 +01:00
Ido Akkerman 5416209e9d Gen-Alpha also using statedata 2023-11-02 13:44:47 +01:00
Ido Akkerman 448a395e5b AB + AM works -- GA not 2023-11-02 13:36:42 +01:00
Ido Akkerman baacaa9726 State moved to ODESolver 2023-11-02 12:05:03 +01:00
Ido Akkerman 6fa0fb9efd Style + remove timecheck function 2023-11-02 10:17:49 +01:00
Ido Akkerman f5580dd673 Also let AM use the state class 2023-11-01 10:52:55 +01:00
Ido Akkerman 4d7c1c959f Add state class to ode 2023-11-01 10:29:43 +01:00
Ido Akkerman 3c4e2a65a6 Fix small typo 2023-11-01 10:29:16 +01:00
camierjs 9c51412156 Merge master in mdspan 2023-08-29 08:30:49 -07:00
Tzanio Kolev 1cfbc0b1bb Merge branch 'master' into mdspan 2023-06-24 14:43:25 -07:00
camierjs bd56e90473 [mdspan] Test case sections rename 2023-05-15 09:37:01 -07:00
camierjs a0682753a4 Merge master in mdspan 2023-05-14 09:50:44 -07:00
camierjs 97990ae027 Merge master in mdspan 2023-05-08 14:31:56 -07:00
camierjs 7369d788cb Merge master in mdspan 2023-05-04 08:56:13 -07:00
camierjs b8c7313496 Merge master in mdspan 2023-05-03 14:13:09 -07:00
camierjs ea352b71ba Use mfem::forall_3D 2023-04-26 10:11:37 -07:00
camierjs 1b7ca16ce1 Merge master in mdspan 2023-04-26 09:57:56 -07:00
camierjs 4008b3534a Update fem/CMakeLists.txt 2023-04-24 15:16:31 -07:00
camierjs 9d9949ca28 Update CMakeLists 2023-04-24 15:11:19 -07:00
camierjs ed954237ef Add fem/mdgridfunc.hpp, general/mdarray.hpp and linalg/mdvector.hpp 2023-04-24 15:04:27 -07:00
camierjs 24ef091537 make style 2023-04-24 15:03:20 -07:00
camierjs 34e6be463e Update base MDSpan class to protected MFEM derived one and create MDArray, MDVector and MDGridfunction classes 2023-04-24 15:00:20 -07:00
camierjs acc18720f2 make style 2023-04-18 15:11:46 -07:00
camierjs 5d3b0e656c Merge master in mdspan 2023-04-18 13:31:17 -07:00
camierjs a727d9052c Merge master in mdspan 2023-04-18 10:37:22 -07:00
camierjs fce1e105fe Merge master in mdspan 2023-04-17 08:12:37 -07:00
camierjs e117a21117 Merge master in mdspan 2023-04-14 07:54:31 -07:00
camierjs 81daf02d20 Merge master in mdspan 2023-04-11 07:55:25 -07:00
camierjs 53c40fcdce Merge master in mdspan 2023-04-10 08:34:03 -07:00
camierjs a7f97c469b Update with missing const in MDRead 2023-04-06 11:31:00 -07:00
Ido Akkerman 3c53fbf767 Fixed ode solver index changes 2023-03-31 11:37:01 +02:00
Ido Akkerman 68b0c3c55f Resolved merge conflicts 2023-03-31 11:36:38 +02:00
Ido Akkerman 3fb8003f06 Fix static 2023-03-31 09:48:33 +02:00
Tzanio Kolev dc0f236629 Merge branch 'master' into mdspan 2023-03-30 11:51:37 -07:00
Ido Akkerman 830eebd35e Remove tmp files 2023-03-30 15:06:35 +02:00
camierjs abd3e78ab1 mdspan test direct layout set 2023-03-27 11:24:12 -07:00
Ido Akkerman e36aaf91ed Mult or Step choice 2023-03-27 16:54:38 +02:00
Ido Akkerman 29e2b929f4 make style 2023-03-27 12:00:01 +02:00
Ido Akkerman 932b7dfa81 Change second order Type string 2023-03-27 11:59:22 +02:00
Ido Akkerman 36464a6ea5 Small fixes 2023-03-27 11:55:20 +02:00
Ido Akkerman 5c88b180e9 Avoid Mult to start second order integrators 2023-03-27 11:49:48 +02:00
Ido Akkerman b9e6521123 Fix windows error 2023-03-27 11:44:20 +02:00
Ido Akkerman 1f564b2674 Split implicit and explicit solvers in selection routine 2023-03-27 10:52:14 +02:00
Ido Akkerman 53e85b8bf4 Merge branch 'ab-am-refactor' of https://github.com/mfem/mfem into ab-am-refactor 2023-03-27 09:07:36 +02:00
Ido Akkerman 2a797169aa Fix include statement to be relative 2023-03-27 09:07:08 +02:00
camierjs 1479cd6001 Merge master in mdspan 2023-03-26 09:04:18 -07:00
camierjs adabfbc465 _WIN32 include order fix 2023-03-26 08:45:38 -07:00
camierjs de0113b01f Define WIN32 USE_MATH_DEFINES 2023-03-26 08:23:22 -07:00
camierjs a688e8fa6a mdspan tests MSVC include fix 2023-03-25 20:14:42 -07:00
camierjs 9a13525047 Documentation & style 2023-03-25 18:07:00 -07:00
camierjs e83bd2cc55 mdspan general header and unit tests 2023-03-25 15:31:58 -07:00
Ido Akkerman 98f7556b21 Merge branch 'master' into ab-am-refactor 2023-03-24 09:20:23 +01:00
Ido Akkerman e185360c24 Merge master manually 2023-03-23 15:28:51 +01:00
Ido Akkerman 66cff6eeb4 Add comment regarding ownership 2023-03-23 12:15:19 +01:00
Ido AkkermanandChris Vogl a400c72ab6 Fix error message
Co-authored-by: Chris Vogl <vogl2@llnl.gov>
2023-03-23 10:02:18 +01:00
Ido AkkermanandChris Vogl 27b920d975 Fix error message
Co-authored-by: Chris Vogl <vogl2@llnl.gov>
2023-03-23 10:01:52 +01:00
Ido AkkermanandChris Vogl 058ad32dd9 Update linalg/ode.cpp
Fix error message

Co-authored-by: Chris Vogl <vogl2@llnl.gov>
2023-03-23 10:01:24 +01:00
Ido Akkerman c0476063a2 Merge branch 'master' into ab-am-refactor 2023-03-07 10:37:50 +01:00
Ido Akkerman 53f203ee79 fixing includes 2023-03-06 08:51:01 +01:00
Ido Akkerman 85f8b9b07f check if root every time 2023-03-06 08:27:43 +01:00
Ido Akkerman 336b82fafe Use order for RK selection 2023-02-23 12:48:15 +01:00
Ido Akkerman 222945b705 Modified stage handling for AM. Removed AM0, as it no longer works, and is redudant with BackwardEuler 2023-02-23 12:33:05 +01:00
Ido Akkerman 4d7e19e5e7 Add RK6 and RK8 unit tests. Routines and coefficients needed to change 2023-02-23 12:31:28 +01:00
Ido Akkerman 87d20a162c Fic conflicts 2023-02-23 10:54:55 +01:00
Ido Akkerman 8e1b422b61 Make compiler happy? 2023-02-22 09:05:02 +01:00
Ido Akkerman 965d8f7d4b Make compiler happy? 2023-02-21 17:56:32 +01:00
Ido Akkerman 470479f17a Make compiler happy? 2023-02-21 17:53:29 +01:00
Ido Akkerman fe8bd7c1bd Modify examples to use ODE selection machinery 2023-02-21 17:42:03 +01:00
Ido Akkerman 9314475e22 Adding LMS class and selector function 2023-02-21 17:41:12 +01:00
Ido Akkerman f5687330c7 Add timestep check. Flush history when step changes 2023-02-17 17:20:58 +01:00
Will Pazner f907191e58 Remove unneeded MassIntegrator member functions 2022-11-30 09:24:55 -08:00
Will Pazner 62a00562de Merge remote-tracking branch 'origin/master' into dispatch-map
# Conflicts:
#	fem/bilininteg_mass_pa.cpp
#	fem/bilininteg_mass_pa.hpp
2022-11-30 09:10:52 -08:00
Will Pazner 3316d89c63 Use 0 for default NBZ in kernel dispatch unless T::NBZ is defined 2022-11-30 09:00:28 -08:00
Will Pazner 6bf590c3ee Mass kernel dispatch 2022-11-29 21:05:43 -08:00
Will Pazner 78bf9951e3 Kernel dispatch WIP 2022-11-29 16:32:21 -08:00
Will Pazner 532060a646 Add generic dispatch table for PA kernels 2022-08-18 09:43:32 -07:00
Will Pazner 59f76ced6a Rename AddApplySpecialization to AddSpecialization 2022-08-10 21:40:56 -05:00
Will Pazner 0c2766ee76 Add dispatch table for DiffusionIntegrator::AssembleDiagonalPA 2022-08-10 16:40:19 -05:00
Will Pazner a90df38643 Calculate NBZ with constexpr pow 2022-08-10 14:15:50 -05:00
Will Pazner 407741b8e3 Add NBZ to DiffusionIntegrator kernel specialization 2022-08-10 12:32:32 -05:00
Will Pazner 3859678772 Runtime dispatch for specialized DiffusionIntegrator kernels 2022-08-10 12:10:04 -05:00
366 changed files with 14531 additions and 23886 deletions
-61
View File
@@ -1,61 +0,0 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 30
# Number of days of inactivity before an Issue or Pull Request with the stale
# label is closed. Set to false to disable. If disabled, issues still need to
# be closed manually, but will remain marked as stale.
daysUntilClose: 7
# Only issues or pull requests with all of these labels are check if stale.
# Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set
# to `[]` to disable
exemptLabels:
- bug
- WIP
- ready-for-review
- in-review
- in-next
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
:warning: This issue or PR has been automatically marked as stale because it has not
had any activity in the last month. *If no activity occurs in the next week, it will
be automatically closed.* Thank you for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.
# issues:
# exemptLabels:
# - confirmed
+31
View File
@@ -0,0 +1,31 @@
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
# For more information, see: https://github.com/actions/stale
name: Mark stale issues and pull requests
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
actions: write
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: ':warning: This issue has been automatically marked as stale because it has not had any activity in the last month. *If no activity occurs in the next week, it will be automatically closed.* Thank you for your contributions.'
stale-pr-message: ':warning: This PR has been automatically marked as stale because it has not had any activity in the last month. *If no activity occurs in the next week, it will be automatically closed.* Thank you for your contributions.'
days-before-stale: 30
days-before-close: 7
stale-issue-label: 'stale'
stale-pr-label: 'stale'
operations-per-run: 500
exempt-issue-labels: "bug,WIP,ready-for-review,in-review,in-next"
exempt-pr-labels: "bug,WIP,ready-for-review,in-review,in-next"
+31
View File
@@ -0,0 +1,31 @@
# Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
name: "Trigger PyMFEM CI"
on:
push:
branches:
- master
jobs:
trigger-pymfem:
runs-on: ubuntu-latest
steps:
- name: Send POST request to trigger PyMFEM CI
run: |
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.PYMFEM_CI_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/mfem/pymfem/actions/workflows/build-and-test-dispatch.yml/dispatches \
-d '{"ref":"master", "inputs":{"test_options":"fast"}}'
+3
View File
@@ -15,6 +15,9 @@
CMakeCache.txt
CMakeFiles/
# Clangd server cache
*.cache*
# Backup files
*~
+47
View File
@@ -10,6 +10,8 @@
Version 4.7.1 (development)
===========================
- Refactored ALGOIM cut integration rules. The interface is unified with
the interface for moment based cut integration rules.
Discretization improvements
---------------------------
@@ -18,6 +20,8 @@ Discretization improvements
- Added support for boundary constraints to the hybridization class.
- Added support for external boundary submeshes with nonconformal mesh adaptation.
Meshing improvements
--------------------
- The ExodusII reader now handles pyramid and wedge element types. Mixed meshes
@@ -30,13 +34,35 @@ New and updated examples and miniapps
- Added an MFEM example for the eikonal equation. This new solver is based on
the proximal Galerkin method introduced by Keith and Surowiec.
- Added a command line option to all miniapps (`-p` or `--send-port`) for
specifying the GLVis server socket port (19916 by default).
GPU computing
-------------
- Added support for GPU-accelerated batched linear algebra (using cuBLAS,
hipBLAS, MAGMA, or native MFEM functionality) through the BatchedLinAlg class.
- A new GPU kernel dispatch mechanism was introduced. Users can instantiate
specialized kernels for specific combinations of (for example) polynomial
degree and number of quadrature points using
`DiffusionIntegrator::AddSpecialization` and
`MassIntegrator::AddSpecialization` (this functionality may be added to more
integrators in the future).
- Calls to slower fallback kernels can be reported to `mfem::err` by setting
the environment variable `MFEM_REPORT_KERNELS` to any value other than `NO`
or by explicitly calling `KernelReporter::Enable`. Users can then add
specializations for these kernels to achieve higher performance.
- Element assembly kernels have been added for low-order refined to
high-order transfer operators. New kernels can be offloaded as device
kernels. Example usage may be found in lor-transfer.cpp under miniapps/tools.
Miscellaneous
-------------
- Added support for SUNDIALS v7. See the section "API changes" for some small
changes related to this new version.
- Refactored the `ARKStepSolver` class (ARKODE interface) to use
`TimeDependentOperator::Mult` only when the associated ODE operator is
expressed in explicit form (i.e., `TimeDependentOperator::isExplicit()`),
@@ -53,6 +79,18 @@ API changes
-----------
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
- API change: support for SUNDIALS v7:
* the SUNDIALS types `realtype` and `booleantype` are no longer defined by v7
and therefore MFEM now uses the new type names `sunrealtype` and
`sunbooleantype`, respectively, which MFEM defines when using SUNDIALS < v6
where these types were not defined.
* The SUNDIALS macro `SUNLS_SUCCESS` and some other `*_SUCCESS` macros were
removed and replaced by `SUN_SUCCESS` in v7, so to avoid tedious checks for
SUNDIALS versions, MFEM now defines and uses the constant `SUN_SUCCESS` when
using SUNDIALS < v7.
* The constants `SUN_PREC_*`, introduced by SUNDIALS v6 are now introduced by
MFEM when using SUNDIALS < v6 to avoid tedious version checks.
Version 4.7, released on May 7, 2024
====================================
@@ -139,6 +177,15 @@ New and updated examples and miniapps
- Added two new example codes: 38 and 39/39p described above. Substantially
updated Example 18/18p.
- Added ODE solvers selection routines. This creates a uniformity across examples,
miniapps and other executables in regard to ODE(time-integrator) selection.
- Added new mechanism for retrieving and setting state vectors in ODE solvers.
This is relevant for AB/AM and gen-alpha solvers.
- Added ODEsolver/ODEsolver2 unit tests to verify order of convergence and
read/write functionality.
Miscellaneous
-------------
- Updated the Doxygen documentation style, which now requires Doxygen version
+5 -10
View File
@@ -340,7 +340,10 @@ if (MFEM_USE_SUNDIALS)
if (MFEM_USE_HIP)
list(APPEND SUNDIALS_COMPONENTS NVector_Hip)
endif()
find_package(SUNDIALS REQUIRED ${SUNDIALS_COMPONENTS})
# The Core component was added in SUNDIALS v7, so we treat it as optional in
# order to support older versions.
find_package(SUNDIALS REQUIRED ${SUNDIALS_COMPONENTS}
OPTIONAL_COMPONENTS Core)
endif()
# SuperLU_DIST can only be enabled in parallel
@@ -522,10 +525,7 @@ endif()
# Enzyme
if (MFEM_USE_ENZYME)
find_package(Enzyme REQUIRED HINTS ${ENZYME_DIR})
message(STATUS "Enzyme found in ${ENZYME_DIR}.")
set(ENZYME_INCLUDE_DIRS ${ENZYME_DIR}/include)
set(ENZYME_FOUND 1)
find_package(ENZYME REQUIRED)
endif()
# MFEM_TIMER_TYPE
@@ -632,11 +632,6 @@ set(MFEM_INSTALL_DIR ${CMAKE_INSTALL_PREFIX} CACHE PATH
mfem_add_library(mfem ${SOURCES} ${HEADERS} ${MASTER_HEADERS})
# message(STATUS "TPL_LIBRARIES = ${TPL_LIBRARIES}")
target_link_libraries(mfem PUBLIC ${TPL_LIBRARIES})
if (MFEM_USE_ENZYME)
target_link_libraries(mfem PUBLIC ClangEnzymeFlags)
endif()
if (MINGW)
target_link_libraries(mfem PRIVATE ws2_32)
endif()
+7 -3
View File
@@ -502,10 +502,14 @@ MFEM_USE_CODIPACK = YES/NO
MFEM_USE_ALGOIM = YES/NO
Enable the usage of Algoim - a collection of high-order accurate numerical
methods and C++ algorithms for working with implicitly-defined geometry and
level set methods. The Algoim library requires the Blitz++ library. The MFEM
provides interface to Algoim v1. Thus, to check out the specific state use:
level set methods, see https://algoim.github.io. MFEM provides interface to
Algoim v1. To check out the specific Algoim state use:
https://github.com/algoim/algoim
git checkout 9c9ca0ef094d8ab0390ed36367a1151b459bbe0a
https://algoim.github.io
The Algoim library requires the Blitz++ library. To use the latest state of
Blitz++ that has been tested with MFEM, use:
https://github.com/blitzpp/blitz
git checkout f24a250a43dff88c31ad92916da828b7ea9a98b7
MFEM_USE_ADFORWARD = YES/NO
Enable forward mode for AD packages. This option is valid
+27
View File
@@ -0,0 +1,27 @@
# Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
message(STATUS "Looking for ENZYME ...")
message(STATUS " in ENZYME_DIR = ${ENZYME_DIR}")
# Make sure the directory and version combination works. Do nothing otherwise.
if(EXISTS "${ENZYME_DIR}/ClangEnzyme-${ENZYME_VERSION}.so")
message(STATUS "Found ENZYME: ${ENZYME_DIR}/ClangEnzyme-${ENZYME_VERSION}.so")
# Set ENZYME_FOUND
set(ENZYME_FOUND TRUE CACHE BOOL "ENZYME was found." FORCE)
# Set CXX flags to accommodate the Enzyme Clang plugin
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xclang -load -Xclang ${ENZYME_DIR}/ClangEnzyme-${ENZYME_VERSION}.so -mllvm -enzyme-loose-types=1")
set(MFEM_USE_ENZYME YES)
else()
endif()
+2 -1
View File
@@ -31,4 +31,5 @@ mfem_find_package(SUNDIALS SUNDIALS SUNDIALS_DIR
ADD_COMPONENT CVODE "include" cvode/cvode.h "lib" sundials_cvode
ADD_COMPONENT CVODES "include" cvodes/cvodes.h "lib" sundials_cvodes
ADD_COMPONENT ARKODE "include" arkode/arkode.h "lib" sundials_arkode
ADD_COMPONENT KINSOL "include" kinsol/kinsol.h "lib" sundials_kinsol)
ADD_COMPONENT KINSOL "include" kinsol/kinsol.h "lib" sundials_kinsol
ADD_COMPONENT Core "include" sundials/sundials_core.h "lib" sundials_core)
+10 -1
View File
@@ -289,6 +289,13 @@ endif
ifeq ($(MFEM_USE_HIP),YES)
SUNDIALS_LIB += -lsundials_nvechip
endif
SUNDIALS_CORE_PAT = $(subst\
@MFEM_DIR@,$(MFEM_DIR),$(SUNDIALS_DIR))/lib*/libsundials_core.*
ifeq ($(MFEM_USE_SUNDIALS),YES)
ifneq ($(wildcard $(SUNDIALS_CORE_PAT)),)
SUNDIALS_LIB += -lsundials_core
endif
endif
# If SUNDIALS was built with KLU:
# MFEM_USE_SUITESPARSE = YES
@@ -533,8 +540,10 @@ ifdef GOTCHA_DIR
endif
# BLITZ library configuration
BLITZ_DIR = @MFEM_DIR@/../blitz
# BLITZ_DIR must be the custom installation folder (-DCMAKE_INSTALL_PREFIX).
BLITZ_DIR = @MFEM_DIR@/../blitz/install
BLITZ_OPT = -I$(BLITZ_DIR)/include
# On intel machines, use /lib64 instead of /lib.
BLITZ_LIB = $(XLINKER)-rpath,$(BLITZ_DIR)/lib -L$(BLITZ_DIR)/lib -lblitz
# ALGOIM library configuration
-35
View File
@@ -1,35 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
2
elements
1
1 3 0 1 2 3
boundary
4
1 1 0 1
2 1 1 2
3 1 2 3
4 1 3 0
vertices
4
2
0 0
1 0.3
1.4 1.2
0.25 1.34
-33
View File
@@ -50,28 +50,6 @@ list(APPEND ALL_EXE_SRCS
if (MFEM_USE_MPI)
list(APPEND ALL_EXE_SRCS
dfem_poisson.cpp
dfem_stokes.cpp
enzyme_interface_smoketest.cpp
test_dfem_dual.cpp
test_dfem.cpp
dfem_laghos.cpp
dfem_minimal_example.cpp
dfem_test_diffusion_2d.cpp
dfem_test_diffusion_3d.cpp
dfem_test_diffusion_3d_refactor.cpp
dfem_test_ordering.cpp
dfem_test_vector_diffusion.cpp
dfem_test_elasticity.cpp
dfem_test_nonlinear_elasticity_3d.cpp
dfem_test_nonlinear_diffusion_3d.cpp
dfem_test_interpolate_linear_scalar.cpp
dfem_test_interpolate_linear_scalar_3d.cpp
dfem_test_interpolate_gradient_linear_scalar_3d.cpp
dfem_test_mass_scalar_3d.cpp
dfem_test_mass_scalar_2d.cpp
dfem_test_interpolate_linear_vector.cpp
dfem_test_interpolate_linear_vector_3d.cpp
ex0p.cpp
ex1p.cpp
ex2p.cpp
@@ -132,17 +110,6 @@ include_directories(BEFORE ${PROJECT_BINARY_DIR})
# Add one executable per cpp file
add_mfem_examples(ALL_EXE_SRCS)
target_link_libraries(dfem_poisson ClangEnzymeFlags)
target_link_libraries(dfem_stokes ClangEnzymeFlags)
target_link_libraries(enzyme_interface_smoketest ClangEnzymeFlags)
target_link_libraries(test_dfem ClangEnzymeFlags)
target_link_libraries(dfem_laghos ClangEnzymeFlags)
target_link_libraries(dfem_minimal_example ClangEnzymeFlags)
target_link_libraries(dfem_test_diffusion_3d ClangEnzymeFlags)
target_link_libraries(dfem_test_diffusion_3d_refactor ClangEnzymeFlags)
target_link_libraries(dfem_test_nonlinear_diffusion_3d ClangEnzymeFlags)
target_link_libraries(dfem_test_nonlinear_elasticity_3d ClangEnzymeFlags)
# Add a test for each example
if (MFEM_ENABLE_TESTING)
foreach(SRC_FILE ${ALL_EXE_SRCS})
-184
View File
@@ -1,184 +0,0 @@
/*
MIT License
Copyright (c) 2017 André L. Maravilha
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef CXX_TIMER_HPP
#define CXX_TIMER_HPP
#include <chrono>
namespace cxxtimer {
/**
* This class works as a stopwatch.
*/
class Timer {
public:
/**
* Constructor.
*
* @param start
* If true, the timer is started just after construction.
* Otherwise, it will not be automatically started.
*/
Timer(bool start = false);
/**
* Copy constructor.
*
* @param other
* The object to be copied.
*/
Timer(const Timer& other) = default;
/**
* Transfer constructor.
*
* @param other
* The object to be transferred.
*/
Timer(Timer&& other) = default;
/**
* Destructor.
*/
virtual ~Timer() = default;
/**
* Assignment operator by copy.
*
* @param other
* The object to be copied.
*
* @return A reference to this object.
*/
Timer& operator=(const Timer& other) = default;
/**
* Assignment operator by transfer.
*
* @param other
* The object to be transferred.
*
* @return A reference to this object.
*/
Timer& operator=(Timer&& other) = default;
/**
* Start/resume the timer.
*/
void start();
/**
* Stop/pause the timer.
*/
void stop();
/**
* Reset the timer.
*/
void reset();
/**
* Return the elapsed time.
*
* @param duration_t
* The duration type used to return the time elapsed. If not
* specified, it returns the time as represented by
* std::chrono::milliseconds.
*
* @return The elapsed time.
*/
template <class duration_t = std::chrono::milliseconds>
typename duration_t::rep count() const;
private:
bool started_;
bool paused_;
std::chrono::steady_clock::time_point reference_;
std::chrono::duration<long double> accumulated_;
};
}
inline cxxtimer::Timer::Timer(bool start) :
started_(false), paused_(false),
reference_(std::chrono::steady_clock::now()),
accumulated_(std::chrono::duration<long double>(0)) {
if (start) {
this->start();
}
}
inline void cxxtimer::Timer::start() {
if (!started_) {
started_ = true;
paused_ = false;
accumulated_ = std::chrono::duration<long double>(0);
reference_ = std::chrono::steady_clock::now();
} else if (paused_) {
reference_ = std::chrono::steady_clock::now();
paused_ = false;
}
}
inline void cxxtimer::Timer::stop() {
if (started_ && !paused_) {
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
accumulated_ = accumulated_ + std::chrono::duration_cast< std::chrono::duration<long double> >(now - reference_);
paused_ = true;
}
}
inline void cxxtimer::Timer::reset() {
if (started_) {
started_ = false;
paused_ = false;
reference_ = std::chrono::steady_clock::now();
accumulated_ = std::chrono::duration<long double>(0);
}
}
template <class duration_t>
typename duration_t::rep cxxtimer::Timer::count() const {
if (started_) {
if (paused_) {
return std::chrono::duration_cast<duration_t>(accumulated_).count();
} else {
return std::chrono::duration_cast<duration_t>(
accumulated_ + (std::chrono::steady_clock::now() - reference_)).count();
}
} else {
return duration_t(0).count();
}
}
#endif
-4
View File
@@ -1,4 +0,0 @@
#pragma once
#include "dfem_differentiable_operator.hpp"
#include "dfem_element_operator.hpp"
-232
View File
@@ -1,232 +0,0 @@
template <
typename kernels_tuple,
size_t num_solutions,
size_t num_parameters,
size_t num_fields,
size_t num_kernels
>
template <
typename kernel_t
>
void DifferentiableOperator<kernels_tuple,
num_solutions,
num_parameters,
num_fields,
num_kernels>::Action::create_action_callback(
kernel_t kernel,
mult_func_t &func)
{
using entity_t = typename kernel_t::entity_t;
auto kinput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.inputs, std::make_index_sequence<kernel.num_kinputs> {});
auto koutput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.outputs, std::make_index_sequence<kernel.num_koutputs> {});
constexpr int hardcoded_output_idx = 0;
const int test_space_field_idx = koutput_to_field[hardcoded_output_idx];
const Operator *R = get_restriction<entity_t>(op.fields[test_space_field_idx],
element_dof_ordering);
auto output_fop = mfem::get<hardcoded_output_idx>(kernel.outputs);
const int num_elements = GetNumEntities<Entity::Element>(op.mesh);
const int num_entities = GetNumEntities<entity_t>(op.mesh);
const int num_qp = op.integration_rule.GetNPoints();
// All solutions T-vector sizes make up the width of the operator, since
// they are explicitly provided in Mult() for example.
op.width = GetTrueVSize(op.fields[test_space_field_idx]);
op.residual_lsize = GetVSize(op.fields[test_space_field_idx]);
if constexpr (std::is_same_v<decltype(output_fop), One>)
{
op.height = 1;
}
else
{
op.height = op.residual_lsize;
}
residual_l.SetSize(op.residual_lsize);
// assume only a single element type for now
std::vector<const DofToQuad*> dtq;
for (const auto &field : op.fields)
{
dtq.emplace_back(GetDofToQuad<entity_t>(field, op.integration_rule,
doftoquad_mode));
}
const int q1d = (int)floor(pow(num_qp, 1.0/op.mesh.Dimension()) + 0.5);
residual_e.SetSize(R->Height());
const int residual_size_on_qp = GetSizeOnQP<entity_t>(
mfem::get<hardcoded_output_idx>(kernel.outputs),
op.fields[test_space_field_idx]);
auto input_dtq_maps = create_dtq_maps<entity_t>(kernel.inputs, dtq,
kinput_to_field);
auto output_dtq_maps = create_dtq_maps<entity_t>(kernel.outputs, dtq,
koutput_to_field);
auto input_fops = create_bare_fops(kernel.inputs);
auto output_fops = create_bare_fops(kernel.outputs);
const int test_vdim = mfem::get<hardcoded_output_idx>(output_fops).vdim;
const int test_op_dim =
mfem::get<hardcoded_output_idx>(output_fops).size_on_qp /
mfem::get<hardcoded_output_idx>(output_fops).vdim;
const int num_test_dof = R->Height() /
mfem::get<hardcoded_output_idx>(output_fops).vdim /
num_entities;
auto ir_weights = Reshape(this->op.integration_rule.GetWeights().Read(),
num_qp);
auto input_size_on_qp = get_input_size_on_qp(kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto shmem_info = get_shmem_info<entity_t>(input_dtq_maps,
output_dtq_maps,
op.fields,
num_entities,
kernel.inputs,
num_qp,
input_size_on_qp,
residual_size_on_qp);
Vector shmem_cache(shmem_info.total_size);
print_shared_memory_info(shmem_info);
func = [=](Vector &ye_mem) mutable
{
restriction<entity_t>(op.solutions, solutions_l, this->fields_e,
op.element_dof_ordering);
restriction<entity_t>(op.parameters, parameters_l, this->fields_e,
op.element_dof_ordering,
op.solutions.size());
auto ye = Reshape(ye_mem.ReadWrite(), test_vdim, num_test_dof, num_entities);
auto wrapped_fields_e = wrap_fields(this->fields_e, shmem_info.field_sizes, num_entities);
forall([=] MFEM_HOST_DEVICE (int e, void *shmem)
{
// printf("\ne: %d\n", e);
// tic();
auto input_dtq_shmem = load_dtq_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::INPUT_DTQ],
shmem_info.input_dtq_sizes,
input_dtq_maps);
auto output_dtq_shmem = load_dtq_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::OUTPUT_DTQ],
shmem_info.output_dtq_sizes,
output_dtq_maps);
auto fields_shmem = load_field_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::FIELD],
shmem_info.field_sizes,
kinput_to_field,
wrapped_fields_e,
e);
// These methods don't copy, they simply create a `DeviceTensor` object
// that points to correct chunks of the shared memory pool.
auto input_shmem = load_input_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::INPUT],
shmem_info.input_sizes,
num_qp);
auto residual_shmem = load_residual_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::OUTPUT],
shmem_info.residual_size,
num_qp);
auto scratch_mem = load_scratch_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::TEMP],
shmem_info.temp_sizes);
MFEM_SYNC_THREAD;
// printf("shmem load elapsed: %.1fus\n", toc() * 1e6);
// tic();
map_fields_to_quadrature_data<TensorProduct>(
input_shmem, fields_shmem, input_dtq_shmem, input_fops, ir_weights, scratch_mem,
std::make_index_sequence<kernel.num_kinputs> {});
// printf("interpolate elapsed: %.1fus\n", toc() * 1e6);
// tic();
MFEM_FOREACH_THREAD(qx, x, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(qz, z, q1d)
{
const int q = qx + q1d * (qy + q1d * qz);
auto kernel_args = decay_tuple<typename kernel_t::kf_param_ts> {};
auto r = Reshape(&residual_shmem(0, q), residual_size_on_qp);
apply_kernel(r, kernel.func, kernel_args, input_shmem, q);
}
}
}
MFEM_SYNC_THREAD;
// printf("qf elapsed: %.1fus\n", toc() * 1e6);
// tic();
auto fhat = Reshape(&residual_shmem(0, 0), test_vdim, test_op_dim, num_qp);
auto y = Reshape(&ye(0, 0, e), num_test_dof, test_vdim);
map_quadrature_data_to_fields<TensorProduct>(y, fhat,
mfem::get<0>(output_fops),
output_dtq_shmem[hardcoded_output_idx],
scratch_mem);
// printf("integrate elapsed: %.1fus\n", toc() * 1e6);
}, num_entities, q1d, q1d, q1d, shmem_info.total_size, shmem_cache.ReadWrite());
if constexpr (std::is_same_v<decltype(output_fop), None>)
{
residual_l = ye_mem;
}
else
{
R->MultTranspose(ye_mem, residual_l);
}
};
if constexpr (std::is_same_v<decltype(output_fop), None>)
{
prolongation_transpose = [&](Vector &r_local, Vector &y)
{
y = r_local;
};
}
else if constexpr (std::is_same_v<decltype(output_fop), One>)
{
prolongation_transpose = [&](Vector &r_local, Vector &y)
{
double local_sum = r_local.Sum();
MPI_Allreduce(&local_sum, y.GetData(), 1, MPI_DOUBLE, MPI_SUM,
op.mesh.GetComm());
MFEM_ASSERT(y.Size() == 1, "output size doesn't match kernel description");
};
}
else
{
auto P = get_prolongation(op.fields[test_space_field_idx]);
prolongation_transpose = [P](const Vector &r_local, Vector &y)
{
P->MultTranspose(r_local, y);
};
}
}
@@ -1,308 +0,0 @@
template <
typename kernels_tuple,
size_t num_solutions,
size_t num_parameters,
size_t num_fields,
size_t num_kernels
>
template <
size_t derivative_idx
>
template <
typename kernel_t
>
void DifferentiableOperator<kernels_tuple,
num_solutions,
num_parameters,
num_fields,
num_kernels>::Derivative<derivative_idx>::assemble_hypreparmatrix_impl(
kernel_t kernel, HypreParMatrix &A)
{
using entity_t = typename kernel_t::entity_t;
auto kinput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto koutput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.outputs,
std::make_index_sequence<kernel.num_koutputs> {});
auto output_fop = std::get<0>(kernel.outputs);
constexpr int hardcoded_output_idx = 0;
int num_qp = op.integration_rule.GetNPoints();;
int num_el = 0;
int dimension = 0;
if constexpr (std::is_same_v<entity_t, Entity::Element>)
{
num_el = op.mesh.GetNE();
dimension = op.dim;
}
else if (std::is_same_v<entity_t, Entity::Face>)
{
num_el = op.mesh.GetNumFacesWithGhost();
dimension = op.dim - 1;
}
else
{
static_assert(always_false<entity_t>, "not implemented");
}
std::vector<const DofToQuad*> dtqmaps;
for (const auto &field : op.fields)
{
dtqmaps.emplace_back(GetDofToQuad<entity_t>(field, op.integration_rule,
doftoquad_mode));
}
// Allocate memory for fields on quadrature points
auto input_qp_mem = create_input_qp_memory(num_qp, kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto directions_qp_mem = create_input_qp_memory(num_qp, kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
for (auto &d_qp_mem : directions_qp_mem)
{
d_qp_mem = 0.0;
}
std::array<bool, kernel.num_kinputs> kinput_is_dependent;
bool no_kinput_is_dependent = true;
for (int i = 0; i < kinput_is_dependent.size(); i++)
{
if (kinput_to_field[i] == derivative_idx)
{
no_kinput_is_dependent = false;
kinput_is_dependent[i] = true;
// out << "function input " << i << " is dependent on "
// << op.fields[kinput_to_field[i]].field_label << "\n";
}
else
{
kinput_is_dependent[i] = false;
}
}
if (no_kinput_is_dependent)
{
return;
}
auto kernel_args = decay_tuple<typename kernel_t::kf_param_ts> {};
auto kernel_shadow_args = decay_tuple<typename kernel_t::kf_param_ts> {};
DeviceTensor<1, const double> integration_weights(
this->op.integration_rule.GetWeights().Read(), num_qp);
Vector zero;
GeometricFactorMaps geometric_factors
{
DeviceTensor<3, const double>(zero.Read(), 0, 0, 0)
};
// fields interpolated to the quadrature points in the order of
// kernel function arguments
auto input_qp = map_inputs_to_memory(input_qp_mem, num_qp,
kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto directions_qp = map_inputs_to_memory(directions_qp_mem, num_qp,
kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto input_dtq_ops = create_dtq_operators<entity_t>(kernel.inputs, dtqmaps,
kinput_to_field);
auto dependent_input_dtq_ops = create_dtq_operators_conditional<entity_t>(
kernel.inputs,
dtqmaps,
kinput_to_field,
kinput_is_dependent, std::make_index_sequence<kernel.num_kinputs> {});
auto output_dtq_ops = create_dtq_operators<entity_t>(kernel.outputs, dtqmaps,
koutput_to_field);
constexpr int fixed_output_idx = 0;
auto Bv = output_dtq_ops[fixed_output_idx];
auto [num_test_qp, test_op_dim, num_test_dof] = Bv.GetShape();
const int test_vdim = std::get<0>(kernel.outputs).vdim;
const int num_trial_dof = dependent_input_dtq_ops[0].GetShape()[2];
int trial_vdim = 0;
for (int i = 0; i < kinput_is_dependent.size(); i++)
{
if (kinput_is_dependent[i])
{
trial_vdim = GetVDim(op.fields[kinput_to_field[i]]);
break;
}
}
// All trial operators dimensions accumulated
int total_trial_op_dim = 0;
for (int s = 0; s < dependent_input_dtq_ops.size(); s++)
{
total_trial_op_dim += dependent_input_dtq_ops[s].GetShape()[1];
}
Vector a_qp_mem(test_vdim * test_op_dim * trial_vdim * total_trial_op_dim *
num_qp *
num_el);
const auto a_qp = Reshape(a_qp_mem.ReadWrite(), test_vdim, test_op_dim,
trial_vdim, total_trial_op_dim, num_qp,
num_el);
Vector Ae_mem(num_test_dof * test_vdim * num_trial_dof * trial_vdim * num_el);
Ae_mem = 0.0;
auto A_e = Reshape(Ae_mem.ReadWrite(), num_test_dof, test_vdim, num_trial_dof,
trial_vdim, num_el);
for (int e = 0; e < num_el; e++)
{
map_fields_to_quadrature_data(
input_qp, e, this->fields_e,
kinput_to_field, input_dtq_ops,
integration_weights, geometric_factors, kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
for (int q = 0; q < num_qp; q++)
{
for (int j = 0; j < trial_vdim; j++)
{
size_t m_offset = 0;
for (int s = 0; s < dependent_input_dtq_ops.size(); s++)
{
auto Bu = dependent_input_dtq_ops[s];
auto [unused1, trial_op_dim, unused2] = Bu.GetShape();
auto d_qp = Reshape(&(directions_qp[Bu.which_input])[0], trial_vdim,
trial_op_dim, num_qp);
for (int m = 0; m < trial_op_dim; m++)
{
d_qp(j, m, q) = 1.0;
Vector f_qp = apply_kernel_fwddiff_enzyme(
kernel.func,
kernel_args,
input_qp,
kernel_shadow_args,
directions_qp,
q);
// Vector f_qp = apply_kernel_fwddiff_dual(
// kernel.func,
// kernel_args,
// input_qp,
// directions_qp,
// q);
d_qp(j, m, q) = 0.0;
auto f = Reshape(f_qp.Read(), test_vdim, test_op_dim);
for (int i = 0; i < test_vdim; i++)
{
for (int k = 0; k < test_op_dim; k++)
{
a_qp(i, k, j, m + m_offset, q, e) = f(i, k);
}
}
}
m_offset += trial_op_dim;
}
}
}
Vector fhat_mem(test_op_dim * num_qp * dimension);
auto fhat = Reshape(fhat_mem.ReadWrite(), test_vdim, test_op_dim, num_qp);
for (int J = 0; J < num_trial_dof; J++)
{
for (int j = 0; j < trial_vdim; j++)
{
fhat_mem = 0.0;
size_t m_offset = 0;
for (int s = 0; s < dependent_input_dtq_ops.size(); s++)
{
auto Bu = dependent_input_dtq_ops[s];
int trial_op_dim = dependent_input_dtq_ops[s].GetShape()[1];
for (int q = 0; q < num_qp; q++)
{
for (int i = 0; i < test_vdim; i++)
{
for (int k = 0; k < test_op_dim; k++)
{
for (int m = 0; m < trial_op_dim; m++)
{
fhat(i, k, q) += a_qp(i, k, j, m + m_offset, q, e) * Bu(q, m, J);
}
}
}
}
m_offset += trial_op_dim;
}
auto bvtfhat = Reshape(&A_e(0, 0, J, j, e), num_test_dof, test_vdim);
map_quadrature_data_to_fields(bvtfhat, fhat, output_fop,
output_dtq_ops[hardcoded_output_idx]);
}
}
}
bool same_test_and_trial = false;
if (koutput_to_field[0] ==
kinput_to_field[dependent_input_dtq_ops[0].which_input])
{
same_test_and_trial = true;
}
auto trial_fes = *std::get_if<const ParFiniteElementSpace *>
(&op.fields[kinput_to_field[dependent_input_dtq_ops[0].which_input]].data);
auto test_fes = *std::get_if<const ParFiniteElementSpace *>
(&op.fields[koutput_to_field[0]].data);
SparseMatrix mat(test_fes->GlobalVSize(), trial_fes->GlobalVSize());
if (test_fes == nullptr)
{
MFEM_ABORT("error");
}
for (int e = 0; e < num_el; e++)
{
auto tmp = Reshape(Ae_mem.ReadWrite(), num_test_dof * test_vdim,
num_trial_dof * trial_vdim,
num_el);
DenseMatrix A_e(&tmp(0, 0, e), num_test_dof * test_vdim,
num_trial_dof * trial_vdim);
Array<int> test_vdofs, trial_vdofs;
test_fes->GetElementVDofs(e, test_vdofs);
GetElementVDofs(
op.fields[kinput_to_field[dependent_input_dtq_ops[0].which_input]], e,
trial_vdofs);
mat.AddSubMatrix(test_vdofs, trial_vdofs, A_e, 1);
}
mat.Finalize();
if (same_test_and_trial)
{
HypreParMatrix tmp(test_fes->GetComm(),
test_fes->GlobalVSize(),
test_fes->GetDofOffsets(),
&mat);
A = *RAP(&tmp, test_fes->Dof_TrueDof_Matrix());
A.EliminateBC(op.ess_tdof_list, DiagonalPolicy::DIAG_ONE);
}
else
{
HypreParMatrix tmp(test_fes->GetComm(),
test_fes->GlobalVSize(),
trial_fes->GlobalVSize(),
test_fes->GetDofOffsets(),
trial_fes->GetDofOffsets(),
&mat);
A = *RAP(test_fes->Dof_TrueDof_Matrix(), &tmp, trial_fes->Dof_TrueDof_Matrix());
// A.EliminateBC(op.ess_tdof_list, DiagonalPolicy::DIAG_ONE);
}
}
-233
View File
@@ -1,233 +0,0 @@
template <
typename kernels_tuple,
size_t num_solutions,
size_t num_parameters,
size_t num_fields,
size_t num_kernels
>
template <
size_t derivative_idx
>
template <
typename kernel_t
>
void DifferentiableOperator<kernels_tuple,
num_solutions,
num_parameters,
num_fields,
num_kernels>::Derivative<derivative_idx>::assemble_vector_impl(
kernel_t kernel, Vector &v)
{
using entity_t = typename kernel_t::entity_t;
auto kinput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto koutput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.outputs,
std::make_index_sequence<kernel.num_koutputs> {});
auto output_fop = std::get<0>(kernel.outputs);
constexpr int hardcoded_output_idx = 0;
int num_qp = op.integration_rule.GetNPoints();;
int num_el = 0;
int dimension = 0;
if constexpr (std::is_same_v<entity_t, Entity::Element>)
{
num_el = op.mesh.GetNE();
dimension = op.dim;
}
else if (std::is_same_v<entity_t, Entity::Face>)
{
num_el = op.mesh.GetNumFacesWithGhost();
dimension = op.dim - 1;
}
else
{
static_assert(always_false<entity_t>, "not implemented");
}
std::vector<const DofToQuad*> dtqmaps;
for (const auto &field : op.fields)
{
dtqmaps.emplace_back(GetDofToQuad<entity_t>(field, op.integration_rule,
doftoquad_mode));
}
// Allocate memory for fields on quadrature points
auto input_qp_mem = create_input_qp_memory(num_qp, kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto directions_qp_mem = create_input_qp_memory(num_qp, kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
for (auto &d_qp_mem : directions_qp_mem)
{
d_qp_mem = 0.0;
}
std::array<bool, kernel.num_kinputs> kinput_is_dependent;
bool no_kinput_is_dependent = true;
for (int i = 0; i < kinput_is_dependent.size(); i++)
{
if (kinput_to_field[i] == derivative_idx)
{
no_kinput_is_dependent = false;
kinput_is_dependent[i] = true;
// out << "function input " << i << " is dependent on "
// << op.fields[kinput_to_field[i]].field_label << "\n";
}
else
{
kinput_is_dependent[i] = false;
}
}
if (no_kinput_is_dependent)
{
return;
}
auto kernel_args = decay_tuple<typename kernel_t::kf_param_ts> {};
auto kernel_shadow_args = decay_tuple<typename kernel_t::kf_param_ts> {};
DeviceTensor<1, const double> integration_weights(
this->op.integration_rule.GetWeights().Read(), num_qp);
Vector zero;
GeometricFactorMaps geometric_factors
{
DeviceTensor<3, const double>(zero.Read(), 0, 0, 0)
};
// fields interpolated to the quadrature points in the order of
// kernel function arguments
auto input_qp = map_inputs_to_memory(input_qp_mem, num_qp,
kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto directions_qp = map_inputs_to_memory(directions_qp_mem, num_qp,
kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto input_dtq_ops = create_dtq_operators<entity_t>(kernel.inputs, dtqmaps,
kinput_to_field);
auto dependent_input_dtq_ops = create_dtq_operators_conditional<entity_t>(
kernel.inputs,
dtqmaps,
kinput_to_field,
kinput_is_dependent, std::make_index_sequence<kernel.num_kinputs> {});
auto output_dtq_ops = create_dtq_operators<entity_t>(kernel.outputs, dtqmaps,
koutput_to_field);
constexpr int fixed_output_idx = 0;
auto Bv = output_dtq_ops[fixed_output_idx];
auto [num_test_qp, test_op_dim, num_test_dof] = Bv.GetShape();
const int test_vdim = std::get<0>(kernel.outputs).vdim;
const int num_trial_dof = dependent_input_dtq_ops[0].GetShape()[2];
int trial_vdim = 0;
int dependent_field_idx = -1;
for (int i = 0; i < kinput_is_dependent.size(); i++)
{
if (kinput_is_dependent[i])
{
dependent_field_idx = kinput_to_field[i];
break;
}
}
trial_vdim = GetVDim(op.fields[dependent_field_idx]);
// All trial operators dimensions accumulated
int total_trial_op_dim = 0;
for (int s = 0; s < dependent_input_dtq_ops.size(); s++)
{
total_trial_op_dim += dependent_input_dtq_ops[s].GetShape()[1];
}
Vector a_qp_mem(trial_vdim * total_trial_op_dim * num_qp * num_el);
const auto a_qp = Reshape(a_qp_mem.ReadWrite(), trial_vdim,
total_trial_op_dim, num_qp, num_el);
Vector ve_mem(num_trial_dof * trial_vdim * num_el);
ve_mem = 0.0;
for (int e = 0; e < num_el; e++)
{
map_fields_to_quadrature_data(
input_qp, e, this->fields_e,
kinput_to_field, input_dtq_ops,
integration_weights, geometric_factors, kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
for (int q = 0; q < num_qp; q++)
{
for (int j = 0; j < trial_vdim; j++)
{
size_t m_offset = 0;
for (int s = 0; s < dependent_input_dtq_ops.size(); s++)
{
auto Bu = dependent_input_dtq_ops[s];
auto [unused1, trial_op_dim, unused2] = Bu.GetShape();
auto d_qp = Reshape(&(directions_qp[Bu.which_input])[0], trial_vdim,
trial_op_dim, num_qp);
for (int m = 0; m < trial_op_dim; m++)
{
d_qp(j, m, q) = 1.0;
// Vector f_qp = apply_kernel_fwddiff_dual(
// kernel.func,
// kernel_args,
// input_qp,
// directions_qp,
// q);
Vector f_qp = apply_kernel_fwddiff_enzyme(
kernel.func,
kernel_args,
input_qp,
kernel_shadow_args,
directions_qp,
q);
d_qp(j, m, q) = 0.0;
auto f = Reshape(f_qp.Read(), test_vdim);
a_qp(j, m + m_offset, q, e) = f(0);
}
m_offset += trial_op_dim;
}
}
}
auto shat = Reshape(ve_mem.ReadWrite(), num_trial_dof, trial_vdim, num_el);
for (int J = 0; J < num_trial_dof; J++)
{
for (int j = 0; j < trial_vdim; j++)
{
size_t m_offset = 0;
for (int s = 0; s < dependent_input_dtq_ops.size(); s++)
{
auto Bu = dependent_input_dtq_ops[s];
int trial_op_dim = dependent_input_dtq_ops[s].GetShape()[1];
for (int q = 0; q < num_qp; q++)
{
for (int m = 0; m < trial_op_dim; m++)
{
shat(J, j, e) += a_qp(j, m + m_offset, q, e) * Bu(q, m, J);
}
}
m_offset += trial_op_dim;
}
}
}
}
auto R = get_element_restriction(op.fields[dependent_field_idx],
element_dof_ordering);
Vector ve(R->Width());
R->MultTranspose(ve_mem, ve);
get_prolongation(op.fields[dependent_field_idx])->MultTranspose(ve, v);
}
-244
View File
@@ -1,244 +0,0 @@
template <
typename kernels_tuple,
size_t num_solutions,
size_t num_parameters,
size_t num_fields,
size_t num_kernels
>
template <
size_t derivative_idx
>
template <
typename kernel_t
>
void DifferentiableOperator<kernels_tuple,
num_solutions,
num_parameters,
num_fields,
num_kernels>::Derivative<derivative_idx>::create_callback(kernel_t kernel,
mult_func_t &func)
{
using entity_t = typename kernel_t::entity_t;
auto kinput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.inputs, std::make_index_sequence<kernel.num_kinputs> {});
auto koutput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.outputs, std::make_index_sequence<kernel.num_koutputs> {});
constexpr int hardcoded_output_idx = 0;
const int test_space_field_idx = koutput_to_field[hardcoded_output_idx];
const Operator *R = get_restriction<entity_t>(op.fields[test_space_field_idx],
element_dof_ordering);
auto output_fop = mfem::get<hardcoded_output_idx>(kernel.outputs);
const int num_elements = GetNumEntities<Entity::Element>(op.mesh);
const int num_entities = GetNumEntities<entity_t>(op.mesh);
const int num_qp = op.integration_rule.GetNPoints();
// assume only a single element type for now
std::vector<const DofToQuad*> dtq;
for (const auto &field : op.fields)
{
dtq.emplace_back(GetDofToQuad<entity_t>(field, op.integration_rule,
doftoquad_mode));
}
const int q1d = dtq[0]->nqpt;
derivative_action_e.SetSize(R->Height());
const int da_size_on_qp = GetSizeOnQP<entity_t>(
mfem::get<hardcoded_output_idx>(kernel.outputs),
op.fields[test_space_field_idx]);
auto input_dtq_maps = create_dtq_maps<entity_t>(kernel.inputs, dtq,
kinput_to_field);
auto output_dtq_maps = create_dtq_maps<entity_t>(kernel.outputs, dtq,
koutput_to_field);
auto input_fops = create_bare_fops(kernel.inputs);
auto output_fops = create_bare_fops(kernel.outputs);
const int test_vdim = mfem::get<hardcoded_output_idx>(output_fops).vdim;
const int test_op_dim =
mfem::get<hardcoded_output_idx>(output_fops).size_on_qp /
mfem::get<hardcoded_output_idx>(output_fops).vdim;
const int num_test_dof = R->Height() /
mfem::get<hardcoded_output_idx>(output_fops).vdim /
num_entities;
auto ir_weights = Reshape(this->op.integration_rule.GetWeights().Read(),
num_qp);
auto input_size_on_qp = get_input_size_on_qp(kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
// Check which qf inputs are dependent on the dependent variable
std::array<bool, kernel.num_kinputs> kinput_is_dependent;
bool no_kinput_is_dependent = true;
for (int i = 0; i < kinput_is_dependent.size(); i++)
{
if (kinput_to_field[i] == derivative_idx)
{
no_kinput_is_dependent = false;
kinput_is_dependent[i] = true;
// out << "function input " << i << " is dependent on "
// << op.fields[kinput_to_field[i]].field_label << "\n";
}
else
{
kinput_is_dependent[i] = false;
}
}
bool with_derivatives = true;
auto shmem_info = get_shmem_info<entity_t>(input_dtq_maps,
output_dtq_maps,
op.fields,
num_entities,
kernel.inputs,
num_qp,
input_size_on_qp,
da_size_on_qp,
derivative_idx);
Vector shmem_cache(shmem_info.total_size);
print_shared_memory_info(shmem_info);
func = [=](Vector &ye_mem) mutable
{
if (no_kinput_is_dependent)
{
return;
}
restriction<entity_t>(direction, direction_l, direction_e,
op.element_dof_ordering);
auto ye = Reshape(ye_mem.ReadWrite(), num_test_dof, test_vdim, num_entities);
auto wrapped_fields_e = wrap_fields(this->fields_e, shmem_info.field_sizes, num_entities);
auto wrapped_direction_e = Reshape(direction_e.Read(), shmem_info.direction_size, num_entities);
forall([=] MFEM_HOST_DEVICE (int e, double *shmem)
{
auto input_dtq_shmem = load_dtq_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::INPUT_DTQ],
shmem_info.input_dtq_sizes,
input_dtq_maps);
auto output_dtq_shmem = load_dtq_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::OUTPUT_DTQ],
shmem_info.output_dtq_sizes,
output_dtq_maps);
auto fields_shmem = load_field_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::FIELD],
shmem_info.field_sizes,
kinput_to_field,
wrapped_fields_e,
e);
auto direction_shmem = load_direction_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::DIRECTION],
shmem_info.direction_size,
wrapped_direction_e,
e);
// These methods don't copy, they simply create a `DeviceTensor` object
// that points to correct chunks of the shared memory pool.
auto input_shmem = load_input_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::INPUT],
shmem_info.input_sizes,
num_qp);
auto shadow_shmem = load_input_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::SHADOW],
shmem_info.input_sizes,
num_qp);
auto residual_shmem = load_residual_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::OUTPUT],
shmem_info.residual_size,
num_qp);
auto scratch_mem = load_scratch_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::TEMP],
shmem_info.temp_sizes);
map_fields_to_quadrature_data<TensorProduct>(
input_shmem, fields_shmem, input_dtq_shmem, input_fops, ir_weights, scratch_mem,
std::make_index_sequence<kernel.num_kinputs> {});
zero_all(shadow_shmem);
map_direction_to_quadrature_data_conditional<TensorProduct>(
shadow_shmem, direction_shmem, input_dtq_shmem, input_fops, ir_weights,
scratch_mem, kinput_is_dependent,
std::make_index_sequence<kernel.num_kinputs> {});
MFEM_FOREACH_THREAD(qx, x, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(qz, z, q1d)
{
const int q = qx + q1d * (qy + q1d * qz);
auto kernel_args = decay_tuple<typename kernel_t::kf_param_ts> {};
auto kernel_shadow_args = decay_tuple<typename kernel_t::kf_param_ts> {};
auto r = Reshape(&residual_shmem(0, q), da_size_on_qp);
apply_kernel_fwddiff_enzyme(
r,
kernel.func,
kernel_args,
input_shmem,
kernel_shadow_args,
shadow_shmem,
q);
// printf(">>>>> WARNING: AD DISABLED\n");
}
}
}
MFEM_SYNC_THREAD;
auto fhat = Reshape(&residual_shmem(0, 0), test_vdim, test_op_dim, num_qp);
auto y = Reshape(&ye(0, 0, e), num_test_dof, test_vdim);
map_quadrature_data_to_fields<TensorProduct>(y, fhat,
mfem::get<0>(output_fops),
output_dtq_shmem[hardcoded_output_idx],
scratch_mem);
}, num_entities, q1d, q1d, 1, shmem_info.total_size, shmem_cache.ReadWrite());
R->MultTranspose(ye_mem, derivative_action_l);
};
if constexpr (std::is_same_v<decltype(output_fop), One>)
{
prolongation_transpose = [&](Vector &r_local, Vector &y)
{
double local_sum = r_local.Sum();
MPI_Allreduce(&local_sum, y.GetData(), 1, MPI_DOUBLE, MPI_SUM,
op.mesh.GetComm());
MFEM_ASSERT(y.Size() == 1, "output size doesn't match kernel description");
};
}
else
{
auto P = get_prolongation(op.fields[test_space_field_idx]);
prolongation_transpose = [P](const Vector &r_local, Vector &y)
{
P->MultTranspose(r_local, y);
};
}
}
@@ -1,820 +0,0 @@
#pragma once
#include <algorithm>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <utility>
#include <variant>
#include <vector>
#include <type_traits>
#include <mfem.hpp>
#include <type_traits>
#include "dfem_fieldoperator.hpp"
#include "dfem_parametricspace.hpp"
#include "general/tic_toc.hpp"
#include "tuple.hpp"
#include <linalg/tensor.hpp>
#include <enzyme/utils>
#include <enzyme/enzyme>
#include "dfem_util.hpp"
#include "dfem_interpolate.hpp"
#include "dfem_qfunction.hpp"
#include "dfem_qfunction_dual.hpp"
#include "dfem_integrate.hpp"
namespace mfem
{
using mult_func_t = std::function<void(Vector &)>;
template <
typename kernels_tuple,
size_t num_solutions,
size_t num_parameters,
size_t num_fields = num_solutions + num_parameters,
size_t num_kernels = mfem::tuple_size<kernels_tuple>::value,
typename autodiff_t = AutoDiff::NativeDualNumber
>
class DifferentiableOperator : public Operator
{
public:
DifferentiableOperator(DifferentiableOperator&) = delete;
DifferentiableOperator(DifferentiableOperator&&) = delete;
class Action : public Operator
{
public:
template <typename kernel_t>
void create_action_callback(kernel_t kernel, mult_func_t &func);
template<std::size_t... idx>
void materialize_callbacks(kernels_tuple &ks,
std::array<mult_func_t, num_kernels>,
std::index_sequence<idx...> const&)
{
(create_action_callback(mfem::get<idx>(ks), funcs[idx]), ...);
}
Action(DifferentiableOperator &op, kernels_tuple &ks) : op(op)
{
materialize_callbacks(ks, funcs,
std::make_index_sequence<mfem::tuple_size<kernels_tuple>::value>());
}
void Mult(const Vector &x, Vector &y) const
{
prolongation(op.solutions, x, solutions_l);
residual_e = 0.0;
for (const auto &f : funcs)
{
f(residual_e);
}
prolongation_transpose(residual_l, y);
y.SetSubVector(op.ess_tdof_list, 0.0);
}
void SetParameters(std::vector<Vector *> p) const
{
MFEM_ASSERT(num_parameters == p.size(),
"number of parameters doesn't match descriptors");
for (int i = 0; i < num_parameters; i++)
{
p[i]->Read();
parameters_l[i] = *p[i];
// parameters_l[i].MakeRef(p[i], 0, p[i]->Size());
}
}
protected:
DifferentiableOperator &op;
std::array<mult_func_t, num_kernels> funcs;
std::function<void(Vector &, Vector &)> prolongation_transpose;
mutable std::array<Vector, num_solutions> solutions_l;
mutable std::array<Vector, num_parameters> parameters_l;
mutable Vector residual_l;
mutable std::array<Vector, num_fields> fields_e;
mutable Vector residual_e;
};
template <size_t derivative_idx>
class Derivative : public Operator
{
public:
template <typename kernel_t>
void create_callback(kernel_t kernel, mult_func_t &func);
template<std::size_t... idx>
void materialize_callbacks(kernels_tuple &ks,
std::array<mult_func_t, num_kernels>,
std::index_sequence<idx...> const&)
{
(create_callback(mfem::get<idx>(ks), funcs[idx]), ...);
}
Derivative(
DifferentiableOperator &op,
std::array<Vector *, num_solutions> &solutions,
std::array<Vector *, num_parameters> &parameters,
kernels_tuple &ks) : op(op), ks(ks)
{
for (int i = 0; i < num_solutions; i++)
{
solutions_l[i] = *solutions[i];
}
for (int i = 0; i < num_parameters; i++)
{
parameters_l[i] = *parameters[i];
}
// G
// if constexpr (std::is_same_v<OperatesOn, OperatesOnElement>)
// {
element_restriction(op.solutions, solutions_l, fields_e,
op.element_dof_ordering);
element_restriction(op.parameters, parameters_l, fields_e,
op.element_dof_ordering,
op.solutions.size());
// }
// else
// {
// MFEM_ABORT("restriction not implemented for OperatesOn");
// }
direction = op.fields[derivative_idx];
size_t derivative_action_l_size = 0;
for (auto &s : op.solutions)
{
derivative_action_l_size += GetVSize(s);
this->width += GetTrueVSize(s);
}
this->height = derivative_action_l_size;
derivative_action_l.SetSize(derivative_action_l_size);
materialize_callbacks(ks, funcs,
std::make_index_sequence<num_kernels>());
}
void Mult(const Vector &x, Vector &y) const override
{
current_direction_t = x;
current_direction_t.SetSubVector(op.ess_tdof_list, 0.0);
prolongation(direction, current_direction_t, direction_l);
derivative_action_e = 0.0;
for (const auto &f : funcs)
{
f(derivative_action_e);
}
prolongation_transpose(derivative_action_l, y);
y.SetSubVector(op.ess_tdof_list, 0.0);
}
template <typename kernel_t>
void assemble_vector_impl(kernel_t kernel, Vector &v);
template<std::size_t... idx>
void assemble_vector(
kernels_tuple &ks,
Vector &v,
std::index_sequence<idx...> const&)
{
(assemble_vector_impl(mfem::get<idx>(ks), v), ...);
}
void Assemble(Vector &v)
{
assemble_vector(ks, v, std::make_index_sequence<num_kernels>());
}
template <typename kernel_t>
void assemble_hypreparmatrix_impl(kernel_t kernel, HypreParMatrix &A);
template<std::size_t... idx>
void assemble_hypreparmatrix(
kernels_tuple &ks,
HypreParMatrix &A,
std::index_sequence<idx...> const&)
{
(assemble_hypreparmatrix_impl(mfem::get<idx>(ks), A), ...);
}
void Assemble(HypreParMatrix &A)
{
assemble_hypreparmatrix(ks, A, std::make_index_sequence<num_kernels>());
}
void AssembleDiagonal(Vector &d) const override {}
protected:
DifferentiableOperator &op;
kernels_tuple &ks;
std::array<mult_func_t, num_kernels> funcs;
std::function<void(Vector &, Vector &)> prolongation_transpose;
FieldDescriptor direction;
std::array<Vector, num_solutions> solutions_l;
std::array<Vector, num_parameters> parameters_l;
mutable Vector direction_l;
mutable Vector derivative_action_l;
mutable std::array<Vector, num_fields> fields_e;
mutable Vector direction_e;
mutable Vector derivative_action_e;
mutable Vector current_direction_t;
};
DifferentiableOperator(std::array<FieldDescriptor, num_solutions> s,
std::array<FieldDescriptor, num_parameters> p,
kernels_tuple ks,
ParMesh &m,
autodiff_t ad = AutoDiff::NativeDualNumber{}) :
kernels(ks),
mesh(m),
dim(mesh.Dimension()),
solutions(s),
parameters(p)
{
for (int i = 0; i < num_solutions; i++)
{
fields[i] = solutions[i];
}
for (int i = 0; i < num_parameters; i++)
{
fields[i + num_solutions] = parameters[i];
}
residual.reset(new Action(*this, kernels));
}
void SetParameters(std::vector<Vector *> p) const
{
residual->SetParameters(p);
}
void Mult(const Vector &x, Vector &y) const override
{
residual->Mult(x, y);
}
template <int derivative_idx>
std::shared_ptr<Derivative<derivative_idx>>
GetDerivativeWrt(std::array<Vector *, num_solutions> solutions,
std::array<Vector *, num_parameters> parameters)
{
return std::shared_ptr<Derivative<derivative_idx>>(
new Derivative<derivative_idx>(*this, solutions, parameters, kernels));
}
void SetEssentialTrueDofs(const Array<int> &l)
{
l.Copy(ess_tdof_list);
}
kernels_tuple kernels;
ParMesh &mesh;
const int dim;
std::array<FieldDescriptor, num_solutions> solutions;
std::array<FieldDescriptor, num_parameters> parameters;
// solutions and parameters
std::array<FieldDescriptor, num_fields> fields;
int residual_lsize = 0;
mutable std::array<Vector, num_solutions> current_state_l;
mutable Vector direction_l;
mutable Vector current_direction_t;
Array<int> ess_tdof_list;
static constexpr ElementDofOrdering element_dof_ordering =
ElementDofOrdering::LEXICOGRAPHIC;
static constexpr DofToQuad::Mode doftoquad_mode =
DofToQuad::Mode::TENSOR;
// static constexpr ElementDofOrdering element_dof_ordering =
// ElementDofOrdering::NATIVE;
// static constexpr DofToQuad::Mode doftoquad_mode =
// DofToQuad::Mode::FULL;
std::shared_ptr<Action> residual;
};
template <
typename kernels_tuple,
size_t num_solutions,
size_t num_parameters,
size_t num_fields,
size_t num_kernels,
typename autodiff_t
>
template <
typename kernel_t
>
void DifferentiableOperator<kernels_tuple,
num_solutions,
num_parameters,
num_fields,
num_kernels,
autodiff_t>::Action::create_action_callback(
kernel_t kernel,
mult_func_t &func)
{
using entity_t = typename kernel_t::entity_t;
auto kinput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.inputs, std::make_index_sequence<kernel.num_kinputs> {});
auto koutput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.outputs, std::make_index_sequence<kernel.num_koutputs> {});
constexpr int hardcoded_output_idx = 0;
const int test_space_field_idx = koutput_to_field[hardcoded_output_idx];
const Operator *R = get_restriction<entity_t>(op.fields[test_space_field_idx],
element_dof_ordering);
auto output_fop = mfem::get<hardcoded_output_idx>(kernel.outputs);
const int num_elements = GetNumEntities<Entity::Element>(op.mesh);
const int num_entities = GetNumEntities<entity_t>(op.mesh);
const int num_qp = kernel.integration_rule.GetNPoints();
// All solutions T-vector sizes make up the width of the operator, since
// they are explicitly provided in Mult() for example.
op.width = GetTrueVSize(op.fields[test_space_field_idx]);
op.residual_lsize = GetVSize(op.fields[test_space_field_idx]);
if constexpr (std::is_same_v<decltype(output_fop), One>)
{
op.height = 1;
}
else
{
op.height = op.residual_lsize;
}
residual_l.SetSize(op.residual_lsize);
// assume only a single element type for now
std::vector<const DofToQuad*> dtq;
for (const auto &field : op.fields)
{
dtq.emplace_back(GetDofToQuad<entity_t>(field, kernel.integration_rule,
doftoquad_mode));
}
const int q1d = (int)floor(pow(num_qp, 1.0/op.mesh.Dimension()) + 0.5);
residual_e.SetSize(R->Height());
const int residual_size_on_qp = GetSizeOnQP<entity_t>(
mfem::get<hardcoded_output_idx>(kernel.outputs),
op.fields[test_space_field_idx]);
auto input_dtq_maps = create_dtq_maps<entity_t>(kernel.inputs, dtq,
kinput_to_field);
auto output_dtq_maps = create_dtq_maps<entity_t>(kernel.outputs, dtq,
koutput_to_field);
auto input_fops = create_bare_fops(kernel.inputs);
auto output_fops = create_bare_fops(kernel.outputs);
const int test_vdim = mfem::get<hardcoded_output_idx>(output_fops).vdim;
const int test_op_dim =
mfem::get<hardcoded_output_idx>(output_fops).size_on_qp /
mfem::get<hardcoded_output_idx>(output_fops).vdim;
const int num_test_dof = R->Height() /
mfem::get<hardcoded_output_idx>(output_fops).vdim /
num_entities;
auto ir_weights = Reshape(kernel.integration_rule.GetWeights().Read(), num_qp);
auto input_size_on_qp = get_input_size_on_qp(kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto shmem_info = get_shmem_info<entity_t>(input_dtq_maps,
output_dtq_maps,
op.fields,
num_entities,
kernel.inputs,
num_qp,
input_size_on_qp,
residual_size_on_qp);
Vector shmem_cache(shmem_info.total_size);
// print_shared_memory_info(shmem_info);
func = [=](Vector &ye_mem) mutable
{
restriction<entity_t>(op.solutions, solutions_l, this->fields_e,
op.element_dof_ordering);
restriction<entity_t>(op.parameters, parameters_l, this->fields_e,
op.element_dof_ordering,
op.solutions.size());
auto ye = Reshape(ye_mem.ReadWrite(), test_vdim, num_test_dof, num_entities);
auto wrapped_fields_e = wrap_fields(this->fields_e, shmem_info.field_sizes, num_entities);
forall([=] MFEM_HOST_DEVICE (int e, void *shmem)
{
// printf("\ne: %d\n", e);
// tic();
auto input_dtq_shmem = load_dtq_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::INPUT_DTQ],
shmem_info.input_dtq_sizes,
input_dtq_maps);
auto output_dtq_shmem = load_dtq_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::OUTPUT_DTQ],
shmem_info.output_dtq_sizes,
output_dtq_maps);
auto fields_shmem = load_field_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::FIELD],
shmem_info.field_sizes,
kinput_to_field,
input_fops,
wrapped_fields_e,
e,
std::make_index_sequence<kernel.num_kinputs> {});
// These functions don't copy, they simply create a `DeviceTensor` object
// that points to correct chunks of the shared memory pool.
auto input_shmem = load_input_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::INPUT],
shmem_info.input_sizes,
num_qp);
auto residual_shmem = load_residual_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::OUTPUT],
shmem_info.residual_size,
num_qp);
auto scratch_mem = load_scratch_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::TEMP],
shmem_info.temp_sizes);
MFEM_SYNC_THREAD;
// printf("shmem load elapsed: %.1fus\n", toc() * 1e6);
// tic();
map_fields_to_quadrature_data<TensorProduct>(
input_shmem, fields_shmem, input_dtq_shmem, input_fops, ir_weights, scratch_mem,
std::make_index_sequence<kernel.num_kinputs> {});
// printf("interpolate elapsed: %.1fus\n", toc() * 1e6);
// tic();
MFEM_FOREACH_THREAD(qx, x, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(qz, z, q1d)
{
const int q = qx + q1d * (qy + q1d * qz);
auto kernel_args = decay_tuple<typename kernel_t::kf_param_ts> {};
auto r = Reshape(&residual_shmem(0, q), residual_size_on_qp);
apply_kernel(r, kernel.func, kernel_args, input_shmem, q);
}
}
}
MFEM_SYNC_THREAD;
// printf("qf elapsed: %.1fus\n", toc() * 1e6);
// tic();
auto fhat = Reshape(&residual_shmem(0, 0), test_vdim, test_op_dim, num_qp);
auto y = Reshape(&ye(0, 0, e), num_test_dof, test_vdim);
map_quadrature_data_to_fields<TensorProduct>(y, fhat,
mfem::get<0>(output_fops),
output_dtq_shmem[hardcoded_output_idx],
scratch_mem);
// printf("integrate elapsed: %.1fus\n", toc() * 1e6);
}, num_entities, q1d, q1d, q1d, shmem_info.total_size, shmem_cache.ReadWrite());
if constexpr (std::is_same_v<decltype(output_fop), None>)
{
residual_l = ye_mem;
}
else
{
R->MultTranspose(ye_mem, residual_l);
}
};
if constexpr (std::is_same_v<decltype(output_fop), None>)
{
prolongation_transpose = [&](Vector &r_local, Vector &y)
{
y = r_local;
};
}
else if constexpr (std::is_same_v<decltype(output_fop), One>)
{
prolongation_transpose = [&](Vector &r_local, Vector &y)
{
double local_sum = r_local.Sum();
MPI_Allreduce(&local_sum, y.GetData(), 1, MPI_DOUBLE, MPI_SUM,
op.mesh.GetComm());
MFEM_ASSERT(y.Size() == 1, "output size doesn't match kernel description");
};
}
else
{
auto P = get_prolongation(op.fields[test_space_field_idx]);
prolongation_transpose = [P](const Vector &r_local, Vector &y)
{
P->MultTranspose(r_local, y);
};
}
}
template <
typename kernels_tuple,
size_t num_solutions,
size_t num_parameters,
size_t num_fields,
size_t num_kernels,
typename autodiff_t
>
template <
size_t derivative_idx
>
template <
typename kernel_t
>
void DifferentiableOperator<kernels_tuple,
num_solutions,
num_parameters,
num_fields,
num_kernels,
autodiff_t>::Derivative<derivative_idx>::create_callback(kernel_t kernel,
mult_func_t &func)
{
using entity_t = typename kernel_t::entity_t;
auto kinput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.inputs, std::make_index_sequence<kernel.num_kinputs> {});
auto koutput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.outputs, std::make_index_sequence<kernel.num_koutputs> {});
constexpr int hardcoded_output_idx = 0;
const int test_space_field_idx = koutput_to_field[hardcoded_output_idx];
const Operator *R = get_restriction<entity_t>(op.fields[test_space_field_idx],
element_dof_ordering);
auto output_fop = mfem::get<hardcoded_output_idx>(kernel.outputs);
const int num_elements = GetNumEntities<Entity::Element>(op.mesh);
const int num_entities = GetNumEntities<entity_t>(op.mesh);
const int num_qp = kernel.integration_rule.GetNPoints();
// assume only a single element type for now
std::vector<const DofToQuad*> dtq;
for (const auto &field : op.fields)
{
dtq.emplace_back(GetDofToQuad<entity_t>(field, kernel.integration_rule,
doftoquad_mode));
}
const int q1d = dtq[0]->nqpt;
derivative_action_e.SetSize(R->Height());
const int da_size_on_qp = GetSizeOnQP<entity_t>(
mfem::get<hardcoded_output_idx>(kernel.outputs),
op.fields[test_space_field_idx]);
auto input_dtq_maps = create_dtq_maps<entity_t>(kernel.inputs, dtq,
kinput_to_field);
auto output_dtq_maps = create_dtq_maps<entity_t>(kernel.outputs, dtq,
koutput_to_field);
auto input_fops = create_bare_fops(kernel.inputs);
auto output_fops = create_bare_fops(kernel.outputs);
const int test_vdim = mfem::get<hardcoded_output_idx>(output_fops).vdim;
const int test_op_dim =
mfem::get<hardcoded_output_idx>(output_fops).size_on_qp /
mfem::get<hardcoded_output_idx>(output_fops).vdim;
const int num_test_dof = R->Height() /
mfem::get<hardcoded_output_idx>(output_fops).vdim /
num_entities;
auto ir_weights = Reshape(kernel.integration_rule.GetWeights().Read(), num_qp);
auto input_size_on_qp = get_input_size_on_qp(kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
// Check which qf inputs are dependent on the dependent variable
std::array<bool, kernel.num_kinputs> kinput_is_dependent;
bool no_kinput_is_dependent = true;
for (int i = 0; i < kinput_is_dependent.size(); i++)
{
if (kinput_to_field[i] == derivative_idx)
{
no_kinput_is_dependent = false;
kinput_is_dependent[i] = true;
// out << "function input " << i << " is dependent on "
// << op.fields[kinput_to_field[i]].field_label << "\n";
}
else
{
kinput_is_dependent[i] = false;
}
}
bool with_derivatives = true;
auto shmem_info = get_shmem_info<entity_t>(input_dtq_maps,
output_dtq_maps,
op.fields,
num_entities,
kernel.inputs,
num_qp,
input_size_on_qp,
da_size_on_qp,
derivative_idx);
Vector shmem_cache(shmem_info.total_size);
// print_shared_memory_info(shmem_info);
func = [=](Vector &ye_mem) mutable
{
if (no_kinput_is_dependent)
{
return;
}
restriction<entity_t>(direction, direction_l, direction_e,
op.element_dof_ordering);
auto ye = Reshape(ye_mem.ReadWrite(), num_test_dof, test_vdim, num_entities);
auto wrapped_fields_e = wrap_fields(this->fields_e, shmem_info.field_sizes, num_entities);
auto wrapped_direction_e = Reshape(direction_e.ReadWrite(), shmem_info.direction_size, num_entities);
forall([=] MFEM_HOST_DEVICE (int e, double *shmem)
{
auto input_dtq_shmem = load_dtq_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::INPUT_DTQ],
shmem_info.input_dtq_sizes,
input_dtq_maps);
auto output_dtq_shmem = load_dtq_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::OUTPUT_DTQ],
shmem_info.output_dtq_sizes,
output_dtq_maps);
auto fields_shmem = load_field_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::FIELD],
shmem_info.field_sizes,
kinput_to_field,
input_fops,
wrapped_fields_e,
e,
std::make_index_sequence<kernel.num_kinputs> {});
auto direction_shmem = load_direction_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::DIRECTION],
shmem_info.direction_size,
wrapped_direction_e,
e);
// These methods don't copy, they simply create a `DeviceTensor` object
// that points to correct chunks of the shared memory pool.
auto input_shmem = load_input_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::INPUT],
shmem_info.input_sizes,
num_qp);
auto shadow_shmem = load_input_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::SHADOW],
shmem_info.input_sizes,
num_qp);
auto residual_shmem = load_residual_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::OUTPUT],
shmem_info.residual_size,
num_qp);
auto scratch_mem = load_scratch_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::TEMP],
shmem_info.temp_sizes);
map_fields_to_quadrature_data<TensorProduct>(
input_shmem, fields_shmem, input_dtq_shmem, input_fops, ir_weights, scratch_mem,
std::make_index_sequence<kernel.num_kinputs> {});
zero_all(shadow_shmem);
map_direction_to_quadrature_data_conditional<TensorProduct>(
shadow_shmem, direction_shmem, input_dtq_shmem, input_fops, ir_weights,
scratch_mem, kinput_is_dependent,
std::make_index_sequence<kernel.num_kinputs> {});
MFEM_FOREACH_THREAD(qx, x, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(qz, z, q1d)
{
const int q = qx + q1d * (qy + q1d * qz);
auto r = Reshape(&residual_shmem(0, q), da_size_on_qp);
auto kernel_args = decay_tuple<typename kernel_t::kf_param_ts> {};
if constexpr (std::is_same_v<autodiff_t, AutoDiff::EnzymeForward>)
{
auto kernel_shadow_args = decay_tuple<typename kernel_t::kf_param_ts> {};
apply_kernel_fwddiff_enzyme(
r,
kernel.func,
kernel_args,
kernel_shadow_args,
input_shmem,
shadow_shmem,
q);
}
else if constexpr (std::is_same_v<autodiff_t, AutoDiff::NativeDualNumber>)
{
apply_kernel_native_dual(
r,
kernel.func,
kernel_args,
input_shmem,
shadow_shmem,
q);
}
else
{
static_assert(always_false<autodiff_t>, "unknown autodiff type");
}
}
}
}
MFEM_SYNC_THREAD;
auto fhat = Reshape(&residual_shmem(0, 0), test_vdim, test_op_dim, num_qp);
auto y = Reshape(&ye(0, 0, e), num_test_dof, test_vdim);
map_quadrature_data_to_fields<TensorProduct>(y, fhat,
mfem::get<0>(output_fops),
output_dtq_shmem[hardcoded_output_idx],
scratch_mem);
}, num_entities, q1d, q1d, 1, shmem_info.total_size, shmem_cache.ReadWrite());
R->MultTranspose(ye_mem, derivative_action_l);
};
if constexpr (std::is_same_v<decltype(output_fop), One>)
{
prolongation_transpose = [&](Vector &r_local, Vector &y)
{
double local_sum = r_local.Sum();
MPI_Allreduce(&local_sum, y.GetData(), 1, MPI_DOUBLE, MPI_SUM,
op.mesh.GetComm());
MFEM_ASSERT(y.Size() == 1, "output size doesn't match kernel description");
};
}
else
{
auto P = get_prolongation(op.fields[test_space_field_idx]);
prolongation_transpose = [P](const Vector &r_local, Vector &y)
{
P->MultTranspose(r_local, y);
};
}
}
} // namespace mfem
-79
View File
@@ -1,79 +0,0 @@
#include "dfem_util.hpp"
namespace mfem
{
template <typename func_t, typename input_t, typename output_t, typename dependency_map_t>
struct ElementOperator;
template <typename func_t, typename... input_ts, typename... output_ts, typename dependency_map_t>
struct ElementOperator<func_t, mfem::tuple<input_ts...>, mfem::tuple<output_ts...>, dependency_map_t>
{
using entity_t = Entity::Element;
func_t qfunc;
mfem::tuple<input_ts...> inputs;
mfem::tuple<output_ts...> outputs;
dependency_map_t dependency_map;
using qf_param_ts = typename create_function_signature<
decltype(&func_t::operator())>::type::parameter_ts;
using qf_output_t = typename create_function_signature<
decltype(&func_t::operator())>::type::return_t;
static constexpr size_t num_inputs =
mfem::tuple_size<decltype(inputs)>::value;
static constexpr size_t num_outputs =
mfem::tuple_size<decltype(outputs)>::value;
ElementOperator(func_t qfunc,
mfem::tuple<input_ts...> inputs,
mfem::tuple<output_ts...> outputs)
: qfunc(qfunc), inputs(inputs), outputs(outputs),
dependency_map(make_dependency_map(inputs))
{
// Consistency checks
if constexpr (num_outputs > 1)
{
static_assert(always_false<func_t>,
"more than one output per kernel is not supported right now");
}
constexpr size_t num_qfinputs = mfem::tuple_size<qf_param_ts>::value;
static_assert(num_qfinputs == num_inputs,
"kernel function inputs and descriptor inputs have to match");
constexpr size_t num_qf_outputs = mfem::tuple_size<qf_output_t>::value;
static_assert(num_qf_outputs == num_qf_outputs,
"kernel function outputs and descriptor outputs have to match");
}
};
template <typename func_t, typename... input_ts, typename... output_ts>
ElementOperator(func_t, mfem::tuple<input_ts...>, mfem::tuple<output_ts...>)
-> ElementOperator<func_t, mfem::tuple<input_ts...>, mfem::tuple<output_ts...>,
decltype(make_dependency_map(std::declval<mfem::tuple<input_ts...>>()))>;
// template <typename func_t, typename input_t, typename output_t>
// struct BoundaryElementOperator : public
// ElementOperator<func_t, input_t, output_t>
// {
// public:
// using entity_t = Entity::BoundaryElement;
// BoundaryElementOperator(func_t func, input_t inputs, output_t outputs)
// : ElementOperator<func_t, input_t, output_t>(func, inputs, outputs) {}
// };
// template <typename func_t, typename input_t, typename output_t>
// struct FaceOperator : public
// ElementOperator<func_t, input_t, output_t>
// {
// public:
// using entity_t = Entity::Face;
// FaceOperator(func_t func, input_t inputs, output_t outputs)
// : ElementOperator<func_t, input_t, output_t>(func, inputs, outputs) {}
// };
} // namespace mfem
-227
View File
@@ -1,227 +0,0 @@
#pragma once
#include <string>
namespace mfem
{
template <int FIELD_ID = -1>
class FieldOperator
{
public:
constexpr FieldOperator(int size_on_qp = 0) :
size_on_qp(size_on_qp) {};
static constexpr int GetFieldId() { return FIELD_ID; }
int size_on_qp = -1;
int dim = -1;
int vdim = -1;
};
template <int FIELD_ID = -1>
class None : public FieldOperator<FIELD_ID>
{
public:
constexpr None() : FieldOperator<FIELD_ID>() {}
};
template< typename T >
struct is_none_fop
{
static const bool value = false;
};
template <int FIELD_ID>
struct is_none_fop<None<FIELD_ID>>
{
static const bool value = true;
};
template <typename T>
struct DisableAD
{
T& operator()() const { return fop; }
T fop;
};
class Weight : public FieldOperator<-1>
{
public:
constexpr Weight() : FieldOperator<-1>() {};
};
template< typename T >
struct is_weight_fop
{
static const bool value = false;
};
template <>
struct is_weight_fop<Weight>
{
static const bool value = true;
};
template <int FIELD_ID = -1>
class Value : public FieldOperator<FIELD_ID>
{
public:
constexpr Value() : FieldOperator<FIELD_ID>() {};
};
template< typename T >
struct is_value_fop
{
static const bool value = false;
};
template <int FIELD_ID>
struct is_value_fop<Value<FIELD_ID>>
{
static const bool value = true;
};
template <typename T>
struct is_value_fop<DisableAD<T>>
{
static const bool value = is_value_fop<T>::value;
};
template <int FIELD_ID = -1>
class Gradient : public FieldOperator<FIELD_ID>
{
public:
constexpr Gradient() : FieldOperator<FIELD_ID>() {};
};
template< typename T >
struct is_gradient_fop
{
static const bool value = false;
};
template <int FIELD_ID>
struct is_gradient_fop<Gradient<FIELD_ID>>
{
static const bool value = true;
};
// class FieldOperator
// {
// public:
// FieldOperator(std::string field_label = "", int size_on_qp = 0) :
// field_label(field_label),
// size_on_qp(size_on_qp) {};
// std::string field_label;
// int size_on_qp = -1;
// int dim = -1;
// int vdim = -1;
// };
// class None : public FieldOperator
// {
// public:
// None(std::string field_label) :
// FieldOperator(field_label) {}
// };
// class Weight : public FieldOperator
// {
// public:
// Weight() : FieldOperator("quadrature_weights") {};
// };
// class Value : public FieldOperator
// {
// public:
// Value(std::string field_label) : FieldOperator(field_label) {};
// };
// class Gradient : public FieldOperator
// {
// public:
// Gradient(std::string field_label) : FieldOperator(field_label) {};
// };
// class Curl : public FieldOperator
// {
// public:
// Curl(std::string field_label) : FieldOperator(field_label) {};
// };
// class Div : public FieldOperator
// {
// public:
// Div(std::string field_label) : FieldOperator(field_label) {};
// };
// class FaceValueLeft : public FieldOperator
// {
// public:
// FaceValueLeft(std::string field_label) : FieldOperator(field_label) {};
// };
// class FaceValueRight : public FieldOperator
// {
// public:
// FaceValueRight(std::string field_label) : FieldOperator(field_label) {};
// };
// class FaceNormal : public FieldOperator
// {
// public:
// FaceNormal(std::string field_label) : FieldOperator(field_label) {};
// };
// class One : public FieldOperator
// {
// public:
// One(std::string field_label) : FieldOperator(field_label) {};
// };
// namespace BareFieldOperator
// {
// struct Base
// {
// Base(FieldOperator &o)
// {
// size_on_qp = o.size_on_qp;
// dim = o.dim;
// vdim = o.vdim;
// };
// int size_on_qp = -1;
// int dim = -1;
// int vdim = -1;
// };
// struct None : Base
// {
// None(FieldOperator &o) : Base(o) {}
// };
// struct Weight : Base
// {
// Weight(FieldOperator &o) : Base(o) {}
// };
// struct Value : Base
// {
// Value(FieldOperator &o) : Base(o) {}
// };
// struct Gradient : Base
// {
// Gradient(FieldOperator &o) : Base(o) {}
// };
// }
} // namespace mfem
-290
View File
@@ -1,290 +0,0 @@
#pragma once
#include "dfem_util.hpp"
#include <type_traits>
namespace mfem
{
template <typename output_t>
MFEM_HOST_DEVICE
void map_quadrature_data_to_fields_impl(DeviceTensor<2, double> &y,
const DeviceTensor<3, double> &f,
const output_t &output,
const DofToQuadMap &dtq)
{
auto B = dtq.B;
auto G = dtq.G;
// assuming the quadrature point residual has to "play nice with
// the test function"
if constexpr (std::is_same_v<std::decay_t<output_t>, Value<>>)
{
const auto [num_qp, cdim, num_dof] = B.GetShape();
const int vdim = output.vdim > 0 ? output.vdim : cdim ;
for (int dof = 0; dof < num_dof; dof++)
{
for (int vd = 0; vd < vdim; vd++)
{
double acc = 0.0;
for (int qp = 0; qp < num_qp; qp++)
{
acc += B(qp, 0, dof) * f(vd, 0, qp);
}
y(dof, vd) += acc;
}
}
}
else if constexpr (
std::is_same_v<std::decay_t<output_t>, Gradient<>>)
{
const auto [num_qp, dim, num_dof] = G.GetShape();
const int vdim = output.vdim;
for (int dof = 0; dof < num_dof; dof++)
{
for (int vd = 0; vd < vdim; vd++)
{
double acc = 0.0;
for (int d = 0; d < dim; d++)
{
for (int qp = 0; qp < num_qp; qp++)
{
acc += G(qp, d, dof) * f(vd, d, qp);
}
}
y(dof, vd) += acc;
}
}
}
// else if constexpr (std::is_same_v<std::decay_t<output_t>, One>)
// {
// // This is the "integral over all quadrature points type" applying
// // B = 1 s.t. B^T * C \in R^1.
// const auto [a, b, num_qp] = B.GetShape();
// auto cc = Reshape(&c(0, 0, 0), num_qp);
// for (int i = 0; i < num_qp; i++)
// {
// y(0, 0) += cc(i);
// }
// }
else if constexpr (
std::is_same_v<std::decay_t<output_t>, None<>>)
{
const auto [vdim, dim, num_qp] = G.GetShape();
auto cc = Reshape(&f(0, 0, 0), num_qp * vdim);
auto yy = Reshape(&y(0, 0), num_qp * vdim);
for (int i = 0; i < num_qp * vdim; i++)
{
yy(i) = cc(i);
}
}
else
{
MFEM_ABORT("quadrature data mapping to field is not implemented for"
" this field descriptor");
}
}
template <typename output_t>
MFEM_HOST_DEVICE
void map_quadrature_data_to_fields_tensor_impl(DeviceTensor<2, double> &y,
const DeviceTensor<3, double> &f,
const output_t &output,
const DofToQuadMap &dtq,
std::array<DeviceTensor<1>, 6> &scratch_mem)
{
auto B = dtq.B;
auto G = dtq.G;
if constexpr (is_value_fop<std::decay_t<output_t>>::value)
{
const auto [q1d, unused, d1d] = B.GetShape();
const int vdim = output.vdim;
const int test_dim = output.size_on_qp / vdim;
auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d, q1d, q1d);
auto yd = Reshape(&y(0, 0), d1d, d1d, d1d, vdim);
auto s0 = Reshape(&scratch_mem[0](0), q1d, q1d, d1d);
auto s1 = Reshape(&scratch_mem[1](0), q1d, d1d, d1d);
for (int vd = 0; vd < vdim; vd++)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(dx, x, d1d)
{
MFEM_FOREACH_THREAD(qz, z, q1d)
{
double acc = 0.0;
for (int qx = 0; qx < q1d; qx++)
{
acc += fqp(vd, 0, qx, qy, qz) * B(qx, 0, dx);
}
s0(qz, qy, dx) = acc;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy, y, d1d)
{
MFEM_FOREACH_THREAD(dx, x, d1d)
{
MFEM_FOREACH_THREAD(qz, z, q1d)
{
double acc = 0.0;
for (int qy = 0; qy < q1d; qy++)
{
acc += s0(qz, qy, dx) * B(qy, 0, dy);
}
s1(qz, dy, dx) = acc;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy, y, d1d)
{
MFEM_FOREACH_THREAD(dx, x, d1d)
{
MFEM_FOREACH_THREAD(dz, z, d1d)
{
double acc = 0.0;
for (int qz = 0; qz < q1d; qz++)
{
acc += s1(qz, dy, dx) * B(qz, 0, dz);
}
yd(dx, dy, dz, vd) += acc;
}
}
}
MFEM_SYNC_THREAD;
}
}
else if constexpr (is_gradient_fop<std::decay_t<output_t>>::value)
{
const auto [q1d, unused, d1d] = G.GetShape();
const int vdim = output.vdim;
const int test_dim = output.size_on_qp / vdim;
auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d, q1d, q1d);
auto yd = Reshape(&y(0, 0), d1d, d1d, d1d, vdim);
auto s0 = Reshape(&scratch_mem[0](0), q1d, q1d, d1d);
auto s1 = Reshape(&scratch_mem[1](0), q1d, q1d, d1d);
auto s2 = Reshape(&scratch_mem[2](0), q1d, q1d, d1d);
auto s3 = Reshape(&scratch_mem[3](0), q1d, d1d, d1d);
auto s4 = Reshape(&scratch_mem[4](0), q1d, d1d, d1d);
auto s5 = Reshape(&scratch_mem[5](0), q1d, d1d, d1d);
for (int vd = 0; vd < vdim; vd++)
{
MFEM_FOREACH_THREAD(qz, z, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(dx, x, d1d)
{
real_t uvw[3] = {0.0, 0.0, 0.0};
for (int qx = 0; qx < q1d; qx++)
{
uvw[0] += fqp(vd, 0, qx, qy, qz) * G(qx, 0, dx);
uvw[1] += fqp(vd, 1, qx, qy, qz) * B(qx, 0, dx);
uvw[2] += fqp(vd, 2, qx, qy, qz) * B(qx, 0, dx);
}
s0(qz, qy, dx) = uvw[0];
s1(qz, qy, dx) = uvw[1];
s2(qz, qy, dx) = uvw[2];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz, z, q1d)
{
MFEM_FOREACH_THREAD(dy, y, d1d)
{
MFEM_FOREACH_THREAD(dx, x, d1d)
{
real_t uvw[3] = {0.0, 0.0, 0.0};
for (int qy = 0; qy < q1d; qy++)
{
uvw[0] += s0(qz, qy, dx) * B(qy, 0, dy);
uvw[1] += s1(qz, qy, dx) * G(qy, 0, dy);
uvw[2] += s2(qz, qy, dx) * B(qy, 0, dy);
}
s3(qz, dy, dx) = uvw[0];
s4(qz, dy, dx) = uvw[1];
s5(qz, dy, dx) = uvw[2];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz, z, d1d)
{
MFEM_FOREACH_THREAD(dy, y, d1d)
{
MFEM_FOREACH_THREAD(dx, x, d1d)
{
real_t uvw[3] = {0.0, 0.0, 0.0};
for (int qz = 0; qz < q1d; qz++)
{
uvw[0] += s3(qz, dy, dx) * B(qz, 0, dz);
uvw[1] += s4(qz, dy, dx) * B(qz, 0, dz);
uvw[2] += s5(qz, dy, dx) * G(qz, 0, dz);
}
yd(dx, dy, dz, vd) += uvw[0] + uvw[1] + uvw[2];
}
}
}
MFEM_SYNC_THREAD;
}
}
else if constexpr (is_none_fop<std::decay_t<output_t>>::value)
{
const auto [q1d, unused, d1d] = B.GetShape();
auto fqp = Reshape(&f(0, 0, 0), output.size_on_qp, q1d, q1d, q1d);
auto yqp = Reshape(&y(0, 0), output.size_on_qp, q1d, q1d, q1d);
for (int sq = 0; sq < output.size_on_qp; sq++)
{
MFEM_FOREACH_THREAD(qx, x, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(qz, z, q1d)
{
yqp(sq, qx, qy, qz) = fqp(sq, qx, qy, qz);
}
}
}
MFEM_SYNC_THREAD;
}
}
else
{
MFEM_ABORT("quadrature data mapping to field is not implemented for"
" this field descriptor with sum factorization on tensor product elements");
}
}
template <typename T = NonTensorProduct, typename output_t>
MFEM_HOST_DEVICE
void map_quadrature_data_to_fields(DeviceTensor<2, double> &y,
const DeviceTensor<3, double> &f,
const output_t &output,
const DofToQuadMap &dtq,
std::array<DeviceTensor<1>, 6> &scratch_mem)
{
if constexpr (std::is_same_v<T, NonTensorProduct>)
{
map_quadrature_data_to_fields_impl(y, f, output, dtq);
}
else if constexpr (std::is_same_v<T, TensorProduct>)
{
map_quadrature_data_to_fields_tensor_impl(y, f, output, dtq, scratch_mem);
}
}
}
-403
View File
@@ -1,403 +0,0 @@
#pragma once
#include "dfem_util.hpp"
namespace mfem
{
template <typename field_operator_t>
MFEM_HOST_DEVICE inline
void map_field_to_quadrature_data_tensor_product(
DeviceTensor<2> &field_qp,
const DofToQuadMap &dtq,
const DeviceTensor<1> &field_e,
const field_operator_t &input,
const DeviceTensor<1, const double> &integration_weights,
const std::array<DeviceTensor<1>, 6> &scratch_mem)
{
auto B = dtq.B;
auto G = dtq.G;
if constexpr (is_value_fop<std::decay_t<field_operator_t>>::value)
{
auto [q1d, unused, d1d] = B.GetShape();
const int vdim = input.vdim;
const auto field = Reshape(&field_e[0], d1d, d1d, d1d, vdim);
auto fqp = Reshape(&field_qp[0], vdim, q1d, q1d, q1d);
auto s0 = Reshape(&scratch_mem[0](0), d1d, d1d, q1d);
auto s1 = Reshape(&scratch_mem[1](0), d1d, q1d, q1d);
for (int vd = 0; vd < vdim; vd++)
{
MFEM_FOREACH_THREAD(dz, z, d1d)
{
MFEM_FOREACH_THREAD(dy, y, d1d)
{
MFEM_FOREACH_THREAD(qx, x, q1d)
{
double acc = 0.0;
for (int dx = 0; dx < d1d; dx++)
{
acc += B(qx, 0, dx) * field(dx, dy, dz, vd);
}
s0(dz, dy, qx) = acc;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz, z, d1d)
{
MFEM_FOREACH_THREAD(qx, x, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
double acc = 0.0;
for (int dy = 0; dy < d1d; dy++)
{
acc += s0(dz, dy, qx) * B(qy, 0, dy);
}
s1(dz, qy, qx) = acc;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz, z, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(qx, x, q1d)
{
double acc = 0.0;
for (int dz = 0; dz < d1d; dz++)
{
acc += s1(dz, qy, qx) * B(qz, 0, dz);
}
fqp(vd, qx, qy, qz) = acc;
}
}
}
MFEM_SYNC_THREAD;
}
}
else if constexpr (
is_gradient_fop<std::decay_t<field_operator_t>>::value)
{
const auto [q1d, unused, d1d] = B.GetShape();
const int vdim = input.vdim;
const int dim = input.dim;
const auto field = Reshape(&field_e[0], d1d, d1d, d1d, vdim);
auto fqp = Reshape(&field_qp[0], vdim, dim, q1d, q1d, q1d);
auto s0 = Reshape(&scratch_mem[0](0), d1d, d1d, q1d);
auto s1 = Reshape(&scratch_mem[1](0), d1d, d1d, q1d);
auto s2 = Reshape(&scratch_mem[2](0), d1d, q1d, q1d);
auto s3 = Reshape(&scratch_mem[3](0), d1d, q1d, q1d);
auto s4 = Reshape(&scratch_mem[4](0), d1d, q1d, q1d);
for (int vd = 0; vd < vdim; vd++)
{
MFEM_FOREACH_THREAD(dz, z, d1d)
{
MFEM_FOREACH_THREAD(dy, y, d1d)
{
MFEM_FOREACH_THREAD(qx, x, q1d)
{
real_t uv[2] = {0.0, 0.0};
for (int dx = 0; dx < d1d; dx++)
{
const real_t f = field(dx, dy, dz, vd);
uv[0] += f * B(qx, 0, dx);
uv[1] += f * G(qx, 0, dx);
}
s0(dz, dy, qx) = uv[0];
s1(dz, dy, qx) = uv[1];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz, z, d1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(qx, x, q1d)
{
real_t uvw[3] = {0.0, 0.0, 0.0};
for (int dy = 0; dy < d1d; dy++)
{
const real_t s0i = s0(dz, dy, qx);
uvw[0] += s1(dz, dy, qx) * B(qy, 0, dy);
uvw[1] += s0i * G(qy, 0, dy);
uvw[2] += s0i * B(qy, 0, dy);
}
s2(dz, qy, qx) = uvw[0];
s3(dz, qy, qx) = uvw[1];
s4(dz, qy, qx) = uvw[2];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz, z, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(qx, x, q1d)
{
real_t uvw[3] = {0.0, 0.0, 0.0};
for (int dz = 0; dz < d1d; dz++)
{
uvw[0] += s2(dz, qy, qx) * B(qz, 0, dz);
uvw[1] += s3(dz, qy, qx) * B(qz, 0, dz);
uvw[2] += s4(dz, qy, qx) * G(qz, 0, dz);
}
fqp(vd, 0, qx, qy, qz) = uvw[0];
fqp(vd, 1, qx, qy, qz) = uvw[1];
fqp(vd, 2, qx, qy, qz) = uvw[2];
}
}
}
MFEM_SYNC_THREAD;
}
}
// TODO: Create separate function for clarity
else if constexpr (
std::is_same_v<std::decay_t<field_operator_t>, Weight>)
{
const int num_qp = integration_weights.GetShape()[0];
// TODO: eeek
const int q1d = (int)floor(pow(num_qp, 1.0/input.dim) + 0.5);
auto w = Reshape(&integration_weights[0], q1d, q1d, q1d);
auto f = Reshape(&field_qp[0], q1d, q1d, q1d);
MFEM_FOREACH_THREAD(qx, x, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(qz, z, q1d)
{
f(qx, qy, qz) = w(qx, qy, qz);
}
}
}
MFEM_SYNC_THREAD;
}
else if constexpr (is_none_fop<std::decay_t<field_operator_t>>::value)
{
const int q1d = B.GetShape()[0];
auto field = Reshape(&field_e[0], input.size_on_qp, q1d * q1d * q1d);
field_qp = field;
}
else
{
static_assert(always_false<std::decay_t<field_operator_t>>,
"can't map field to quadrature data");
}
}
template <typename field_operator_t>
MFEM_HOST_DEVICE
void map_field_to_quadrature_data(
DeviceTensor<2> field_qp,
const DofToQuadMap &dtq,
const DeviceTensor<1, const double> &field_e,
field_operator_t &input,
DeviceTensor<1, const double> integration_weights)
{
auto B = dtq.B;
auto G = dtq.G;
if constexpr (is_value_fop<field_operator_t>::value)
{
auto [num_qp, dim, num_dof] = B.GetShape();
const int vdim = input.vdim;
const auto field = Reshape(&field_e(0), num_dof, vdim);
for (int vd = 0; vd < vdim; vd++)
{
for (int qp = 0; qp < num_qp; qp++)
{
double acc = 0.0;
for (int dof = 0; dof < num_dof; dof++)
{
acc += B(qp, 0, dof) * field(dof, vd);
}
field_qp(vd, qp) = acc;
}
}
}
else if constexpr (is_gradient_fop<field_operator_t>::value)
{
const auto [num_qp, dim, num_dof] = G.GetShape();
const int vdim = input.vdim;
const auto field = Reshape(&field_e(0), num_dof, vdim);
auto f = Reshape(&field_qp[0], vdim, dim, num_qp);
for (int qp = 0; qp < num_qp; qp++)
{
for (int vd = 0; vd < vdim; vd++)
{
for (int d = 0; d < dim; d++)
{
double acc = 0.0;
for (int dof = 0; dof < num_dof; dof++)
{
acc += G(qp, d, dof) * field(dof, vd);
}
f(vd, d, qp) = acc;
}
}
}
}
// else if constexpr (std::is_same_v<field_operator_t, FaceNormal>)
// {
// auto normal = geometric_factors.normal;
// auto [num_qp, dim, num_entities] = normal.GetShape();
// auto f = Reshape(&field_qp[0], dim, num_qp);
// for (int qp = 0; qp < num_qp; qp++)
// {
// for (int d = 0; d < dim; d++)
// {
// f(d, qp) = normal(qp, d, entity_idx);
// }
// }
// }
// TODO: Create separate function for clarity
else if constexpr (std::is_same_v<field_operator_t, Weight>)
{
const int num_qp = integration_weights.GetShape()[0];
auto f = Reshape(&field_qp[0], num_qp);
for (int qp = 0; qp < num_qp; qp++)
{
f(qp) = integration_weights(qp);
}
}
else if constexpr (is_none_fop<field_operator_t>::value)
{
auto [num_qp, unused, num_dof] = B.GetShape();
const int size_on_qp = input.size_on_qp;
const auto field = Reshape(&field_e[0], size_on_qp * num_qp);
auto f = Reshape(&field_qp[0], size_on_qp * num_qp);
for (int i = 0; i < size_on_qp * num_qp; i++)
{
f(i) = field(i);
}
}
else
{
static_assert(always_false<field_operator_t>,
"can't map field to quadrature data");
}
}
template <typename T = NonTensorProduct, typename field_operator_ts, size_t num_inputs, size_t num_fields>
MFEM_HOST_DEVICE inline
void map_fields_to_quadrature_data(
std::array<DeviceTensor<2>, num_inputs> &fields_qp,
const std::array<DeviceTensor<1>, num_fields> &fields_e,
const std::array<DofToQuadMap, num_inputs> &dtqmaps,
const std::array<int, num_inputs> &input_to_field,
const field_operator_ts &fops,
const DeviceTensor<1, const double> &integration_weights,
const std::array<DeviceTensor<1>, 6> &scratch_mem)
{
for_constexpr<num_inputs>([&](auto i)
{
if constexpr (std::is_same_v<T, TensorProduct>)
{
map_field_to_quadrature_data_tensor_product(
fields_qp[i],
dtqmaps[i],
fields_e[input_to_field[i]],
mfem::get<i>(fops),
integration_weights,
scratch_mem);
}
else
{
map_field_to_quadrature_data(
fields_qp[i],
dtqmaps[i],
fields_e[i],
mfem::get<i>(fops),
integration_weights);
}
});
}
template <typename T, typename field_operator_t>
MFEM_HOST_DEVICE
void map_field_to_quadrature_data_conditional(
DeviceTensor<2> &field_qp,
const DeviceTensor<1> &field_e,
const DofToQuadMap &dtqmap,
field_operator_t &fop,
const DeviceTensor<1, const double> &integration_weights,
const std::array<DeviceTensor<1>, 6> &scratch_mem,
const bool &condition)
{
if (condition)
{
if constexpr (std::is_same_v<T, TensorProduct>)
{
map_field_to_quadrature_data_tensor_product(field_qp, dtqmap,
field_e, fop,
integration_weights,
scratch_mem);
}
else
{
map_field_to_quadrature_data(field_qp, dtqmap, field_e, fop,
integration_weights);
}
}
}
template <typename T = NonTensorProduct, size_t num_fields, size_t num_kinputs, typename field_operator_ts, std::size_t... i>
MFEM_HOST_DEVICE
void map_fields_to_quadrature_data_conditional(
std::array<DeviceTensor<2>, num_kinputs> &fields_qp,
const std::array<DeviceTensor<1, const double>, num_fields> &fields_e,
const std::array<DofToQuadMap, num_kinputs> &dtqmaps,
field_operator_ts fops,
const DeviceTensor<1, const double> &integration_weights,
const std::array<DeviceTensor<1>, 6> &scratch_mem,
const std::array<bool, num_kinputs> &conditions,
std::index_sequence<i...>)
{
(map_field_to_quadrature_data_conditional<T>(fields_qp[i],
fields_e[i],
dtqmaps[i],
mfem::get<i>(fops),
integration_weights,
scratch_mem,
conditions[i]),
...);
}
template <typename T = NonTensorProduct, size_t num_inputs, typename field_operator_ts>
MFEM_HOST_DEVICE
void map_direction_to_quadrature_data_conditional(
std::array<DeviceTensor<2>, num_inputs> &directions_qp,
const DeviceTensor<1> &direction_e,
const std::array<DofToQuadMap, num_inputs> &dtqmaps,
field_operator_ts fops,
const DeviceTensor<1, const double> &integration_weights,
const std::array<DeviceTensor<1>, 6> &scratch_mem,
const std::array<bool, num_inputs> &conditions)
{
for_constexpr<num_inputs>([&](auto i)
{
map_field_to_quadrature_data_conditional<T>(directions_qp[i],
direction_e,
dtqmaps[i],
mfem::get<i>(fops),
integration_weights,
scratch_mem,
conditions[i]);
});
}
}
-99
View File
@@ -1,99 +0,0 @@
#pragma once
#include <mfem.hpp>
namespace mfem
{
class ParametricSpace
{
public:
ParametricSpace(int spatial_dim, int local_size, int element_size,
int total_size) :
spatial_dim(spatial_dim),
local_size(local_size),
element_size(element_size),
total_size(total_size),
identity(total_size)
{
dtq.ndof = (int)floor(pow(element_size, 1.0/spatial_dim) + 0.5);
dtq.nqpt = dtq.ndof;
}
ParametricSpace(int local_size) :
local_size(local_size),
element_size(local_size),
total_size(local_size),
identity(local_size)
{
dtq.ndof = (int)floor(pow(element_size, 1.0/spatial_dim) + 0.5);
dtq.nqpt = dtq.ndof;
}
int Dimension() const
{
return spatial_dim;
}
int GetLocalSize() const
{
return local_size;
}
int GetElementSize() const
{
return element_size;
}
int GetTotalSize() const
{
return total_size;
}
const DofToQuad &GetDofToQuad() const
{
return dtq;
}
const Operator *GetProlongation() const
{
return &identity;
}
const Operator *GetRestriction() const
{
return &identity;
}
private:
int spatial_dim;
// Hint for the local dimension. E.g. the size on the quadrature point or vdim.
int local_size;
// Size of the data on an element
int element_size;
int total_size;
IdentityOperator identity;
DofToQuad dtq;
};
class ParametricFunction : public Vector
{
public:
ParametricFunction(ParametricSpace &space) :
Vector(space.GetTotalSize()),
space(space)
{}
ParametricSpace &space;
using Vector::operator=;
};
}
-253
View File
@@ -1,253 +0,0 @@
#pragma once
#include "dfem_util.hpp"
#ifdef MFEM_USE_ENZYME
#include <enzyme/utils>
#include <enzyme/enzyme>
#endif
namespace mfem
{
template <typename T0, typename T1>
MFEM_HOST_DEVICE
void process_kf_arg(const T0 &, T1 &)
{
static_assert(always_false<T0, T1>,
"process_kf_arg not implemented for arg type");
}
template <typename T>
MFEM_HOST_DEVICE
void process_kf_arg(
const DeviceTensor<1, T> &u,
T &arg)
{
arg = u(0);
}
template <typename T>
MFEM_HOST_DEVICE
void process_kf_arg(
const DeviceTensor<1, T> &u,
internal::tensor<T> &arg)
{
arg(0) = u(0);
}
template <typename T, int n>
MFEM_HOST_DEVICE
void process_kf_arg(
const DeviceTensor<1> &u,
internal::tensor<T, n> &arg)
{
for (int i = 0; i < n; i++)
{
arg(i) = u(i);
}
}
template <typename T, int n, int m>
MFEM_HOST_DEVICE
void process_kf_arg(
const DeviceTensor<1> &u,
internal::tensor<T, n, m> &arg)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
arg(j, i) = u((i * m) + j);
}
}
}
template <typename arg_type>
MFEM_HOST_DEVICE
void process_kf_arg(const DeviceTensor<2> &u, arg_type &arg, int qp)
{
const auto u_qp = Reshape(&u(0, qp), u.GetShape()[0]);
process_kf_arg(u_qp, arg);
}
template <size_t num_fields, typename kf_args, std::size_t... i>
MFEM_HOST_DEVICE
void process_kf_args(
const std::array<DeviceTensor<2>, num_fields> &u,
kf_args &args,
const int &qp,
std::index_sequence<i...>)
{
(process_kf_arg(u[i], mfem::get<i>(args), qp), ...);
}
template <typename T0, typename T1> inline
Vector process_kf_result(T0, T1)
{
static_assert(always_false<T0, T1>,
"process_kf_result not implemented for result type");
}
template <typename T>
MFEM_HOST_DEVICE inline
void process_kf_result(
DeviceTensor<1, T> &r,
const double &x)
{
r(0) = x;
}
template <typename T>
MFEM_HOST_DEVICE inline
void process_kf_result(
DeviceTensor<1, T> &r,
const internal::tensor<T> &x)
{
r(0) = x(0);
}
template <typename T, int n>
MFEM_HOST_DEVICE inline
void process_kf_result(
DeviceTensor<1, T> &r,
const internal::tensor<T, n> &x)
{
for (size_t i = 0; i < n; i++)
{
r(i) = x(i);
}
}
template <typename T, int n, int m>
MFEM_HOST_DEVICE inline
void process_kf_result(
DeviceTensor<1, T> &r,
const internal::tensor<T, n, m> &x)
{
for (size_t i = 0; i < n; i++)
{
for (size_t j = 0; j < m; j++)
{
r(i + n * j) = x(i, j);
}
}
}
template <typename T>
MFEM_HOST_DEVICE inline
void process_kf_arg(
const DeviceTensor<1> &u,
const DeviceTensor<1> &v,
double &arg)
{
arg = u(0);
}
template <int n, int m>
MFEM_HOST_DEVICE inline
void process_kf_arg(
const DeviceTensor<1> &u,
const DeviceTensor<1> &v,
internal::tensor<double, n, m> &arg)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
arg(j, i) = u((i * m) + j);
}
}
}
template <typename kernel_func_t, typename kernel_args_ts, size_t num_args>
MFEM_HOST_DEVICE inline
void apply_kernel(
DeviceTensor<1, double> &f_qp,
const kernel_func_t &kf,
kernel_args_ts &args,
const std::array<DeviceTensor<2>, num_args> &u,
int qp)
{
process_kf_args(u, args, qp,
std::make_index_sequence<mfem::tuple_size<kernel_args_ts>::value> {});
process_kf_result(f_qp, mfem::get<0>(mfem::apply(kf, args)));
}
#ifdef MFEM_USE_ENZYME
// Version for active function arguments only
//
// This is an Enzyme regression and can be removed in later versions.
template <typename kernel_t, typename arg_ts, std::size_t... Is,
typename inactive_arg_ts>
MFEM_HOST_DEVICE inline
auto fwddiff_apply_enzyme_indexed(kernel_t kernel, arg_ts &&args,
arg_ts &&shadow_args,
std::index_sequence<Is...>,
inactive_arg_ts &&inactive_args,
std::index_sequence<>)
{
using kf_return_t = typename create_function_signature<
decltype(&kernel_t::operator())>::type::return_t;
return __enzyme_fwddiff<kf_return_t>(
+kernel, enzyme_dup, &mfem::get<Is>(args)..., enzyme_interleave,
&mfem::get<Is>(shadow_args)...);
}
// Interleave function arguments for enzyme
template <typename kernel_t, typename arg_ts, std::size_t... Is,
typename inactive_arg_ts, std::size_t... Js>
MFEM_HOST_DEVICE inline
auto fwddiff_apply_enzyme_indexed(kernel_t kernel, arg_ts &&args,
arg_ts &&shadow_args,
std::index_sequence<Is...>,
inactive_arg_ts &&inactive_args,
std::index_sequence<Js...>)
{
using kf_return_t = typename create_function_signature<
decltype(&kernel_t::operator())>::type::return_t;
return __enzyme_fwddiff<kf_return_t>(
+kernel, enzyme_dup, &std::get<Is>(args)..., enzyme_const,
&mfem::get<Js>(inactive_args)..., enzyme_interleave,
&mfem::get<Is>(shadow_args)...);
}
template <typename kernel_t, typename arg_ts, typename inactive_arg_ts>
MFEM_HOST_DEVICE inline
auto fwddiff_apply_enzyme(kernel_t kernel, arg_ts &&args,
arg_ts &&shadow_args,
inactive_arg_ts &&inactive_args)
{
auto arg_indices = std::make_index_sequence<
mfem::tuple_size<std::remove_reference_t<arg_ts>>::value> {};
auto inactive_arg_indices = std::make_index_sequence<
mfem::tuple_size<std::remove_reference_t<inactive_arg_ts>>::value> {};
return fwddiff_apply_enzyme_indexed(kernel, args, shadow_args, arg_indices,
inactive_args, inactive_arg_indices);
}
template <typename kf_t, typename kernel_arg_ts, size_t num_args>
MFEM_HOST_DEVICE inline
void apply_kernel_fwddiff_enzyme(
DeviceTensor<1, double> &f_qp,
const kf_t &kf,
kernel_arg_ts &args,
kernel_arg_ts &shadow_args,
const std::array<DeviceTensor<2>, num_args> &u,
const std::array<DeviceTensor<2>, num_args> &v,
int qp_idx)
{
process_kf_args(u, args, qp_idx,
std::make_index_sequence<mfem::tuple_size<kernel_arg_ts>::value> {});
process_kf_args(v, shadow_args, qp_idx,
std::make_index_sequence<mfem::tuple_size<kernel_arg_ts>::value> {});
process_kf_result(f_qp,
mfem::get<0>(fwddiff_apply_enzyme(kf, args, shadow_args, mfem::tuple<> {})));
}
#endif // MFEM_USE_ENZYME
} // namespace mfem
-187
View File
@@ -1,187 +0,0 @@
#pragma once
#include "dfem_util.hpp"
#include "dfem_qfunction.hpp"
namespace mfem
{
MFEM_HOST_DEVICE
template <typename T0, typename T1, typename T2>
void process_kf_arg(const T0 &, const T1 &, T2 &)
{
static_assert(always_false<T0, T1, T2>,
"process_kf_arg not implemented for arg type");
}
template <typename T>
MFEM_HOST_DEVICE
void process_kf_arg(
const DeviceTensor<1, T> &u,
const DeviceTensor<1, T> &v,
T &arg)
{
arg = u(0);
}
template <typename T, int n, int m>
MFEM_HOST_DEVICE inline
void process_kf_arg(
const DeviceTensor<1> &u,
internal::tensor<internal::dual<T, T>, n, m> &arg)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
arg(j, i).value = u((i * m) + j);
}
}
}
template <typename T>
MFEM_HOST_DEVICE inline
void process_kf_arg(
const DeviceTensor<1> &u,
internal::dual<T, T> &arg)
{
arg.value = u(0);
}
template <typename T>
MFEM_HOST_DEVICE inline
void process_kf_arg(
const DeviceTensor<1> &u,
const DeviceTensor<1> &v,
internal::dual<T, T> &arg)
{
arg.value = u(0);
arg.gradient = v(0);
}
template <typename T, int n>
MFEM_HOST_DEVICE inline
void process_kf_arg(
const DeviceTensor<1> &u,
const DeviceTensor<1> &v,
internal::tensor<internal::dual<T, T>, n> &arg)
{
for (int i = 0; i < n; i++)
{
arg(i).value = u(i);
arg(i).gradient = v(i);
}
}
template <typename T, int n, int m>
MFEM_HOST_DEVICE inline
void process_kf_arg(
const DeviceTensor<1> &u,
const DeviceTensor<1> &v,
internal::tensor<internal::dual<T, T>, n, m> &arg)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
arg(j, i).value = u((i * m) + j);
arg(j, i).gradient = v((i * m) + j);
}
}
}
template <typename T, int n>
MFEM_HOST_DEVICE inline
void process_kf_result(
DeviceTensor<1, T> &r,
const internal::tensor<internal::dual<T, T>, n> &x)
{
for (size_t i = 0; i < n; i++)
{
r(i) = x(i).value;
}
}
template <typename T, int n, int m>
MFEM_HOST_DEVICE inline
void process_kf_result(
DeviceTensor<1, T> &r,
const internal::tensor<internal::dual<T, T>, n, m> &x)
{
for (size_t i = 0; i < n; i++)
{
for (size_t j = 0; j < m; j++)
{
r(i + n * j) = x(i, j).value;
}
}
}
template <typename arg_type>
MFEM_HOST_DEVICE inline
void process_kf_arg(
const DeviceTensor<2> &u,
const DeviceTensor<2> &v,
arg_type &arg,
const int &qp)
{
const auto u_qp = Reshape(&u(0, qp), u.GetShape()[0]);
const auto v_qp = Reshape(&v(0, qp), v.GetShape()[0]);
process_kf_arg(u_qp, v_qp, arg);
}
template <size_t num_args, typename kf_args, std::size_t... Is>
MFEM_HOST_DEVICE inline
void process_kf_args(
const std::array<DeviceTensor<2>, num_args> &u,
const std::array<DeviceTensor<2>, num_args> &v,
kf_args &args,
const int &qp,
std::index_sequence<Is...>)
{
(process_kf_arg(u[Is], v[Is], mfem::get<Is>(args), qp), ...);
}
template <typename T, int n, int m>
MFEM_HOST_DEVICE inline
void process_derivative_from_native_dual(
DeviceTensor<1, T> &r,
const internal::tensor<internal::dual<T, T>, n, m> &x)
{
for (size_t i = 0; i < n; i++)
{
for (size_t j = 0; j < m; j++)
{
r(i + n * j) = x(i, j).gradient;
}
}
}
template <typename T, int n>
MFEM_HOST_DEVICE inline
void process_derivative_from_native_dual(
DeviceTensor<1, T> &r,
const internal::tensor<internal::dual<T, T>, n> &x)
{
for (size_t i = 0; i < n; i++)
{
r(i) = x(i).gradient;
}
}
template <typename kf_t, typename kernel_arg_ts, size_t num_args>
MFEM_HOST_DEVICE inline
void apply_kernel_native_dual(
DeviceTensor<1, double> &f_qp,
const kf_t &kf,
kernel_arg_ts &args,
const std::array<DeviceTensor<2>, num_args> &u,
const std::array<DeviceTensor<2>, num_args> &v,
const int &qp_idx)
{
process_kf_args(u, v, args, qp_idx,
std::make_index_sequence<mfem::tuple_size<kernel_arg_ts>::value> {});
auto r = mfem::get<0>(mfem::apply(kf, args));
process_derivative_from_native_dual(f_qp, r);
}
} // namespace mfem
-530
View File
@@ -1,530 +0,0 @@
#pragma once
#include <mfem.hpp>
#include <utility>
#include "dfem_interpolate.hpp"
#include "dfem_integrate.hpp"
#include "dfem_qfunction.hpp"
#include "dfem_qfunction_dual.hpp"
#include "examples/dfem/dfem_util.hpp"
namespace mfem
{
class DerivativeOperator : public Operator
{
using derivative_action_t =
std::function<void(std::vector<Vector> &, const Vector &, Vector &)>;
using restriction_callback_t =
std::function<void(std::vector<Vector> &,
const std::vector<Vector> &,
std::vector<Vector> &)>;
public:
DerivativeOperator(
const std::vector<derivative_action_t> &derivative_actions,
const FieldDescriptor &direction,
const std::vector<Vector *> &solutions_l,
const std::vector<Vector *> &parameters_l,
const std::vector<restriction_callback_t> &restriction_callbacks,
const std::function<void(Vector &, Vector &)> prolongation_transpose) :
derivative_actions(derivative_actions),
direction(direction),
restriction_callbacks(restriction_callbacks),
derivative_action_l(GetVSize(direction)),
prolongation_transpose(prolongation_transpose)
{
MFEM_ASSERT(derivative_actions.size() == restriction_callbacks.size(),
"internal error");
derivative_action_l = 0.0;
this->solutions_l.resize(solutions_l.size());
this->parameters_l.resize(parameters_l.size());
for (int i = 0; i < solutions_l.size(); i++)
{
this->solutions_l[i] = *solutions_l[i];
}
for (int i = 0; i < parameters_l.size(); i++)
{
this->parameters_l[i] = *parameters_l[i];
}
fields_e.resize(solutions_l.size() + parameters_l.size());
}
void Mult(const Vector &x, Vector &y) const override
{
direction_t = x;
direction_t.SetSubVector(ess_tdof_list, 0.0);
prolongation(direction, direction_t, direction_l);
for (int i = 0; i < derivative_actions.size(); i++)
{
restriction_callbacks[i](solutions_l, parameters_l, fields_e);
derivative_actions[i](fields_e, direction_l, derivative_action_l);
}
prolongation_transpose(derivative_action_l, y);
y.SetSubVector(ess_tdof_list, 0.0);
};
private:
std::vector<derivative_action_t> derivative_actions;
mutable std::vector<Vector> solutions_l;
std::vector<Vector> parameters_l;
FieldDescriptor direction;
mutable Vector direction_t;
mutable Vector direction_e;
mutable Vector direction_l;
mutable Vector derivative_action_e;
mutable Vector derivative_action_l;
mutable std::vector<Vector> fields_e;
Array<int> ess_tdof_list;
std::vector<restriction_callback_t> restriction_callbacks;
std::function<void(Vector &, Vector &)> prolongation_transpose;
};
class DifferentiableOperator : public Operator
{
using action_t =
std::function<void(std::vector<Vector> &, const std::vector<Vector> &, Vector &)>;
using derivative_action_t =
std::function<void(std::vector<Vector> &, const Vector &, Vector &)>;
using restriction_callback_t =
std::function<void(std::vector<Vector> &,
const std::vector<Vector> &,
std::vector<Vector> &)>;
public:
DifferentiableOperator(
const std::vector<FieldDescriptor> &solutions,
const std::vector<FieldDescriptor> &parameters,
const ParMesh &mesh);
void Mult(const Vector &x, Vector &y) const override
{
MFEM_ASSERT(!action_callbacks.empty(), "no integrators have been set");
prolongation(solutions, x, solutions_l);
for (auto &action : action_callbacks)
{
action(solutions_l, parameters_l, residual_l);
}
prolongation_transpose(residual_l, y);
y.SetSubVector(ess_tdof_list, 0.0);
}
template <
typename func_t,
typename... input_ts,
typename... output_ts,
typename derivative_indices_t>
void AddDomainIntegrator(
func_t qfunc,
mfem::tuple<input_ts...> inputs,
mfem::tuple<output_ts...> outputs,
const IntegrationRule &integration_rule,
const derivative_indices_t derivative_indices = {});
void SetParameters(std::vector<Vector *> p) const;
std::shared_ptr<DerivativeOperator> GetDerivative(
size_t derivative_idx,
std::vector<Vector *> solutions_l,
std::vector<Vector *> parameters_l)
{
MFEM_ASSERT(derivative_action_callbacks.find(derivative_idx) !=
derivative_action_callbacks.end(),
"no derivative action has been found for index " << derivative_idx);
return std::make_shared<DerivativeOperator>(
derivative_action_callbacks[derivative_idx],
fields[derivative_idx],
solutions_l,
parameters_l,
restriction_callbacks,
prolongation_transpose);
}
private:
const ParMesh &mesh;
std::vector<action_t> action_callbacks;
std::map<size_t, std::vector<derivative_action_t>> derivative_action_callbacks;
std::vector<FieldDescriptor> solutions;
std::vector<FieldDescriptor> parameters;
// solutions and parameters
std::vector<FieldDescriptor> fields;
Array<int> ess_tdof_list;
mutable std::vector<Vector> solutions_l;
mutable std::vector<Vector> parameters_l;
mutable Vector residual_l;
mutable std::vector<Vector> fields_e;
mutable Vector residual_e;
std::function<void(Vector &, Vector &)> prolongation_transpose;
std::vector<restriction_callback_t> restriction_callbacks;
};
void DifferentiableOperator::SetParameters(std::vector<Vector *> p) const
{
MFEM_ASSERT(parameters.size() == p.size(),
"number of parameters doesn't match descriptors");
for (int i = 0; i < parameters.size(); i++)
{
p[i]->Read();
parameters_l[i] = *p[i];
}
}
DifferentiableOperator::DifferentiableOperator(
const std::vector<FieldDescriptor> &solutions,
const std::vector<FieldDescriptor> &parameters,
const ParMesh &mesh) :
mesh(mesh),
solutions(solutions),
parameters(parameters)
{
fields.resize(solutions.size() + parameters.size());
fields_e.resize(fields.size());
solutions_l.resize(solutions.size());
parameters_l.resize(parameters.size());
for (int i = 0; i < solutions.size(); i++)
{
fields[i] = solutions[i];
}
for (int i = 0; i < parameters.size(); i++)
{
fields[i + solutions.size()] = parameters[i];
}
}
template <
typename func_t,
typename... input_ts,
typename... output_ts,
typename derivative_indices_t = std::make_index_sequence<0>>
void DifferentiableOperator::AddDomainIntegrator(
func_t qfunc,
mfem::tuple<input_ts...> inputs,
mfem::tuple<output_ts...> outputs,
const IntegrationRule &integration_rule,
const derivative_indices_t derivative_indices)
{
using entity_t = Entity::Element;
static constexpr size_t num_inputs =
mfem::tuple_size<decltype(inputs)>::value;
static constexpr size_t num_outputs =
mfem::tuple_size<decltype(outputs)>::value;
using qf_param_ts = typename create_function_signature<
decltype(&func_t::operator())>::type::parameter_ts;
using qf_output_t = typename create_function_signature<
decltype(&func_t::operator())>::type::return_t;
// Consistency checks
if constexpr (num_outputs > 1)
{
static_assert(always_false<func_t>,
"more than one output per kernel is not supported right now");
}
constexpr size_t num_qfinputs = mfem::tuple_size<qf_param_ts>::value;
static_assert(num_qfinputs == num_inputs,
"kernel function inputs and descriptor inputs have to match");
constexpr size_t num_qf_outputs = mfem::tuple_size<qf_output_t>::value;
static_assert(num_qf_outputs == num_qf_outputs,
"kernel function outputs and descriptor outputs have to match");
constexpr auto field_tuple = std::tuple_cat(std::tuple<input_ts...> {},
std::tuple<output_ts...> {});
constexpr auto filtered_field_tuple = filter_fields(field_tuple);
constexpr size_t num_fields = count_unique_field_ids(filtered_field_tuple);
constexpr auto dependency_map = make_dependency_map(mfem::tuple<input_ts...> {});
// Create the action callback
auto input_to_field = create_descriptors_to_fields_map<entity_t>(
fields,
inputs,
std::make_index_sequence<num_inputs> {});
auto output_to_field = create_descriptors_to_fields_map<entity_t>(
fields,
outputs,
std::make_index_sequence<num_outputs> {});
constexpr int hardcoded_output_idx = 0;
const int test_space_field_idx = output_to_field[hardcoded_output_idx];
ElementDofOrdering element_dof_ordering = ElementDofOrdering::LEXICOGRAPHIC;
DofToQuad::Mode doftoquad_mode = DofToQuad::Mode::TENSOR;
const Operator *R = get_restriction<entity_t>(fields[test_space_field_idx],
element_dof_ordering);
// The explicit captures are necessary to avoid dependency on
// the specific instance of this class (this pointer).
auto restriction_callback =
[=, solutions = this->solutions, parameters = this->parameters]
(std::vector<Vector> &solutions_l,
const std::vector<Vector> &parameters_l,
std::vector<Vector> &fields_e)
{
restriction<entity_t>(solutions, solutions_l, fields_e,
element_dof_ordering);
restriction<entity_t>(parameters, parameters_l, fields_e,
element_dof_ordering,
solutions.size());
};
restriction_callbacks.push_back(restriction_callback);
auto output_fop = mfem::get<hardcoded_output_idx>(outputs);
if constexpr (is_none_fop<decltype(output_fop)>::value)
{
prolongation_transpose = [&](Vector &r_local, Vector &y)
{
y = r_local;
};
}
// else if constexpr (std::is_same_v<decltype(output_fop), One>)
// {
// prolongation_transpose = [&](Vector &r_local, Vector &y)
// {
// double local_sum = r_local.Sum();
// MPI_Allreduce(&local_sum, y.GetData(), 1, MPI_DOUBLE, MPI_SUM,
// op.mesh.GetComm());
// MFEM_ASSERT(y.Size() == 1, "output size doesn't match kernel description");
// };
// }
else
{
auto P = get_prolongation(fields[test_space_field_idx]);
prolongation_transpose = [P](const Vector &r_local, Vector &y)
{
P->MultTranspose(r_local, y);
};
}
const int num_elements = GetNumEntities<Entity::Element>(mesh);
const int num_entities = GetNumEntities<entity_t>(mesh);
const int num_qp = integration_rule.GetNPoints();
size_t residual_lsize = GetVSize(fields[test_space_field_idx]);
// if constexpr (std::is_same_v<decltype(output_fop), One>)
// {
// this->width = 1;
// }
// else
{
width = residual_lsize;
}
residual_l.SetSize(residual_lsize);
std::vector<const DofToQuad*> dtq;
for (const auto &field : fields)
{
dtq.emplace_back(GetDofToQuad<entity_t>(
field,
integration_rule,
doftoquad_mode));
}
const int q1d = (int)floor(pow(num_qp, 1.0/mesh.Dimension()) + 0.5);
residual_e.SetSize(R->Height());
const int residual_size_on_qp =
GetSizeOnQP<entity_t>(mfem::get<hardcoded_output_idx>(outputs),
fields[test_space_field_idx]);
auto input_dtq_maps =
create_dtq_maps<entity_t>(inputs, dtq, input_to_field);
auto output_dtq_maps =
create_dtq_maps<entity_t>(outputs, dtq, output_to_field);
const int test_vdim = mfem::get<hardcoded_output_idx>(outputs).vdim;
const int test_op_dim =
mfem::get<hardcoded_output_idx>(inputs).size_on_qp /
mfem::get<hardcoded_output_idx>(outputs).vdim;
const int num_test_dof = R->Height() /
mfem::get<hardcoded_output_idx>(outputs).vdim /
num_entities;
auto ir_weights = Reshape(integration_rule.GetWeights().Read(), num_qp);
auto input_size_on_qp =
get_input_size_on_qp(inputs, std::make_index_sequence<num_inputs> {});
auto action_shmem_info =
get_shmem_info<entity_t, num_fields, num_inputs, num_outputs>
(input_dtq_maps, output_dtq_maps, fields, num_entities, inputs, num_qp,
input_size_on_qp, residual_size_on_qp);
Vector shmem_cache(action_shmem_info.total_size);
// print_shared_memory_info(action_shmem_info);
action_callbacks.push_back(
[=](std::vector<Vector> &solutions_l,
const std::vector<Vector> &parameters_l,
Vector &residual_l) mutable
{
restriction_callback(solutions_l, parameters_l, fields_e);
residual_e = 0.0;
auto ye = Reshape(residual_e.ReadWrite(), test_vdim, num_test_dof, num_entities);
auto wrapped_fields_e = wrap_fields(fields_e,
action_shmem_info.field_sizes,
num_entities);
forall([=] MFEM_HOST_DEVICE (int e, void *shmem)
{
auto [input_dtq_shmem, output_dtq_shmem, fields_shmem, input_shmem,
residual_shmem, scratch_shmem] =
unpack_shmem(shmem, action_shmem_info, input_dtq_maps, output_dtq_maps,
wrapped_fields_e, num_qp, e);
map_fields_to_quadrature_data<TensorProduct>(
input_shmem, fields_shmem, input_dtq_shmem, input_to_field, inputs, ir_weights,
scratch_shmem);
call_qfunction<TensorProduct, qf_param_ts>(
qfunc, input_shmem, residual_shmem,
residual_size_on_qp, num_qp, q1d);
auto fhat = Reshape(&residual_shmem(0, 0), test_vdim, test_op_dim, num_qp);
auto y = Reshape(&ye(0, 0, e), num_test_dof, test_vdim);
map_quadrature_data_to_fields<TensorProduct>(y, fhat,
mfem::get<0>(outputs),
output_dtq_shmem[hardcoded_output_idx],
scratch_shmem);
}, num_entities, q1d, q1d, q1d, action_shmem_info.total_size, shmem_cache.ReadWrite());
if constexpr (is_none_fop<decltype(output_fop)>::value)
{
residual_l = residual_e;
}
else
{
R->MultTranspose(residual_e, residual_l);
}
});
for_constexpr([&](auto derivative_idx)
{
// bool is_dependent = false;
// for_constexpr<num_inputs>([&](auto input_idx)
// {
// constexpr auto input_is_dependent_on_field_idx =
// std::get<derivative_idx>(std::get<input_idx>(dependency_map));
// if constexpr (input_is_dependent_on_field_idx == 1)
// {
// is_dependent = true;
// }
// });
// if (!is_dependent)
// {
// derivative_action_callbacks[derivative_idx].push_back(
// [=](const Vector &direction_l, Vector &y) mutable
// {
// y += 0.0;
// });
// return;
// }
auto direction = fields[derivative_idx];
size_t derivative_action_l_size = GetVSize(direction);
const int da_size_on_qp = GetSizeOnQP<entity_t>(
mfem::get<hardcoded_output_idx>(outputs),
fields[test_space_field_idx]);
auto shmem_info =
get_shmem_info<entity_t, num_fields, num_inputs, num_outputs>
(input_dtq_maps, output_dtq_maps, fields, num_entities, inputs, num_qp,
input_size_on_qp, residual_size_on_qp, derivative_idx);
Vector shmem_cache(shmem_info.total_size);
// print_shared_memory_info(shmem_info);
Vector direction_e;
Vector derivative_action_e(R->Height());
derivative_action_e = 0.0;
auto input_is_dependent = get_array_from_tuple(std::get<derivative_idx>
(dependency_map));
derivative_action_callbacks[derivative_idx].push_back(
[=](std::vector<Vector> &fields_e, const Vector &direction_l,
Vector &derivative_action_l) mutable
{
restriction<entity_t>(direction, direction_l, direction_e, element_dof_ordering);
auto ye = Reshape(derivative_action_e.ReadWrite(), num_test_dof, test_vdim, num_entities);
auto wrapped_fields_e = wrap_fields(fields_e, shmem_info.field_sizes, num_entities);
auto wrapped_direction_e = Reshape(direction_e.ReadWrite(), shmem_info.direction_size, num_entities);
forall([=] MFEM_HOST_DEVICE (int e, double *shmem)
{
auto [input_dtq_shmem, output_dtq_shmem, fields_shmem, direction_shmem,
input_shmem, shadow_shmem, residual_shmem, scratch_shmem] =
unpack_shmem(shmem, shmem_info, input_dtq_maps,
output_dtq_maps, wrapped_fields_e, wrapped_direction_e, num_qp, e);
map_fields_to_quadrature_data<TensorProduct>(
input_shmem, fields_shmem, input_dtq_shmem, input_to_field, inputs, ir_weights,
scratch_shmem);
zero_all(shadow_shmem);
map_direction_to_quadrature_data_conditional<TensorProduct>(
shadow_shmem, direction_shmem, input_dtq_shmem, inputs, ir_weights,
scratch_shmem, input_is_dependent);
call_qfunction_derivative_action<TensorProduct, qf_param_ts>(
qfunc, input_shmem, shadow_shmem, residual_shmem,
da_size_on_qp, num_qp, q1d);
auto fhat = Reshape(&residual_shmem(0, 0), test_vdim, test_op_dim, num_qp);
auto y = Reshape(&ye(0, 0, e), num_test_dof, test_vdim);
map_quadrature_data_to_fields<TensorProduct>(y, fhat,
mfem::get<0>(outputs),
output_dtq_shmem[hardcoded_output_idx],
scratch_shmem);
}, num_entities, q1d, q1d, q1d, shmem_info.total_size, shmem_cache.ReadWrite());
R->MultTranspose(derivative_action_e, derivative_action_l);
});
}, derivative_indices);
}
} // namespace mfem
// #include "dfem_refactor_action.hpp"
// #include "dfem_refactor_derivatives.hpp"
-232
View File
@@ -1,232 +0,0 @@
#pragma once
#include "dfem_refactor.hpp"
namespace mfem
{
template <typename element_operator_t, size_t num_fields>
void DifferentiableOperator::instantiate_action(
element_operator_t element_operator, action_t &action)
{
using entity_t = typename element_operator_t::entity_t;
auto kinput_to_field = create_descriptors_to_fields_map<entity_t>(
fields,
element_operator.inputs,
std::make_index_sequence<element_operator.num_inputs> {});
auto koutput_to_field = create_descriptors_to_fields_map<entity_t>(
fields,
element_operator.outputs,
std::make_index_sequence<element_operator.num_outputs> {});
constexpr int hardcoded_output_idx = 0;
const int test_space_field_idx = koutput_to_field[hardcoded_output_idx];
const Operator *R = get_restriction<entity_t>(fields[test_space_field_idx],
element_dof_ordering);
auto output_fop = mfem::get<hardcoded_output_idx>(element_operator.outputs);
const int num_elements = GetNumEntities<Entity::Element>(mesh);
const int num_entities = GetNumEntities<entity_t>(mesh);
const int num_qp = integration_rule.GetNPoints();
this->width = GetTrueVSize(fields[test_space_field_idx]);
size_t residual_lsize = GetVSize(fields[test_space_field_idx]);
// if constexpr (std::is_same_v<decltype(output_fop), One>)
// {
// this->width = 1;
// }
// else
{
this->width = residual_lsize;
}
residual_l.SetSize(residual_lsize);
// assume only a single element type for now
std::vector<const DofToQuad*> dtq;
for (const auto &field : fields)
{
dtq.emplace_back(GetDofToQuad<entity_t>(
field,
integration_rule,
doftoquad_mode));
}
const int q1d = (int)floor(pow(num_qp, 1.0/mesh.Dimension()) + 0.5);
residual_e.SetSize(R->Height());
const int residual_size_on_qp = GetSizeOnQP<entity_t>(
mfem::get<hardcoded_output_idx>(element_operator.outputs),
fields[test_space_field_idx]);
auto input_dtq_maps = create_dtq_maps<entity_t>(element_operator.inputs, dtq,
kinput_to_field);
auto output_dtq_maps = create_dtq_maps<entity_t>(element_operator.outputs, dtq,
koutput_to_field);
// auto input_fops = create_bare_fops(element_operator.inputs);
// auto output_fops = create_bare_fops(element_operator.outputs);
const int test_vdim = mfem::get<hardcoded_output_idx>
(element_operator.outputs).vdim;
const int test_op_dim =
mfem::get<hardcoded_output_idx>(element_operator.inputs).size_on_qp /
mfem::get<hardcoded_output_idx>(element_operator.outputs).vdim;
const int num_test_dof = R->Height() /
mfem::get<hardcoded_output_idx>(element_operator.outputs).vdim /
num_entities;
auto ir_weights = Reshape(integration_rule.GetWeights().Read(), num_qp);
auto input_size_on_qp = get_input_size_on_qp(
element_operator.inputs,
std::make_index_sequence<element_operator.num_inputs> {});
auto shmem_info =
get_shmem_info<entity_t, num_fields, element_operator.num_inputs, element_operator.num_outputs>
(input_dtq_maps,
output_dtq_maps,
fields,
num_entities,
element_operator.inputs,
num_qp,
input_size_on_qp,
residual_size_on_qp);
Vector shmem_cache(shmem_info.total_size);
print_shared_memory_info(shmem_info);
action = [=](const Vector &x, Vector &y) mutable
{
prolongation(solutions, x, solutions_l);
restriction<entity_t>(solutions, solutions_l, this->fields_e,
element_dof_ordering);
restriction<entity_t>(parameters, parameters_l, this->fields_e,
element_dof_ordering,
solutions.size());
residual_e = 0.0;
auto ye = Reshape(residual_e.ReadWrite(), test_vdim, num_test_dof,
num_entities);
auto wrapped_fields_e = wrap_fields(this->fields_e,
shmem_info.field_sizes,
num_entities);
forall([=] MFEM_HOST_DEVICE (int e, void *shmem)
{
// printf("\ne: %d\n", e);
// tic();
auto input_dtq_shmem = load_dtq_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::INPUT_DTQ],
shmem_info.input_dtq_sizes,
input_dtq_maps);
auto output_dtq_shmem = load_dtq_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::OUTPUT_DTQ],
shmem_info.output_dtq_sizes,
output_dtq_maps);
auto fields_shmem = load_field_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::FIELD],
shmem_info.field_sizes,
kinput_to_field,
element_operator.inputs,
wrapped_fields_e,
e,
std::make_index_sequence<element_operator.num_inputs> {});
// These functions don't copy, they simply create a `DeviceTensor` object
// that points to correct chunks of the shared memory pool.
auto input_shmem = load_input_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::INPUT],
shmem_info.input_sizes,
num_qp);
auto residual_shmem = load_residual_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::OUTPUT],
shmem_info.residual_size,
num_qp);
auto scratch_mem = load_scratch_mem(
shmem,
shmem_info.offsets[SharedMemory::Index::TEMP],
shmem_info.temp_sizes);
MFEM_SYNC_THREAD;
// // printf("shmem load elapsed: %.1fus\n", toc() * 1e6);
// // tic();
map_fields_to_quadrature_data<TensorProduct>(
input_shmem, fields_shmem, input_dtq_shmem, element_operator.inputs, ir_weights,
scratch_mem,
std::make_index_sequence<element_operator.num_inputs> {});
// printf("interpolate elapsed: %.1fus\n", toc() * 1e6);
// // tic();
MFEM_FOREACH_THREAD(qx, x, q1d)
{
MFEM_FOREACH_THREAD(qy, y, q1d)
{
MFEM_FOREACH_THREAD(qz, z, q1d)
{
const int q = qx + q1d * (qy + q1d * qz);
auto qf_args = decay_tuple<typename element_operator_t::qf_param_ts> {};
auto r = Reshape(&residual_shmem(0, q), residual_size_on_qp);
apply_kernel(r, element_operator.qfunc, qf_args, input_shmem, q);
}
}
}
MFEM_SYNC_THREAD;
// // printf("qf elapsed: %.1fus\n", toc() * 1e6);
// // tic();
auto fhat = Reshape(&residual_shmem(0, 0), test_vdim, test_op_dim, num_qp);
auto y = Reshape(&ye(0, 0, e), num_test_dof, test_vdim);
map_quadrature_data_to_fields<TensorProduct>(y, fhat,
mfem::get<0>(element_operator.outputs),
output_dtq_shmem[hardcoded_output_idx],
scratch_mem);
// printf("integrate elapsed: %.1fus\n", toc() * 1e6);
}, num_entities, q1d, q1d, q1d, shmem_info.total_size, shmem_cache.ReadWrite());
if constexpr (std::is_same_v<decltype(output_fop), None<>>)
{
residual_l = y;
}
else
{
R->MultTranspose(residual_e, residual_l);
}
if constexpr (std::is_same_v<decltype(output_fop), None<>>)
{
y = residual_l;
}
// else if constexpr (std::is_same_v<decltype(output_fop), One>)
// {
// double local_sum = residual_l.Sum();
// MPI_Allreduce(&local_sum, y.GetData(), 1, MPI_DOUBLE, MPI_SUM, mesh.GetComm());
// MFEM_ASSERT(y.Size() == 1, "output size doesn't match kernel description");
// }
else
{
get_prolongation(fields[test_space_field_idx])->MultTranspose(residual_l, y);
}
};
}
}
-132
View File
@@ -1,132 +0,0 @@
#pragma once
#include "dfem_refactor.hpp"
template<typename T, T... Ints>
void print_sequence(std::integer_sequence<T, Ints...>)
{
((std::cout << Ints << " "), ...);
std::cout << std::endl;
}
namespace mfem
{
template <
typename element_operator_t,
size_t num_solutions,
size_t num_parameters,
size_t derivative_idx>
DerivativeOperator::DerivativeOperator(
element_operator_t element_operator,
const std::array<FieldDescriptor, num_solutions> &solutions,
const std::array<FieldDescriptor, num_parameters> &parameters,
const std::vector<FieldDescriptor> &fields,
ParMesh &mesh,
const IntegrationRule &integration_rule,
const ElementDofOrdering &element_dof_ordering,
const DofToQuad::Mode &doftoquad_mode,
std::integral_constant<size_t, derivative_idx>)
{
direction = fields[derivative_idx];
size_t derivative_action_l_size = 0;
for (auto &s : solutions)
{
derivative_action_l_size += GetVSize(s);
this->width += GetTrueVSize(s);
}
this->height = derivative_action_l_size;
derivative_action_l.SetSize(derivative_action_l_size);
constexpr size_t num_fields = num_solutions + num_parameters;
using entity_t = typename element_operator_t::entity_t;
auto kinput_to_field = create_descriptors_to_fields_map<entity_t>(
fields,
element_operator.inputs,
std::make_index_sequence<element_operator.num_inputs> {});
auto koutput_to_field = create_descriptors_to_fields_map<entity_t>(
fields,
element_operator.outputs,
std::make_index_sequence<element_operator.num_outputs> {});
constexpr int hardcoded_output_idx = 0;
const int test_space_field_idx = koutput_to_field[hardcoded_output_idx];
const Operator *R = get_restriction<entity_t>(fields[test_space_field_idx],
element_dof_ordering);
auto output_fop = mfem::get<hardcoded_output_idx>(element_operator.outputs);
const int num_elements = GetNumEntities<Entity::Element>(mesh);
const int num_entities = GetNumEntities<entity_t>(mesh);
const int num_qp = integration_rule.GetNPoints();
// assume only a single element type for now
std::vector<const DofToQuad*> dtq;
for (const auto &field : fields)
{
dtq.emplace_back(GetDofToQuad<entity_t>(
field,
integration_rule,
doftoquad_mode));
}
const int q1d = (int)floor(pow(num_qp, 1.0/mesh.Dimension()) + 0.5);
derivative_action_e.SetSize(R->Height());
const int da_size_on_qp = GetSizeOnQP<entity_t>(
mfem::get<hardcoded_output_idx>(element_operator.outputs),
fields[test_space_field_idx]);
auto input_dtq_maps = create_dtq_maps<entity_t>(element_operator.inputs, dtq,
kinput_to_field);
auto output_dtq_maps = create_dtq_maps<entity_t>(element_operator.outputs, dtq,
koutput_to_field);
const int test_vdim = mfem::get<hardcoded_output_idx>
(element_operator.outputs).vdim;
const int test_op_dim =
mfem::get<hardcoded_output_idx>(element_operator.inputs).size_on_qp /
mfem::get<hardcoded_output_idx>(element_operator.outputs).vdim;
const int num_test_dof = R->Height() /
mfem::get<hardcoded_output_idx>(element_operator.outputs).vdim /
num_entities;
auto ir_weights = Reshape(integration_rule.GetWeights().Read(), num_qp);
auto input_size_on_qp = get_input_size_on_qp(
element_operator.inputs,
std::make_index_sequence<element_operator.num_inputs> {});
auto input_is_dependent = std::get<derivative_idx>
(element_operator.dependency_map);
constexpr bool with_derivatives = true;
auto shmem_info =
get_shmem_info<entity_t, num_fields, element_operator.num_inputs, element_operator.num_outputs>
(input_dtq_maps,
output_dtq_maps,
fields,
num_entities,
element_operator.inputs,
num_qp,
input_size_on_qp,
da_size_on_qp,
derivative_idx);
Vector shmem_cache(shmem_info.total_size);
print_shared_memory_info(shmem_info);
action_callback = [=](const Vector &x, Vector &y) mutable
{
restriction<entity_t>(direction, direction_l, direction_e,
element_dof_ordering);
};
}
} // namespace mfem
-116
View File
@@ -1,116 +0,0 @@
#pragma once
#include <mfem.hpp>
class SharedMemoryManager
{
private:
struct MemoryBlock
{
char* ptr;
int size;
bool used;
};
MFEM_HOST_DEVICE static const int MAX_BLOCKS = 16;
MFEM_HOST_DEVICE static MemoryBlock blocks[MAX_BLOCKS];
MFEM_HOST_DEVICE static int num_blocks;
MFEM_HOST_DEVICE static char* base_ptr;
public:
MFEM_HOST_DEVICE static void init(void* shmem, int total_size)
{
base_ptr = static_cast<char*>(shmem);
num_blocks = 1;
blocks[0] = {base_ptr, total_size, false};
}
template<typename T>
MFEM_HOST_DEVICE static T* reserve(int n)
{
int size_bytes = n * sizeof(T);
for (int i = 0; i < num_blocks; ++i)
{
if (!blocks[i].used && blocks[i].size >= size_bytes)
{
blocks[i].used = true;
if (blocks[i].size > size_bytes)
{
// Split block
if (num_blocks < MAX_BLOCKS)
{
blocks[num_blocks] = {blocks[i].ptr + size_bytes, blocks[i].size - size_bytes, false};
++num_blocks;
blocks[i].size = size_bytes;
}
}
return reinterpret_cast<T*>(blocks[i].ptr);
}
}
return nullptr; // Allocation failed
}
MFEM_HOST_DEVICE static void release(void* ptr)
{
for (int i = 0; i < num_blocks; ++i)
{
if (blocks[i].ptr == ptr)
{
blocks[i].used = false;
return;
}
}
}
MFEM_HOST_DEVICE static void release_and_try_merge(void* ptr)
{
for (int i = 0; i < num_blocks; ++i)
{
if (blocks[i].ptr == ptr)
{
blocks[i].used = false;
merge_adjacent_free_blocks();
return;
}
}
}
private:
MFEM_HOST_DEVICE static void merge_adjacent_free_blocks()
{
// Simple bubble sort for simplicity (can be optimized)
for (int i = 0; i < num_blocks - 1; ++i)
{
for (int j = 0; j < num_blocks - i - 1; ++j)
{
if (blocks[j].ptr > blocks[j + 1].ptr)
{
MemoryBlock temp = blocks[j];
blocks[j] = blocks[j + 1];
blocks[j + 1] = temp;
}
}
}
for (int i = 0; i < num_blocks - 1; ++i)
{
if (!blocks[i].used && !blocks[i + 1].used)
{
blocks[i].size += blocks[i + 1].size;
for (int j = i + 1; j < num_blocks - 1; ++j)
{
blocks[j] = blocks[j + 1];
}
--num_blocks;
--i;
}
}
}
};
MFEM_HOST_DEVICE SharedMemoryManager::MemoryBlock
SharedMemoryManager::blocks[SharedMemoryManager::MAX_BLOCKS];
MFEM_HOST_DEVICE int SharedMemoryManager::num_blocks;
MFEM_HOST_DEVICE char* SharedMemoryManager::base_ptr;
-39
View File
@@ -1,39 +0,0 @@
#pragma once
#include "dfem_refactor.hpp"
#define DFEM_TEST_MAIN(function) \
int main(int argc, char* argv[]) \
{ \
Mpi::Init(); \
\
const char* device_config = "cpu"; \
const char* mesh_file = "../data/ref-square.mesh"; \
int polynomial_order = 1; \
int ir_order = 2; \
int refinements = 0; \
\
OptionsParser args(argc, argv); \
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); \
args.AddOption(&polynomial_order, "-o", "--order", ""); \
args.AddOption(&refinements, "-r", "--r", ""); \
args.AddOption(&ir_order, "-iro", "--iro", ""); \
args.AddOption(&device_config, "-d", "--device", \
"Device configuration string, see Device::Configure()."); \
args.ParseCheck(); \
\
Device device(device_config); \
if (Mpi::Root() == 0) \
{ \
device.Print(); \
} \
\
out << std::setprecision(12); \
\
int ret; \
\
ret = function(mesh_file, refinements, polynomial_order); \
out << #function; \
ret ? out << " FAILURE\n" : out << " OK\n"; \
\
return ret; \
}\
File diff suppressed because it is too large Load Diff
-130
View File
@@ -1,130 +0,0 @@
// SPDX-ArtifactOfProjectName: noisy
// SPDX-ArtifactOfProjectHomePage: https://github.com/VincentZalzal/noisy
// SPDX-FileCopyrightText: Copyright 2024 Vincent Zalzal
// SPDX-License-Identifier: MIT
#pragma once
#include <iomanip>
#include <iostream>
namespace vz {
struct Counters {
unsigned m_def_ctor = 0;
unsigned m_copy_ctor = 0;
unsigned m_move_ctor = 0;
unsigned m_copy_assign = 0;
unsigned m_move_assign = 0;
unsigned m_dtor = 0;
void reset() {
*this = {};
}
bool leaks() const {
return m_def_ctor + m_copy_ctor + m_move_ctor != m_dtor;
}
friend std::ostream& operator<<(std::ostream& os, const Counters& c) {
stream_counter(os, "Default constructor count: ", c.m_def_ctor );
stream_counter(os, "Copy constructor count: ", c.m_copy_ctor );
stream_counter(os, "Move constructor count: ", c.m_move_ctor );
stream_counter(os, "Copy assignment count: ", c.m_copy_assign);
stream_counter(os, "Move assignment count: ", c.m_move_assign);
stream_counter(os, "Destructor count: ", c.m_dtor );
return os;
}
friend bool operator==(const Counters& lhs, const Counters& rhs) {
return
lhs.m_def_ctor == rhs.m_def_ctor &&
lhs.m_copy_ctor == rhs.m_copy_ctor &&
lhs.m_move_ctor == rhs.m_move_ctor &&
lhs.m_copy_assign == rhs.m_copy_assign &&
lhs.m_move_assign == rhs.m_move_assign &&
lhs.m_dtor == rhs.m_dtor ;
}
friend bool operator!=(const Counters& lhs, const Counters& rhs) { return !(lhs == rhs); }
private:
static void stream_counter(std::ostream& os, const char* msg, unsigned value) {
if (value != 0)
os << msg << std::setw(2) << value << '\n';
}
};
namespace detail {
struct Globals {
~Globals() {
if (m_verbose)
std::cout << "\n===== Noisy counters =====\n" << m_counters;
}
Counters m_counters;
unsigned m_next_id = 0;
bool m_verbose = true;
};
}
class Noisy {
private:
static detail::Globals& globals() {
static detail::Globals s_globals;
return s_globals;
}
public:
static Counters& counters() { return globals().m_counters; }
static void set_verbose(bool verbose) { globals().m_verbose = verbose; }
Noisy() {
if (globals().m_verbose)
std::cout << *this << ": default constructor\n";
globals().m_counters.m_def_ctor++;
}
Noisy(const Noisy& other) {
if (globals().m_verbose)
std::cout << *this << ": copy constructor from " << other << '\n';
globals().m_counters.m_copy_ctor++;
}
Noisy(Noisy&& other) noexcept {
if (globals().m_verbose)
std::cout << *this << ": move constructor from " << other << '\n';
globals().m_counters.m_move_ctor++;
}
~Noisy() {
if (globals().m_verbose)
std::cout << *this << ": destructor\n";
globals().m_counters.m_dtor++;
}
Noisy& operator=(const Noisy& other) {
if (globals().m_verbose)
std::cout << *this << ": copy assignment from " << other << '\n';
globals().m_counters.m_copy_assign++;
return *this;
}
Noisy& operator=(Noisy&& other) noexcept {
if (globals().m_verbose)
std::cout << *this << ": move assignment from " << other << '\n';
globals().m_counters.m_move_assign++;
return *this;
}
unsigned id() const { return m_id; }
friend std::ostream& operator<<(std::ostream& os, const Noisy& noisy) { return os << "Noisy(" << std::setw(2) << noisy.m_id << ')'; }
private:
unsigned m_id = globals().m_next_id++;
};
}
@@ -1,188 +0,0 @@
{
using entity_t = typename kernel_t::entity_t;
auto kinput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.inputs, std::make_index_sequence<kernel.num_kinputs> {});
auto koutput_to_field = create_descriptors_to_fields_map<entity_t>(op.fields,
kernel.outputs, std::make_index_sequence<kernel.num_koutputs> {});
constexpr int hardcoded_output_idx = 0;
const int test_space_field_idx = koutput_to_field[hardcoded_output_idx];
const Operator *R = get_restriction<entity_t>(op.fields[test_space_field_idx],
element_dof_ordering);
auto output_fop = mfem::get<hardcoded_output_idx>(kernel.outputs);
const int num_elements = GetNumEntities<Entity::Element>(op.mesh);
const int num_entities = GetNumEntities<entity_t>(op.mesh);
const int num_qp = op.integration_rule.GetNPoints();
// assume only a single element type for now
std::vector<const DofToQuad*> dtq;
for (const auto &field : op.fields)
{
dtq.emplace_back(GetDofToQuad<entity_t>(field, op.integration_rule,
doftoquad_mode));
}
const int q1d = dtq[0]->nqpt;
derivative_action_e.SetSize(R->Height());
const int da_size_on_qp = GetSizeOnQP<entity_t>(
mfem::get<hardcoded_output_idx>(kernel.outputs),
op.fields[test_space_field_idx]);
auto input_dtq_maps = create_dtq_maps<entity_t>(kernel.inputs, dtq,
kinput_to_field);
auto output_dtq_maps = create_dtq_maps<entity_t>(kernel.outputs, dtq,
koutput_to_field);
auto input_fops = create_bare_fops(kernel.inputs);
auto output_fops = create_bare_fops(kernel.outputs);
const int test_vdim = mfem::get<hardcoded_output_idx>(output_fops).vdim;
const int test_op_dim =
mfem::get<hardcoded_output_idx>(output_fops).size_on_qp /
mfem::get<hardcoded_output_idx>(output_fops).vdim;
const int num_test_dof = R->Height() /
mfem::get<hardcoded_output_idx>(output_fops).vdim /
num_entities;
auto ir_weights = Reshape(this->op.integration_rule.GetWeights().Read(),
num_qp);
auto input_size_on_qp = get_input_size_on_qp(kernel.inputs,
std::make_index_sequence<kernel.num_kinputs> {});
auto shmem_info = get_shmem_info<entity_t>(input_dtq_maps,
output_dtq_maps,
op.fields,
num_entities,
kernel.inputs,
num_qp,
input_size_on_qp,
da_size_on_qp);
Vector shmem_cache(shmem_info.total_size);
func = [=](Vector &ye_mem) mutable
{
restriction<entity_t>(direction, direction_l, direction_e,
op.element_dof_ordering, derivative_idx);
// Check which qf inputs are dependent on the dependent variable
std::array<bool, kernel.num_kinputs> kinput_is_dependent;
bool no_qfinput_is_dependent = true;
for (int i = 0; i < kinput_is_dependent.size(); i++)
{
if (kinput_to_field[i] == derivative_idx)
{
no_qfinput_is_dependent = false;
kinput_is_dependent[i] = true;
// out << "function input " << i << " is dependent on "
// << op.fields[kinput_to_field[i]].field_label << "\n";
}
else
{
kinput_is_dependent[i] = false;
}
}
if (no_qfinput_is_dependent)
{
return;
}
// auto kernel_args = decay_tuple<typename kernel_t::kf_param_ts> {};
// auto kernel_shadow_args = decay_tuple<typename kernel_t::kf_param_ts> {};
// DeviceTensor<1, const double> integration_weights(
// this->op.integration_rule.GetWeights().Read(), num_qp);
// Vector zero;
// GeometricFactorMaps geometric_factors
// {
// DeviceTensor<3, const double>(zero.Read(), 0, 0, 0)
// };
// // Fields interpolated to the quadrature points in the order of
// // kernel function arguments
// auto input_qp = map_inputs_to_memory(input_qp_mem, num_qp,
// kernel.inputs,
// std::make_index_sequence<kernel.num_kinputs> {});
// auto directions_qp = map_inputs_to_memory(directions_qp_mem, num_qp,
// kernel.inputs,
// std::make_index_sequence<kernel.num_kinputs> {});
// constexpr int fixed_output_idx = 0;
// auto Bv = output_dtq_maps[fixed_output_idx];
// auto [num_test_qp, test_op_dim, num_test_dof] = Bv.GetShape();
// const int test_vdim = mfem::get<0>(kernel.outputs).vdim;
// DeviceTensor<3> ye = Reshape(ye_mem.ReadWrite(), num_test_dof, test_vdim, num_entities);
forall([=] MFEM_HOST_DEVICE (int e, double *shmem)
{
// map_fields_to_quadrature_data(
// input_qp, e, this->fields_e,
// kinput_to_field, input_dtq_maps,
// integration_weights, geometric_factors, kernel.inputs,
// std::make_index_sequence<kernel.num_kinputs> {});
// map_fields_to_quadrature_data_conditional(
// directions_qp, e,
// directions_e, kinput_to_field,
// input_dtq_maps,
// integration_weights,
// geometric_factors,
// kinput_is_dependent,
// kernel.inputs,
// std::make_index_sequence<kernel.num_kinputs> {});
// for (int qp = 0; qp < num_qp; qp++)
// {
// auto f_qp = apply_kernel_fwddiff_enzyme(
// kernel.func,
// kernel_args,
// input_qp,
// kernel_shadow_args,
// directions_qp,
// qp);
// auto r_qp = Reshape(&da_qp(0, qp, e), da_size_on_qp);
// for (int i = 0; i < da_size_on_qp; i++)
// {
// r_qp(i) = f_qp(i);
// }
// }
// DeviceTensor<3> fhat = Reshape(&da_qp(0, 0, e), test_vdim, test_op_dim, num_qp);
// DeviceTensor<2> y = Reshape(&ye(0, 0, e), num_test_dof, test_vdim);
// map_quadrature_data_to_fields(y, fhat,
// output_fop,
// output_dtq_maps[hardcoded_output_idx]);
}, num_entities, q1d, q1d, 1, shmem_info.total_size, shmem_cache.GetData());
R->MultTranspose(ye_mem, derivative_action_l);
};
if constexpr (std::is_same_v<decltype(output_fop), One>)
{
prolongation_transpose = [&](Vector &r_local, Vector &y)
{
double local_sum = r_local.Sum();
MPI_Allreduce(&local_sum, y.GetData(), 1, MPI_DOUBLE, MPI_SUM,
op.mesh.GetComm());
MFEM_ASSERT(y.Size() == 1, "output size doesn't match kernel description");
};
}
else
{
auto P = get_prolongation(op.fields[test_space_field_idx]);
prolongation_transpose = [P](Vector &r_l, Vector &y)
{
P->MultTranspose(r_l, y);
};
}
-49
View File
@@ -1,49 +0,0 @@
* Calculate shared memory requirements
* Interpolation and integration
---
* If grad involved, need B and G
* Fit largest field, depends on polynomial order (#dofs)
-> vdim is irrelevant
* Temporaries for each sum
- DDQ (d1d x d1d x q1d) x 2 -> DDQ0, DDQ1
- DQQ (d1d x q1d x q1d) x 3 -> DQQ0, DQQ1, DQQ2
- QQQ (q1d x q1d x q1d) x 3 -> QQQ0, QQQ1, QQQ2
We need the following combinations at the same time
(1) DDQ0 + DDQ1 + DQQ0 + DQQ1 + DQQ2
(2) DQQ0 + DQQ1 + DQQ2 + QQQ0 + QQQ1 + QQQ2
(3) QQQ0 + QQQ1 + QQQ2 + QQD0 + QQD1 + QQD2
(4) QQD0 + QQD1 + QQD2 + QDD0 + QDD1 + QDD2
Allocate largest memory footprint from 2, 3 or 4 and
add memory footprint of fields and B/G.
Annotations with NR and R mean "not reusable" and
"reusable", respectively. This means the memory location is
reused for _all_ e.g. interpolation of a value etc.
----
For the action of nonlinear diffusion in 2D we have
(rho * |u|^2 \nabla u, \nabla v)
* Load
RHO (D x D) | R (after interpolation)
U (D x D x VDIM) | R (after interpolation)
B (Q x D) | NR
G (Q x D) | NR
* Interpolate Value
Temporary (Q x D) | R
R (Q x Q) | NR
U (Q x Q x VDIM) | NR
* Interpolate Grad
Temporaries (Q x D) + (Q x D) | R
U (Q x Q x DIM x VDIM) | NR
Quadrature point function
-> purely thread local
* Integrate Grad
R | temp from Interpolation
R | U from Load
-845
View File
@@ -1,845 +0,0 @@
// This is serac's tuple implementation
#pragma once
#include "general/backends.hpp"
#include <utility>
#include <mfem.hpp>
#include <tuple>
namespace mfem
{
/**
* @tparam T the types stored in the tuple
* @brief This is a class that mimics most of std::tuple's interface,
* except that it is usable in CUDA kernels and admits some arithmetic operator overloads.
*
* see https://en.cppreference.com/w/cpp/utility/tuple for more information about std::tuple
*/
template <typename... T>
struct tuple
{
};
/**
* @brief Type that mimics std::tuple
*
* @tparam T0 The first type stored in the tuple
*/
template <typename T0>
struct tuple<T0>
{
T0 v0; ///< The first member of the tuple
};
/**
* @brief Type that mimics std::tuple
*
* @tparam T0 The first type stored in the tuple
* @tparam T1 The second type stored in the tuple
*/
template <typename T0, typename T1>
struct tuple<T0, T1>
{
T0 v0; ///< The first member of the tuple
T1 v1; ///< The second member of the tuple
};
/**
* @brief Type that mimics std::tuple
*
* @tparam T0 The first type stored in the tuple
* @tparam T1 The second type stored in the tuple
* @tparam T2 The third type stored in the tuple
*/
template <typename T0, typename T1, typename T2>
struct tuple<T0, T1, T2>
{
T0 v0; ///< The first member of the tuple
T1 v1; ///< The second member of the tuple
T2 v2; ///< The third member of the tuple
};
/**
* @brief Type that mimics std::tuple
*
* @tparam T0 The first type stored in the tuple
* @tparam T1 The second type stored in the tuple
* @tparam T2 The third type stored in the tuple
* @tparam T3 The fourth type stored in the tuple
*/
template <typename T0, typename T1, typename T2, typename T3>
struct tuple<T0, T1, T2, T3>
{
T0 v0; ///< The first member of the tuple
T1 v1; ///< The second member of the tuple
T2 v2; ///< The third member of the tuple
T3 v3; ///< The fourth member of the tuple
};
/**
* @brief Type that mimics std::tuple
*
* @tparam T0 The first type stored in the tuple
* @tparam T1 The second type stored in the tuple
* @tparam T2 The third type stored in the tuple
* @tparam T3 The fourth type stored in the tuple
* @tparam T4 The fifth type stored in the tuple
*/
template <typename T0, typename T1, typename T2, typename T3, typename T4>
struct tuple<T0, T1, T2, T3, T4>
{
T0 v0; ///< The first member of the tuple
T1 v1; ///< The second member of the tuple
T2 v2; ///< The third member of the tuple
T3 v3; ///< The fourth member of the tuple
T4 v4; ///< The fifth member of the tuple
};
/**
* @brief Type that mimics std::tuple
*
* @tparam T0 The first type stored in the tuple
* @tparam T1 The second type stored in the tuple
* @tparam T2 The third type stored in the tuple
* @tparam T3 The fourth type stored in the tuple
* @tparam T4 The fifth type stored in the tuple
* @tparam T5 The sixth type stored in the tuple
*/
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
struct tuple<T0, T1, T2, T3, T4, T5>
{
T0 v0; ///< The first member of the tuple
T1 v1; ///< The second member of the tuple
T2 v2; ///< The third member of the tuple
T3 v3; ///< The fourth member of the tuple
T4 v4; ///< The fifth member of the tuple
T5 v5; ///< The sixth member of the tuple
};
/**
* @brief Type that mimics std::tuple
*
* @tparam T0 The first type stored in the tuple
* @tparam T1 The second type stored in the tuple
* @tparam T2 The third type stored in the tuple
* @tparam T3 The fourth type stored in the tuple
* @tparam T4 The fifth type stored in the tuple
* @tparam T5 The sixth type stored in the tuple
* @tparam T6 The seventh type stored in the tuple
*/
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
struct tuple<T0, T1, T2, T3, T4, T5, T6>
{
T0 v0; ///< The first member of the tuple
T1 v1; ///< The second member of the tuple
T2 v2; ///< The third member of the tuple
T3 v3; ///< The fourth member of the tuple
T4 v4; ///< The fifth member of the tuple
T5 v5; ///< The sixth member of the tuple
T6 v6; ///< The seventh member of the tuple
};
/**
* @brief Type that mimics std::tuple
*
* @tparam T0 The first type stored in the tuple
* @tparam T1 The second type stored in the tuple
* @tparam T2 The third type stored in the tuple
* @tparam T3 The fourth type stored in the tuple
* @tparam T4 The fifth type stored in the tuple
* @tparam T5 The sixth type stored in the tuple
* @tparam T6 The seventh type stored in the tuple
* @tparam T7 The eighth type stored in the tuple
*/
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
struct tuple<T0, T1, T2, T3, T4, T5, T6, T7>
{
T0 v0; ///< The first member of the tuple
T1 v1; ///< The second member of the tuple
T2 v2; ///< The third member of the tuple
T3 v3; ///< The fourth member of the tuple
T4 v4; ///< The fifth member of the tuple
T5 v5; ///< The sixth member of the tuple
T6 v6; ///< The seventh member of the tuple
T7 v7; ///< The eighth member of the tuple
};
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
struct tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8>
{
T0 v0; ///< The first member of the tuple
T1 v1; ///< The second member of the tuple
T2 v2; ///< The third member of the tuple
T3 v3; ///< The fourth member of the tuple
T4 v4; ///< The fifth member of the tuple
T5 v5; ///< The sixth member of the tuple
T6 v6; ///< The seventh member of the tuple
T7 v7; ///< The eighth member of the tuple
T8 v8;
};
/**
* @brief Class template argument deduction rule for tuples
* @tparam T The variadic template parameter for tuple types
*/
template <typename... T>
MFEM_HOST_DEVICE
tuple(T...) -> tuple<T...>;
/**
* @brief helper function for combining a list of values into a tuple
* @tparam T types of the values to be tuple-d
* @param args the actual values to be put into a tuple
*/
template <typename... T>
MFEM_HOST_DEVICE tuple<T...> make_tuple(const T&... args)
{
return tuple<T...> {args...};
}
template <class... Types>
struct tuple_size
{
};
template <class... Types>
struct tuple_size<mfem::tuple<Types...>> :
std::integral_constant<std::size_t, sizeof...(Types)>
{
};
/**
* @tparam i the tuple index to access
* @tparam T the types stored in the tuple
* @brief return a reference to the ith tuple entry
*/
template <int i, typename... T>
MFEM_HOST_DEVICE constexpr auto& get(tuple<T...>& values)
{
static_assert(i < sizeof...(T), "");
if constexpr (i == 0)
{
return values.v0;
}
if constexpr (i == 1)
{
return values.v1;
}
if constexpr (i == 2)
{
return values.v2;
}
if constexpr (i == 3)
{
return values.v3;
}
if constexpr (i == 4)
{
return values.v4;
}
if constexpr (i == 5)
{
return values.v5;
}
if constexpr (i == 6)
{
return values.v6;
}
if constexpr (i == 7)
{
return values.v7;
}
if constexpr (i == 8)
{
return values.v8;
}
}
/**
* @tparam i the tuple index to access
* @tparam T the types stored in the tuple
* @brief return a copy of the ith tuple entry
*/
template <int i, typename... T>
MFEM_HOST_DEVICE constexpr const auto& get(const tuple<T...>& values)
{
static_assert(i < sizeof...(T), "");
if constexpr (i == 0)
{
return values.v0;
}
if constexpr (i == 1)
{
return values.v1;
}
if constexpr (i == 2)
{
return values.v2;
}
if constexpr (i == 3)
{
return values.v3;
}
if constexpr (i == 4)
{
return values.v4;
}
if constexpr (i == 5)
{
return values.v5;
}
if constexpr (i == 6)
{
return values.v6;
}
if constexpr (i == 7)
{
return values.v7;
}
if constexpr (i == 8)
{
return values.v8;
}
}
/**
* @brief a function intended to be used for extracting the ith type from a tuple.
*
* @note type<i>(my_tuple) returns a value, whereas get<i>(my_tuple) returns a reference
*
* @tparam i the index of the tuple to query
* @tparam T the types stored in the tuple
* @param values the tuple of values
* @return a copy of the ith entry of the input
*/
template <int i, typename... T>
MFEM_HOST_DEVICE constexpr auto type(const tuple<T...>& values)
{
static_assert(i < sizeof...(T), "");
if constexpr (i == 0)
{
return values.v0;
}
if constexpr (i == 1)
{
return values.v1;
}
if constexpr (i == 2)
{
return values.v2;
}
if constexpr (i == 3)
{
return values.v3;
}
if constexpr (i == 4)
{
return values.v4;
}
if constexpr (i == 5)
{
return values.v5;
}
if constexpr (i == 6)
{
return values.v6;
}
if constexpr (i == 7)
{
return values.v7;
}
if constexpr (i == 8)
{
return values.v8;
}
}
/**
* @brief A helper function for the + operator of tuples
*
* @tparam S the types stored in the tuple x
* @tparam T the types stored in the tuple y
* @tparam i The integer sequence to i
* @param x tuple of values
* @param y tuple of values
* @return the returned tuple sum
*/
template <typename... S, typename... T, int... i>
MFEM_HOST_DEVICE constexpr auto plus_helper(const tuple<S...>& x,
const tuple<T...>& y,
std::integer_sequence<int, i...>)
{
return tuple{get<i>(x) + get<i>(y)...};
}
/**
* @tparam S the types stored in the tuple x
* @tparam T the types stored in the tuple y
* @param x a tuple of values
* @param y a tuple of values
* @brief return a tuple of values defined by elementwise sum of x and y
*/
template <typename... S, typename... T>
MFEM_HOST_DEVICE constexpr auto operator+(const tuple<S...>& x,
const tuple<T...>& y)
{
static_assert(sizeof...(S) == sizeof...(T));
return plus_helper(x, y,
std::make_integer_sequence<int, static_cast<int>(sizeof...(S))>());
}
/**
* @brief A helper function for the += operator of tuples
*
* @tparam T the types stored in the tuples x and y
* @tparam i integer sequence used to index the tuples
* @param x tuple of values to be incremented
* @param y tuple of increment values
*/
template <typename... T, int... i>
MFEM_HOST_DEVICE constexpr void plus_equals_helper(tuple<T...>& x,
const tuple<T...>& y,
std::integer_sequence<int, i...>)
{
((get<i>(x) += get<i>(y)), ...);
}
/**
* @tparam T the types stored in the tuples x and y
* @param x a tuple of values
* @param y a tuple of values
* @brief add values contained in y, to the tuple x
*/
template <typename... T>
MFEM_HOST_DEVICE constexpr auto operator+=(tuple<T...>& x,
const tuple<T...>& y)
{
return plus_equals_helper(x, y,
std::make_integer_sequence<int, static_cast<int>(sizeof...(T))>());
}
/**
* @brief A helper function for the -= operator of tuples
*
* @tparam T the types stored in the tuples x and y
* @tparam i integer sequence used to index the tuples
* @param x tuple of values to be subracted from
* @param y tuple of values to subtract from x
*/
template <typename... T, int... i>
MFEM_HOST_DEVICE constexpr void minus_equals_helper(tuple<T...>& x,
const tuple<T...>& y,
std::integer_sequence<int, i...>)
{
((get<i>(x) -= get<i>(y)), ...);
}
/**
* @tparam T the types stored in the tuples x and y
* @param x a tuple of values
* @param y a tuple of values
* @brief add values contained in y, to the tuple x
*/
template <typename... T>
MFEM_HOST_DEVICE constexpr auto operator-=(tuple<T...>& x,
const tuple<T...>& y)
{
return minus_equals_helper(x, y,
std::make_integer_sequence<int, static_cast<int>(sizeof...(T))>());
}
/**
* @brief A helper function for the - operator of tuples
*
* @tparam S the types stored in the tuple x
* @tparam T the types stored in the tuple y
* @tparam i The integer sequence to i
* @param x tuple of values
* @param y tuple of values
* @return the returned tuple difference
*/
template <typename... S, typename... T, int... i>
MFEM_HOST_DEVICE constexpr auto minus_helper(const tuple<S...>& x,
const tuple<T...>& y,
std::integer_sequence<int, i...>)
{
return tuple{get<i>(x) - get<i>(y)...};
}
/**
* @tparam S the types stored in the tuple x
* @tparam T the types stored in the tuple y
* @param x a tuple of values
* @param y a tuple of values
* @brief return a tuple of values defined by elementwise difference of x and y
*/
template <typename... S, typename... T>
MFEM_HOST_DEVICE constexpr auto operator-(const tuple<S...>& x,
const tuple<T...>& y)
{
static_assert(sizeof...(S) == sizeof...(T));
return minus_helper(x, y,
std::make_integer_sequence<int, static_cast<int>(sizeof...(S))>());
}
/**
* @brief A helper function for the - operator of tuples
*
* @tparam T the types stored in the tuple y
* @tparam i The integer sequence to i
* @param x tuple of values
* @return the returned tuple difference
*/
template <typename... T, int... i>
MFEM_HOST_DEVICE constexpr auto unary_minus_helper(const tuple<T...>& x,
std::integer_sequence<int, i...>)
{
return tuple{-get<i>(x)...};
}
/**
* @tparam T the types stored in the tuple y
* @param x a tuple of values
* @brief return a tuple of values defined by applying the unary minus operator to each element of x
*/
template <typename... T>
MFEM_HOST_DEVICE constexpr auto operator-(const tuple<T...>& x)
{
return unary_minus_helper(x,
std::make_integer_sequence<int, static_cast<int>(sizeof...(T))>());
}
/**
* @brief A helper function for the / operator of tuples
*
* @tparam S the types stored in the tuple x
* @tparam T the types stored in the tuple y
* @tparam i The integer sequence to i
* @param x tuple of values
* @param y tuple of values
* @return the returned tuple ratio
*/
template <typename... S, typename... T, int... i>
MFEM_HOST_DEVICE constexpr auto div_helper(const tuple<S...>& x,
const tuple<T...>& y,
std::integer_sequence<int, i...>)
{
return tuple{get<i>(x) / get<i>(y)...};
}
/**
* @tparam S the types stored in the tuple x
* @tparam T the types stored in the tuple y
* @param x a tuple of values
* @param y a tuple of values
* @brief return a tuple of values defined by elementwise division of x by y
*/
template <typename... S, typename... T>
MFEM_HOST_DEVICE constexpr auto operator/(const tuple<S...>& x,
const tuple<T...>& y)
{
static_assert(sizeof...(S) == sizeof...(T));
return div_helper(x, y,
std::make_integer_sequence<int, static_cast<int>(sizeof...(S))>());
}
/**
* @brief A helper function for the / operator of tuples
*
* @tparam T the types stored in the tuple y
* @tparam i The integer sequence to i
* @param x tuple of values
* @param a the constant numerator
* @return the returned tuple ratio
*/
template <typename... T, int... i>
MFEM_HOST_DEVICE constexpr auto div_helper(const double a,
const tuple<T...>& x, std::integer_sequence<int, i...>)
{
return tuple{a / get<i>(x)...};
}
/**
* @brief A helper function for the / operator of tuples
*
* @tparam T the types stored in the tuple y
* @tparam i The integer sequence to i
* @param x tuple of values
* @param a the constant denomenator
* @return the returned tuple ratio
*/
template <typename... T, int... i>
MFEM_HOST_DEVICE constexpr auto div_helper(const tuple<T...>& x,
const double a, std::integer_sequence<int, i...>)
{
return tuple{get<i>(x) / a...};
}
/**
* @tparam T the types stored in the tuple x
* @param a the numerator
* @param x a tuple of denominator values
* @brief return a tuple of values defined by division of a by the elements of x
*/
template <typename... T>
MFEM_HOST_DEVICE constexpr auto operator/(const double a, const tuple<T...>& x)
{
return div_helper(a, x,
std::make_integer_sequence<int, static_cast<int>(sizeof...(T))>());
}
/**
* @tparam T the types stored in the tuple y
* @param x a tuple of numerator values
* @param a a denominator
* @brief return a tuple of values defined by elementwise division of x by a
*/
template <typename... T>
MFEM_HOST_DEVICE constexpr auto operator/(const tuple<T...>& x, const double a)
{
return div_helper(x, a,
std::make_integer_sequence<int, static_cast<int>(sizeof...(T))>());
}
/**
* @brief A helper function for the * operator of tuples
*
* @tparam S the types stored in the tuple x
* @tparam T the types stored in the tuple y
* @tparam i The integer sequence to i
* @param x tuple of values
* @param y tuple of values
* @return the returned tuple product
*/
template <typename... S, typename... T, int... i>
MFEM_HOST_DEVICE constexpr auto mult_helper(const tuple<S...>& x,
const tuple<T...>& y,
std::integer_sequence<int, i...>)
{
return tuple{get<i>(x) * get<i>(y)...};
}
/**
* @tparam S the types stored in the tuple x
* @tparam T the types stored in the tuple y
* @param x a tuple of values
* @param y a tuple of values
* @brief return a tuple of values defined by elementwise multiplication of x and y
*/
template <typename... S, typename... T>
MFEM_HOST_DEVICE constexpr auto operator*(const tuple<S...>& x,
const tuple<T...>& y)
{
static_assert(sizeof...(S) == sizeof...(T));
return mult_helper(x, y,
std::make_integer_sequence<int, static_cast<int>(sizeof...(S))>());
}
/**
* @brief A helper function for the * operator of tuples
*
* @tparam T the types stored in the tuple y
* @tparam i The integer sequence to i
* @param x tuple of values
* @param a a constant multiplier
* @return the returned tuple product
*/
template <typename... T, int... i>
MFEM_HOST_DEVICE constexpr auto mult_helper(const double a,
const tuple<T...>& x, std::integer_sequence<int, i...>)
{
return tuple{a * get<i>(x)...};
}
/**
* @brief A helper function for the * operator of tuples
*
* @tparam T the types stored in the tuple y
* @tparam i The integer sequence to i
* @param x tuple of values
* @param a a constant multiplier
* @return the returned tuple product
*/
template <typename... T, int... i>
MFEM_HOST_DEVICE constexpr auto mult_helper(const tuple<T...>& x,
const double a, std::integer_sequence<int, i...>)
{
return tuple{get<i>(x) * a...};
}
/**
* @tparam T the types stored in the tuple
* @param a a scaling factor
* @param x the tuple object
* @brief multiply each component of x by the value a on the left
*/
template <typename... T>
MFEM_HOST_DEVICE constexpr auto operator*(const double a, const tuple<T...>& x)
{
return mult_helper(a, x,
std::make_integer_sequence<int, static_cast<int>(sizeof...(T))>());
}
/**
* @tparam T the types stored in the tuple
* @param x the tuple object
* @param a a scaling factor
* @brief multiply each component of x by the value a on the right
*/
template <typename... T>
MFEM_HOST_DEVICE constexpr auto operator*(const tuple<T...>& x, const double a)
{
return mult_helper(x, a,
std::make_integer_sequence<int, static_cast<int>(sizeof...(T))>());
}
/**
* @tparam T the types stored in the tuple
* @tparam i a list of indices used to acces each element of the tuple
* @param out the ostream to write the output to
* @param A the tuple of values
* @brief helper used to implement printing a tuple of values
*/
template <typename... T, std::size_t... i>
auto& print_helper(std::ostream& out, const mfem::tuple<T...>& A,
std::integer_sequence<size_t, i...>)
{
out << "tuple{";
(..., (out << (i == 0 ? "" : ", ") << mfem::get<i>(A)));
out << "}";
return out;
}
/**
* @tparam T the types stored in the tuple
* @param out the ostream to write the output to
* @param A the tuple of values
* @brief print a tuple of values
*/
template <typename... T>
auto& operator<<(std::ostream& out, const mfem::tuple<T...>& A)
{
return print_helper(out, A, std::make_integer_sequence<size_t, sizeof...(T)>());
}
/**
* @brief A helper to apply a lambda to a tuple
*
* @tparam lambda The functor type
* @tparam T The tuple types
* @tparam i The integer sequence to i
* @param f The functor to apply to the tuple
* @param args The input tuple
* @return The functor output
*/
template <typename lambda, typename... T, int... i>
MFEM_HOST_DEVICE auto apply_helper(lambda f, tuple<T...>& args,
std::integer_sequence<int, i...>)
{
return f(get<i>(args)...);
}
/**
* @tparam lambda a callable type
* @tparam T the types of arguments to be passed in to f
* @param f the callable object
* @param args a tuple of arguments
* @brief a way of passing an n-tuple to a function that expects n separate arguments
*
* e.g. foo(bar, baz) is equivalent to apply(foo, mfem::tuple(bar,baz));
*/
template <typename lambda, typename... T>
MFEM_HOST_DEVICE auto apply(lambda f, tuple<T...>& args)
{
return apply_helper(f, std::move(args),
std::make_integer_sequence<int, static_cast<int>(sizeof...(T))>());
}
/**
* @overload
*/
template <typename lambda, typename... T, int... i>
MFEM_HOST_DEVICE auto apply_helper(lambda f, const tuple<T...>& args,
std::integer_sequence<int, i...>)
{
return f(get<i>(args)...);
}
/**
* @tparam lambda a callable type
* @tparam T the types of arguments to be passed in to f
* @param f the callable object
* @param args a tuple of arguments
* @brief a way of passing an n-tuple to a function that expects n separate arguments
*
* e.g. foo(bar, baz) is equivalent to apply(foo, mfem::tuple(bar,baz));
*/
template <typename lambda, typename... T>
MFEM_HOST_DEVICE auto apply(lambda f, const tuple<T...>& args)
{
return apply_helper(f, std::move(args),
std::make_integer_sequence<int, static_cast<int>(sizeof...(T))>());
}
/**
* @brief a struct used to determine the type at index I of a tuple
*
* @note see: https://en.cppreference.com/w/cpp/utility/tuple/tuple_element
*
* @tparam I the index of the desired type
* @tparam T a tuple of different types
*/
template <size_t I, class T>
struct tuple_element;
// recursive case
/// @overload
template <size_t I, class Head, class... Tail>
struct tuple_element<I, tuple<Head, Tail...>> : tuple_element<I - 1,
tuple<Tail...>>
{
};
// base case
/// @overload
template <class Head, class... Tail>
struct tuple_element<0, tuple<Head, Tail...>>
{
using type = Head; ///< the type at the specified index
};
/**
* @brief Trait for checking if a type is a @p mfem::tuple
*/
template <typename T>
struct is_tuple : std::false_type
{
};
/// @overload
template <typename... T>
struct is_tuple<mfem::tuple<T...>> : std::true_type
{
};
/**
* @brief Trait for checking if a type if a @p mfem::tuple containing only @p mfem::tuple
*/
template <typename T>
struct is_tuple_of_tuples : std::false_type
{
};
/**
* @brief Trait for checking if a type if a @p mfem::tuple containing only @p mfem::tuple
*/
template <typename... T>
struct is_tuple_of_tuples<mfem::tuple<T...>>
{
static constexpr bool value = (is_tuple<T>::value &&
...); ///< true/false result of type check
};
} // namespace mfem
-123
View File
@@ -1,123 +0,0 @@
#include "dfem/dfem_refactor.hpp"
#include "fem/bilininteg.hpp"
#include "fem/coefficient.hpp"
#include "linalg/auxiliary.hpp"
#include "linalg/hypre.hpp"
using namespace mfem;
using mfem::internal::tensor;
int main(int argc, char *argv[])
{
Mpi::Init();
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
const char *mesh_file = "../data/ref-square.mesh";
int polynomial_order = 1;
int ir_order = 2;
int refinements = 1;
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
const int dim = mesh.Dimension();
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
L2_FECollection fec(polynomial_order, dim, BasisType::GaussLobatto);
ParFiniteElementSpace fes(&mesh, &fec);
const IntegrationRule &ir = IntRules.Get(fes.GetFE(0)->GetGeomType(),
ir_order * fec.GetOrder());
const IntegrationRule &ir_face = IntRules.Get(
fes.GetTraceElement(0, fes.GetMesh()->GetFaceGeometry(0))->GetGeomType(),
ir_order * fec.GetOrder());
ParGridFunction u(&fes);
// // -\nabla \cdot (\nabla u + p * I) -> (\nabla u + p * I, \nabla v)
// auto advection_kernel = [](const tensor<double, 2> &dudxi,
// const tensor<double, 2, 2> &J,
// const double &w)
// {
// constexpr tensor<double, 2> b{1.0, 1.0};
// return std::tuple{dot(b, dudxi * inv(J)) * det(J) * w};
// };
// std::tuple argument_operators_0{Gradient{"quantity"}, Gradient{"coordinates"}, Weight{"integration_weights"}};
// std::tuple output_operator_0{Value{"quantity"}};
// ElementOperator op_0{advection_kernel, argument_operators_0, output_operator_0};
// std::array solutions{FieldDescriptor{&fes, "quantity"}};
// std::array parameters{FieldDescriptor{&mesh_fes, "coordinates"}};
// DifferentiableOperator advection_op{solutions, parameters, std::tuple{op_0}, mesh, ir};
// auto adv_du = advection_op.template GetDerivativeWrt<0>({&u}, {mesh_nodes});
// HypreParMatrix A;
// adv_du->Assemble(A);
// std::ofstream mmatofs("dfem_mat.dat");
// A.PrintMatlab(mmatofs);
// mmatofs.close();
auto trace_kernel = [](const double &uL, const double &uR, const double &J,
const double &w)
{
return std::tuple{1.0 / J * w};
};
std::tuple argument_operators_0
{
FaceValueLeft{"quantity"},
FaceValueRight{"quantity"},
Gradient{"coordinates"},
Weight{"integration_weights"}
};
std::tuple output_operator_0{Value{"quantity"}};
FaceElementOperator op_0{trace_kernel, argument_operators_0, output_operator_0};
std::array solutions{FieldDescriptor{&fes, "quantity"}};
std::array parameters{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator trace_op{solutions, parameters, std::tuple{op_0}, mesh, ir_face};
auto vector_func = [](const Vector &, Vector &u)
{
u = 1.0;
};
VectorFunctionCoefficient vel_coeff(dim, vector_func);
ParBilinearForm adv_form(&fes);
constexpr double alpha = 1.0;
auto integ = new ConvectionIntegrator(vel_coeff, alpha);
integ->SetIntRule(&ir);
adv_form.AddInteriorFaceIntegrator(
new NonconservativeDGTraceIntegrator(vel_coeff, alpha));
// adv_form.AddDomainIntegrator(integ);
adv_form.Assemble();
adv_form.Finalize();
auto K = adv_form.ParallelAssemble();
std::ofstream kmatofs("mfem_mat.dat");
K->PrintMatlab(kmatofs);
kmatofs.close();
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" << mesh << u << std::flush;
return 0;
}
-150
View File
@@ -1,150 +0,0 @@
#include "dfem.hpp"
int main(int argc, char *argv[])
{
Mpi::Init();
std::cout << std::setprecision(9);
const char *mesh_file = "../data/star.mesh";
int polynomial_order = 1;
int refinements = 0;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
args.AddOption(&polynomial_order, "-o", "--order", "");
args.AddOption(&refinements, "-r", "--r", "");
args.ParseCheck();
Mesh mesh_serial(mesh_file, 1, 1);
mesh_serial.SetCurvature(1);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
const int dim = mesh_serial.Dimension();
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh_serial.Clear();
constexpr int vdim = 2;
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, vdim);
Array<int> ess_tdof_list;
Array<int> ess_bdr(mesh.bdr_attributes.Max());
ess_bdr = 1;
h1fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() + 1);
std::cout << "nqpts = " << ir.GetNPoints() << std::endl;
std::cout << "ndofs = " << h1fes.GlobalTrueVSize() << std::endl;
ParGridFunction u(&h1fes);
auto exact_solution = [](const Vector &coords, Vector &u)
{
const double x = coords(0);
const double y = coords(1);
u(0) = x*x + y;
u(1) = x + 0.5*y*y;
};
VectorFunctionCoefficient exact_solution_coeff(dim, exact_solution);
auto elasticity_kernel = [](tensor<double, 2, 2> &dudxi,
tensor<double, 2, 2> &J,
double &w)
{
using mfem::internal::tensor;
using mfem::internal::IsotropicIdentity;
double lambda, mu;
{
lambda = 1.0;
mu = 1.0;
}
static constexpr auto I = IsotropicIdentity<2>();
auto eps = sym(dudxi * inv(J));
auto JxW = transpose(inv(J)) * det(J) * w;
auto r = (lambda * tr(eps) * I + 2.0 * mu * eps) * JxW;
return r;
};
tensor<double, 2, 2> dudxi, s_dudxi, J;
double w = 1.0;
enzyme::get<0>
(enzyme::autodiff<enzyme::Forward,
enzyme::DuplicatedNoNeed<tensor<double, 2, 2>>>
(+elasticity_kernel,
enzyme::Duplicated<tensor<double, 2, 2> *>(&dudxi, &s_dudxi),
enzyme::Const<tensor<double, 2, 2>*>(&J),
enzyme::Const<double*>(&w)));
// std::tuple input_descriptors = {Gradient{"displacement"}, Gradient{"coordinates"}, Weight{"integration_weight"}};
// std::tuple output_descriptors = {Gradient{"displacement"}};
// ElementOperator qf {elasticity_kernel, input_descriptors, output_descriptors};
// ElementOperator forcing_qf
// {
// [](tensor<double, 2> x, tensor<double, 2, 2> J, double w)
// {
// double lambda, mu;
// {
// lambda = 1.0;
// mu = 1.0;
// }
// auto f = x;
// f(0) = 4.0*mu + 2.0*lambda;
// f(1) = 2.0*mu + lambda;
// return f * det(J) * w;
// },
// // inputs
// std::tuple{
// Value{"coordinates"},
// Gradient{"coordinates"},
// Weight{"integration_weight"}},
// // outputs
// std::tuple{
// Value{"displacement"}}
// };
// std::vector<Field> solutions{{&u, "displacement"}};
// std::vector<Field> parameters{{mesh.GetNodes(), "coordinates"}};
// std::vector<Field> dependent_fields{{&u, "displacement"}};
// DifferentiableForm dop(solutions, parameters, dependent_fields, mesh);
// dop.AddElementOperator<AD::Enzyme>(qf, ir);
// dop.AddElementOperator<AD::None>(forcing_qf, ir);
// dop.SetEssentialTrueDofs(ess_tdof_list);
// GMRESSolver gmres(MPI_COMM_WORLD);
// gmres.SetRelTol(1e-12);
// gmres.SetMaxIter(5000);
// gmres.SetPrintLevel(IterativeSolver::PrintLevel().Summary());
// NewtonSolver newton(MPI_COMM_WORLD);
// newton.SetSolver(gmres);
// newton.SetOperator(dop);
// newton.SetRelTol(1e-12);
// newton.SetMaxIter(100);
// newton.SetPrintLevel(1);
// u = 1e-6;
// u.ProjectBdrCoefficient(exact_solution_coeff, ess_bdr);
// Vector x;
// u.GetTrueDofs(x);
// Vector zero;
// newton.Mult(zero, x);
// u.Distribute(x);
// std::cout << "|u-u_ex|_L2 = " << u.ComputeL2Error(exact_solution_coeff) << "\n";
return 0;
}
File diff suppressed because it is too large Load Diff
-115
View File
@@ -1,115 +0,0 @@
#include <tuple>
#include <type_traits>
#include <iostream>
#include <enzyme/enzyme>
template <typename T>
constexpr auto get_type_name() -> std::string_view
{
#if defined(__clang__)
constexpr auto prefix = std::string_view {"[T = "};
constexpr auto suffix = "]";
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
#elif defined(__GNUC__)
constexpr auto prefix = std::string_view {"with T = "};
constexpr auto suffix = "; ";
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
#elif defined(_MSC_VER)
constexpr auto prefix = std::string_view {"get_type_name<"};
constexpr auto suffix = ">(void)";
constexpr auto function = std::string_view{__FUNCSIG__};
#else
#error Unsupported compiler
#endif
const auto start = function.find(prefix) + prefix.size();
const auto end = function.find(suffix);
const auto size = end - start;
return function.substr(start, size);
}
template <typename ... Ts>
constexpr auto decay_types(std::tuple<Ts...> const &)
-> std::tuple<std::remove_cv_t<std::remove_reference_t<Ts>>...>;
template <typename T>
using decay_tuple = decltype(decay_types(std::declval<T>()));
template <class F> struct FunctionSignature;
template <typename output_t, typename... input_ts>
struct FunctionSignature<output_t(input_ts...)>
{
using return_t = output_t;
using parameter_ts = std::tuple<input_ts...>;
};
template <class T> struct create_function_signature;
template <typename output_t, typename T, typename... input_ts>
struct create_function_signature<output_t (T::*)(input_ts...) const>
{
using type = FunctionSignature<output_t(input_ts...)>;
};
template <typename arg_ts, std::size_t... Is>
auto create_enzyme_args(arg_ts &args,
arg_ts &shadow_args,
std::index_sequence<Is...>)
{
((std::cout << std::get<Is>(shadow_args) << "\n"), ...);
return std::tuple<enzyme::Duplicated<decltype(std::get<Is>(args))>...>
{
{ std::get<Is>(args), std::get<Is>(shadow_args) }...
};
}
template <typename kernel_t, typename arg_ts>
auto fwddiff_apply_enzyme(kernel_t kernel, arg_ts &&args, arg_ts &&shadow_args)
{
auto arg_indices =
std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<arg_ts>>> {};
auto enzyme_args = create_enzyme_args(args, shadow_args, arg_indices);
using kf_return_t = typename create_function_signature<
decltype(&kernel_t::operator())>::type::return_t;
std::cout << "args is " << get_type_name<decltype(args)>() << "\n\n";
std::cout << "enzyme_args type is " << get_type_name<decltype(enzyme_args)>() <<
"\n\n";
std::cout << "return type is " << get_type_name<decltype(kf_return_t{})>() <<
"\n\n";
return std::apply([&](auto &&...args)
{
return enzyme::get<0>(
enzyme::autodiff<enzyme::Forward>
(+kernel, args...));
},
enzyme_args);
}
int main()
{
auto func = [](const double &x)
{
return x*x;
};
using kf_param_ts = typename create_function_signature<
decltype(&decltype(func)::operator())>::type::parameter_ts;
using kf_output_t = typename create_function_signature<
decltype(&decltype(func)::operator())>::type::return_t;
auto kernel_args = decay_tuple<kf_param_ts> {};
auto kernel_shadow_args = decay_tuple<kf_param_ts> {};
std::get<0>(kernel_args) = 3;
std::get<0>(kernel_shadow_args) = 1;
const auto res = fwddiff_apply_enzyme(func, kernel_args, kernel_shadow_args);
std::cout << res << " == 6\n";
return 0;
}
-114
View File
@@ -1,114 +0,0 @@
#include "dfem.hpp"
int main(int argc, char *argv[])
{
Mpi::Init();
std::cout << std::setprecision(9);
const char *mesh_file = "../data/star.mesh";
int polynomial_order = 1;
int refinements = 0;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
args.AddOption(&polynomial_order, "-o", "--order", "");
args.AddOption(&refinements, "-r", "--r", "");
args.ParseCheck();
Mesh mesh_serial(mesh_file, 1, 1);
mesh_serial.SetCurvature(1);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
const int dim = mesh_serial.Dimension();
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh_serial.Clear();
constexpr int vdim = 2;
// test_partial_assembly_setup_qf(mesh, 1, polynomial_order);
// exit(0);
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, vdim);
Array<int> ess_tdof_list;
Array<int> ess_bdr(mesh.bdr_attributes.Max());
ess_bdr = 1;
h1fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() + 1);
std::cout << "nqpts = " << ir.GetNPoints() << std::endl;
std::cout << "ndofs = " << h1fes.GlobalTrueVSize() << std::endl;
ParGridFunction u(&h1fes);
ParGridFunction g(&h1fes);
ParGridFunction rho(&h1fes);
auto exact_solution = [](const Vector &coords, Vector &u)
{
const double x = coords(0);
const double y = coords(1);
u(0) = x*x + y;
u(1) = x + 0.5*y*y;
};
VectorFunctionCoefficient exact_solution_coeff(dim, exact_solution);
auto objective = [](tensor<double, 2> u, double rho,
tensor<double, 2, 2> J,
double w)
{
return sqnorm(u) * det(J) * w;
};
std::tuple inputs{Value{"displacement"}, Value{"density"}, Gradient{"coordinates"}, Weight{"integration_weight"}};
std::tuple outputs{ One{"integral"} };
ElementOperator objective_eop { objective, inputs, outputs };
std::vector<Field> solution_fields{{&u, "displacement"}};
std::vector<Field> parameter_fields{{mesh.GetNodes(), "coordinates"}, {&rho, "density"}};
std::vector<Field> dependent_variables{{&u, "displacement"}};
DifferentiableForm dop(solution_fields, parameter_fields, dependent_variables,
mesh);
dop.AddElementOperator(objective_eop, ir);
u.ProjectCoefficient(exact_solution_coeff);
Vector zero;
Vector y(1);
Vector utdof;
u.GetTrueDofs(utdof);
dop.Mult(utdof, y);
// finite difference test
Vector dgdu(u.Size());
Vector fx(y);
out << "g: ";
print_vector(fx);
out << "\n";
for (int i = 0; i < u.Size(); i++)
{
double h = 1e-6;
u(i) += h;
dop.Mult(u, y);
u(i) -= h;
y -= fx;
y /= h;
dgdu(i) = y(0);
}
out << "dgdu: ";
print_vector(dgdu);
// Vector dgdu = dop.GetGradientWrt({&u, "displacement"});
return 0;
}
-138
View File
@@ -1,138 +0,0 @@
#include "dfem.hpp"
int main(int argc, char *argv[])
{
Mpi::Init();
std::cout << std::setprecision(9);
const char *mesh_file = "../data/star.mesh";
int polynomial_order = 1;
int refinements = 0;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
args.AddOption(&polynomial_order, "-o", "--order", "");
args.AddOption(&refinements, "-r", "--r", "");
args.ParseCheck();
Mesh mesh_serial(mesh_file, 1, 1);
mesh_serial.SetCurvature(1);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
const int dim = mesh_serial.Dimension();
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh_serial.Clear();
constexpr int vdim = 1;
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, vdim);
Array<int> ess_tdof_list;
Array<int> ess_bdr(mesh.bdr_attributes.Max());
ess_bdr = 1;
h1fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() + 1);
std::cout << "nqpts = " << ir.GetNPoints() << std::endl;
std::cout << "ndofs = " << h1fes.GlobalTrueVSize() << std::endl;
ParGridFunction u(&h1fes);
auto exact_solution = [](const Vector &coords)
{
const double x = coords(0);
const double y = coords(1);
// PRESENT
return pow(x,2) + 0.5*x*pow(y,2);
};
FunctionCoefficient exact_solution_coeff(exact_solution);
auto plaplacian = [](double u,
tensor<double, 2> dudxi,
tensor<double, 2, 2> J,
double w)
{
using mfem::internal::tensor;
auto dudx = dudxi * inv(J);
auto JxW = transpose(inv(J)) * det(J) * w;
// PRESENT: Implement (1+u^2) * ∇u
return (1.0 + u*u) * dudx * JxW;
};
// PRESENT: Implement descriptors
std::tuple input_descriptors = {Value{"potential"}, Gradient{"potential"}, Gradient{"coordinates"}, Weight{"integration_weights"}};
// PRESENT: Implement descriptors
std::tuple output_descriptors = {Gradient{"potential"}};
ElementOperator qf {plaplacian, input_descriptors, output_descriptors};
ElementOperator forcing_qf
{
[](tensor<double, 2> coords, tensor<double, 2, 2> J, double w)
{
int p = 2;
double x = coords(0);
double y = coords(1);
// *INDENT-OFF*
double mathematica_please_help_me = 2.*pow(x,2)*pow(y,2)*(pow(x,2) + 0.5*x*pow(y,2)) + 2*pow(2*x + 0.5*pow(y,2),2)*(pow(x,2) + 0.5*x*pow(y,2)) + 2*(1 + pow(pow(x,2) + 0.5*x*pow(y,2),2)) + 1.*x*(1 + pow(pow(x,2) + 0.5*x*pow(y,2),2));
return mathematica_please_help_me * det(J) * w;
// *INDENT-ON*
},
// inputs
std::tuple{
Value{"coordinates"},
Gradient{"coordinates"},
Weight{"integration_weight"}},
// outputs
std::tuple{
Value{"potential"}}
};
std::tuple list_of_qfs{qf_1, qf_2, qf_n};
std::vector<Field> solutions{{&u, "potential"}};
std::vector<Field> parameters{{mesh.GetNodes(), "coordinates"}};
DifferentiableForm dop(solutions, parameters, mesh);
dop.SetEssentialTrueDofs(ess_tdof_list);
auto R = dop.GetResidual(list_of_qfs, ir);
auto Jacobian_aka_dRdu = dop.GetDerivative<0>(list_of_qfs, ir);
// R(u) = (\grad u, \grad v) + (f, v)
// dop.AddElementOperator<AD::Enzyme>(qf, ir);
// dop.AddElementOperator<AD::None>(forcing_qf, ir);
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetRelTol(1e-12);
gmres.SetMaxIter(5000);
gmres.SetPrintLevel(IterativeSolver::PrintLevel().Summary());
NewtonSolver newton(MPI_COMM_WORLD);
newton.SetSolver(gmres);
newton.SetOperator(dop);
newton.SetRelTol(1e-12);
newton.SetMaxIter(100);
newton.SetPrintLevel(1);
u = 1e-6;
u.ProjectBdrCoefficient(exact_solution_coeff, ess_bdr);
Vector x;
u.GetTrueDofs(x);
Vector zero;
newton.Mult(zero, x);
u.Distribute(x);
std::cout << "|u-u_ex|_L2 = " << u.ComputeL2Error(exact_solution_coeff) << "\n";
return 0;
}
-192
View File
@@ -1,192 +0,0 @@
#include "dfem/dfem_refactor.hpp"
#include "linalg/hypre.hpp"
using namespace mfem;
using mfem::internal::tensor;
template <typename diffusion_t, typename force_t>
class DiffusionOperator : public Operator
{
template <typename diffusion_du_t>
class DiffusionJacobianOperator : public Operator
{
public:
DiffusionJacobianOperator(const DiffusionOperator *diffusion,
std::shared_ptr<diffusion_du_t> diff_du) :
Operator(diffusion->Height()), s(diffusion)
{
diff_du->Assemble(A);
A.EliminateBC(s->ess_tdofs, Operator::DiagonalPolicy::DIAG_ONE);
}
void Mult(const Vector &x, Vector &y) const override
{
A.Mult(x, y);
}
const DiffusionOperator *s;
HypreParMatrix A;
};
public:
DiffusionOperator(diffusion_t &diffusion, force_t &force,
Array<int> &ess_tdofs) :
Operator(diffusion.Height()), diffusion(diffusion),
force(force), ess_tdofs(ess_tdofs), f(force.Height()) {}
void SetParameters(ParGridFunction &mesh_nodes)
{
diffusion.SetParameters({&mesh_nodes});
force.SetParameters({&mesh_nodes});
Vector zero;
this->mesh_nodes.SetSpace(mesh_nodes.ParFESpace());
this->mesh_nodes = mesh_nodes;
}
void Mult(const Vector &x, Vector &r) const override
{
diffusion.Mult(x, r);
force.Mult(x, f);
r -= f;
r.SetSubVector(ess_tdofs, 0.0);
}
Operator &GetGradient(const Vector &x) const override
{
ParGridFunction u(const_cast<ParFiniteElementSpace *>
(*std::get_if<const ParFiniteElementSpace *>
(&diffusion.solutions[0].data)));
u.SetFromTrueDofs(x);
auto dfdu = diffusion.template GetDerivativeWrt<0>({&u}, {&mesh_nodes});
dfdu->Assemble(A);
A.EliminateBC(ess_tdofs, DiagonalPolicy::DIAG_ONE);
return A;
// delete jacobian_operator;
// jacobian_operator = new
// DiffusionJacobianOperator<typename std::remove_pointer<decltype(dfdu.get())>::type>
// (this, dfdu);
// return *jacobian_operator;
}
diffusion_t &diffusion;
force_t &force;
const Array<int> ess_tdofs;
mutable Vector f;
mutable ParGridFunction mesh_nodes;
mutable Operator *jacobian_operator = nullptr;
mutable HypreParMatrix A;
};
int main(int argc, char *argv[])
{
Mpi::Init();
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
const char *mesh_file = "../data/ref-square.mesh";
int polynomial_order = 2;
int ir_order = 2;
int refinements = 4;
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
const int dim = mesh.Dimension();
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection potential_fec(polynomial_order, dim);
ParFiniteElementSpace potential_fes(&mesh, &potential_fec);
const IntegrationRule &potential_ir =
IntRules.Get(potential_fes.GetFE(0)->GetGeomType(),
ir_order * potential_fec.GetOrder());
Array<int> bdr_attr_is_ess(mesh.bdr_attributes.Max());
bdr_attr_is_ess = 1;
Array<int> ess_tdofs;
potential_fes.GetEssentialTrueDofs(bdr_attr_is_ess, ess_tdofs);
ParGridFunction u(&potential_fes);
u = 0.0;
auto diffusion_kernel = [](const internal::dual<double, double> &u,
const tensor<internal::dual<double, double>, 2> &dudxi,
const tensor<double, 2, 2> &J,
const double &w)
{
auto invJ = inv(J);
auto dudx = dudxi * invJ;
return std::tuple{(1.0 + u * u) * dudx * det(J) * w * transpose(invJ)};
};
std::tuple argument_operators_0{Value{"potential"}, Gradient{"potential"}, Gradient{"coordinates"}, Weight{"integration_weights"}};
std::tuple output_operator_0{Gradient{"potential"}};
ElementOperator op_0{diffusion_kernel, argument_operators_0, output_operator_0};
auto force_kernel = [](const tensor<double, 2, 2> &J,
const double &w)
{
return std::tuple{1.0 * det(J) * w};
};
std::tuple argument_operators_1{Gradient{"coordinates"}, Weight{"integration_weights"}};
std::tuple output_operator_1{Value{"potential"}};
ElementOperator op_1{force_kernel, argument_operators_1, output_operator_1};
std::array solutions{FieldDescriptor{&potential_fes, "potential"}};
std::array parameters{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator diffusion_op{solutions, parameters, std::tuple{op_0}, mesh, potential_ir};
DifferentiableOperator force_op{solutions, parameters, std::tuple{op_1}, mesh, potential_ir};
DiffusionOperator diffusion(diffusion_op, force_op, ess_tdofs);
diffusion.SetParameters({*mesh_nodes});
HypreBoomerAMG amg;
amg.SetPrintLevel(0);
CGSolver solver(MPI_COMM_WORLD);
solver.SetAbsTol(1e-12);
solver.SetRelTol(1e-12);
solver.SetMaxIter(500);
solver.SetPrintLevel(2);
solver.SetPreconditioner(amg);
NewtonSolver newton(MPI_COMM_WORLD);
newton.SetOperator(diffusion);
newton.SetSolver(solver);
newton.SetRelTol(1e-8);
newton.SetMaxIter(10);
newton.SetPrintLevel(1);
Vector zero;
Vector x(potential_fes.GetTrueVSize());
u.ParallelProject(x);
newton.Mult(zero, x);
u.SetFromTrueDofs(x);
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" << mesh << u << std::flush;
return 0;
}
-102
View File
@@ -1,102 +0,0 @@
#include "mfem.hpp"
#include "dfem/dfem_refactor.hpp"
using namespace mfem;
auto main(int argc, char *argv[]) -> int
{
Mpi::Init();
std::cout << std::setprecision(9);
const char *mesh_file = "../data/star.mesh";
int polynomial_order = 1;
int refinements = 0;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
args.AddOption(&polynomial_order, "-o", "--order", "");
args.AddOption(&refinements, "-r", "--r", "");
args.ParseCheck();
Mesh mesh_serial(mesh_file, 1, 1);
mesh_serial.SetCurvature(1);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
const int dim = mesh_serial.Dimension();
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
constexpr int vdim = 1;
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, vdim);
Array<int> ess_tdof_list;
Array<int> ess_bdr(mesh.bdr_attributes.Max());
ess_bdr = 1;
h1fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() + 1);
std::cout << "nqpts = " << ir.GetNPoints() << std::endl;
std::cout << "ndofs = " << h1fes.GlobalTrueVSize() << std::endl;
ParGridFunction u(&h1fes);
auto exact_solution = [](const Vector &coords)
{
const double x = coords(0);
const double y = coords(1);
return 2.345 + x + y;
};
FunctionCoefficient exact_solution_coeff(exact_solution);
u.ProjectCoefficient(exact_solution_coeff);
auto domain_qf = [](const double &u,
const tensor<double, 2, 2> &J,
const double &w)
{
out << u << "\n" << J << "\n" << w << "\n\n";
return std::tuple{u * det(J) * w};
};
std::tuple input_descriptors = {Value{"potential"}, Gradient{"coordinates"}, Weight{"integration_weights"}};
std::tuple output_descriptors = {Value{"potential"}};
ElementOperator eop{domain_qf, input_descriptors, output_descriptors};
auto ops = std::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop{solutions, parameters, ops, mesh, ir};
Vector x(h1fes.GetTrueVSize()), y(h1fes.GetTrueVSize());
u.GetTrueDofs(x);
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
// Derivative wrt "potential", indicated by the index 0 of the set {solutions} \cup {parameters}
auto dFd0 = dop.GetDerivativeWrt<0>({&u}, {mesh_nodes});
dFd0->Mult(x, y);
Vector dFd0_vec;
dFd0->Assemble(dFd0_vec);
// Derivative wrt "coordinates", indicated by the index 1 of the set {solutions} \cup {parameters}
auto dFd1 = dop.GetDerivativeWrt<1>({&u}, {mesh_nodes});
dFd1->Mult(x, y);
return 0;
}
-302
View File
@@ -1,302 +0,0 @@
#include "dfem/dfem.hpp"
using namespace mfem;
using mfem::internal::tensor;
template <typename momentum_t, typename mass_conservation_t>
class NavierStokesOperator : public Operator
{
template <typename momentum_du_t, typename momentum_dp_t>
class NavierStokesJacobianOperator : public Operator
{
public:
NavierStokesJacobianOperator(const NavierStokesOperator *ns,
std::shared_ptr<momentum_du_t> mom_du,
std::shared_ptr<momentum_dp_t> mom_dp) :
Operator(ns->Height()), ns(ns), block_op(ns->block_offsets)
{
mom_du->Assemble(A);
A.EliminateBC(ns->vel_ess_tdofs, Operator::DiagonalPolicy::DIAG_ONE);
mom_dp->Assemble(D);
D.EliminateRows(ns->vel_ess_tdofs);
Dt = new TransposeOperator(D);
block_op.SetBlock(0, 0, &A);
block_op.SetBlock(0, 1, &D);
block_op.SetBlock(1, 0, Dt);
// std::ofstream amatofs("dfem_mat.dat");
// block_op.PrintMatlab(amatofs);
// amatofs.close();
}
void Mult(const Vector &x, Vector &y) const override
{
block_op.Mult(x, y);
}
~NavierStokesJacobianOperator()
{
delete Dt;
}
const NavierStokesOperator *ns = nullptr;
HypreParMatrix A, D;
TransposeOperator *Dt = nullptr;
BlockOperator block_op;
};
public:
NavierStokesOperator(momentum_t &momentum,
mass_conservation_t &mass_conservation,
Array<int> &offsets, Array<int> &vel_ess_tdofs) :
Operator(offsets.Last()), momentum(momentum),
mass_conservation(mass_conservation),
block_offsets(offsets), vel_ess_tdofs(vel_ess_tdofs) {}
void SetParameters(ParGridFunction &mesh_nodes)
{
momentum.SetParameters({&mesh_nodes});
mass_conservation.SetParameters({&mesh_nodes});
this->mesh_nodes.SetSpace(mesh_nodes.ParFESpace());
this->mesh_nodes = mesh_nodes;
}
void Mult(const Vector &x, Vector &r) const override
{
Vector ru(r.ReadWrite() + block_offsets[0],
block_offsets[1] - block_offsets[0]);
Vector rp(r.ReadWrite() + block_offsets[1],
block_offsets[2] - block_offsets[1]);
momentum.Mult(x, ru);
mass_conservation.Mult(x, rp);
ru.SetSubVector(vel_ess_tdofs, 0.0);
}
Operator &GetGradient(const Vector &x) const override
{
xtmp = x;
BlockVector xb(xtmp.ReadWrite(), block_offsets);
ParGridFunction u(const_cast<ParFiniteElementSpace *>
(*std::get_if<const ParFiniteElementSpace *>
(&momentum.solutions[0].data)));
ParGridFunction p(const_cast<ParFiniteElementSpace *>
(*std::get_if<const ParFiniteElementSpace *>
(&momentum.solutions[1].data)));
u.SetFromTrueDofs(xb.GetBlock(0));
p.SetFromTrueDofs(xb.GetBlock(1));
auto mom_du = momentum.template GetDerivativeWrt<0>({&u, &p}, {&mesh_nodes});
auto mom_dp = momentum.template GetDerivativeWrt<1>({&u, &p}, {&mesh_nodes});
delete jacobian_operator;
jacobian_operator = new NavierStokesJacobianOperator<
typename std::remove_pointer<decltype(mom_du.get())>::type,
typename std::remove_pointer<decltype(mom_dp.get())>::type>(this, mom_du,
mom_dp);
return *jacobian_operator;
}
momentum_t &momentum;
mass_conservation_t &mass_conservation;
const Array<int> block_offsets;
const Array<int> vel_ess_tdofs;
mutable Vector xtmp;
mutable ParGridFunction mesh_nodes;
mutable Operator *jacobian_operator = nullptr;
};
double reynolds = 10.0;
int main(int argc, char *argv[])
{
constexpr int dim = 3;
constexpr int vdim = dim;
Mpi::Init();
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
const char *mesh_file = "../data/ref-cube.mesh";
int polynomial_order = 2;
int ir_order = 2;
int refinements = 2;
OptionsParser args(argc, argv);
args.AddOption(&refinements, "-r", "--refinements", "");
args.AddOption(&reynolds, "-rey", "--reynolds", "");
args.ParseCheck();
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection velocity_fec(polynomial_order, dim);
ParFiniteElementSpace velocity_fes(&mesh, &velocity_fec, dim);
H1_FECollection pressure_fec(polynomial_order - 1, dim);
ParFiniteElementSpace pressure_fes(&mesh, &pressure_fec);
const IntegrationRule &velocity_ir =
IntRules.Get(velocity_fes.GetFE(0)->GetGeomType(),
ir_order * velocity_fec.GetOrder());
const IntegrationRule &pressure_ir =
IntRules.Get(pressure_fes.GetFE(0)->GetGeomType(),
ir_order * pressure_fec.GetOrder());
Array<int> bdr_attr_is_ess(mesh.bdr_attributes.Max());
bdr_attr_is_ess = 1;
Array<int> vel_ess_tdofs;
velocity_fes.GetEssentialTrueDofs(bdr_attr_is_ess, vel_ess_tdofs);
ParGridFunction u(&velocity_fes);
ParGridFunction p(&pressure_fes);
auto u_f = [](const Vector &coords, Vector &u)
{
const double x = coords(0);
const double z = coords(2);
if (z >= 1.0)
{
u(0) = 1.0;
}
else
{
u(0) = 0.0;
}
u(1) = 0.0;
u(2) = 0.0;
};
auto u_coef = VectorFunctionCoefficient(dim, u_f);
u.ProjectCoefficient(u_coef);
p = 0.0;
// -\nabla \cdot (\nabla u + p * I) -> (\nabla u + p * I, \nabla v)
auto momentum_kernel = [](const tensor<double, dim> &u,
const tensor<double, dim, dim> &dudxi,
const double &p,
const tensor<double, dim, dim> &J,
const double &w)
{
static constexpr auto I = mfem::internal::IsotropicIdentity<dim>();
auto invJ = inv(J);
auto dudx = dudxi * invJ;
double Re = reynolds;
return mfem::tuple{(outer(u, u) - 1.0 / Re * dudx + p * I) * det(J) * w * transpose(invJ)};
};
mfem::tuple argument_operators_0{Value{"velocity"}, Gradient{"velocity"}, Value{"pressure"}, Gradient{"coordinates"}, Weight{}};
mfem::tuple output_operator_0{Gradient{"velocity"}};
ElementOperator op_0{momentum_kernel, argument_operators_0, output_operator_0};
// (\nabla \cdot u, q)
auto mass_conservation_kernel = [](const tensor<double, dim, dim> &dudxi,
const tensor<double, dim, dim> &J,
const double &w)
{
return mfem::tuple{tr(dudxi * inv(J)) * det(J) * w};
};
mfem::tuple argument_operators_1{Gradient{"velocity"}, Gradient{"coordinates"}, Weight{}};
mfem::tuple output_operator_1{Value{"pressure"}};
ElementOperator op_1{mass_conservation_kernel, argument_operators_1, output_operator_1};
std::array solutions{FieldDescriptor{&velocity_fes, "velocity"}, FieldDescriptor{&pressure_fes, "pressure"}};
std::array parameters{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator momentum_op{solutions, parameters, mfem::tuple{op_0}, mesh, velocity_ir};
DifferentiableOperator mass_conservation_op{solutions, parameters, mfem::tuple{op_1}, mesh, pressure_ir};
// Preconditioner form
auto pressure_mass_kernel = [](const double &p,
const tensor<double, dim, dim> &J,
const double &w)
{
return mfem::tuple{p * det(J) * w};
};
mfem::tuple pms_args{Value{"pressure"}, Gradient{"coordinates"}, Weight{}};
mfem::tuple pms_outs{Value{"pressure"}};
ElementOperator pressure_mass{pressure_mass_kernel, pms_args, pms_outs};
std::array pms_sols{FieldDescriptor{&pressure_fes, "pressure"}};
std::array pms_params{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator pressure_mass_op{pms_sols, pms_params, mfem::tuple{pressure_mass}, mesh, pressure_ir};
Array<int> block_offsets(3);
block_offsets[0] = 0;
block_offsets[1] = velocity_fes.GetTrueVSize();
block_offsets[2] = pressure_fes.GetTrueVSize();
block_offsets.PartialSum();
NavierStokesOperator navierstokes(momentum_op, mass_conservation_op,
block_offsets,
vel_ess_tdofs);
BlockVector x(block_offsets), y(block_offsets);
u.ParallelProject(x.GetBlock(0));
// p.ParallelProject(x.GetBlock(1));
navierstokes.SetParameters(*mesh_nodes);
HypreParMatrix A;
momentum_op.template GetDerivativeWrt<0>({&u, &p}, {mesh_nodes})->Assemble(A);
A.EliminateBC(vel_ess_tdofs, Operator::DiagonalPolicy::DIAG_ONE);
HypreBoomerAMG amg(A);
amg.SetMaxLevels(50);
amg.SetPrintLevel(0);
HypreParMatrix Mp;
pressure_mass_op.template GetDerivativeWrt<0>({&p}, {mesh_nodes})->Assemble(Mp);
HypreDiagScale Mp_inv(Mp);
BlockDiagonalPreconditioner prec(block_offsets);
prec.SetDiagonalBlock(0, &amg);
prec.SetDiagonalBlock(1, &Mp_inv);
GMRESSolver solver(MPI_COMM_WORLD);
solver.SetAbsTol(0.0);
solver.SetRelTol(1e-8);
solver.SetKDim(100);
solver.SetMaxIter(500);
solver.SetPrintLevel(2);
solver.SetPreconditioner(prec);
NewtonSolver newton(MPI_COMM_WORLD);
newton.SetOperator(navierstokes);
newton.SetSolver(solver);
newton.SetRelTol(1e-8);
newton.SetMaxIter(50);
newton.SetPrintLevel(1);
Vector zero;
newton.Mult(zero, x);
u.SetFromTrueDofs(x.GetBlock(0));
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" << mesh << u << std::flush;
return 0;
}
-174
View File
@@ -1,174 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_diffusion(
std::string mesh_file, int refinements, int polynomial_order)
{
Mesh mesh_serial = Mesh(mesh_file);
MFEM_ASSERT(mesh_serial.Dimension() == 2, "incorrect mesh dimension");
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
const int dim = mesh.Dimension();
mesh_serial.Clear();
out << "#el: " << mesh.GetNE() << "\n";
ParGridFunction* mesh_nodes = static_cast<ParGridFunction*>(mesh.GetNodes());
ParFiniteElementSpace& mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec);
out << "#dofs " << h1fes.GetTrueVSize() << "\n";
const IntegrationRule& ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder());
out << "#qp: " << ir.GetNPoints() << "\n";
ParGridFunction f1_g(&h1fes);
ParGridFunction rho_g(&h1fes);
auto kernel = [] MFEM_HOST_DEVICE(const tensor<double, 2, 2>& J,
const double& w, const tensor<double, 2>& dudxi)
{
auto invJ = inv(J);
return mfem::tuple{dudxi * invJ * transpose(invJ) * det(J) * w};
};
mfem::tuple argument_operators =
{
Gradient{"coordinates"}, Weight{}, Gradient{"potential"}
};
mfem::tuple output_operator = {Gradient{"potential"}};
ElementOperator eop = {kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto f1 = [](const Vector& coords)
{
const double x = coords(0);
const double y = coords(1);
return 2.345 + 0.25 * x * x * y + y * y * x;
};
FunctionCoefficient f1_c(f1);
f1_g.ProjectCoefficient(f1_c);
Vector x(f1_g), y(h1fes.TrueVSize());
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
y.HostRead();
ParBilinearForm a(&h1fes);
a.AddDomainIntegrator(new DiffusionIntegrator);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a.Assemble();
a.Finalize();
Vector y2(h1fes.TrueVSize());
a.Mult(x, y2);
y2.HostRead();
Vector diff(y2);
diff -= y;
if (diff.Norml2() > 1e-10)
{
print_vector(diff);
print_vector(y2);
print_vector(y);
return 1;
}
// // Test linearization here as well
// auto dFdu = dop.GetDerivativeWrt<0>({&f1_g}, {mesh_nodes});
// if (dFdu->Height() != h1fes.GetTrueVSize())
// {
// out << "dFdu unexpected height of " << dFdu->Height() << "\n";
// return 1;
// }
// dFdu->Mult(x, y);
// y.HostRead();
// a.Mult(x, y2);
// y2.HostRead();
// diff = y2;
// diff -= y;
// if (diff.Norml2() > 1e-10)
// {
// print_vector(diff);
// print_vector(y2);
// print_vector(y);
// return 1;
// }
// // fd jacobian test
// {
// double eps = 1.0e-6;
// Vector v(x), xpv(x), xmv(x), fxpv(x.Size()), fxmv(x.Size());
// v *= eps;
// xpv += v;
// xmv -= v;
// dop.Mult(xpv, fxpv);
// dop.Mult(xmv, fxmv);
// fxpv -= fxmv;
// fxpv /= (2.0*eps);
// fxpv -= y;
// if (fxpv.Norml2() > eps)
// {
// out << "||dFdu_FD u^* - ex||_l2 = " << fxpv.Norml2() << "\n";
// return 1;
// }
// }
// f1_g.ProjectCoefficient(f1_c);
// rho_g.ProjectCoefficient(rho_c);
// auto dFdrho = dop.GetDerivativeWrt<1>({&f1_g}, {&rho_g, mesh_nodes});
// if (dFdrho->Height() != h1fes.GetTrueVSize())
// {
// out << "dFdrho unexpected height of " << dFdrho->Height() << "\n";
// return 1;
// }
// dFdrho->Mult(rho_g, y);
// // fd test
// {
// double eps = 1.0e-6;
// Vector v(rho_g), rhopv(rho_g), rhomv(rho_g), frhopv(x.Size()),
// frhomv(x.Size()); v *= eps; rhopv += v; rhomv -= v;
// dop.SetParameters({&rhopv, mesh_nodes});
// dop.Mult(x, frhopv);
// dop.SetParameters({&rhomv, mesh_nodes});
// dop.Mult(x, frhomv);
// frhopv -= frhomv;
// frhopv /= (2.0*eps);
// frhopv -= y;
// if (frhopv.Norml2() > eps)
// {
// out << "||dFdu_FD u^* - ex||_l2 = " << frhopv.Norml2() << "\n";
// return 1;
// }
// }
return 0;
}
DFEM_TEST_MAIN(test_diffusion);
-296
View File
@@ -1,296 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
#include "examples/dfem/dfem_parametricspace.hpp"
#include "fem/bilininteg.hpp"
#include "general/tic_toc.hpp"
using namespace mfem;
using mfem::internal::tensor;
using mfem::internal::dual;
int test_diffusion_3d(
std::string mesh_file, int refinements, int polynomial_order)
{
constexpr int num_samples = 10;
constexpr int dim = 3;
Mesh mesh_serial = Mesh(mesh_file);
MFEM_ASSERT(mesh_serial.Dimension() == dim, "incorrect mesh dimension");
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(polynomial_order);
mesh_serial.Clear();
out << "#el: " << mesh.GetNE() << "\n";
ParGridFunction* mesh_nodes = static_cast<ParGridFunction*>(mesh.GetNodes());
ParFiniteElementSpace& mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec);
out << "#dofs " << h1fes.GetTrueVSize() << "\n";
const IntegrationRule& ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(),
h1fes.GetFE(0)->GetOrder() + h1fes.GetFE(0)->GetOrder() + h1fes.GetFE(
0)->GetDim() - 1);
printf("#ndof per el = %d\n", h1fes.GetFE(0)->GetDof());
printf("#nqp = %d\n", ir.GetNPoints());
printf("#q1d = %d\n", (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5));
ParametricSpace qdata_space(dim, dim * dim, ir.GetNPoints(),
dim * dim * ir.GetNPoints() * mesh.GetNE());
ParametricFunction qdata(qdata_space);
ParGridFunction f1_g(&h1fes);
ParGridFunction rho_g(&h1fes);
auto f1 = [](const Vector& coords)
{
const double x = coords(0);
const double y = coords(1);
const double z = coords(2);
return 2.345 + x + x*y + 1.25 * z*x;
};
FunctionCoefficient f1_c(f1);
f1_g.ProjectCoefficient(f1_c);
Vector x(f1_g), y(h1fes.GetTrueVSize());
{
auto diffusion_mf_kernel =
[] MFEM_HOST_DEVICE (
const tensor<dual<real_t, real_t>, dim>& dudxi,
const tensor<double, dim, dim>& J,
const double& w)
{
auto invJ = inv(J);
return mfem::tuple{dudxi * invJ * transpose(invJ) * det(J) * w};
};
mfem::tuple argument_operators = {Gradient{"potential"}, Gradient{"coordinates"}, Weight{}};
mfem::tuple output_operator = {Gradient{"potential"}};
ElementOperator eop = {diffusion_mf_kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
dop.SetParameters({mesh_nodes});
StopWatch sw;
sw.Start();
for (int i = 0; i < num_samples; i++)
{
dop.Mult(x, y);
}
sw.Stop();
printf("dfem mf: %fs\n", sw.RealTime() / num_samples);
y.HostRead();
}
{
auto diffusion_setup_kernel =
[] MFEM_HOST_DEVICE (
const tensor<double, dim, dim>& J,
const double& w)
{
auto invJ = inv(J);
return mfem::tuple{invJ * transpose(invJ) * det(J) * w};
};
mfem::tuple argument_operators = {Gradient{"coordinates"}, Weight{}};
mfem::tuple output_operator = {None{"qdata"}};
ElementOperator eop = {diffusion_setup_kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array
{
FieldDescriptor{&mesh_fes, "coordinates"},
FieldDescriptor{&qdata_space, "qdata"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
dop.SetParameters({mesh_nodes, &qdata});
StopWatch sw;
sw.Start();
for (int i = 0; i < num_samples; i++)
{
dop.Mult(x, qdata);
}
sw.Stop();
printf("dfem pa setup: %fs\n", sw.RealTime() / num_samples);
qdata.HostRead();
}
// printf("qdata: ");
// print_vector(qdata);
{
auto diffusion_apply_kernel =
[] MFEM_HOST_DEVICE (
const tensor<dual<real_t, real_t>, dim>& dudxi,
const tensor<double, dim, dim>& qdata)
{
return mfem::tuple{dudxi * qdata};
};
mfem::tuple argument_operators = {Gradient{"potential"}, None{"qdata"}};
mfem::tuple output_operator = {Gradient{"potential"}};
ElementOperator eop = {diffusion_apply_kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array{FieldDescriptor{&qdata_space, "qdata"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
dop.SetParameters({&qdata});
StopWatch sw;
sw.Start();
for (int i = 0; i < num_samples; i++)
{
dop.Mult(x, y);
}
sw.Stop();
printf("dfem pa apply: %fs\n", sw.RealTime() / num_samples);
y.HostRead();
}
// printf("y: ");
// print_vector(y);
Vector y2(h1fes.TrueVSize());
{
ParBilinearForm a(&h1fes);
auto diff_integ = new DiffusionIntegrator;
diff_integ->SetIntRule(&ir);
a.AddDomainIntegrator(diff_integ);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
OperatorPtr A;
StopWatch sw;
sw.Start();
a.Assemble();
a.Finalize();
Array<int> empty;
a.FormSystemMatrix(empty, A);
sw.Stop();
printf("mfem pa setup: %fs\n", sw.RealTime());
sw.Clear();
sw.Start();
for (int i = 0; i < num_samples; i++)
{
A->Mult(x, y2);
}
sw.Stop();
printf("mfem pa apply: %fs\n", sw.RealTime() / num_samples);
y2.HostRead();
}
// printf("y2: ");
// print_vector(y2);
Vector diff(y2);
diff -= y;
if (diff.Norml2() > 1e-15)
{
// printf("y ");
// print_vector(y);
// printf("y2: ");
// print_vector(y2);
// printf("diff: ");
// print_vector(diff);
return 1;
}
// Test linearization here as well
// auto dFdu = dop.GetDerivativeWrt<0>({&f1_g}, {mesh_nodes});
// if (dFdu->Height() != h1fes.GetTrueVSize())
// {
// out << "dFdu unexpected height of " << dFdu->Height() << "\n";
// return 1;
// }
// dFdu->Mult(x, y);
// y.HostRead();
// a.Mult(x, y2);
// y2.HostRead();
// diff = y2;
// diff -= y;
// if (diff.Norml2() > 1e-10)
// {
// print_vector(diff);
// print_vector(y2);
// print_vector(y);
// return 1;
// }
// // fd jacobian test
// {
// double eps = 1.0e-6;
// Vector v(x), xpv(x), xmv(x), fxpv(x.Size()), fxmv(x.Size());
// v *= eps;
// xpv += v;
// xmv -= v;
// dop.Mult(xpv, fxpv);
// dop.Mult(xmv, fxmv);
// fxpv -= fxmv;
// fxpv /= (2.0*eps);
// fxpv -= y;
// if (fxpv.Norml2() > eps)
// {
// out << "||dFdu_FD u^* - ex||_l2 = " << fxpv.Norml2() << "\n";
// return 1;
// }
// }
// f1_g.ProjectCoefficient(f1_c);
// rho_g.ProjectCoefficient(rho_c);
// auto dFdrho = dop.GetDerivativeWrt<1>({&f1_g}, {&rho_g, mesh_nodes});
// if (dFdrho->Height() != h1fes.GetTrueVSize())
// {
// out << "dFdrho unexpected height of " << dFdrho->Height() << "\n";
// return 1;
// }
// dFdrho->Mult(rho_g, y);
// // fd test
// {
// double eps = 1.0e-6;
// Vector v(rho_g), rhopv(rho_g), rhomv(rho_g), frhopv(x.Size()),
// frhomv(x.Size()); v *= eps; rhopv += v; rhomv -= v;
// dop.SetParameters({&rhopv, mesh_nodes});
// dop.Mult(x, frhopv);
// dop.SetParameters({&rhomv, mesh_nodes});
// dop.Mult(x, frhomv);
// frhopv -= frhomv;
// frhopv /= (2.0*eps);
// frhopv -= y;
// if (frhopv.Norml2() > eps)
// {
// out << "||dFdu_FD u^* - ex||_l2 = " << frhopv.Norml2() << "\n";
// return 1;
// }
// }
return 0;
}
DFEM_TEST_MAIN(test_diffusion_3d);
@@ -1,309 +0,0 @@
#include "dfem/dfem_test_macro.hpp"
#include "examples/dfem/dfem_fieldoperator.hpp"
#include "examples/dfem/dfem_refactor.hpp"
#include "fem/bilininteg.hpp"
#include "general/tic_toc.hpp"
#include <utility>
using namespace mfem;
using mfem::internal::tensor;
using mfem::internal::dual;
int test_diffusion_3d(
std::string mesh_file, int refinements, int polynomial_order)
{
constexpr int num_samples = 100;
constexpr int dim = 3;
Mesh mesh_serial = Mesh(mesh_file);
MFEM_ASSERT(mesh_serial.Dimension() == dim, "incorrect mesh dimension");
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(polynomial_order);
mesh_serial.Clear();
out << "#el: " << mesh.GetNE() << "\n";
ParGridFunction* mesh_nodes = static_cast<ParGridFunction*>(mesh.GetNodes());
ParFiniteElementSpace& mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec);
out << "#dofs " << h1fes.GetTrueVSize() << "\n";
const IntegrationRule& ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(),
h1fes.GetFE(0)->GetOrder() + h1fes.GetFE(0)->GetOrder() + h1fes.GetFE(
0)->GetDim() - 1);
printf("#ndof per el = %d\n", h1fes.GetFE(0)->GetDof());
printf("#nqp = %d\n", ir.GetNPoints());
printf("#q1d = %d\n", (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5));
ParametricSpace qdata_space(dim, dim * dim, ir.GetNPoints(),
dim * dim * ir.GetNPoints() * mesh.GetNE());
ParametricFunction qdata(qdata_space);
ParGridFunction f1_g(&h1fes);
ParGridFunction rho_g(&h1fes);
auto f1 = [](const Vector& coords)
{
const double x = coords(0);
const double y = coords(1);
const double z = coords(2);
return 2.345 + x + x*y + 1.25 * z*x;
};
FunctionCoefficient f1_c(f1);
f1_g.ProjectCoefficient(f1_c);
Vector x(f1_g), y(h1fes.GetTrueVSize());
{
std::shared_ptr<DerivativeOperator> dpotential;
{
auto diffusion_mf_kernel =
[] MFEM_HOST_DEVICE (
const tensor<real_t, dim>& dudxi,
const tensor<real_t, dim, dim>& J,
const real_t& w)
{
auto invJ = inv(J);
return mfem::tuple{dudxi * invJ * transpose(invJ) * det(J) * w};
};
constexpr int Potential = 0;
constexpr int Coordinates = 1;
auto input_operators = mfem::tuple{Gradient<Potential>{}, Gradient<Coordinates>{}, Weight{}};
auto output_operator = mfem::tuple{Gradient<Potential>{}};
auto solutions = std::vector{FieldDescriptor{Potential, &h1fes}};
auto parameters = std::vector{FieldDescriptor{Coordinates, &mesh_fes}};
DifferentiableOperator dop(solutions, parameters, mesh);
auto derivatives = std::integer_sequence<size_t, Potential> {};
dop.AddDomainIntegrator(
diffusion_mf_kernel, input_operators, output_operator, ir, derivatives);
dop.SetParameters({mesh_nodes});
StopWatch sw;
sw.Start();
for (int i = 0; i < num_samples; i++)
{
dop.Mult(x, y);
}
sw.Stop();
printf("dfem mf: %fs\n", sw.RealTime() / num_samples);
y.HostRead();
dpotential = dop.GetDerivative(Potential, {&f1_g}, {mesh_nodes});
}
dpotential->Mult(x, y);
}
{
auto diffusion_setup_kernel =
[] MFEM_HOST_DEVICE (
const tensor<double, dim, dim>& J,
const double& w)
{
auto invJ = inv(J);
return mfem::tuple{invJ * transpose(invJ) * det(J) * w};
};
constexpr int Potential = 0;
constexpr int Coordinates = 1;
constexpr int QData = 2;
auto input_operators = mfem::tuple{Gradient<Coordinates>{}, Weight{}};
auto output_operator = mfem::tuple{None<QData>{}};
auto solutions = std::vector{FieldDescriptor{Potential, &h1fes}};
auto parameters = std::vector{FieldDescriptor{Coordinates, &mesh_fes},
FieldDescriptor{QData, &qdata_space}};
DifferentiableOperator dop(solutions, parameters, mesh);
dop.AddDomainIntegrator(
diffusion_setup_kernel, input_operators, output_operator, ir);
dop.SetParameters({mesh_nodes, &qdata});
StopWatch sw;
sw.Start();
for (int i = 0; i < num_samples; i++)
{
dop.Mult(x, qdata);
}
sw.Stop();
printf("dfem pa setup: %fs\n", sw.RealTime() / num_samples);
qdata.HostRead();
}
// printf("qdata: ");
// print_vector(qdata);
{
auto diffusion_apply_kernel =
[] MFEM_HOST_DEVICE (
const tensor<real_t, dim>& dudxi,
const tensor<double, dim, dim>& qdata)
{
return mfem::tuple{dudxi * qdata};
};
constexpr int Potential = 0;
constexpr int QData = 1;
auto input_operators = mfem::tuple{Gradient<Potential>{}, None<QData>{}};
auto output_operator = mfem::tuple{Gradient<Potential>{}};
auto solutions = std::vector{FieldDescriptor{Potential, &h1fes}};
auto parameters = std::vector{FieldDescriptor{QData, &qdata_space}};
DifferentiableOperator dop(solutions, parameters, mesh);
dop.AddDomainIntegrator(
diffusion_apply_kernel, input_operators, output_operator, ir);
dop.SetParameters({&qdata});
StopWatch sw;
sw.Start();
for (int i = 0; i < num_samples; i++)
{
dop.Mult(x, y);
}
sw.Stop();
printf("dfem pa apply: %fs\n", sw.RealTime() / num_samples);
y.HostRead();
}
// printf("y: ");
// print_vector(y);
Vector y2(h1fes.TrueVSize());
{
ParBilinearForm a(&h1fes);
auto diff_integ = new DiffusionIntegrator;
diff_integ->SetIntRule(&ir);
a.AddDomainIntegrator(diff_integ);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
OperatorPtr A;
StopWatch sw;
sw.Start();
a.Assemble();
a.Finalize();
Array<int> empty;
a.FormSystemMatrix(empty, A);
sw.Stop();
printf("mfem pa setup: %fs\n", sw.RealTime());
sw.Clear();
sw.Start();
y2 = 0.0;
for (int i = 0; i < num_samples; i++)
{
A->Mult(x, y2);
}
sw.Stop();
printf("mfem pa apply: %fs\n", sw.RealTime() / num_samples);
y2.HostRead();
}
// printf("y2: ");
// print_vector(y2);
Vector diff(y2);
diff -= y;
if (diff.Norml2() > 1e-15)
{
printf("y: ");
print_vector(y);
printf("y2: ");
print_vector(y2);
printf("diff: ");
print_vector(diff);
return 1;
}
// Test linearization here as well
// auto dFdu = dop.GetDerivativeWrt<0>({&f1_g}, {mesh_nodes});
// if (dFdu->Height() != h1fes.GetTrueVSize())
// {
// out << "dFdu unexpected height of " << dFdu->Height() << "\n";
// return 1;
// }
// dFdu->Mult(x, y);
// y.HostRead();
// a.Mult(x, y2);
// y2.HostRead();
// diff = y2;
// diff -= y;
// if (diff.Norml2() > 1e-10)
// {
// print_vector(diff);
// print_vector(y2);
// print_vector(y);
// return 1;
// }
// // fd jacobian test
// {
// double eps = 1.0e-6;
// Vector v(x), xpv(x), xmv(x), fxpv(x.Size()), fxmv(x.Size());
// v *= eps;
// xpv += v;
// xmv -= v;
// dop.Mult(xpv, fxpv);
// dop.Mult(xmv, fxmv);
// fxpv -= fxmv;
// fxpv /= (2.0*eps);
// fxpv -= y;
// if (fxpv.Norml2() > eps)
// {
// out << "||dFdu_FD u^* - ex||_l2 = " << fxpv.Norml2() << "\n";
// return 1;
// }
// }
// f1_g.ProjectCoefficient(f1_c);
// rho_g.ProjectCoefficient(rho_c);
// auto dFdrho = dop.GetDerivativeWrt<1>({&f1_g}, {&rho_g, mesh_nodes});
// if (dFdrho->Height() != h1fes.GetTrueVSize())
// {
// out << "dFdrho unexpected height of " << dFdrho->Height() << "\n";
// return 1;
// }
// dFdrho->Mult(rho_g, y);
// // fd test
// {
// double eps = 1.0e-6;
// Vector v(rho_g), rhopv(rho_g), rhomv(rho_g), frhopv(x.Size()),
// frhomv(x.Size()); v *= eps; rhopv += v; rhomv -= v;
// dop.SetParameters({&rhopv, mesh_nodes});
// dop.Mult(x, frhopv);
// dop.SetParameters({&rhomv, mesh_nodes});
// dop.Mult(x, frhomv);
// frhopv -= frhomv;
// frhopv /= (2.0*eps);
// frhopv -= y;
// if (frhopv.Norml2() > eps)
// {
// out << "||dFdu_FD u^* - ex||_l2 = " << frhopv.Norml2() << "\n";
// return 1;
// }
// }
return 0;
}
DFEM_TEST_MAIN(test_diffusion_3d);
-109
View File
@@ -1,109 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_elasticity(std::string mesh_file,
int refinements,
int polynomial_order)
{
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
const int dim = mesh.Dimension();
const int vdim = dim;
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, vdim);
Array<int> ess_bdr(mesh.bdr_attributes.Max());
Array<int> ess_tdof;
ess_bdr = 1;
h1fes.GetEssentialTrueDofs(ess_bdr, ess_tdof);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 6 * h1fec.GetOrder());
out << "#qp: " << ir.GetNPoints() << "\n";
out << "#dof_el: " << h1fes.GetRestrictionMatrix()->Height() / mesh.GetNE() <<
"\n";
ParGridFunction u(&h1fes);
auto f1 = [](const Vector& coords, Vector &u)
{
const double x = coords(0);
const double y = coords(1);
u(0) = 2.345 + 0.25 * x * x * y + y * y * x;
u(1) = 2.345 - 0.25 * x * y * y + y * x * x;
};
VectorFunctionCoefficient u_c(dim, f1);
u.ProjectCoefficient(u_c);
ConstantCoefficient l_coeff(0.5), m_coeff(0.25);
ParBilinearForm A_form(&h1fes);
auto A_integ = new ElasticityIntegrator(l_coeff, m_coeff);
A_integ->SetIntegrationRule(ir);
A_form.AddDomainIntegrator(A_integ);
A_form.Assemble();
A_form.Finalize();
auto elasticity_kernel = [](const tensor<double, 2, 2> &dudxi,
const tensor<double, 2, 2> &J,
const double &w)
{
constexpr double lambda = 0.5;
constexpr double mu = 0.25;
static constexpr auto I = mfem::internal::IsotropicIdentity<2>();
auto invJ = inv(J);
auto eps = sym(dudxi * invJ);
return mfem::tuple{transpose(lambda * tr(eps) * I + 2.0 * mu * eps) * det(J) * w * transpose(invJ)};
};
mfem::tuple argument_operators{Gradient{"displacement"}, Gradient{"coordinates"}, Weight{}};
mfem::tuple output_operator{Gradient{"displacement"}};
ElementOperator op{elasticity_kernel, argument_operators, output_operator};
std::array solutions{FieldDescriptor{&h1fes, "displacement"}};
std::array parameters{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop{solutions, parameters, mfem::tuple{op}, mesh, ir};
Vector x(u), y1(h1fes.GetTrueVSize()),
y2(h1fes.GetTrueVSize());
dop.SetParameters({mesh_nodes});
dop.Mult(x, y1);
y1.HostRead();
A_form.Mult(x, y2);
y2.HostRead();
Vector diff(y2);
diff -= y1;
if (diff.Norml2() > 1e-10)
{
out << "||F(u) - ex||_l2 = " << diff.Norml2() << "\n";
print_vector(diff);
print_vector(y1);
print_vector(y2);
return 1;
}
return 0;
}
DFEM_TEST_MAIN(test_elasticity);
@@ -1,115 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
#include "examples/dfem/dfem_parametricspace.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_interpolate_gradient_linear_scalar_3d(std::string mesh_file,
int refinements,
int polynomial_order)
{
constexpr int dim = 3;
Mesh mesh_serial = Mesh(mesh_file);
MFEM_ASSERT(mesh_serial.Dimension() == dim, "wrong mesh dimension");
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
mesh_serial.Clear();
ParGridFunction *mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec);
// const IntegrationRule &ir =
// IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() + 1);
IntegrationRules gll_rules(0, Quadrature1D::GaussLobatto);
const IntegrationRule &ir = gll_rules.Get(h1fes.GetFE(0)->GetGeomType(),
2 * polynomial_order - 1);
ParGridFunction f1_g(&h1fes);
ParametricSpace pspace(dim, dim, ir.GetNPoints(),
dim * ir.GetNPoints() * mesh.GetNE());
ParametricFunction qdata(pspace);
auto kernel = [](const tensor<double, dim> &dudxi,
const tensor<double, dim, dim> &J)
{
return mfem::tuple{dudxi * inv(J)};
};
mfem::tuple argument_operators = {Gradient{"potential"}, Gradient{"coordinates"}};
mfem::tuple output_operator = {None{"qdata"}};
ElementOperator eop = {kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array
{
FieldDescriptor{&mesh_fes, "coordinates"},
FieldDescriptor{&pspace, "qdata"}
};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto f1 = [](const Vector &coords)
{
const double x = coords(0);
const double y = coords(1);
const double z = coords(2);
return 2.345 + x * y * z + y * z;
};
FunctionCoefficient f1_c(f1);
f1_g.ProjectCoefficient(f1_c);
Vector x(*f1_g.GetTrueDofs()), y(h1fes.TrueVSize() * dim);
dop.SetParameters({mesh_nodes, &qdata});
dop.Mult(x, y);
Vector f_test(h1fes.GetElementRestriction(
ElementDofOrdering::LEXICOGRAPHIC)->Height() * dim);
for (int e = 0; e < mesh.GetNE(); e++)
{
ElementTransformation *T = mesh.GetElementTransformation(e);
for (int qp = 0; qp < ir.GetNPoints(); qp++)
{
const IntegrationPoint &ip = ir.IntPoint(qp);
T->SetIntPoint(&ip);
Vector g(dim);
f1_g.GetGradient(*T, g);
// printf("(%f, %f, %f): (%f, %f, %f)\n", ip.x, ip.y, ip.z, g(0), g(1), g(2));
for (int d = 0; d < dim; d++)
{
int qpo = qp * dim;
int eo = e * (ir.GetNPoints() * dim);
f_test(d + qpo + eo) = g(d);
}
}
}
Vector diff(f_test);
diff -= y;
if (diff.Norml2() > 1e-10)
{
print_vector(diff);
print_vector(f_test);
print_vector(y);
return 1;
}
return 0;
}
DFEM_TEST_MAIN(test_interpolate_gradient_linear_scalar_3d);
@@ -1,91 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_interpolate_linear_scalar(std::string mesh_file,
int refinements,
int polynomial_order)
{
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
const int dim = mesh.Dimension();
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() + 1);
ParGridFunction f1_g(&h1fes);
auto kernel = [](const double &u, const tensor<double, 2, 2> &J,
const double &w)
{
return mfem::tuple{u};
};
mfem::tuple argument_operators = {Value{"potential"}, Gradient{"coordinates"}, Weight{}};
mfem::tuple output_operator = {None{"potential"}};
ElementOperator eop = {kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto f1 = [](const Vector &coords)
{
const double x = coords(0);
const double y = coords(1);
return 2.345 + x + y;
};
FunctionCoefficient f1_c(f1);
f1_g.ProjectCoefficient(f1_c);
Vector x(*f1_g.GetTrueDofs()), y(h1fes.TrueVSize());
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
Vector f_test(h1fes.GetElementRestriction(
ElementDofOrdering::LEXICOGRAPHIC)->Height());
for (int e = 0; e < mesh.GetNE(); e++)
{
ElementTransformation *T = mesh.GetElementTransformation(e);
for (int qp = 0; qp < ir.GetNPoints(); qp++)
{
const IntegrationPoint &ip = ir.IntPoint(qp);
T->SetIntPoint(&ip);
f_test((e * ir.GetNPoints()) + qp) = f1_c.Eval(*T, ip);
}
}
Vector diff(f_test);
diff -= y;
if (diff.Norml2() > 1e-10)
{
print_vector(diff);
print_vector(f_test);
print_vector(y);
return 1;
}
return 0;
}
DFEM_TEST_MAIN(test_interpolate_linear_scalar);
@@ -1,93 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_interpolate_linear_scalar_3d(std::string mesh_file,
int refinements,
int polynomial_order)
{
constexpr int dim = 3;
Mesh mesh_serial = Mesh(mesh_file);
MFEM_ASSERT(mesh_serial.Dimension() == dim, "wrong mesh dimension");
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
mesh_serial.Clear();
ParGridFunction *mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() + 1);
ParGridFunction f1_g(&h1fes);
auto kernel = [](const double &u)
{
return mfem::tuple{u};
};
mfem::tuple argument_operators = {Value{"potential"}};
mfem::tuple output_operator = {None{"potential"}};
ElementOperator eop = {kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto f1 = [](const Vector &coords)
{
const double x = coords(0);
const double y = coords(1);
const double z = coords(2);
return 2.345 + x + y + 1.25 * z;
};
FunctionCoefficient f1_c(f1);
f1_g.ProjectCoefficient(f1_c);
Vector x(*f1_g.GetTrueDofs()), y(h1fes.TrueVSize());
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
Vector f_test(h1fes.GetElementRestriction(
ElementDofOrdering::LEXICOGRAPHIC)->Height());
for (int e = 0; e < mesh.GetNE(); e++)
{
ElementTransformation *T = mesh.GetElementTransformation(e);
for (int qp = 0; qp < ir.GetNPoints(); qp++)
{
const IntegrationPoint &ip = ir.IntPoint(qp);
T->SetIntPoint(&ip);
f_test((e * ir.GetNPoints()) + qp) = f1_c.Eval(*T, ip);
}
}
Vector diff(f_test);
diff -= y;
if (diff.Norml2() > 1e-10)
{
print_vector(diff);
print_vector(f_test);
print_vector(y);
return 1;
}
return 0;
}
DFEM_TEST_MAIN(test_interpolate_linear_scalar_3d);
@@ -1,100 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_interpolate_linear_vector(std::string mesh_file, int refinements,
int polynomial_order)
{
constexpr int vdim = 2;
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
const int dim = mesh.Dimension();
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, vdim);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() + 1);
QuadratureSpace qspace(mesh, ir);
QuadratureFunction qf(&qspace, vdim);
ParGridFunction f1_g(&h1fes);
auto kernel = [](const tensor<double, 2> &u)
{
return mfem::tuple{u};
};
mfem::tuple argument_operators = {Value{"potential"}};
mfem::tuple output_operator = {None{"potential"}};
ElementOperator eop{kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto f1 = [](const Vector &coords, Vector &u)
{
const double x = coords(0);
const double y = coords(1);
u(0) = 2.345 + x + y;
u(1) = 12.345 + x + y;
};
VectorFunctionCoefficient f1_c(vdim, f1);
f1_g.ProjectCoefficient(f1_c);
Vector x(f1_g), y(f1_g.Size());
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
Vector f_test(qf.Size());
for (int e = 0; e < mesh.GetNE(); e++)
{
ElementTransformation *T = mesh.GetElementTransformation(e);
for (int qp = 0; qp < ir.GetNPoints(); qp++)
{
const IntegrationPoint &ip = ir.IntPoint(qp);
T->SetIntPoint(&ip);
Vector f(vdim);
f1_g.GetVectorValue(*T, ip, f);
for (int d = 0; d < vdim; d++)
{
int qpo = qp * vdim;
int eo = e * (ir.GetNPoints() * vdim);
f_test(d + qpo + eo) = f(d);
}
}
}
Vector diff(f_test);
diff -= y;
if (diff.Norml2() > 1e-10)
{
print_vector(diff);
print_vector(f_test);
print_vector(y);
return 1;
}
return 0;
}
DFEM_TEST_MAIN(test_interpolate_linear_vector);
@@ -1,105 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_interpolate_linear_vector_3d(std::string mesh_file, int refinements,
int polynomial_order)
{
constexpr int dim = 3;
constexpr int vdim = 3;
Mesh mesh_serial = Mesh(mesh_file);
MFEM_ASSERT(mesh_serial.Dimension() == dim, "wrong mesh dimension");
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, vdim);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() + 1);
QuadratureSpace qspace(mesh, ir);
QuadratureFunction qf(&qspace, vdim);
ParGridFunction f1_g(&h1fes);
auto kernel = [](const tensor<double, vdim> &u)
{
return mfem::tuple{u};
};
mfem::tuple argument_operators = {Value{"potential"}};
mfem::tuple output_operator = {None{"potential"}};
ElementOperator eop{kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto f1 = [](const Vector &coords, Vector &u)
{
const double x = coords(0);
const double y = coords(1);
const double z = coords(2);
u(0) = 2.345 + x + y + 3.0 * z;
u(1) = 12.345 + x + y + 2.0 * z;
u(2) = 5.345 + x + y + 1.0 * z;
};
VectorFunctionCoefficient f1_c(vdim, f1);
f1_g.ProjectCoefficient(f1_c);
Vector x(f1_g), y(f1_g.Size());
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
Vector f_test(qf.Size());
for (int e = 0; e < mesh.GetNE(); e++)
{
ElementTransformation *T = mesh.GetElementTransformation(e);
for (int qp = 0; qp < ir.GetNPoints(); qp++)
{
const IntegrationPoint &ip = ir.IntPoint(qp);
T->SetIntPoint(&ip);
Vector f(vdim);
f1_g.GetVectorValue(*T, ip, f);
for (int d = 0; d < vdim; d++)
{
int qpo = qp * vdim;
int eo = e * (ir.GetNPoints() * vdim);
f_test(d + qpo + eo) = f(d);
}
}
}
Vector diff(f_test);
diff -= y;
if (diff.Norml2() > 1e-10)
{
print_vector(diff);
print_vector(f_test);
print_vector(y);
return 1;
}
return 0;
}
DFEM_TEST_MAIN(test_interpolate_linear_vector_3d);
-113
View File
@@ -1,113 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
#include "fem/bilininteg.hpp"
#include "fem/normal_deriv_restriction.hpp"
#include <fstream>
using namespace mfem;
using mfem::internal::tensor;
int dfem_test_mass_scalar_2d(std::string mesh_file,
int refinements,
int polynomial_order)
{
constexpr int dim = 2;
Mesh mesh_serial = Mesh(mesh_file);
MFEM_ASSERT(mesh_serial.Dimension() == dim, "wrong mesh dimension");
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
mesh_serial.Clear();
ParGridFunction *mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() + 1);
// IntegrationRules gll_rules(0, Quadrature1D::GaussLobatto);
// const IntegrationRule &ir = gll_rules.Get(h1fes.GetFE(0)->GetGeomType(),
// 2 * polynomial_order - 1);
printf("#nqp = %d\n", ir.GetNPoints());
printf("#q1d = %d\n", (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5));
ParGridFunction f1_g(&h1fes);
auto kernel = [](const double& u,
const tensor<double, dim> x,
const tensor<double, dim, dim> J,
const double& w)
{
out << x << ": " << u << "\n";
return mfem::tuple{u * w * det(J)};
};
mfem::tuple argument_operators = {Value{"potential"}, Value{"coordinates"}, Gradient{"coordinates"}, Weight{}};
mfem::tuple output_operator = {Value{"potential"}};
ElementOperator eop = {kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto f1 = [](const Vector &coords)
{
const double x = coords(0);
const double y = coords(1);
return 2.345 + x + x*y + 1.25 * x;
};
FunctionCoefficient f1_c(f1);
f1_g.ProjectCoefficient(f1_c);
Vector f1_g_e(f1_g.Size());
auto R = h1fes.GetElementRestriction(ElementDofOrdering::LEXICOGRAPHIC);
// R->Mult(f1_g, f1_g_e);
auto r_out = std::ofstream("r_mat.mtx");
R->PrintMatlab(r_out);
r_out.close();
print_vector(f1_g);
// print_vector(f1_g_e);
Vector x(*f1_g.GetTrueDofs()), y(h1fes.TrueVSize());
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
ParBilinearForm a(&h1fes);
auto mass_integ = new MassIntegrator;
mass_integ->SetIntRule(&ir);
a.AddDomainIntegrator(mass_integ);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a.Assemble();
a.Finalize();
Vector y2(h1fes.TrueVSize());
a.Mult(x, y2);
y2.HostRead();
Vector diff(y2);
diff -= y;
if (diff.Norml2() > 1e-10)
{
print_vector(diff);
print_vector(y2);
print_vector(y);
return 1;
}
return 0;
}
DFEM_TEST_MAIN(dfem_test_mass_scalar_2d);
-147
View File
@@ -1,147 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
#include "fem/bilininteg.hpp"
#include "fem/fe/fe_base.hpp"
using namespace mfem;
using mfem::internal::tensor;
int dfem_test_mass_scalar_3d(std::string mesh_file,
int refinements,
int polynomial_order)
{
constexpr int dim = 3;
Mesh mesh_serial = Mesh(mesh_file);
MFEM_ASSERT(mesh_serial.Dimension() == dim, "wrong mesh dimension");
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(polynomial_order);
mesh_serial.Clear();
ParGridFunction *mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec);
const IntegrationRule& ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(),
h1fes.GetFE(0)->GetOrder() + h1fes.GetFE(0)->GetOrder() + h1fes.GetFE(
0)->GetDim() - 1);
// IntegrationRules gll_rules(0, Quadrature1D::GaussLobatto);
// const IntegrationRule &ir = gll_rules.Get(h1fes.GetFE(0)->GetGeomType(),
// 2 * polynomial_order - 1);
auto dtq = h1fes.GetFE(0)->GetDofToQuad(ir, DofToQuad::TENSOR);
// printf("\n B: ");
// dtq.B.Print(out, dtq.B.Size());
// printf("\n G: ");
// dtq.G.Print(out, dtq.G.Size());
// printf("\n w: ");
// ir.GetWeights().Print(out, ir.GetWeights().Size());
// printf("#ndof per el = %d\n", h1fes.GetFE(0)->GetDof());
// printf("#nqp = %d\n", ir.GetNPoints());
// printf("#q1d = %d\n", (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5));
// printf("nodes: ");
// print_vector(*mesh_nodes);
ParGridFunction f1_g(&h1fes);
auto kernel = [](const double &u,
const tensor<double, dim, dim> &J,
const double &w)
{
return mfem::tuple{u * det(J) * w};
};
mfem::tuple argument_operators = {Value{"potential"}, Gradient{"coordinates"}, Weight{}};
mfem::tuple output_operator = {Value{"potential"}};
ElementOperator eop = {kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto f1 = [](const Vector &coords)
{
const double x = coords(0);
const double y = coords(1);
const double z = coords(2);
return 2.345 + x + x*y + 1.25 * z*x;
};
FunctionCoefficient f1_c(f1);
f1_g.ProjectCoefficient(f1_c);
// printf("\nf1_g: ");
// print_vector(f1_g);
auto R = h1fes.GetElementRestriction(ElementDofOrdering::LEXICOGRAPHIC);
// Vector f1_g_e(R->Height());
// R->Mult(f1_g, f1_g_e);
// printf("\nf1_g_e: ");
// print_vector(f1_g_e);
// auto r_out = std::ofstream("r_mat.mtx");
// R->PrintMatlab(r_out);
// r_out.close();
Vector x(*f1_g.GetTrueDofs()), y(h1fes.TrueVSize());
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
ParBilinearForm a(&h1fes);
auto mass_integ = new MassIntegrator;
mass_integ->SetIntRule(&ir);
a.AddDomainIntegrator(mass_integ);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a.Assemble();
a.Finalize();
Vector y2(h1fes.TrueVSize());
a.Mult(x, y2);
y2.HostRead();
Vector diff(y2);
diff -= y;
if (diff.Norml2() > 1e-15)
{
printf("y ");
print_vector(y);
printf("y2: ");
print_vector(y2);
printf("diff: ");
print_vector(diff);
return 1;
}
Vector y3(h1fes.TrueVSize());
auto dFdu = dop.GetDerivativeWrt<0>({&f1_g}, {mesh_nodes});
dFdu->Mult(x, y3);
diff = y2;
diff -= y;
if (diff.Norml2() > 1e-15)
{
printf("y2 ");
print_vector(y2);
printf("y3: ");
print_vector(y3);
printf("diff: ");
print_vector(diff);
return 1;
}
return 0;
}
DFEM_TEST_MAIN(dfem_test_mass_scalar_3d);
@@ -1,114 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_neo_hookean_elasticity_2d(
std::string mesh_file, int refinements, int polynomial_order)
{
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
const int dim = mesh.Dimension();
MFEM_ASSERT(dim == 2, "This test is for 2D meshes only");
mesh_serial.Clear();
out << "#el: " << mesh.GetNE() << "\n";
ParGridFunction* mesh_nodes = static_cast<ParGridFunction*>(mesh.GetNodes());
ParFiniteElementSpace& mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, dim);
out << "#dofs " << h1fes.GetTrueVSize() << "\n";
const IntegrationRule& ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder());
out << "#qp: " << ir.GetNPoints() << "\n";
ParGridFunction u_g(&h1fes);
auto kernel = [] MFEM_HOST_DEVICE(const tensor<double, 2, 2>& J,
const double& w,
const tensor<double, 2, 2>& dudxi)
{
// Neo-Hookean parameters
const double lambda = 1.0;
const double mu = 0.5;
static constexpr auto I = mfem::internal::IsotropicIdentity<2>();
auto F = I + (dudxi * inv(J));
auto E = 0.5 * (transpose(F) * F - I);
auto invF = inv(F);
// 2D plane strain formulation
auto P = mu * (F - transpose(invF)) + lambda * log(det(F)) * transpose(invF);
return mfem::tuple{P * det(J) * w};
};
mfem::tuple argument_operators = {Gradient{"coordinates"}, Weight{},
Gradient{"displacement"}
};
mfem::tuple output_operator = {Gradient{"displacement"}};
ElementOperator eop = {kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "displacement"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto displacement = [](const Vector& coords, Vector &u)
{
const double x = coords(0);
const double y = coords(1);
u(0) = 0.1 * x * y;
u(1) = 0.1 * y * x;
};
VectorFunctionCoefficient disp_coeff(2, displacement);
u_g.ProjectCoefficient(disp_coeff);
Vector x(u_g), y(h1fes.TrueVSize());
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
y.HostRead();
// Test linearization
auto dFdu = dop.GetDerivativeWrt<0>({&u_g}, {mesh_nodes});
dFdu->Mult(x, y);
// Finite difference Jacobian test
{
double eps = 1.0e-6;
Vector v(x), xpv(x), xmv(x), fxpv(x.Size()), fxmv(x.Size());
v *= eps;
xpv += v;
xmv -= v;
dop.Mult(xpv, fxpv);
dop.Mult(xmv, fxmv);
fxpv -= fxmv;
fxpv /= (2.0*eps);
fxpv -= y;
if (fxpv.Norml2() > eps)
{
out << "||dFdu_FD u^* - ex||_l2 = " << fxpv.Norml2() << "\n";
return 1;
}
}
return 0;
}
DFEM_TEST_MAIN(test_neo_hookean_elasticity_2d);
@@ -1,169 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_nonlinear_diffusion(
std::string mesh_file, int refinements, int polynomial_order)
{
constexpr int dim = 3;
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
mesh_serial.Clear();
out << "#el: " << mesh.GetNE() << "\n";
ParGridFunction* mesh_nodes = static_cast<ParGridFunction*>(mesh.GetNodes());
ParFiniteElementSpace& mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec);
out << "#dofs " << h1fes.GetTrueVSize() << "\n";
const IntegrationRule& ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(),
h1fes.GetFE(0)->GetOrder() + h1fes.GetFE(0)->GetOrder() + h1fes.GetFE(
0)->GetDim() - 1);
out << "#qp: " << ir.GetNPoints() << "\n";
ParGridFunction f1_g(&h1fes);
bool inactive_derivative = false;
auto kernel = [] MFEM_HOST_DEVICE(
const tensor<double, dim, dim>& J,
const double& w,
const tensor<double, dim>& dudxi,
const double& u)
{
auto invJ = inv(J);
return mfem::tuple{(u * u) * dudxi * invJ * transpose(invJ) * det(J) * w};
};
mfem::tuple argument_operators =
{
Gradient{"coordinates"},
Weight{},
Gradient{"potential"},
Value{"potential"}
};
mfem::tuple output_operator =
{
Gradient{"potential"}
};
ElementOperator eop = {kernel, argument_operators, output_operator};
auto ops = mfem::tuple{eop};
auto solutions = std::array
{
FieldDescriptor{&h1fes, "potential"}
};
auto parameters = std::array
{
FieldDescriptor{&mesh_fes, "coordinates"}
};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto f1 = [](const Vector& coords)
{
const double x = coords(0);
const double y = coords(1);
const double z = coords(2);
return 2.345 + 0.25 * x * x * y + y * y * x + z;
};
FunctionCoefficient f1_c(f1);
f1_g.ProjectCoefficient(f1_c);
Vector x(f1_g), y(h1fes.TrueVSize());
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
y.HostRead();
ParBilinearForm a(&h1fes);
GridFunctionCoefficient f1gc(&f1_g);
TransformedCoefficient tf_c(&f1gc, [](double f) { return f * f; });
a.AddDomainIntegrator(new DiffusionIntegrator(tf_c));
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a.Assemble();
a.Finalize();
Vector y2(h1fes.TrueVSize()), diff(h1fes.TrueVSize());
a.Mult(x, y2);
y2.HostRead();
diff = y2;
diff -= y;
if (diff.Norml2() > 1e-10)
{
out << "||F(u) - ex||_l2 = " << diff.Norml2() << "\n";
print_vector(diff);
print_vector(y);
print_vector(y2);
return 1;
}
// Test linearization here as well
auto dFdu = dop.GetDerivativeWrt<0>({&f1_g}, {mesh_nodes});
dFdu->Mult(x, y);
// fd jacobian test
{
double eps = 1.0e-6;
Vector v(x), xpv(x), xmv(x), fxpv(x.Size()), fxmv(x.Size());
v *= eps;
xpv += v;
xmv -= v;
dop.Mult(xpv, fxpv);
dop.Mult(xmv, fxmv);
fxpv -= fxmv;
fxpv /= (2.0*eps);
fxpv -= y;
if (fxpv.Norml2() > eps)
{
out << "||dFdu_FD u^* - ex||_l2 = " << fxpv.Norml2() << "\n";
return 1;
}
}
// ParBilinearForm da(&h1fes);
// TransformedCoefficient dtf_c(&f1gc, [](double f) { return 2.0 * f; });
// da.AddDomainIntegrator(new DiffusionIntegrator(dtf_c));
// da.SetAssemblyLevel(AssemblyLevel::PARTIAL);
// da.Assemble();
// da.Finalize();
// if (dFdu->Height() != h1fes.GetTrueVSize())
// {
// out << "dFdu unexpected height of " << dFdu->Height() << "\n";
// return 1;
// }
// dFdu->Mult(x, y);
// print_vector(y);
// da.Mult(x, y2);
// print_vector(y2);
// y2 -= y;
// out << "||dFdu x - A x||_l2 = " << y2.Norml2() << "\n";
// if (y2.Norml2() > 1e-10)
// {
// out << "||dFdu u^* - ex||_l2 = " << y2.Norml2() << "\n";
// }
return 0;
}
DFEM_TEST_MAIN(test_nonlinear_diffusion);
@@ -1,267 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
#include <fstream>
using namespace mfem;
using mfem::internal::tensor;
using mfem::internal::dual;
class FDJacobian : public Operator
{
public:
FDJacobian(const Operator &op, const Vector &x) :
Operator(op.Height()),
op(op),
x(x)
{
f.SetSize(Height());
xpev.SetSize(Height());
op.Mult(x, f);
xnorm = x.Norml2();
}
void Mult(const Vector &v, Vector &y) const override
{
x.HostRead();
// See [1] for choice of eps.
//
// [1] Woodward, C.S., Gardner, D.J. and Evans, K.J., 2015. On the use of
// finite difference matrix-vector products in Newton-Krylov solvers for
// implicit climate dynamics with spectral elements. Procedia Computer
// Science, 51, pp.2036-2045.
real_t eps = lambda * (lambda + xnorm / v.Norml2());
for (int i = 0; i < x.Size(); i++)
{
xpev(i) = x(i) + eps * v(i);
}
// y = f(x + eps * v)
op.Mult(xpev, y);
// y = (f(x + eps * v) - f(x)) / eps
for (int i = 0; i < x.Size(); i++)
{
y(i) = (y(i) - f(i)) / eps;
}
}
virtual MemoryClass GetMemoryClass() const override
{
return Device::GetDeviceMemoryClass();
}
private:
const Operator &op;
Vector x, f;
mutable Vector xpev;
real_t lambda = 1.0e-6;
real_t xnorm;
};
template <typename elasticity_t>
class ElasticityOperator : public Operator
{
template <typename elasticity_du_t>
class ElasticityJacobianOperator : public Operator
{
public:
ElasticityJacobianOperator(const ElasticityOperator *elasticity,
std::shared_ptr<elasticity_du_t> dRdu) :
Operator(elasticity->Height()),
elasticity(elasticity),
dRdu(dRdu),
x_ess(dRdu->Height())
{
}
void Mult(const Vector &x, Vector &y) const override
{
x_ess = x;
x_ess.SetSubVector(elasticity->ess_tdofs, 0.0);
dRdu->Mult(x_ess, y);
for (int i = 0; i < elasticity->ess_tdofs.Size(); i++)
{
y[elasticity->ess_tdofs[i]] = x[elasticity->ess_tdofs[i]];
}
}
const ElasticityOperator *elasticity = nullptr;
std::shared_ptr<elasticity_du_t> dRdu;
mutable Vector x_ess;
};
public:
ElasticityOperator(ParFiniteElementSpace &fes, elasticity_t &elasticity,
Array<int> &ess_tdofs) :
Operator(fes.GetTrueVSize()),
fes(fes),
elasticity(elasticity),
ess_tdofs(ess_tdofs) {}
void Mult(const Vector &x, Vector &r) const override
{
elasticity.Mult(x, r);
r.SetSubVector(ess_tdofs, 0.0);
}
Operator &GetGradient(const Vector &x) const override
{
ParGridFunction u(const_cast<ParFiniteElementSpace *>
(*std::get_if<const ParFiniteElementSpace *>
(&elasticity.solutions[0].data)));
u.SetFromTrueDofs(x);
auto dRdu = elasticity.template GetDerivativeWrt<0>({&u}, {mesh_nodes});
jacobian.reset(
new ElasticityJacobianOperator<
typename std::remove_pointer<decltype(dRdu.get())>::type> (this, dRdu));
// jacobian.reset(new FDJacobian(*this, x));
return *jacobian;
}
void SetParameters(ParGridFunction &mesh_nodes)
{
elasticity.SetParameters({&mesh_nodes});
this->mesh_nodes = &mesh_nodes;
}
ParFiniteElementSpace &fes;
elasticity_t &elasticity;
Array<int> ess_tdofs;
mutable ParGridFunction *mesh_nodes = nullptr;
mutable std::shared_ptr<Operator> jacobian;
};
int test_nonlinear_elasticity_3d(std::string mesh_file,
int refinements,
int polynomial_order)
{
constexpr int dim = 3;
constexpr int vdim = dim;
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(polynomial_order);
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, vdim);
Array<int> ess_tdof_list, ess_bdr(mesh.bdr_attributes.Max());
ess_bdr = 0;
ess_bdr[0] = 1;
h1fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
const IntegrationRule& ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(),
h1fes.GetFE(0)->GetOrder() + h1fes.GetFE(0)->GetOrder() + h1fes.GetFE(
0)->GetDim() - 1);
out << "#qp: " << ir.GetNPoints() << "\n";
out << "#dof: " << h1fes.GetNDofs() << "\n";
ParGridFunction u(&h1fes);
auto elasticity_kernel = [] MFEM_HOST_DEVICE
(const tensor<dual<real_t, real_t>, dim, dim> &dudxi,
const tensor<real_t, dim, dim> &J,
const real_t &w)
{
// shear modulus
real_t D1{0.1e6};
// bulk modulus
real_t C1{1.0e6};
constexpr auto I = mfem::internal::IsotropicIdentity<dim>();
auto invJ = inv(J);
auto dudx = dudxi * invJ;
auto F = det(I + dudx);
auto p = -2.0 * D1 * F * (F - 1);
auto devB = dev(dudx + transpose(dudx) + dot(dudx, transpose(dudx)));
auto sigma = -(p / F) * I + 2.0 * (C1 / pow(F, 5.0 / 3.0)) * devB;
return mfem::tuple{sigma * det(J) * w * transpose(invJ)};
};
mfem::tuple argument_operators{Gradient{"displacement"}, Gradient{"coordinates"}, Weight{}};
mfem::tuple output_operator{Gradient{"displacement"}};
// B^T D(B0*dudxi, B1*J, B2*w)
ElementOperator op(elasticity_kernel, argument_operators, output_operator, ir);
std::array solutions{FieldDescriptor{&h1fes, "displacement"}};
std::array parameters{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, mfem::tuple{op}, mesh,
AutoDiff::NativeDualNumber{});
ElasticityOperator elasticity(h1fes, dop, ess_tdof_list);
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) = -1.0e-2;
f.Set(dim-1, new PWConstCoefficient(pull_force));
}
ParLinearForm b(&h1fes);
b.AddBoundaryIntegrator(new VectorBoundaryLFIntegrator(f));
b.UseFastAssembly(true);
b.Assemble();
auto B = b.ParallelAssemble();
Vector X = u.GetTrueVector();
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-8);
cg.SetMaxIter(1000);
cg.SetPrintLevel(IterativeSolver::PrintLevel().Summary());
NewtonSolver newton(MPI_COMM_WORLD);
newton.SetSolver(cg);
newton.SetOperator(elasticity);
newton.SetRelTol(1e-6);
newton.SetMaxIter(100);
// newton.SetAdaptiveLinRtol();
newton.SetPrintLevel(IterativeSolver::PrintLevel().Iterations());
elasticity.SetParameters(*mesh_nodes);
// Vector zero;
newton.Mult(*B, X);
u.SetFromTrueDofs(X);
ParaViewDataCollection paraview_dc("dfem", &mesh);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(polynomial_order);
paraview_dc.SetDataFormat(VTKFormat::BINARY);
paraview_dc.SetHighOrderOutput(true);
paraview_dc.SetCycle(0);
paraview_dc.SetTime(0.0);
paraview_dc.RegisterField("displacement", &u);
paraview_dc.Save();
return 0;
}
DFEM_TEST_MAIN(test_nonlinear_elasticity_3d);
-82
View File
@@ -1,82 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
#include "fem/coefficient.hpp"
#include "fem/pgridfunc.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_ordering(std::string mesh_file,
int refinements,
int polynomial_order)
{
constexpr int dim = 2;
constexpr int vdim = dim;
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(polynomial_order);
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
const IntegrationRule &ir =
IntRules.Get(mesh_fes.GetFE(0)->GetGeomType(),
2 * mesh_fes.FEColl()->GetOrder() - 1);
for (int q = 0; q < ir.GetNPoints(); q++)
{
out << "(" << ir.IntPoint(q).x << ", " << ir.IntPoint(q).y << ")\n";
}
ParGridFunction u(&mesh_fes);
auto f = [](const Vector &coords, Vector &u)
{
const double x = coords(0);
const double y = coords(1);
u(0) = x*x*y + 1.0;
u(1) = y*y*x*x + 2.0;
};
VectorFunctionCoefficient uc(dim, f);
u.ProjectCoefficient(uc);
auto kernel = [](const tensor<double, dim> &xi,
const tensor<double, vdim, dim> &J,
const tensor<double, dim> &u,
const tensor<double, vdim, dim> &dudxi)
{
out << "xi: " << xi << "\n";
out << "J: " << J << "\n";
out << "u: " << u << "\n";
out << "dudxi: " << dudxi << "\n\n";
return mfem::tuple{J};
};
mfem::tuple argument_operators{Value{"coordinates"}, Gradient{"coordinates"}, Value{"potential"}, Gradient{"potential"}};
mfem::tuple output_operator{Gradient{"potential"}};
ElementOperator op{kernel, argument_operators, output_operator};
std::array solutions{FieldDescriptor{&mesh_fes, "potential"}};
std::array parameters{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop{solutions, parameters, mfem::tuple{op}, mesh, ir};
Vector y(u);
dop.SetParameters({mesh_nodes});
dop.Mult(u, y);
print_vector(y);
return 0;
}
DFEM_TEST_MAIN(test_ordering);
-102
View File
@@ -1,102 +0,0 @@
#include "dfem/dfem.hpp"
#include "dfem/dfem_test_macro.hpp"
using namespace mfem;
using mfem::internal::tensor;
int test_vector_diffusion(std::string mesh_file,
int refinements,
int polynomial_order)
{
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
const int dim = mesh.Dimension();
const int vdim = dim;
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, vdim);
Array<int> ess_bdr(mesh.bdr_attributes.Max());
Array<int> ess_tdof;
ess_bdr = 1;
h1fes.GetEssentialTrueDofs(ess_bdr, ess_tdof);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder() - 1);
ParGridFunction u(&h1fes);
auto f1 = [](const Vector& coords, Vector &u)
{
const double x = coords(0);
const double y = coords(1);
u(0) = 2.345 + 0.25 * x * x * y + y * y * x;
u(1) = 2.345 - 0.25 * x * y * y + y * x * x;
};
VectorFunctionCoefficient u_c(dim, f1);
u.ProjectCoefficient(u_c);
auto vector_diffusion_kernel = [](const tensor<double, 2> &xi,
const tensor<double, 2, 2> &dudxi,
const tensor<double, 2, 2> &J,
const double &w)
{
out << "xi: " << xi << "\n";
out << "dudxi: " << dudxi << "\n";
return mfem::tuple{dudxi * inv(J) * det(J) * w * transpose(inv(J))};
// return mfem::tuple{dudxi};
};
mfem::tuple argument_operators{Value{"coordinates"}, Gradient{"potential"}, Gradient{"coordinates"}, Weight{}};
mfem::tuple output_operator{Gradient{"potential"}};
ElementOperator op{vector_diffusion_kernel, argument_operators, output_operator};
std::array solutions{FieldDescriptor{&h1fes, "potential"}};
std::array parameters{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop{solutions, parameters, mfem::tuple{op}, mesh, ir};
Vector x(u), y1(h1fes.GetTrueVSize()),
y2(h1fes.GetTrueVSize());
ParBilinearForm A_form(&h1fes);
auto A_integ = new VectorDiffusionIntegrator(vdim);
A_integ->SetIntegrationRule(ir);
A_form.AddDomainIntegrator(A_integ);
A_form.Assemble();
A_form.Finalize();
dop.SetParameters({mesh_nodes});
dop.Mult(x, y1);
y1.HostRead();
A_form.Mult(x, y2);
y2.HostRead();
Vector diff(y2);
diff -= y1;
if (diff.Norml2() > 1e-10)
{
out << "||F(u) - ex||_l2 = " << diff.Norml2() << "\n";
print_vector(diff);
print_vector(y1);
print_vector(y2);
return 1;
}
return 0;
}
DFEM_TEST_MAIN(test_vector_diffusion);
-122
View File
@@ -1,122 +0,0 @@
#include <tuple>
#include <type_traits>
#include <iostream>
#include <enzyme/enzyme>
template <typename T>
constexpr auto get_type_name() -> std::string_view
{
#if defined(__clang__)
constexpr auto prefix = std::string_view {"[T = "};
constexpr auto suffix = "]";
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
#elif defined(__GNUC__)
constexpr auto prefix = std::string_view {"with T = "};
constexpr auto suffix = "; ";
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
#elif defined(_MSC_VER)
constexpr auto prefix = std::string_view {"get_type_name<"};
constexpr auto suffix = ">(void)";
constexpr auto function = std::string_view{__FUNCSIG__};
#else
#error Unsupported compiler
#endif
const auto start = function.find(prefix) + prefix.size();
const auto end = function.find(suffix);
const auto size = end - start;
return function.substr(start, size);
}
template <typename ... Ts>
constexpr auto decay_types(std::tuple<Ts...> const &)
-> std::tuple<std::remove_cv_t<std::remove_reference_t<Ts>>...>;
template <typename T>
using decay_tuple = decltype(decay_types(std::declval<T>()));
template <class F> struct FunctionSignature;
template <typename output_t, typename... input_ts>
struct FunctionSignature<output_t(input_ts...)>
{
using return_t = output_t;
using parameter_ts = std::tuple<input_ts...>;
};
template <class T> struct create_function_signature;
template <typename output_t, typename T, typename... input_ts>
struct create_function_signature<output_t (T::*)(input_ts...) const>
{
using type = FunctionSignature<output_t(input_ts...)>;
};
template <typename arg_ts, std::size_t... Is>
auto create_enzyme_args(arg_ts &args,
arg_ts &shadow_args,
std::index_sequence<Is...>)
{
// (std::cout << ... << std::get<Is>(shadow_args));
return std::tuple<enzyme::Duplicated<decltype(std::get<Is>(args))>...>
{
{ std::get<Is>(args), std::get<Is>(shadow_args) }...
};
}
template <typename kernel_t, typename arg_ts>
auto fwddiff_apply_enzyme(kernel_t kernel, arg_ts &&args, arg_ts &&shadow_args)
{
auto arg_indices =
std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<arg_ts>>> {};
auto enzyme_args = create_enzyme_args(args, shadow_args, arg_indices);
// using kf_return_t = typename create_function_signature<
// decltype(&kernel_t::operator())>::type::return_t;
std::cout << "\n";
std::cout << "args is " << get_type_name<decltype(args)>() << "\n\n";
std::cout << "enzyme_args type is " << get_type_name<decltype(enzyme_args)>() <<
"\n\n";
// std::cout << "return type is " << get_type_name<decltype(kf_return_t{})>() <<
// "\n\n";
std::cout << "args " << std::get<0>(args) << "\n";
std::cout << "shadow args " << std::get<0>(shadow_args) << "\n";
return std::apply([&](auto &&...args)
{
// std::cout << enzyme::autodiff<enzyme::Forward>(+kernel, args...) << "\n";
return enzyme::get<0>
(enzyme::autodiff<enzyme::Forward>(+kernel, args...));
},
enzyme_args);
}
int main()
{
auto func = [](const double &x, double &y)
{
std::cout << "func( x = " << x << " )\n";
return x*x;
};
using kf_param_ts = typename create_function_signature<
decltype(&decltype(func)::operator())>::type::parameter_ts;
using kf_output_t = typename create_function_signature<
decltype(&decltype(func)::operator())>::type::return_t;
auto kernel_args = decay_tuple<kf_param_ts> {};
auto kernel_shadow_args = decay_tuple<kf_param_ts> {};
std::get<0>(kernel_args) = 3;
std::get<0>(kernel_shadow_args) = 1;
auto dx = fwddiff_apply_enzyme(func, kernel_args, kernel_shadow_args);
std::cout << "dfdx = " << dx << "\n";
return 0;
}
+19 -45
View File
@@ -3,14 +3,14 @@
// Compile with: make ex10
//
// Sample runs:
// ex10 -m ../data/beam-quad.mesh -s 3 -r 2 -o 2 -dt 3
// ex10 -m ../data/beam-tri.mesh -s 3 -r 2 -o 2 -dt 3
// ex10 -m ../data/beam-hex.mesh -s 2 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-tet.mesh -s 2 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-wedge.mesh -s 2 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-quad.mesh -s 14 -r 2 -o 2 -dt 0.03 -vs 20
// ex10 -m ../data/beam-hex.mesh -s 14 -r 1 -o 2 -dt 0.05 -vs 20
// ex10 -m ../data/beam-quad-amr.mesh -s 3 -r 2 -o 2 -dt 3
// ex10 -m ../data/beam-quad.mesh -s 23 -r 2 -o 2 -dt 3
// ex10 -m ../data/beam-tri.mesh -s 23 -r 2 -o 2 -dt 3
// ex10 -m ../data/beam-hex.mesh -s 22 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-tet.mesh -s 22 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-wedge.mesh -s 22 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-quad.mesh -s 4 -r 2 -o 2 -dt 0.03 -vs 20
// ex10 -m ../data/beam-hex.mesh -s 4 -r 1 -o 2 -dt 0.05 -vs 20
// ex10 -m ../data/beam-quad-amr.mesh -s 23 -r 2 -o 2 -dt 3
//
// Description: This examples solves a time dependent nonlinear elasticity
// problem of the form dv/dt = H(x) + S v, dx/dt = v, where H is a
@@ -87,16 +87,16 @@ public:
real_t visc, real_t mu, real_t K);
/// Compute the right-hand side of the ODE system.
virtual void Mult(const Vector &vx, Vector &dvx_dt) const;
void Mult(const Vector &vx, Vector &dvx_dt) const override;
/** Solve the Backward-Euler equation: k = f(x + dt*k, t), for the unknown k.
This is the only requirement for high-order SDIRK implicit integration.*/
virtual void ImplicitSolve(const real_t dt, const Vector &x, Vector &k);
void ImplicitSolve(const real_t dt, const Vector &x, Vector &k) override;
real_t ElasticEnergy(const Vector &x) const;
real_t KineticEnergy(const Vector &v) const;
void GetElasticEnergyDensity(const GridFunction &x, GridFunction &w) const;
virtual ~HyperelasticOperator();
~HyperelasticOperator() override;
};
/** Nonlinear operator of the form:
@@ -120,12 +120,12 @@ public:
void SetParameters(real_t dt_, const Vector *v_, const Vector *x_);
/// Compute y = H(x + dt (v + dt k)) + M k + S (v + dt k).
virtual void Mult(const Vector &k, Vector &y) const;
void Mult(const Vector &k, Vector &y) const override;
/// Compute J = M + dt S + dt^2 grad_H(x + dt (v + dt k)).
virtual Operator &GetGradient(const Vector &k) const;
Operator &GetGradient(const Vector &k) const override;
virtual ~ReducedSystemOperator();
~ReducedSystemOperator() override;
};
@@ -141,8 +141,8 @@ private:
public:
ElasticEnergyCoefficient(HyperelasticModel &m, const GridFunction &x_)
: model(m), x(x_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
virtual ~ElasticEnergyCoefficient() { }
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
~ElasticEnergyCoefficient() override { }
};
void InitialDeformation(const Vector &x, Vector &y);
@@ -160,7 +160,7 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/beam-quad.mesh";
int ref_levels = 2;
int order = 2;
int ode_solver_type = 3;
int ode_solver_type = 23;
real_t t_final = 300.0;
real_t dt = 3.0;
real_t visc = 1e-2;
@@ -177,11 +177,7 @@ int main(int argc, char *argv[])
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"
" 11 - Forward Euler, 12 - RK2,\n\t"
" 13 - RK3 SSP, 14 - RK4."
" 22 - Implicit Midpoint Method,\n\t"
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
ODESolver::Types.c_str());
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -213,28 +209,7 @@ int main(int argc, char *argv[])
// 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;
}
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
@@ -371,7 +346,6 @@ int main(int argc, char *argv[])
}
// 10. Free the used memory.
delete ode_solver;
delete mesh;
return 0;
+19 -48
View File
@@ -3,14 +3,14 @@
// Compile with: make ex10p
//
// Sample runs:
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 3 -rs 2 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-tri.mesh -s 3 -rs 2 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 2 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-tet.mesh -s 2 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-wedge.mesh -s 2 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 14 -rs 2 -dt 0.03 -vs 20
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 14 -rs 1 -dt 0.05 -vs 20
// mpirun -np 4 ex10p -m ../data/beam-quad-amr.mesh -s 3 -rs 2 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 23 -rs 2 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-tri.mesh -s 23 -rs 2 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 22 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-tet.mesh -s 22 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-wedge.mesh -s 22 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 4 -rs 2 -dt 0.03 -vs 20
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 4 -rs 1 -dt 0.05 -vs 20
// mpirun -np 4 ex10p -m ../data/beam-quad-amr.mesh -s 23 -rs 2 -dt 3
//
// Description: This examples solves a time dependent nonlinear elasticity
// problem of the form dv/dt = H(x) + S v, dx/dt = v, where H is a
@@ -89,17 +89,17 @@ public:
real_t visc, real_t mu, real_t K);
/// Compute the right-hand side of the ODE system.
virtual void Mult(const Vector &vx, Vector &dvx_dt) const;
void Mult(const Vector &vx, Vector &dvx_dt) const override;
/** Solve the Backward-Euler equation: k = f(x + dt*k, t), for the unknown k.
This is the only requirement for high-order SDIRK implicit integration.*/
virtual void ImplicitSolve(const real_t dt, const Vector &x, Vector &k);
void ImplicitSolve(const real_t dt, const Vector &x, Vector &k) override;
real_t ElasticEnergy(const ParGridFunction &x) const;
real_t KineticEnergy(const ParGridFunction &v) const;
void GetElasticEnergyDensity(const ParGridFunction &x,
ParGridFunction &w) const;
virtual ~HyperelasticOperator();
~HyperelasticOperator() override;
};
/** Nonlinear operator of the form:
@@ -125,12 +125,12 @@ public:
void SetParameters(real_t dt_, const Vector *v_, const Vector *x_);
/// Compute y = H(x + dt (v + dt k)) + M k + S (v + dt k).
virtual void Mult(const Vector &k, Vector &y) const;
void Mult(const Vector &k, Vector &y) const override;
/// Compute J = M + dt S + dt^2 grad_H(x + dt (v + dt k)).
virtual Operator &GetGradient(const Vector &k) const;
Operator &GetGradient(const Vector &k) const override;
virtual ~ReducedSystemOperator();
~ReducedSystemOperator() override;
};
@@ -146,8 +146,8 @@ private:
public:
ElasticEnergyCoefficient(HyperelasticModel &m, const ParGridFunction &x_)
: model(m), x(x_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
virtual ~ElasticEnergyCoefficient() { }
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
~ElasticEnergyCoefficient() override { }
};
void InitialDeformation(const Vector &x, Vector &y);
@@ -172,7 +172,7 @@ int main(int argc, char *argv[])
int ser_ref_levels = 2;
int par_ref_levels = 0;
int order = 2;
int ode_solver_type = 3;
int ode_solver_type = 23;
real_t t_final = 300.0;
real_t dt = 3.0;
real_t visc = 1e-2;
@@ -192,11 +192,7 @@ int main(int argc, char *argv[])
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"
" 11 - Forward Euler, 12 - RK2,\n\t"
" 13 - RK3 SSP, 14 - RK4."
" 22 - Implicit Midpoint Method,\n\t"
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
ODESolver::Types.c_str());
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -238,31 +234,7 @@ int main(int argc, char *argv[])
// 4. 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:
if (myid == 0)
{
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
}
delete mesh;
return 3;
}
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
// 5. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
@@ -433,7 +405,6 @@ int main(int argc, char *argv[])
}
// 12. Free the used memory.
delete ode_solver;
delete pmesh;
return 0;
+1 -1
View File
@@ -53,7 +53,7 @@ public:
pmesh(pmesh_),
pgf(pgf_) {}
void MonitorSolution(int i, real_t norm, const Vector &x, bool final)
void MonitorSolution(int i, real_t norm, const Vector &x, bool final) override
{
char vishost[] = "localhost";
int visport = 19916;
+12 -33
View File
@@ -5,10 +5,10 @@
// 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 -s 21 -a 0.0 -k 1.0
// ex16 -s 22 -a 1.0 -k 0.0
// ex16 -s 23 -a 0.5 -k 0.5 -o 4
// ex16 -s 4 -dt 1.0e-4 -tf 4.0e-2 -vs 40
// ex16 -m ../data/fichera-q2.mesh
// ex16 -m ../data/fichera-mixed.mesh
// ex16 -m ../data/escher.mesh
@@ -76,15 +76,15 @@ public:
ConductionOperator(FiniteElementSpace &f, real_t alpha, real_t kappa,
const Vector &u);
virtual void Mult(const Vector &u, Vector &du_dt) const;
void Mult(const Vector &u, Vector &du_dt) const override;
/** 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 real_t dt, const Vector &u, Vector &k);
void ImplicitSolve(const real_t dt, const Vector &u, Vector &k) override;
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
void SetParameters(const Vector &u);
virtual ~ConductionOperator();
~ConductionOperator() override;
};
real_t InitialTemperature(const Vector &x);
@@ -95,11 +95,13 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int ref_levels = 2;
int order = 2;
int ode_solver_type = 3;
int ode_solver_type = 23; // SDIRK33Solver
real_t t_final = 0.5;
real_t dt = 1.0e-2;
real_t alpha = 1.0e-2;
real_t kappa = 0.5;
bool visualization = true;
bool visit = false;
int vis_steps = 5;
@@ -115,8 +117,7 @@ int main(int argc, char *argv[])
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.");
ODESolver::Types.c_str());
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -149,28 +150,7 @@ int main(int argc, char *argv[])
// 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;
}
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
@@ -287,7 +267,6 @@ int main(int argc, char *argv[])
}
// 10. Free the used memory.
delete ode_solver;
delete mesh;
return 0;
+12 -33
View File
@@ -5,10 +5,10 @@
// Sample runs: mpirun -np 4 ex16p
// mpirun -np 4 ex16p -m ../data/inline-tri.mesh
// mpirun -np 4 ex16p -m ../data/disc-nurbs.mesh -tf 2
// mpirun -np 4 ex16p -s 1 -a 0.0 -k 1.0
// mpirun -np 4 ex16p -s 2 -a 1.0 -k 0.0
// mpirun -np 8 ex16p -s 3 -a 0.5 -k 0.5 -o 4
// mpirun -np 4 ex16p -s 14 -dt 1.0e-4 -tf 4.0e-2 -vs 40
// mpirun -np 4 ex16p -s 21 -a 0.0 -k 1.0
// mpirun -np 4 ex16p -s 22 -a 1.0 -k 0.0
// mpirun -np 8 ex16p -s 23 -a 0.5 -k 0.5 -o 4
// mpirun -np 4 ex16p -s 4 -dt 1.0e-4 -tf 4.0e-2 -vs 40
// mpirun -np 16 ex16p -m ../data/fichera-q2.mesh
// mpirun -np 16 ex16p -m ../data/fichera-mixed.mesh
// mpirun -np 16 ex16p -m ../data/escher-p2.mesh
@@ -78,15 +78,15 @@ public:
ConductionOperator(ParFiniteElementSpace &f, real_t alpha, real_t kappa,
const Vector &u);
virtual void Mult(const Vector &u, Vector &du_dt) const;
void Mult(const Vector &u, Vector &du_dt) const override;
/** 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 real_t dt, const Vector &u, Vector &k);
void ImplicitSolve(const real_t dt, const Vector &u, Vector &k) override;
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
void SetParameters(const Vector &u);
virtual ~ConductionOperator();
~ConductionOperator() override;
};
real_t InitialTemperature(const Vector &x);
@@ -104,11 +104,13 @@ int main(int argc, char *argv[])
int ser_ref_levels = 2;
int par_ref_levels = 1;
int order = 2;
int ode_solver_type = 3;
int ode_solver_type = 23; // SDIRK33Solver
real_t t_final = 0.5;
real_t dt = 1.0e-2;
real_t alpha = 1.0e-2;
real_t kappa = 0.5;
bool visualization = true;
bool visit = false;
int vis_steps = 5;
@@ -127,8 +129,7 @@ int main(int argc, char *argv[])
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.");
ODESolver::Types.c_str());
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -169,28 +170,7 @@ int main(int argc, char *argv[])
// 4. 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;
}
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
// 5. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
@@ -376,7 +356,6 @@ int main(int argc, char *argv[])
}
// 12. Free the used memory.
delete ode_solver;
delete pmesh;
return 0;
+2 -2
View File
@@ -69,7 +69,7 @@ public:
void SetDisplacement(GridFunction &u_) { u = &u_; }
void SetComponent(int i, int j) { si = i; sj = j; }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
};
// Simple GLVis visualization manager.
@@ -89,7 +89,7 @@ public:
void NewWindow();
void CloseConnection();
void PositionWindow();
virtual ~VisMan();
~VisMan() override;
};
// Manipulators for the GLVis visualization manager.
+2 -2
View File
@@ -69,7 +69,7 @@ public:
void SetDisplacement(GridFunction &u_) { u = &u_; }
void SetComponent(int i, int j) { si = i; sj = j; }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
};
// Simple GLVis visualization manager.
@@ -89,7 +89,7 @@ public:
void NewWindow();
void CloseConnection();
void PositionWindow();
virtual ~VisMan();
~VisMan() override;
};
// Manipulators for the GLVis visualization manager.
+2 -17
View File
@@ -90,8 +90,7 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
ODESolver::ExplicitTypes.c_str());
args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
"Time step. Positive number skips CFL timestep calculation.");
@@ -125,18 +124,7 @@ int main(int argc, char *argv[])
// 3. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
ODESolver *ode_solver = NULL;
switch (ode_solver_type)
{
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(1.0); break;
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
case 6: ode_solver = new RK6Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
return 3;
}
unique_ptr<ODESolver> ode_solver = ODESolver::SelectExplicit(ode_solver_type);
// 4. Define the discontinuous DG finite element space of the given
// polynomial order on the refined mesh.
@@ -304,8 +292,5 @@ int main(int argc, char *argv[])
const real_t error = sol.ComputeLpError(2, u0);
cout << "Solution error: " << error << endl;
// Free the used memory.
delete ode_solver;
return 0;
}
+2 -17
View File
@@ -99,8 +99,7 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
ODESolver::ExplicitTypes.c_str());
args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
"Time step. Positive number skips CFL timestep calculation.");
@@ -148,18 +147,7 @@ int main(int argc, char *argv[])
// 3. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
ODESolver *ode_solver = NULL;
switch (ode_solver_type)
{
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(1.0); break;
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
case 6: ode_solver = new RK6Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
return 3;
}
unique_ptr<ODESolver> ode_solver = ODESolver::SelectExplicit(ode_solver_type);
// 4. Define the discontinuous DG finite element space of the given
// polynomial order on the refined mesh.
@@ -360,8 +348,5 @@ int main(int argc, char *argv[])
cout << "Solution error: " << error << endl;
}
// Free the used memory.
delete ode_solver;
return 0;
}
+7 -7
View File
@@ -48,7 +48,7 @@ public:
print_level = print_lvl;
}
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final);
void MonitorResidual(int it, real_t norm, const Vector &r, bool final) override;
private:
const std::string prefix;
@@ -116,10 +116,10 @@ public:
JacobianPreconditioner(Array<FiniteElementSpace *> &fes,
SparseMatrix &mass, Array<int> &offsets);
virtual void Mult(const Vector &k, Vector &y) const;
virtual void SetOperator(const Operator &op);
void Mult(const Vector &k, Vector &y) const override;
void SetOperator(const Operator &op) override;
virtual ~JacobianPreconditioner();
~JacobianPreconditioner() override;
};
// After spatial discretization, the rubber model can be written as:
@@ -161,13 +161,13 @@ public:
int iter, Coefficient &mu);
// Required to use the native newton solver
virtual Operator &GetGradient(const Vector &xp) const;
virtual void Mult(const Vector &k, Vector &y) const;
Operator &GetGradient(const Vector &xp) const override;
void Mult(const Vector &k, Vector &y) const override;
// Driver for the newton solver
void Solve(Vector &xp) const;
virtual ~RubberOperator();
~RubberOperator() override;
};
// Visualization driver
+7 -7
View File
@@ -62,7 +62,7 @@ public:
#endif
}
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final);
void MonitorResidual(int it, real_t norm, const Vector &r, bool final) override;
private:
const std::string prefix;
@@ -130,10 +130,10 @@ public:
JacobianPreconditioner(Array<ParFiniteElementSpace *> &fes,
Operator &mass, Array<int> &offsets);
virtual void Mult(const Vector &k, Vector &y) const;
virtual void SetOperator(const Operator &op);
void Mult(const Vector &k, Vector &y) const override;
void SetOperator(const Operator &op) override;
virtual ~JacobianPreconditioner();
~JacobianPreconditioner() override;
};
// After spatial discretization, the rubber model can be written as:
@@ -175,13 +175,13 @@ public:
int iter, Coefficient &mu);
// Required to use the native newton solver
virtual Operator &GetGradient(const Vector &xp) const;
virtual void Mult(const Vector &k, Vector &y) const;
Operator &GetGradient(const Vector &xp) const override;
void Mult(const Vector &k, Vector &y) const override;
// Driver for the newton solver
void Solve(Vector &xp) const;
virtual ~RubberOperator();
~RubberOperator() override;
};
// Visualization driver
+2 -2
View File
@@ -79,14 +79,14 @@ class GradT : public Operator
{
public:
GradT() : Operator(1) {}
void Mult(const Vector &x, Vector &y) const { y.Set(1.0/m_, x); }
void Mult(const Vector &x, Vector &y) const override { y.Set(1.0/m_, x); }
};
class NegGradV : public TimeDependentOperator
{
public:
NegGradV() : TimeDependentOperator(1) {}
void Mult(const Vector &x, Vector &y) const;
void Mult(const Vector &x, Vector &y) const override;
};
int main(int argc, char *argv[])
+2 -2
View File
@@ -84,14 +84,14 @@ class GradT : public Operator
{
public:
GradT() : Operator(1) {}
void Mult(const Vector &x, Vector &y) const { y.Set(1.0/m_, x); }
void Mult(const Vector &x, Vector &y) const override { y.Set(1.0/m_, x); }
};
class NegGradV : public TimeDependentOperator
{
public:
NegGradV() : TimeDependentOperator(1) {}
void Mult(const Vector &x, Vector &y) const;
void Mult(const Vector &x, Vector &y) const override;
};
int main(int argc, char *argv[])
+7 -34
View File
@@ -61,20 +61,20 @@ public:
WaveOperator(FiniteElementSpace &f, Array<int> &ess_bdr, real_t speed);
using SecondOrderTimeDependentOperator::Mult;
virtual void Mult(const Vector &u, const Vector &du_dt,
Vector &d2udt2) const;
void Mult(const Vector &u, const Vector &du_dt,
Vector &d2udt2) const override;
/** Solve the Backward-Euler equation:
d2udt2 = f(u + fac0*d2udt2,dudt + fac1*d2udt2, t),
for the unknown d2udt2. */
using SecondOrderTimeDependentOperator::ImplicitSolve;
virtual void ImplicitSolve(const real_t fac0, const real_t fac1,
const Vector &u, const Vector &dudt, Vector &d2udt2);
void ImplicitSolve(const real_t fac0, const real_t fac1,
const Vector &u, const Vector &dudt, Vector &d2udt2) override;
///
void SetParameters(const Vector &u);
virtual ~WaveOperator();
~WaveOperator() override;
};
@@ -201,9 +201,7 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: [0--10] - GeneralizedAlpha(0.1 * s),\n\t"
"\t 11 - Average Acceleration, 12 - Linear Acceleration\n"
"\t 13 - CentralDifference, 14 - FoxGoodwin");
SecondOrderODESolver::Types.c_str());
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -238,32 +236,7 @@ int main(int argc, char *argv[])
// 3. Define the ODE solver used for time integration. Several second order
// time integrators are available.
SecondOrderODESolver *ode_solver;
switch (ode_solver_type)
{
// Implicit methods
case 0: ode_solver = new GeneralizedAlpha2Solver(0.0); break;
case 1: ode_solver = new GeneralizedAlpha2Solver(0.1); break;
case 2: ode_solver = new GeneralizedAlpha2Solver(0.2); break;
case 3: ode_solver = new GeneralizedAlpha2Solver(0.3); break;
case 4: ode_solver = new GeneralizedAlpha2Solver(0.4); break;
case 5: ode_solver = new GeneralizedAlpha2Solver(0.5); break;
case 6: ode_solver = new GeneralizedAlpha2Solver(0.6); break;
case 7: ode_solver = new GeneralizedAlpha2Solver(0.7); break;
case 8: ode_solver = new GeneralizedAlpha2Solver(0.8); break;
case 9: ode_solver = new GeneralizedAlpha2Solver(0.9); break;
case 10: ode_solver = new GeneralizedAlpha2Solver(1.0); break;
case 11: ode_solver = new AverageAccelerationSolver(); break;
case 12: ode_solver = new LinearAccelerationSolver(); break;
case 13: ode_solver = new CentralDifferenceSolver(); break;
case 14: ode_solver = new FoxGoodwinSolver(); break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
delete mesh;
return 3;
}
SecondOrderODESolver *ode_solver= SecondOrderODESolver::Select(ode_solver_type);
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
+2 -2
View File
@@ -103,8 +103,8 @@ public:
using VectorCoefficient::Eval;
virtual void Eval(Vector &K, ElementTransformation &T,
const IntegrationPoint &ip)
void Eval(Vector &K, ElementTransformation &T,
const IntegrationPoint &ip) override
{
real_t x[3];
Vector transip(x, 3);
+2 -2
View File
@@ -102,8 +102,8 @@ public:
using VectorCoefficient::Eval;
virtual void Eval(Vector &K, ElementTransformation &T,
const IntegrationPoint &ip)
void Eval(Vector &K, ElementTransformation &T,
const IntegrationPoint &ip) override
{
real_t x[3];
Vector transip(x, 3);
+1 -1
View File
@@ -58,7 +58,7 @@ public:
}
}
virtual ~DiffusionMultigrid()
~DiffusionMultigrid() override
{
delete amg;
}
+3 -3
View File
@@ -53,7 +53,7 @@ public:
real_t min_val_=-36)
: u(&u_), obstacle(&obst_), min_val(min_val_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
};
class ExponentialGridFunctionCoefficient : public Coefficient
@@ -69,7 +69,7 @@ public:
real_t min_val_=0.0, real_t max_val_=1e6)
: u(&u_), obstacle(&obst_), min_val(min_val_), max_val(max_val_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
};
int main(int argc, char *argv[])
@@ -258,7 +258,7 @@ int main(int argc, char *argv[])
MixedBilinearForm a10(&H1fes,&L2fes);
a10.AddDomainIntegrator(new MixedScalarMassIntegrator());
a10.Assemble();
a10.EliminateTrialDofs(ess_bdr, x.GetBlock(0), rhs.GetBlock(1));
a10.EliminateTrialEssentialBC(ess_bdr, x.GetBlock(0), rhs.GetBlock(1));
a10.Finalize();
SparseMatrix &A10 = a10.SpMat();
+2 -2
View File
@@ -53,7 +53,7 @@ public:
real_t min_val_=-36)
: u(&u_), obstacle(&obst_), min_val(min_val_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
};
class ExponentialGridFunctionCoefficient : public Coefficient
@@ -69,7 +69,7 @@ public:
real_t min_val_=0.0, real_t max_val_=1e6)
: u(&u_), obstacle(&obst_), min_val(min_val_), max_val(max_val_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
};
int main(int argc, char *argv[])
+8 -8
View File
@@ -52,8 +52,8 @@ public:
fun(fun_) {}
virtual real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip)
real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip) override
{
return fun(GridFunctionCoefficient::Eval(T, ip));
}
@@ -83,8 +83,8 @@ public:
OtherGridF_cf(OtherGridF),
fun(fun_) {}
virtual real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip)
real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip) override
{
const real_t value1 = fun(GridFunctionCoefficient::Eval(T, ip));
const real_t value2 = fun(OtherGridF_cf.Eval(T, ip));
@@ -108,7 +108,7 @@ public:
: rho_filter(rho_filter_), min_val(min_val_), max_val(max_val_),
exponent(exponent_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip)
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override
{
real_t val = rho_filter->GetValue(T, ip);
real_t coeff = min_val + pow(val,exponent)*(max_val-min_val);
@@ -142,7 +142,7 @@ public:
MFEM_ASSERT(rho_filter, "density field is not set");
}
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip)
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override
{
real_t L = lambda->Eval(T, ip);
real_t M = mu->Eval(T, ip);
@@ -176,8 +176,8 @@ public:
using VectorCoefficient::Eval;
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip) override
{
Vector xx; xx.SetSize(T.GetDimension());
T.Transform(ip,xx);
+121 -87
View File
@@ -3,18 +3,18 @@
// Compile with: make ex38
//
// Sample runs:
// (since all sample runs require LAPACK, the * symbol is used to exclude them
// from the automatically generated internal MFEM tests).
// (since all sample runs require LAPACK or ALGOIM, the * symbol is used to
// exclude them from the automatically generated internal MFEM tests).
// * ex38
// * ex38 -i volumetric1d
// * ex38 -i surface2d
// * ex38 -i surface2d -o 4 -r 5
// * ex38 -i surface2d -o 4 -r 5 -m 1
// * ex38 -i volumetric2d
// * ex38 -i volumetric2d -o 4 -r 5
// * ex38 -i volumetric2d -o 4 -r 5 -m 1
// * ex38 -i surface3d
// * ex38 -i surface3d -o 4 -r 5
// * ex38 -i surface3d -o 3 -r 4 -m 1
// * ex38 -i volumetric3d
// * ex38 -i volumetric3d -o 4 -r 5
// * ex38 -i volumetric3d -o 3 -r 4 -m 1
//
// Description: This example code demonstrates the use of MFEM to integrate
// functions over implicit interfaces and subdomains bounded by
@@ -71,7 +71,7 @@ real_t integrand(const Vector& X)
switch (itype)
{
case IntegrationType::Volumetric1D:
return 1.;
return pow(X(0), 2.);
case IntegrationType::Surface2D:
return 3. * pow(X(0), 2.) - pow(X(1), 2.);
case IntegrationType::Volumetric2D:
@@ -91,7 +91,7 @@ real_t Surface()
switch (itype)
{
case IntegrationType::Volumetric1D:
return 1.;
return .3025;
case IntegrationType::Surface2D:
return 2. * M_PI;
case IntegrationType::Volumetric2D:
@@ -111,7 +111,7 @@ real_t Volume()
switch (itype)
{
case IntegrationType::Volumetric1D:
return .55;
return pow(.55, 3.) / 3.;
case IntegrationType::Surface2D:
return NAN;
case IntegrationType::Volumetric2D:
@@ -125,7 +125,6 @@ real_t Volume()
}
}
#ifdef MFEM_USE_LAPACK
/**
@brief Class for surface IntegrationRule
@@ -135,11 +134,14 @@ real_t Volume()
class SIntegrationRule : public IntegrationRule
{
protected:
/// @brief Space Dimension of the IntegrationRule
/// method 0 is moments-based, 1 is Algoim.
int method, ir_order, ls_order;
Coefficient &level_set;
/// Space Dimension of the IntegrationRule
int dim;
/// @brief Column-wise matrix of the quadtrature weights
/// Column-wise matrix of the quadtrature weights
DenseMatrix Weights;
/// @brief Column-wise matrix of the transformation weights of the normal
/// Column-wise matrix of the transformation weights of the normal
DenseMatrix SurfaceWeights;
public:
@@ -153,15 +155,21 @@ public:
@param [in] lsOrder Polynomial degree for approx of level-set function
@param [in] mesh Pointer to the mesh that is used
*/
SIntegrationRule(int Order, Coefficient& LvlSet, int lsOrder, Mesh* mesh)
SIntegrationRule(int method_, int Order,
Coefficient& LvlSet, int lsOrder, Mesh* mesh)
: method(method_), ir_order(Order), ls_order(lsOrder),
level_set(LvlSet), dim(mesh->Dimension())
{
dim = mesh->Dimension();
// Nothing gets pre-computed for Algoim.
if (method == 1) { return; }
#ifdef MFEM_USE_LAPACK
MomentFittingIntRules mf_ir(ir_order, level_set, ls_order);
IsoparametricTransformation Tr;
MomentFittingIntRules MFIRs(Order, LvlSet, lsOrder);
mesh->GetElementTransformation(0, &Tr);
IntegrationRule ir;
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
mf_ir.GetSurfaceIntegrationRule(Tr, ir);
if (dim >1)
{
Weights.SetSize(ir.GetNPoints(), mesh->GetNE());
@@ -172,7 +180,7 @@ public:
}
SurfaceWeights.SetSize(ir.GetNPoints(), mesh->GetNE());
Vector w;
MFIRs.GetSurfaceWeights(Tr, ir, w);
mf_ir.GetSurfaceWeights(Tr, ir, w);
SurfaceWeights.SetCol(0, w);
SetSize(ir.GetNPoints());
@@ -198,8 +206,8 @@ public:
for (int elem = 1; elem < mesh->GetNE(); elem++)
{
mesh->GetElementTransformation(elem, &Tr);
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
MFIRs.GetSurfaceWeights(Tr, ir, w);
mf_ir.GetSurfaceIntegrationRule(Tr, ir);
mf_ir.GetSurfaceWeights(Tr, ir, w);
SurfaceWeights.SetCol(elem, w);
for (int ip = 0; ip < GetNPoints(); ip++)
@@ -215,48 +223,48 @@ public:
}
}
}
#else
MFEM_ABORT("Moment-fitting requires MFEM to be built with LAPACK!");
#endif
}
/**
@brief Set the weights for the given element and multiply them with the
transformation of the interface
*/
void SetElementinclSurfaceWeight(int Element)
void SetElementAndSurfaceWeight(ElementTransformation &Tr)
{
if (dim == 1)
if (method == 1)
{
IntegrationPoint &intp = IntPoint(0);
intp.x = Weights(0, Element);
intp.weight = Weights(1, Element);
cout << intp.x << " " << Element << endl;
}
else
#ifdef MFEM_USE_ALGOIM
AlgoimIntegrationRules a_ir(ir_order, level_set, ls_order);
a_ir.GetSurfaceIntegrationRule(Tr, *this);
Vector w;
a_ir.GetSurfaceWeights(Tr, *this, w);
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
intp.weight = Weights(ip, Element) * SurfaceWeights(ip, Element);
IntPoint(ip).weight *= w(ip);
}
}
return;
#else
MFEM_ABORT("MFEM is not built with Algoim support!");
#endif
}
/// @brief Set the weights for the given element
void SetElement(int Element)
{
if (dim == 1)
{
IntegrationPoint &intp = IntPoint(0);
intp.x = Weights(0, Element);
intp.weight = Weights(1, Element);
IntPoint(0).x = Weights(0, Tr.ElementNo);
IntPoint(0).weight = Weights(1, Tr.ElementNo);
}
else
{
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
intp.weight = Weights(ip, Element);
IntPoint(ip).weight = Weights(ip, Tr.ElementNo) *
SurfaceWeights(ip, Tr.ElementNo);
}
}
}
/// @brief Destructor of SIntegrationRule
~SIntegrationRule() {}
};
/**
@@ -268,9 +276,12 @@ public:
class CIntegrationRule : public IntegrationRule
{
protected:
/// @brief Space Dimension of the IntegrationRule
/// method 0 is moments-based, 1 is Algoim.
int method, ir_order, ls_order;
Coefficient &level_set;
/// Space Dimension of the IntegrationRule
int dim;
/// @brief Column-wise matrix of the quadtrature weights
/// Column-wise matrix of the quadtrature positions and weights.
DenseMatrix Weights;
public:
@@ -284,15 +295,21 @@ public:
@param [in] lsOrder Polynomial degree for approx of level-set function
@param [in] mesh Pointer to the mesh that is used
*/
CIntegrationRule(int Order, Coefficient& LvlSet, int lsOrder, Mesh* mesh)
CIntegrationRule(int method_, int Order,
Coefficient &LvlSet, int lsOrder, Mesh *mesh)
: method(method_), ir_order(Order), ls_order(lsOrder),
level_set(LvlSet), dim(mesh->Dimension())
{
dim = mesh->Dimension();
// Nothing gets pre-computed for Algoim.
if (method == 1) { return; }
#ifdef MFEM_USE_LAPACK
MomentFittingIntRules mf_ir(ir_order, level_set, ls_order);
IsoparametricTransformation Tr;
MomentFittingIntRules MFIRs(Order, LvlSet, lsOrder);
mesh->GetElementTransformation(0, &Tr);
IntegrationRule ir;
MFIRs.GetVolumeIntegrationRule(Tr, ir);
mf_ir.GetVolumeIntegrationRule(Tr, ir);
if (dim > 1)
{
Weights.SetSize(ir.GetNPoints(), mesh->GetNE());
@@ -324,9 +341,9 @@ public:
for (int elem = 1; elem < mesh->GetNE(); elem++)
{
mesh->GetElementTransformation(elem, &Tr);
MFIRs.GetVolumeIntegrationRule(Tr, ir);
mf_ir.GetVolumeIntegrationRule(Tr, ir);
for (int ip = 0; ip < GetNPoints(); ip++)
for (int ip = 0; ip < ir.GetNPoints(); ip++)
{
if (dim > 1)
{
@@ -339,29 +356,39 @@ public:
}
}
}
#else
MFEM_ABORT("Moment-fitting requires MFEM to be built with LAPACK!");
#endif
}
/// @brief Set the weights for the given element
void SetElement(int Element)
void SetElement(ElementTransformation &Tr)
{
if (dim == 1)
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
intp.x = Weights(2 * ip, Element);
intp.weight = Weights(2 * ip + 1, Element);
}
else
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
intp.weight = Weights(ip, Element);
}
}
if (method == 1)
{
#ifdef MFEM_USE_ALGOIM
AlgoimIntegrationRules a_ir(ir_order, level_set, ls_order);
a_ir.GetVolumeIntegrationRule(Tr, *this);
return;
#else
MFEM_ABORT("MFEM is not built with Algoim support!");
#endif
}
/// @brief Destructor of CIntegrationRule
~CIntegrationRule() {}
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
if (dim == 1)
{
intp.x = Weights(2 * ip, Tr.ElementNo);
intp.weight = Weights(2 * ip + 1, Tr.ElementNo);
}
else { intp.weight = Weights(ip, Tr.ElementNo); }
}
}
};
/**
@brief Class for surface linearform integrator
@@ -408,9 +435,9 @@ public:
@param [in] Tr transformation of finite element
@param [out] elvect vector containing the
*/
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect) override
void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect) override
{
int dof = el.GetDof();
shape.SetSize(dof);
@@ -418,7 +445,7 @@ public:
elvect = 0.;
// Update the surface integration rule for the current element
SIntRule->SetElementinclSurfaceWeight(Tr.ElementNo);
SIntRule->SetElementAndSurfaceWeight(Tr);
for (int ip = 0; ip < SIntRule->GetNPoints(); ip++)
{
@@ -428,6 +455,8 @@ public:
add(elvect, SIntRule->IntPoint(ip).weight * val, shape, elvect);
}
}
using LinearFormIntegrator::AssembleRHSElementVect;
};
/**
@@ -476,9 +505,9 @@ public:
@param [in] Tr transformation of finite element
@param [out] elvect vector containing the
*/
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect) override
void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect) override
{
int dof = el.GetDof();
shape.SetSize(dof);
@@ -486,7 +515,7 @@ public:
elvect = 0.;
// Update the subdomain integration rule
CIntRule->SetElement(Tr.ElementNo);
CIntRule->SetElement(Tr);
for (int ip = 0; ip < CIntRule->GetNPoints(); ip++)
{
@@ -497,18 +526,17 @@ public:
add(elvect, CIntRule->IntPoint(ip).weight * val, shape, elvect);
}
}
using LinearFormIntegrator::AssembleRHSElementVect;
};
#endif // MFEM_USE_LAPACK
int main(int argc, char *argv[])
{
#ifndef MFEM_USE_LAPACK
cout << "MFEM must be built with LAPACK for this example." << endl;
return MFEM_SKIP_RETURN_VALUE;
#else
#if defined(MFEM_USE_LAPACK) || defined(MFEM_USE_ALGOIM)
// 1. Parse he command-line options.
int ref_levels = 3;
int order = 2;
int method = 0;
const char *inttype = "surface2d";
bool visualization = true;
itype = IntegrationType::Surface2D;
@@ -516,6 +544,8 @@ int main(int argc, char *argv[])
OptionsParser args(argc, argv);
args.AddOption(&order, "-o", "--order", "Order of quadrature rule");
args.AddOption(&ref_levels, "-r", "--refine", "Number of meh refinements");
args.AddOption(&method, "-m", "--method",
"Cut integration method: 0 for moments-based, 1 for Algoim.");
args.AddOption(&inttype, "-i", "--integrationtype",
"IntegrationType to demonstrate");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
@@ -550,7 +580,7 @@ int main(int argc, char *argv[])
}
// 2. Construct and refine the mesh.
Mesh *mesh;
Mesh *mesh = nullptr;
if (itype == IntegrationType::Volumetric1D)
{
mesh = new Mesh("../data/inline-segment.mesh");
@@ -598,13 +628,14 @@ int main(int argc, char *argv[])
// 5. Define the necessary Integration rules on element 0.
IsoparametricTransformation Tr;
mesh->GetElementTransformation(0, &Tr);
SIntegrationRule* sir = new SIntegrationRule(order, levelset, 2, mesh);
SIntegrationRule* sir = new SIntegrationRule(method, order,
levelset, 2, mesh);
CIntegrationRule* cir = NULL;
if (itype == IntegrationType::Volumetric1D
|| itype == IntegrationType::Volumetric2D
|| itype == IntegrationType::Volumetric3D)
{
cir = new CIntegrationRule(order, levelset, 2, mesh);
cir = new CIntegrationRule(method, order, levelset, 2, mesh);
}
// 6. Define and assemble the linear forms on the finite element space.
@@ -647,11 +678,11 @@ int main(int argc, char *argv[])
cout << "Number of div free basis functions: " << nbasis << endl;
cout << "Number of quadrature points: " << ir.GetNPoints() << endl;
}
cout << scientific << setprecision(2);
cout << scientific << setprecision(10);
cout << "============================================" << endl;
cout << "Computed value of surface integral: " << surface.Sum() << endl;
cout << "True value of surface integral: " << Surface() << endl;
cout << "Absolute Error (Surface): ";
cout << "Absolute Error (Surface): ";
cout << abs(surface.Sum() - Surface()) << endl;
cout << "Relative Error (Surface): ";
cout << abs(surface.Sum() - Surface()) / Surface() << endl;
@@ -662,7 +693,7 @@ int main(int argc, char *argv[])
cout << "--------------------------------------------" << endl;
cout << "Computed value of volume integral: " << volume.Sum() << endl;
cout << "True value of volume integral: " << Volume() << endl;
cout << "Absolute Error (Volume): ";
cout << "Absolute Error (Volume): ";
cout << abs(volume.Sum() - Volume()) << endl;
cout << "Relative Error (Volume): ";
cout << abs(volume.Sum() - Volume()) / Volume() << endl;
@@ -691,5 +722,8 @@ int main(int argc, char *argv[])
delete fespace;
delete mesh;
return EXIT_SUCCESS;
#endif //MFEM_USE_LAPACK
#else
cout << "MFEM must be built with LAPACK or ALGOIM for this example." << endl;
return MFEM_SKIP_RETURN_VALUE;
#endif // MFEM_USE_LAPACK
}
+4 -4
View File
@@ -69,8 +69,8 @@ public:
using VectorCoefficient::Eval;
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip) override;
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
@@ -84,8 +84,8 @@ public:
DZCoefficient(int height, GridFunction &psi_, real_t alpha_ = 1.0)
: MatrixCoefficient(height), psi(&psi_), alpha(alpha_) { }
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip) override;
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
+4 -4
View File
@@ -69,8 +69,8 @@ public:
using VectorCoefficient::Eval;
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip) override;
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
@@ -84,8 +84,8 @@ public:
DZCoefficient(int height, ParGridFunction &psi_, real_t alpha_ = 1.0)
: MatrixCoefficient(height), psi(&psi_), alpha(alpha_) { }
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip) override;
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
+1 -1
View File
@@ -157,7 +157,7 @@ int main(int argc, char *argv[])
MixedBilinearForm *B0 = new MixedBilinearForm(x0_space,test_space);
B0->AddDomainIntegrator(new DiffusionIntegrator(one));
B0->Assemble();
B0->EliminateTrialDofs(ess_bdr, x.GetBlock(x0_var), F);
B0->EliminateTrialEssentialBC(ess_bdr, x.GetBlock(x0_var), F);
B0->Finalize();
MixedBilinearForm *Bhat = new MixedBilinearForm(xhat_space,test_space);
+8 -35
View File
@@ -9,7 +9,7 @@
// ex9 -m ../data/periodic-square.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/periodic-hexagon.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/amr-quad.mesh -p 1 -r 2 -dt 0.002 -tf 9
// ex9 -m ../data/amr-quad.mesh -p 1 -r 2 -dt 0.02 -s 13 -tf 9
// ex9 -m ../data/amr-quad.mesh -p 1 -r 2 -dt 0.02 -s 23 -tf 9
// ex9 -m ../data/star-q3.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/star-mixed.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/disc-nurbs.mesh -p 1 -r 3 -dt 0.005 -tf 9
@@ -104,12 +104,12 @@ public:
}
}
void SetOperator(const Operator &op)
void SetOperator(const Operator &op) override
{
linear_solver.SetOperator(op);
}
virtual void Mult(const Vector &x, Vector &y) const
void Mult(const Vector &x, Vector &y) const override
{
linear_solver.Mult(x, y);
}
@@ -134,10 +134,10 @@ private:
public:
FE_Evolution(BilinearForm &M_, BilinearForm &K_, const Vector &b_);
virtual void Mult(const Vector &x, Vector &y) const;
virtual void ImplicitSolve(const real_t dt, const Vector &x, Vector &k);
void Mult(const Vector &x, Vector &y) const override;
void ImplicitSolve(const real_t dt, const Vector &x, Vector &k) override;
virtual ~FE_Evolution();
~FE_Evolution() override;
};
@@ -182,12 +182,7 @@ int main(int argc, char *argv[])
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6,\n\t"
" 11 - Backward Euler,\n\t"
" 12 - SDIRK23 (L-stable), 13 - SDIRK33,\n\t"
" 22 - Implicit Midpoint Method,\n\t"
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
ODESolver::Types.c_str());
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -224,28 +219,7 @@ int main(int argc, char *argv[])
// 3. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
ODESolver *ode_solver = NULL;
switch (ode_solver_type)
{
// Explicit methods
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(1.0); break;
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
case 6: ode_solver = new RK6Solver; break;
// Implicit (L-stable) methods
case 11: ode_solver = new BackwardEulerSolver; break;
case 12: ode_solver = new SDIRK23Solver(2); break;
case 13: ode_solver = new SDIRK33Solver; 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';
return 3;
}
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
@@ -440,7 +414,6 @@ int main(int argc, char *argv[])
}
// 10. Free the used memory.
delete ode_solver;
delete pd;
delete dc;
+12 -42
View File
@@ -9,7 +9,7 @@
// mpirun -np 4 ex9p -m ../data/periodic-square.mesh -p 1 -dt 0.005 -tf 9
// mpirun -np 4 ex9p -m ../data/periodic-hexagon.mesh -p 1 -dt 0.005 -tf 9
// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.002 -tf 9
// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.02 -s 13 -tf 9
// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.02 -s 23 -tf 9
// mpirun -np 4 ex9p -m ../data/star-q3.mesh -p 1 -rp 1 -dt 0.004 -tf 9
// mpirun -np 4 ex9p -m ../data/star-mixed.mesh -p 1 -rp 1 -dt 0.004 -tf 9
// mpirun -np 4 ex9p -m ../data/disc-nurbs.mesh -p 1 -rp 1 -dt 0.005 -tf 9
@@ -92,7 +92,7 @@ private:
public:
AIR_prec(int blocksize_) : AIR_solver(NULL), blocksize(blocksize_) { }
void SetOperator(const Operator &op)
void SetOperator(const Operator &op) override
{
width = op.Width();
height = op.Height();
@@ -110,7 +110,7 @@ public:
AIR_solver->SetMaxLevels(50);
}
virtual void Mult(const Vector &x, Vector &y) const
void Mult(const Vector &x, Vector &y) const override
{
// Scale the rhs by block inverse and solve system
HypreParVector z_s;
@@ -119,7 +119,7 @@ public:
AIR_solver->Mult(z_s, y);
}
~AIR_prec()
~AIR_prec() override
{
delete AIR_solver;
}
@@ -185,17 +185,17 @@ public:
}
}
void SetOperator(const Operator &op)
void SetOperator(const Operator &op) override
{
linear_solver.SetOperator(op);
}
virtual void Mult(const Vector &x, Vector &y) const
void Mult(const Vector &x, Vector &y) const override
{
linear_solver.Mult(x, y);
}
~DG_Solver()
~DG_Solver() override
{
delete prec;
delete A;
@@ -223,10 +223,10 @@ public:
FE_Evolution(ParBilinearForm &M_, ParBilinearForm &K_, const Vector &b_,
PrecType prec_type);
virtual void Mult(const Vector &x, Vector &y) const;
virtual void ImplicitSolve(const real_t dt, const Vector &x, Vector &k);
void Mult(const Vector &x, Vector &y) const override;
void ImplicitSolve(const real_t dt, const Vector &x, Vector &k) override;
virtual ~FE_Evolution();
~FE_Evolution() override;
};
@@ -285,12 +285,7 @@ int main(int argc, char *argv[])
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6,\n\t"
" 11 - Backward Euler,\n\t"
" 12 - SDIRK23 (L-stable), 13 - SDIRK33,\n\t"
" 22 - Implicit Midpoint Method,\n\t"
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
ODESolver::Types.c_str());
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -338,31 +333,7 @@ int main(int argc, char *argv[])
// 4. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
ODESolver *ode_solver = NULL;
switch (ode_solver_type)
{
// Explicit methods
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(1.0); break;
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
case 6: ode_solver = new RK6Solver; break;
// Implicit (L-stable) methods
case 11: ode_solver = new BackwardEulerSolver; break;
case 12: ode_solver = new SDIRK23Solver(2); break;
case 13: ode_solver = new SDIRK33Solver; 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:
if (Mpi::Root())
{
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
}
delete mesh;
return 3;
}
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
// 5. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
@@ -642,7 +613,6 @@ int main(int argc, char *argv[])
delete m;
delete fes;
delete pmesh;
delete ode_solver;
delete pd;
#ifdef MFEM_USE_ADIOS2
if (adios2)
+9 -1
View File
@@ -206,6 +206,7 @@ int main(int argc, char *argv[])
bool use_petsc = true;
const char *petscrc_file = "";
bool petsc_use_jfnk = false;
const char *device_config = "cpu";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -243,6 +244,8 @@ int main(int argc, char *argv[])
args.AddOption(&petsc_use_jfnk, "-jfnk", "--jfnk", "-no-jfnk",
"--no-jfnk",
"Use JFNK with user-defined preconditioner factory.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.Parse();
if (!args.Good())
{
@@ -257,7 +260,12 @@ int main(int argc, char *argv[])
args.PrintOptions(cout);
}
// 2b. We initialize PETSc
// 2b. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 2c. We initialize PETSc
if (use_petsc)
{
MFEMInitializePetsc(NULL,NULL,petscrc_file,NULL);
+9 -1
View File
@@ -67,6 +67,7 @@ int main(int argc, char *argv[])
bool use_petsc = true;
const char *petscrc_file = "";
bool use_nonoverlapping = false;
const char *device_config = "cpu";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -95,6 +96,8 @@ 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(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.Parse();
if (!args.Good())
{
@@ -109,7 +112,12 @@ int main(int argc, char *argv[])
args.PrintOptions(cout);
}
// 2b. We initialize PETSc
// 2b. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 2c. We initialize PETSc
if (use_petsc) { MFEMInitializePetsc(NULL,NULL,petscrc_file,NULL); }
// 3. Read the (serial) mesh from the given mesh file on all processors. We
+11 -2
View File
@@ -61,6 +61,7 @@ int main(int argc, char *argv[])
bool use_petsc = true;
const char *petscrc_file = "";
bool use_nonoverlapping = false;
const char *device_config = "cpu";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -87,6 +88,8 @@ 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(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.Parse();
if (!args.Good())
{
@@ -100,10 +103,16 @@ int main(int argc, char *argv[])
{
args.PrintOptions(cout);
}
// 2b. We initialize PETSc
if (use_petsc) { MFEMInitializePetsc(NULL,NULL,petscrc_file,NULL); }
kappa = freq * M_PI;
// 2b. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 2c. We initialize PETSc
if (use_petsc) { MFEMInitializePetsc(NULL,NULL,petscrc_file,NULL); }
// 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.
+11 -2
View File
@@ -58,6 +58,7 @@ int main(int argc, char *argv[])
bool use_petsc = true;
const char *petscrc_file = "";
bool use_nonoverlapping = false;
const char *device_config = "cpu";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -88,6 +89,8 @@ 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(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.Parse();
if (!args.Good())
{
@@ -101,10 +104,16 @@ int main(int argc, char *argv[])
{
args.PrintOptions(cout);
}
// 2b. We initialize PETSc
if (use_petsc) { MFEMInitializePetsc(NULL,NULL,petscrc_file,NULL); }
kappa = freq * M_PI;
// 2b. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 2c. We initialize PETSc
if (use_petsc) { MFEMInitializePetsc(NULL,NULL,petscrc_file,NULL); }
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume, as well as periodic meshes with the same code.
+28 -7
View File
@@ -59,6 +59,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 = 2;
int order = 1;
bool par_format = false;
bool visualization = 1;
@@ -66,15 +68,22 @@ int main(int argc, char *argv[])
bool use_nonoverlapping = false;
bool local_bdr_spec = false;
const char *petscrc_file = "";
const char *device_config = "cpu";
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).");
args.AddOption(&par_format, "-pf", "--parallel-format", "-sf",
"--serial-format",
"Format to use when saving the results for VisIt.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -103,7 +112,13 @@ int main(int argc, char *argv[])
{
args.PrintOptions(cout);
}
// 2b. We initialize PETSc
// 2b. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 2c. We initialize PETSc
if (use_petsc) { MFEMInitializePetsc(NULL,NULL,petscrc_file,NULL); }
// 3. Read the (serial) mesh from the given mesh file on all processors. We
@@ -117,9 +132,11 @@ 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);
for (int l = 0; l < ref_levels; l++)
if (ser_ref_levels < 0)
{
ser_ref_levels = (int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ser_ref_levels; l++)
{
mesh->UniformRefinement();
}
@@ -131,7 +148,6 @@ int main(int argc, char *argv[])
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
int par_ref_levels = 2;
for (int l = 0; l < par_ref_levels; l++)
{
pmesh->UniformRefinement();
@@ -187,21 +203,26 @@ int main(int argc, char *argv[])
// 9. Define the parallel grid function and parallel linear forms, solution
// vector and rhs.
BlockVector x(block_offsets), rhs(block_offsets);
BlockVector trueX(block_trueOffsets), trueRhs(block_trueOffsets);
MemoryType mt = device.GetMemoryType();
BlockVector x(block_offsets, mt), rhs(block_offsets, mt);
BlockVector trueX(block_trueOffsets, mt), trueRhs(block_trueOffsets, mt);
ParLinearForm *fform(new ParLinearForm);
fform->Update(R_space, rhs.GetBlock(0), 0);
fform->AddDomainIntegrator(new VectorFEDomainLFIntegrator(fcoeff));
fform->AddBoundaryIntegrator(new VectorFEBoundaryFluxLFIntegrator(fnatcoeff));
fform->Assemble();
fform->SyncAliasMemory(rhs);
fform->ParallelAssemble(trueRhs.GetBlock(0));
trueRhs.GetBlock(0).SyncAliasMemory(trueRhs);
ParLinearForm *gform(new ParLinearForm);
gform->Update(W_space, rhs.GetBlock(1), 0);
gform->AddDomainIntegrator(new DomainLFIntegrator(gcoeff));
gform->Assemble();
gform->SyncAliasMemory(rhs);
gform->ParallelAssemble(trueRhs.GetBlock(1));
trueRhs.GetBlock(1).SyncAliasMemory(trueRhs);
// 10. Assemble the finite element matrices for the Darcy operator
//
+10 -1
View File
@@ -53,6 +53,7 @@ int main(int argc, char *argv[])
bool use_petsc = true;
const char *petscrc_file = "";
bool use_nonoverlapping = false;
const char *device_config = "cpu";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -73,6 +74,8 @@ 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(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.Parse();
if (!args.Good())
{
@@ -86,7 +89,13 @@ int main(int argc, char *argv[])
{
args.PrintOptions(cout);
}
// 2b. We initialize PETSc
// 2b. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 2c. We initialize PETSc
if (use_petsc) { MFEMInitializePetsc(NULL,NULL,petscrc_file,NULL); }
// 3. Read the (serial) mesh from the given mesh file on all processors. We
+109 -49
View File
@@ -9,9 +9,9 @@
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 12 -dt 0.15 -vs 10
// ex10 -m ../../data/beam-tri.mesh -r 2 -o 2 -s 16 -dt 0.3 -vs 5
// ex10 -m ../../data/beam-hex.mesh -r 1 -o 2 -s 12 -dt 0.2 -vs 5
// ex10 -m ../../data/beam-tri.mesh -r 2 -o 2 -s 2 -dt 3 -nls kinsol
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 2 -dt 3 -nls kinsol
// ex10 -m ../../data/beam-hex.mesh -r 1 -o 2 -s 2 -dt 3 -nls kinsol
// ex10 -m ../../data/beam-tri.mesh -r 2 -o 2 -s 2 -dt 3 -nls 1
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 2 -dt 3 -nls 2
// ex10 -m ../../data/beam-hex.mesh -r 1 -o 2 -s 2 -dt 3 -nls 4
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 14 -dt 0.15 -vs 10
// ex10 -m ../../data/beam-tri.mesh -r 2 -o 2 -s 17 -dt 0.01 -vs 30
// ex10 -m ../../data/beam-hex.mesh -r 1 -o 2 -s 14 -dt 0.15 -vs 10
@@ -99,16 +99,11 @@ protected:
double saved_gamma; // saved gamma value from implicit setup
public:
/// Solver type to use in the ImplicitSolve() method, used by SDIRK methods.
enum NonlinearSolverType
{
NEWTON = 0, ///< Use MFEM's plain NewtonSolver
KINSOL = 1 ///< Use SUNDIALS' KINSOL (through MFEM's class KINSolver)
};
HyperelasticOperator(FiniteElementSpace &f, Array<int> &ess_bdr,
double visc, double mu, double K,
NonlinearSolverType nls_type);
int kinsol_nls_type = -1, double kinsol_damping = 0.0,
int kinsol_aa_n = 0);
/// Compute the right-hand side of the ODE system.
virtual void Mult(const Vector &vx, Vector &dvx_dt) const;
@@ -226,8 +221,10 @@ int main(int argc, char *argv[])
double mu = 0.25;
double K = 5.0;
bool visualization = true;
const char *nls = "newton";
int nonlinear_solver_type = 0;
int vis_steps = 1;
double kinsol_damping = 0.0;
int kinsol_aa_n = -1;
// Relative and absolute tolerances for CVODE and ARKODE.
const double reltol = 1e-1, abstol = 1e-1;
@@ -264,9 +261,18 @@ int main(int argc, char *argv[])
"15 - ARKODE implicit, approximate Jacobian,\n\t"
"16 - ARKODE implicit, specified Jacobian,\n\t"
"17 - ARKODE explicit, 4th order.");
args.AddOption(&nls, "-nls", "--nonlinear-solver",
"Nonlinear systems solver: "
"\"newton\" (plain Newton) or \"kinsol\" (KINSOL).");
args.AddOption(&nonlinear_solver_type, "-nls", "--nonlinear-solver",
"Nonlinear system solver:\n\t"
"0 - MFEM Newton method,\n\t"
"1 - KINSOL Newton method,\n\t"
"2 - KINSOL Newton method with globalization,\n\t"
"3 - KINSOL fixed-point method (with or without AA),\n\t"
"4 - KINSOL Picard method (with or without AA).");
args.AddOption(&kinsol_damping, "-damp", "--kinsol-damping",
"Picard or Fixed-Point damping parameter (only valid with KINSOL): "
"0 < d <= 1.0");
args.AddOption(&kinsol_aa_n, "-aan", "--anderson-subspace",
"Anderson Acceleration subspace size (only valid with KINSOL)");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -297,22 +303,32 @@ int main(int argc, char *argv[])
return 1;
}
// check for valid nonlinear solver options
if (nonlinear_solver_type < 0 || nonlinear_solver_type > 4)
{
cout << "Unknown nonlinear solver type: " << nonlinear_solver_type << "\n";
return 1;
}
if (kinsol_damping > 0.0 &&
!(nonlinear_solver_type == 3 || nonlinear_solver_type == 4))
{
cout << "Only KINSOL fixed-point and Picard methods can use damping\n";
return 1;
}
if (kinsol_aa_n > 0 &&
!(nonlinear_solver_type == 3 || nonlinear_solver_type == 4))
{
cout << "Only KINSOL fixed-point and Picard methods can use AA\n";
return 1;
}
// 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);
int dim = mesh->Dimension();
// 3. Setup the nonlinear solver
map<string,HyperelasticOperator::NonlinearSolverType> nls_map;
nls_map["newton"] = HyperelasticOperator::NEWTON;
nls_map["kinsol"] = HyperelasticOperator::KINSOL;
if (nls_map.find(nls) == nls_map.end())
{
cout << "Unknown type of nonlinear solver: " << nls << endl;
return 4;
}
// 4. Refine the mesh to increase the resolution. In this example we do
// 3. 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++)
@@ -320,7 +336,7 @@ int main(int argc, char *argv[])
mesh->UniformRefinement();
}
// 5. Define the vector finite element spaces representing the mesh
// 4. Define the vector finite element spaces representing the mesh
// deformation x, the velocity v, and the initial configuration, x_ref.
// Define also the elastic energy density, w, which is in a discontinuous
// higher-order space. Since x and v are integrated in time as a system,
@@ -348,7 +364,7 @@ int main(int argc, char *argv[])
FiniteElementSpace w_fespace(mesh, &w_fec);
GridFunction w(&w_fespace);
// 6. Set the initial conditions for v and x, and the boundary conditions on
// 5. Set the initial conditions for v and x, and the boundary conditions on
// a beam-like mesh (see description above).
VectorFunctionCoefficient velo(dim, InitialVelocity);
v.ProjectCoefficient(velo);
@@ -361,9 +377,34 @@ int main(int argc, char *argv[])
ess_bdr = 0;
ess_bdr[0] = 1; // boundary attribute 1 (index 0) is fixed
// 7. Initialize the hyperelastic operator, the GLVis visualization and print
// 6. Initialize the hyperelastic operator, the GLVis visualization and print
// the initial energies.
HyperelasticOperator oper(fespace, ess_bdr, visc, mu, K, nls_map[nls]);
std::unique_ptr<HyperelasticOperator> oper;
if (nonlinear_solver_type == 0)
oper = std::make_unique<HyperelasticOperator>(fespace, ess_bdr, visc, mu,
K);
else
{
switch (nonlinear_solver_type)
{
case 1:
oper = std::make_unique<HyperelasticOperator>(fespace, ess_bdr,
visc, mu, K, KIN_NONE);
break;
case 2:
oper = std::make_unique<HyperelasticOperator>(fespace, ess_bdr,
visc, mu, K, KIN_LINESEARCH);
break;
case 3:
oper = std::make_unique<HyperelasticOperator>(fespace, ess_bdr,
visc, mu, K, KIN_FP, kinsol_damping, kinsol_aa_n);
break;
case 4:
oper = std::make_unique<HyperelasticOperator>(fespace, ess_bdr,
visc, mu, K, KIN_PICARD, kinsol_damping, kinsol_aa_n);
break;
}
}
socketstream vis_v, vis_w;
if (visualization)
@@ -377,23 +418,23 @@ int main(int argc, char *argv[])
vis_w.open(vishost, visport);
if (vis_w)
{
oper.GetElasticEnergyDensity(x, w);
oper->GetElasticEnergyDensity(x, w);
vis_w.precision(8);
visualize(vis_w, mesh, &x, &w, "Elastic energy density", true);
}
}
double ee0 = oper.ElasticEnergy(x.GetTrueVector());
double ke0 = oper.KineticEnergy(v.GetTrueVector());
double ee0 = oper->ElasticEnergy(x.GetTrueVector());
double ke0 = oper->KineticEnergy(v.GetTrueVector());
cout << "initial elastic energy (EE) = " << ee0 << endl;
cout << "initial kinetic energy (KE) = " << ke0 << endl;
cout << "initial total energy (TE) = " << (ee0 + ke0) << endl;
// 8. Define the ODE solver used for time integration. Several implicit
// 7. 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.
double t = 0.0;
oper.SetTime(t);
oper->SetTime(t);
ODESolver *ode_solver = NULL;
CVODESolver *cvode = NULL;
@@ -417,7 +458,7 @@ int main(int argc, char *argv[])
case 11:
case 12:
cvode = new CVODESolver(CV_BDF);
cvode->Init(oper);
cvode->Init(*oper);
cvode->SetSStolerances(reltol, abstol);
CVodeSetEpsLin(cvode->GetMem(), cvode_eps_lin);
cvode->SetMaxStep(dt);
@@ -430,7 +471,7 @@ int main(int argc, char *argv[])
case 13:
case 14:
cvode = new CVODESolver(CV_ADAMS);
cvode->Init(oper);
cvode->Init(*oper);
cvode->SetSStolerances(reltol, abstol);
CVodeSetEpsLin(cvode->GetMem(), cvode_eps_lin);
cvode->SetMaxStep(dt);
@@ -443,9 +484,13 @@ int main(int argc, char *argv[])
case 15:
case 16:
arkode = new ARKStepSolver(ARKStepSolver::IMPLICIT);
arkode->Init(oper);
arkode->Init(*oper);
arkode->SetSStolerances(reltol, abstol);
#if MFEM_SUNDIALS_VERSION < 70100
ARKStepSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
#else
ARKodeSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
#endif
arkode->SetMaxStep(dt);
if (ode_solver_type == 15)
{
@@ -455,16 +500,16 @@ int main(int argc, char *argv[])
// ARKStep Explicit methods
case 17:
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
arkode->Init(oper);
arkode->Init(*oper);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
ode_solver = arkode; break;
}
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
if (ode_solver_type < 11) { ode_solver->Init(oper); }
if (ode_solver_type < 11) { ode_solver->Init(*oper); }
// 9. Perform time-integration (looping over the time iterations, ti, with a
// 8. Perform time-integration (looping over the time iterations, ti, with a
// time-step dt).
bool last_step = false;
for (int ti = 1; !last_step; ti++)
@@ -477,8 +522,8 @@ int main(int argc, char *argv[])
if (last_step || (ti % vis_steps) == 0)
{
double ee = oper.ElasticEnergy(x.GetTrueVector());
double ke = oper.KineticEnergy(v.GetTrueVector());
double ee = oper->ElasticEnergy(x.GetTrueVector());
double ke = oper->KineticEnergy(v.GetTrueVector());
cout << "step " << ti << ", t = " << t << ", EE = " << ee << ", KE = "
<< ke << ", ΔTE = " << (ee+ke)-(ee0+ke0) << endl;
@@ -492,14 +537,14 @@ int main(int argc, char *argv[])
visualize(vis_v, mesh, &x, &v);
if (vis_w)
{
oper.GetElasticEnergyDensity(x, w);
oper->GetElasticEnergyDensity(x, w);
visualize(vis_w, mesh, &x, &w);
}
}
}
}
// 10. Save the displaced mesh, the velocity and elastic energy.
// 9. Save the displaced mesh, the velocity and elastic energy.
{
v.SetFromTrueVector(); x.SetFromTrueVector();
GridFunction *nodes = &x;
@@ -514,11 +559,11 @@ int main(int argc, char *argv[])
v.Save(velo_ofs);
ofstream ee_ofs("elastic_energy.sol");
ee_ofs.precision(8);
oper.GetElasticEnergyDensity(x, w);
oper->GetElasticEnergyDensity(x, w);
w.Save(ee_ofs);
}
// 11. Free the used memory.
// 10. Free the used memory.
delete ode_solver;
delete mesh;
@@ -602,7 +647,9 @@ ReducedSystemOperator::~ReducedSystemOperator()
HyperelasticOperator::HyperelasticOperator(FiniteElementSpace &f,
Array<int> &ess_bdr, double visc,
double mu, double K,
NonlinearSolverType nls_type)
int kinsol_nls_type,
double kinsol_damping,
int kinsol_aa_n)
: TimeDependentOperator(2*f.GetTrueVSize(), 0.0), fespace(f),
M(&fespace), S(&fespace), H(&fespace),
viscosity(visc), z(height/2),
@@ -653,15 +700,28 @@ HyperelasticOperator::HyperelasticOperator(FiniteElementSpace &f,
J_prec = NULL;
#endif
if (nls_type == KINSOL)
if (kinsol_nls_type > 0)
{
KINSolver *kinsolver = new KINSolver(KIN_NONE, true);
KINSolver *kinsolver = new KINSolver(kinsol_nls_type, true);
if (kinsol_nls_type != KIN_PICARD)
{
kinsolver->SetJFNK(true);
kinsolver->SetLSMaxIter(100);
}
if (kinsol_aa_n > 0)
{
kinsolver->EnableAndersonAcc(kinsol_aa_n);
}
newton_solver = kinsolver;
newton_solver->SetOperator(*reduced_oper);
newton_solver->SetMaxIter(200);
newton_solver->SetRelTol(rel_tol);
newton_solver->SetPrintLevel(0);
kinsolver->SetMaxSetupCalls(4);
if (kinsol_damping > 0.0)
{
kinsolver->SetDamping(kinsol_damping);
}
}
else
{
+127 -59
View File
@@ -9,9 +9,9 @@
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 12 -dt 0.15 -vs 10
// mpirun -np 4 ex10p -m ../../data/beam-tri.mesh -rp 1 -o 2 -s 16 -dt 0.25 -vs 10
// mpirun -np 4 ex10p -m ../../data/beam-hex.mesh -rp 0 -o 2 -s 12 -dt 0.15 -vs 10
// mpirun -np 4 ex10p -m ../../data/beam-tri.mesh -rp 1 -o 2 -s 2 -dt 3 -nls kinsol
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 2 -dt 3 -nls kinsol
// mpirun -np 4 ex10p -m ../../data/beam-hex.mesh -rs 1 -o 2 -s 2 -dt 3 -nls kinsol
// mpirun -np 4 ex10p -m ../../data/beam-tri.mesh -rp 1 -o 2 -s 2 -dt 3 -nls 1
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 2 -dt 3 -nls 2
// mpirun -np 4 ex10p -m ../../data/beam-hex.mesh -rs 1 -o 2 -s 2 -dt 3 -nls 4
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 14 -dt 0.15 -vs 10
// mpirun -np 4 ex10p -m ../../data/beam-tri.mesh -rp 1 -o 2 -s 17 -dt 5e-3 -vs 60
// mpirun -np 4 ex10p -m ../../data/beam-hex.mesh -rp 0 -o 2 -s 14 -dt 0.15 -vs 10
@@ -101,16 +101,11 @@ protected:
double saved_gamma; // saved gamma value from implicit setup
public:
/// Solver type to use in the ImplicitSolve() method, used by SDIRK methods.
enum NonlinearSolverType
{
NEWTON = 0, ///< Use MFEM's plain NewtonSolver
KINSOL = 1 ///< Use SUNDIALS' KINSOL (through MFEM's class KINSolver)
};
HyperelasticOperator(ParFiniteElementSpace &f, Array<int> &ess_bdr,
double visc, double mu, double K,
NonlinearSolverType nls_type);
int kinsol_nls_type = -1, double kinsol_damping = 0.0,
int kinsol_aa_n = 0);
/// Compute the right-hand side of the ODE system.
virtual void Mult(const Vector &vx, Vector &dvx_dt) const;
@@ -235,8 +230,10 @@ int main(int argc, char *argv[])
double mu = 0.25;
double K = 5.0;
bool visualization = true;
const char *nls = "newton";
int nonlinear_solver_type = 0;
int vis_steps = 1;
double kinsol_damping = 0.0;
int kinsol_aa_n = -1;
// Relative and absolute tolerances for CVODE and ARKODE.
const double reltol = 1e-1, abstol = 1e-1;
@@ -275,9 +272,18 @@ int main(int argc, char *argv[])
"15 - ARKODE implicit, approximate Jacobian,\n\t"
"16 - ARKODE implicit, specified Jacobian,\n\t"
"17 - ARKODE explicit, 4th order.");
args.AddOption(&nls, "-nls", "--nonlinear-solver",
"Nonlinear systems solver: "
"\"newton\" (plain Newton) or \"kinsol\" (KINSOL).");
args.AddOption(&nonlinear_solver_type, "-nls", "--nonlinear-solver",
"Nonlinear system solver:\n\t"
"0 - MFEM Newton method,\n\t"
"1 - KINSOL Newton method,\n\t"
"2 - KINSOL Newton method with globalization,\n\t"
"3 - KINSOL fixed-point method (with or without AA),\n\t"
"4 - KINSOL Picard method (with or without AA).");
args.AddOption(&kinsol_damping, "-damp", "--kinsol-damping",
"Picard or Fixed-Point damping parameter (only valid with KINSOL): "
"0 < d <= 1.0");
args.AddOption(&kinsol_aa_n, "-aan", "--anderson-subspace",
"Anderson Acceleration subspace size (only valid with KINSOL)");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -317,27 +323,42 @@ int main(int argc, char *argv[])
return 1;
}
// check for valid nonlinear solver options
if (nonlinear_solver_type < 0 || nonlinear_solver_type > 4)
{
if (myid == 0)
{
cout << "Unknown nonlinear solver type: " << nonlinear_solver_type
<< "\n";
}
return 1;
}
if (kinsol_damping > 0.0 &&
!(nonlinear_solver_type == 3 || nonlinear_solver_type == 4))
{
if (myid == 0)
{
cout << "Only KINSOL fixed-point and Picard methods can use damping\n";
}
return 1;
}
if (kinsol_aa_n > 0 &&
!(nonlinear_solver_type == 3 || nonlinear_solver_type == 4))
{
if (myid == 0)
{
cout << "Only KINSOL fixed-point and Picard methods can use AA\n";
}
return 1;
}
// 3. Read the serial mesh from the given mesh file on all processors. We can
// handle triangular, quadrilateral, tetrahedral and hexahedral meshes
// with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Nonlinear solver
map<string,HyperelasticOperator::NonlinearSolverType> nls_map;
nls_map["newton"] = HyperelasticOperator::NEWTON;
nls_map["kinsol"] = HyperelasticOperator::KINSOL;
if (nls_map.find(nls) == nls_map.end())
{
if (myid == 0)
{
cout << "Unknown type of nonlinear solver: " << nls << endl;
}
delete mesh;
return 4;
}
// 5. Refine the mesh in serial to increase the resolution. In this example
// 4. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
// a command-line parameter.
for (int lev = 0; lev < ser_ref_levels; lev++)
@@ -345,7 +366,7 @@ int main(int argc, char *argv[])
mesh->UniformRefinement();
}
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
@@ -355,7 +376,7 @@ int main(int argc, char *argv[])
pmesh->UniformRefinement();
}
// 7. Define the parallel vector finite element spaces representing the mesh
// 6. Define the parallel vector finite element spaces representing the mesh
// deformation x_gf, the velocity v_gf, and the initial configuration,
// x_ref. Define also the elastic energy density, w_gf, which is in a
// discontinuous higher-order space. Since x and v are integrated in time
@@ -387,7 +408,7 @@ int main(int argc, char *argv[])
ParFiniteElementSpace w_fespace(pmesh, &w_fec);
ParGridFunction w_gf(&w_fespace);
// 8. Set the initial conditions for v_gf, x_gf and vx, and define the
// 7. Set the initial conditions for v_gf, x_gf and vx, and define the
// boundary conditions on a beam-like mesh (see description above).
VectorFunctionCoefficient velo(dim, InitialVelocity);
v_gf.ProjectCoefficient(velo);
@@ -402,9 +423,38 @@ int main(int argc, char *argv[])
ess_bdr = 0;
ess_bdr[0] = 1; // boundary attribute 1 (index 0) is fixed
// 9. Initialize the hyperelastic operator, the GLVis visualization and print
// 8. Initialize the hyperelastic operator, the GLVis visualization and print
// the initial energies.
HyperelasticOperator oper(fespace, ess_bdr, visc, mu, K, nls_map[nls]);
std::unique_ptr<HyperelasticOperator> oper;
if (nonlinear_solver_type == 0)
oper = std::make_unique<HyperelasticOperator>(fespace, ess_bdr, visc, mu,
K);
else
{
switch (nonlinear_solver_type)
{
case 1:
oper = std::make_unique<HyperelasticOperator>(fespace, ess_bdr,
visc, mu, K, KIN_NONE);
break;
case 2:
oper = std::make_unique<HyperelasticOperator>(fespace, ess_bdr,
visc, mu, K, KIN_LINESEARCH);
break;
case 3:
oper = std::make_unique<HyperelasticOperator>(fespace, ess_bdr,
visc, mu, K, KIN_FP, kinsol_damping, kinsol_aa_n);
break;
case 4:
oper = std::make_unique<HyperelasticOperator>(fespace, ess_bdr,
visc, mu, K, KIN_PICARD, kinsol_damping, kinsol_aa_n);
break;
default:
cout << "Unknown type of nonlinear solver: "
<< nonlinear_solver_type << endl;
return 4;
}
}
socketstream vis_v, vis_w;
if (visualization)
@@ -420,14 +470,14 @@ int main(int argc, char *argv[])
vis_w.open(vishost, visport);
if (vis_w)
{
oper.GetElasticEnergyDensity(x_gf, w_gf);
oper->GetElasticEnergyDensity(x_gf, w_gf);
vis_w.precision(8);
visualize(vis_w, pmesh, &x_gf, &w_gf, "Elastic energy density", true);
}
}
double ee0 = oper.ElasticEnergy(x_gf);
double ke0 = oper.KineticEnergy(v_gf);
double ee0 = oper->ElasticEnergy(x_gf);
double ke0 = oper->KineticEnergy(v_gf);
if (myid == 0)
{
cout << "initial elastic energy (EE) = " << ee0 << endl;
@@ -435,11 +485,11 @@ int main(int argc, char *argv[])
cout << "initial total energy (TE) = " << (ee0 + ke0) << endl;
}
// 10. 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.
// 9. 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.
double t = 0.0;
oper.SetTime(t);
oper->SetTime(t);
ODESolver *ode_solver = NULL;
CVODESolver *cvode = NULL;
@@ -463,7 +513,7 @@ int main(int argc, char *argv[])
case 11:
case 12:
cvode = new CVODESolver(MPI_COMM_WORLD, CV_BDF);
cvode->Init(oper);
cvode->Init(*oper);
cvode->SetSStolerances(reltol, abstol);
CVodeSetEpsLin(cvode->GetMem(), cvode_eps_lin);
cvode->SetMaxStep(dt);
@@ -476,7 +526,7 @@ int main(int argc, char *argv[])
case 13:
case 14:
cvode = new CVODESolver(MPI_COMM_WORLD, CV_ADAMS);
cvode->Init(oper);
cvode->Init(*oper);
cvode->SetSStolerances(reltol, abstol);
CVodeSetEpsLin(cvode->GetMem(), cvode_eps_lin);
cvode->SetMaxStep(dt);
@@ -489,9 +539,13 @@ int main(int argc, char *argv[])
case 15:
case 16:
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::IMPLICIT);
arkode->Init(oper);
arkode->Init(*oper);
arkode->SetSStolerances(reltol, abstol);
#if MFEM_SUNDIALS_VERSION < 70100
ARKStepSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
#else
ARKodeSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
#endif
arkode->SetMaxStep(dt);
if (ode_solver_type == 15)
{
@@ -501,16 +555,16 @@ int main(int argc, char *argv[])
// ARKStep Explicit methods
case 17:
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::EXPLICIT);
arkode->Init(oper);
arkode->Init(*oper);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
ode_solver = arkode; break;
}
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
if (ode_solver_type < 11) { ode_solver->Init(oper); }
if (ode_solver_type < 11) { ode_solver->Init(*oper); }
// 11. Perform time-integration
// 10. Perform time-integration
// (looping over the time iterations, ti, with a time-step dt).
bool last_step = false;
for (int ti = 1; !last_step; ti++)
@@ -525,8 +579,8 @@ int main(int argc, char *argv[])
{
v_gf.SetFromTrueVector(); x_gf.SetFromTrueVector();
double ee = oper.ElasticEnergy(x_gf);
double ke = oper.KineticEnergy(v_gf);
double ee = oper->ElasticEnergy(x_gf);
double ke = oper->KineticEnergy(v_gf);
if (myid == 0)
{
@@ -542,14 +596,14 @@ int main(int argc, char *argv[])
visualize(vis_v, pmesh, &x_gf, &v_gf);
if (vis_w)
{
oper.GetElasticEnergyDensity(x_gf, w_gf);
oper->GetElasticEnergyDensity(x_gf, w_gf);
visualize(vis_w, pmesh, &x_gf, &w_gf);
}
}
}
}
// 12. Save the displaced mesh, the velocity and elastic energy.
// 11. Save the displaced mesh, the velocity and elastic energy.
{
v_gf.SetFromTrueVector(); x_gf.SetFromTrueVector();
GridFunction *nodes = &x_gf;
@@ -570,11 +624,11 @@ int main(int argc, char *argv[])
v_gf.Save(velo_ofs);
ofstream ee_ofs(ee_name.str().c_str());
ee_ofs.precision(8);
oper.GetElasticEnergyDensity(x_gf, w_gf);
oper->GetElasticEnergyDensity(x_gf, w_gf);
w_gf.Save(ee_ofs);
}
// 13. Free the used memory.
// 12. Free the used memory.
delete ode_solver;
delete pmesh;
@@ -664,7 +718,10 @@ ReducedSystemOperator::~ReducedSystemOperator()
HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f,
Array<int> &ess_bdr, double visc,
double mu, double K,
NonlinearSolverType nls_type)
int kinsol_nls_type,
double kinsol_damping,
int kinsol_aa_n)
: TimeDependentOperator(2*f.TrueVSize(), 0.0), fespace(f),
M(&fespace), S(&fespace), H(&fespace),
viscosity(visc), M_solver(f.GetComm()), z(height/2),
@@ -716,17 +773,28 @@ HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f,
J_minres->SetPreconditioner(*J_prec);
J_solver = J_minres;
if (nls_type == KINSOL)
if (kinsol_nls_type > 0)
{
KINSolver *kinsolver = new KINSolver(f.GetComm(), KIN_LINESEARCH, true);
kinsolver->SetJFNK(true);
kinsolver->SetLSMaxIter(100);
KINSolver *kinsolver = new KINSolver(f.GetComm(), kinsol_nls_type, true);
if (kinsol_nls_type != KIN_PICARD)
{
kinsolver->SetJFNK(true);
kinsolver->SetLSMaxIter(100);
}
if (kinsol_aa_n > 0)
{
kinsolver->EnableAndersonAcc(kinsol_aa_n);
}
newton_solver = kinsolver;
newton_solver->SetOperator(*reduced_oper);
newton_solver->SetMaxIter(200);
newton_solver->SetRelTol(rel_tol);
newton_solver->SetPrintLevel(1);
newton_solver->SetPrintLevel(0);
kinsolver->SetMaxSetupCalls(4);
if (kinsol_damping > 0.0)
{
kinsolver->SetDamping(kinsol_damping);
}
}
else
{
+6 -6
View File
@@ -447,7 +447,7 @@ ConductionOperator::ConductionOperator(FiniteElementSpace &fes,
const Vector &u,
const Type &ode_expression_type)
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace), z(height)
fespace(fes), M(&fespace), alpha(alpha), kappa(kappa), z(height)
{
// specify a relative tolerance for all solves with MFEM integrators
const real_t rel_tol = 1e-8;
@@ -522,7 +522,7 @@ int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
T_solver.SetOperator(*T);
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
return SUNLS_SUCCESS;
return SUN_SUCCESS;
}
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
@@ -544,7 +544,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
}
if (T_solver.GetConverged())
{
return SUNLS_SUCCESS;
return SUN_SUCCESS;
}
else
{
@@ -555,7 +555,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
int ConductionOperator::SUNMassSetup()
{
// Do nothing b/c mass solver was setup in constructor.
return SUNLS_SUCCESS;
return SUN_SUCCESS;
}
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
@@ -565,7 +565,7 @@ int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
M_solver.Mult(b, x);
if (M_solver.GetConverged())
{
return SUNLS_SUCCESS;
return SUN_SUCCESS;
}
else
{
@@ -577,6 +577,6 @@ int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
{
// Compute M x.
Mmat.Mult(x, v);
return SUNLS_SUCCESS;
return SUN_SUCCESS;
}
+6 -6
View File
@@ -499,7 +499,7 @@ ConductionOperator::ConductionOperator(ParFiniteElementSpace &fes,
const Vector &u,
const Type &ode_expression_type)
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace),
fespace(fes), M(&fespace), alpha(alpha), kappa(kappa),
M_solver(fes.GetComm()), T_solver(fes.GetComm()), z(height)
{
// specify a relative tolerance for all solves with MFEM integrators
@@ -576,7 +576,7 @@ int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
T_solver.SetOperator(*T);
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
return SUNLS_SUCCESS;
return SUN_SUCCESS;
}
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
@@ -598,7 +598,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
}
if (T_solver.GetConverged())
{
return SUNLS_SUCCESS;
return SUN_SUCCESS;
}
else
{
@@ -609,7 +609,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
int ConductionOperator::SUNMassSetup()
{
// Do nothing b/c mass solver was setup in constructor.
return SUNLS_SUCCESS;
return SUN_SUCCESS;
}
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
@@ -619,7 +619,7 @@ int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
M_solver.Mult(b, x);
if (M_solver.GetConverged())
{
return SUNLS_SUCCESS;
return SUN_SUCCESS;
}
else
{
@@ -631,5 +631,5 @@ int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
{
// Compute M x.
Mmat.Mult(x, v);
return SUNLS_SUCCESS;
return SUN_SUCCESS;
}
File diff suppressed because it is too large Load Diff
-305
View File
@@ -1,305 +0,0 @@
#include "dfem/dfem_refactor.hpp"
#include "linalg/hypre.hpp"
using namespace mfem;
using mfem::internal::tensor;
using mfem::internal::dual;
int test_diffusion_integrator(std::string mesh_file,
int refinements,
int polynomial_order)
{
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
const int dim = mesh.Dimension();
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder());
ParGridFunction f1_g(&h1fes);
ParGridFunction rho_g(&h1fes);
auto rho_f = [](const Vector &coords)
{
const double x = coords(0);
const double y = coords(1);
return x + y;
};
FunctionCoefficient rho_c(rho_f);
rho_g.ProjectCoefficient(rho_c);
auto kernel = [](const tensor<dual<double, double>, 2> &grad_u,
const dual<double, double> &rho,
const tensor<double, 2, 2> &J,
const double &w)
{
auto invJ = inv(J);
return std::tuple{rho*rho * grad_u * invJ * transpose(invJ) * det(J) * w};
};
std::tuple argument_operators = {Gradient{"potential"}, Value{"density"}, Gradient{"coordinates"}, Weight{"integration_weights"}};
std::tuple output_operator = {Gradient{"potential"}};
ElementOperator eop = {kernel, argument_operators, output_operator};
auto ops = std::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "potential"}};
auto parameters = std::array
{
FieldDescriptor{&h1fes, "density"},
FieldDescriptor{&mesh_fes, "coordinates"}
};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
auto f1 = [](const Vector &coords)
{
const double x = coords(0);
const double y = coords(1);
return 2.345 + 0.25 * x*x*y + y*y*x;
};
FunctionCoefficient f1_c(f1);
f1_g.ProjectCoefficient(f1_c);
Vector x(f1_g), y(h1fes.TrueVSize());
dop.SetParameters({&rho_g, mesh_nodes});
dop.Mult(x, y);
ParBilinearForm a(&h1fes);
TransformedCoefficient rho_c2(&rho_c, [](double c) {return c*c;});
a.AddDomainIntegrator(new DiffusionIntegrator(rho_c2));
a.Assemble();
a.Finalize();
Vector y2(h1fes.TrueVSize());
a.Mult(x, y2);
y2 -= y;
if (y2.Norml2() > 1e-10)
{
out << "||F(u) - ex||_l2 = " << y2.Norml2() << "\n";
return 1;
}
// Test linearization here as well
auto dFdu = dop.GetDerivativeWrt<0>({&f1_g}, {&rho_g, mesh_nodes});
// HypreParMatrix A;
// dFdu->Assemble(A);
if (dFdu->Height() != h1fes.GetTrueVSize())
{
out << "dFdu unexpected height of " << dFdu->Height() << "\n";
return 1;
}
dFdu->Mult(x, y);
a.Mult(x, y2);
y2 -= y;
if (y2.Norml2() > 1e-10)
{
out << "||dFdu u^* - ex||_l2 = " << y2.Norml2() << "\n";
return 1;
}
// fd jacobian test
{
double eps = 1.0e-6;
Vector v(x), xpv(x), xmv(x), fxpv(x.Size()), fxmv(x.Size());
v *= eps;
xpv += v;
xmv -= v;
dop.Mult(xpv, fxpv);
dop.Mult(xmv, fxmv);
fxpv -= fxmv;
fxpv /= (2.0*eps);
fxpv -= y;
if (fxpv.Norml2() > eps)
{
out << "||dFdu_FD u^* - ex||_l2 = " << fxpv.Norml2() << "\n";
return 1;
}
}
f1_g.ProjectCoefficient(f1_c);
rho_g.ProjectCoefficient(rho_c);
auto dFdrho = dop.GetDerivativeWrt<1>({&f1_g}, {&rho_g, mesh_nodes});
if (dFdrho->Height() != h1fes.GetTrueVSize())
{
out << "dFdrho unexpected height of " << dFdrho->Height() << "\n";
return 1;
}
dFdrho->Mult(rho_g, y);
// fd test
{
double eps = 1.0e-6;
Vector v(rho_g), rhopv(rho_g), rhomv(rho_g), frhopv(x.Size()), frhomv(x.Size());
v *= eps;
rhopv += v;
rhomv -= v;
dop.SetParameters({&rhopv, mesh_nodes});
dop.Mult(x, frhopv);
dop.SetParameters({&rhomv, mesh_nodes});
dop.Mult(x, frhomv);
frhopv -= frhomv;
frhopv /= (2.0*eps);
frhopv -= y;
if (frhopv.Norml2() > eps)
{
out << "||dFdu_FD u^* - ex||_l2 = " << frhopv.Norml2() << "\n";
return 1;
}
}
return 0;
}
int test_qoi(std::string mesh_file,
int refinements,
int polynomial_order)
{
Mesh mesh_serial = Mesh(mesh_file);
for (int i = 0; i < refinements; i++)
{
mesh_serial.UniformRefinement();
}
ParMesh mesh(MPI_COMM_WORLD, mesh_serial);
mesh.SetCurvature(1);
const int dim = mesh.Dimension();
mesh_serial.Clear();
ParGridFunction* mesh_nodes = static_cast<ParGridFunction *>(mesh.GetNodes());
ParFiniteElementSpace &mesh_fes = *mesh_nodes->ParFESpace();
H1_FECollection h1fec(polynomial_order, dim);
ParFiniteElementSpace h1fes(&mesh, &h1fec, dim);
const IntegrationRule &ir =
IntRules.Get(h1fes.GetFE(0)->GetGeomType(), 2 * h1fec.GetOrder());
ParGridFunction rho_g(&h1fes);
auto rho_f = [](const Vector &coords, Vector &u)
{
const double x = coords(0);
const double y = coords(1);
u(0) = x + y;
u(1) = x + y;
};
VectorFunctionCoefficient rho_c(dim, rho_f);
rho_g.ProjectCoefficient(rho_c);
auto kernel = [](const tensor<dual<double, double>, 2> &rho,
const tensor<dual<double, double>, 2, 2> &drhodxi,
const tensor<double, 2, 2> &J,
const double &w)
{
const double eps = 1.2345;
const auto drhodx = drhodxi * inv(J);
return std::tuple{(0.5 * eps * dot(rho, rho) + ddot(drhodx, drhodx)) * det(J) * w};
};
std::tuple argument_operators = {Value{"density"}, Gradient{"density"}, Gradient{"coordinates"}, Weight{"integration_weights"}};
std::tuple output_operator = {One{"density"}};
ElementOperator eop = {kernel, argument_operators, output_operator};
auto ops = std::tuple{eop};
auto solutions = std::array{FieldDescriptor{&h1fes, "density"}};
auto parameters = std::array{FieldDescriptor{&mesh_fes, "coordinates"}};
DifferentiableOperator dop(solutions, parameters, ops, mesh, ir);
Vector x(rho_g), y(1);
dop.SetParameters({mesh_nodes});
dop.Mult(x, y);
// print_vector(y);
auto dFdrho = dop.GetDerivativeWrt<0>({&rho_g}, {mesh_nodes});
// Vector dFdrho_vec;
// dFdrho->Assemble(dFdrho_vec);
// print_vector(dFdrho_vec);
// fd jacobian test
{
double eps = 1.0e-8;
Vector v(x), fxpv(1), fxmv(1), dfdx(x.Size());
for (int i = 0; i < x.Size(); i++)
{
v(i) += eps;
dop.Mult(v, fxpv);
v(i) -= 2.0 * eps;
dop.Mult(v, fxmv);
fxpv -= fxmv;
fxpv /= (2.0*eps);
dfdx(i) = fxpv(0);
}
// print_vector(dfdx);
dfdx -= dFdrho_vec;
if (dfdx.Norml2() > 1e-6)
{
out << "||dFdu_FD u^* - ex||_l2 = " << dfdx.Norml2() << "\n";
return 1;
}
}
return 0;
}
int main(int argc, char *argv[])
{
Mpi::Init();
std::cout << std::setprecision(9);
const char *mesh_file = "../data/star.mesh";
int polynomial_order = 1;
int ir_order = 2;
int refinements = 0;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
args.AddOption(&polynomial_order, "-o", "--order", "");
args.AddOption(&refinements, "-r", "--r", "");
args.AddOption(&ir_order, "-iro", "--iro", "");
args.ParseCheck();
out << std::setprecision(12);
int ret;
ret = test_diffusion_integrator(mesh_file,
refinements,
polynomial_order);
out << "test_diffusion_integrator";
ret ? out << " FAILURE\n" : out << " OK\n";
ret = test_qoi(mesh_file, refinements, polynomial_order);
out << "test_qoi";
ret ? out << " FAILURE\n" : out << " OK\n";
return 0;
}

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