diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0f54d49c50652d300d3e7294bab27414d0dc158d..5410c926204ebb36c37364562768e8b0b22f8a58 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,10 +11,10 @@ variables: before_script: - . /duneci/bin/duneci-init-job - - python3 -m venv /duneci/modules/dune-pip - - source /duneci/modules/dune-pip/bin/activate - - pip install --upgrade pip - - pip install ufl numpy matplotlib mpi4py portalocker + #- python3 -m venv /duneci/modules/dune-pip + #- source /duneci/modules/dune-pip/bin/activate + #- pip install --upgrade pip + #- pip install ufl numpy matplotlib mpi4py portalocker - duneci-install-module https://gitlab.dune-project.org/core/dune-common.git - duneci-install-module https://gitlab.dune-project.org/core/dune-geometry.git - duneci-install-module https://gitlab.dune-project.org/core/dune-grid.git @@ -24,24 +24,21 @@ before_script: - duneci-install-module https://gitlab.dune-project.org/dune-fem/dune-fem.git debian-11-gcc-9-17: - image: duneci/debian:11 + image: registry.dune-project.org/docker/ci/debian:11 script: - - source /duneci/modules/dune-pip/bin/activate + #- source /duneci/modules/dune-pip/bin/activate # issue with setup-dunepy: dune-fem-dg not yet build so dependency in dune-fem-dg fails # - python /duneci/modules/dune-python/bin/setup-dunepy.py --opts=$CI_PROJECT_DIR/scripts/opts/ci-gcc.opts install - duneci-standard-test variables: DUNECI_TOOLCHAIN: gcc-9-17 - # DUNE_LOG_FORMAT: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' - # DUNE_LOG_LEVEL: DEBUG - # MAKEFLAGS: "--verbose --output-sync=target --print-directory" -ubuntu:18.04--gcc: - image: duneci/ubuntu:18.04 - script: - - source /duneci/modules/dune-pip/bin/activate - # issue with setup-dunepy: dune-fem-dg not yet build so dependency in dune-fem-dg fails - # - python /duneci/modules/dune-python/bin/setup-dunepy.py --opts=$CI_PROJECT_DIR/scripts/opts/ci-gcc.opts install - - duneci-standard-test - variables: - DUNECI_TOOLCHAIN: gcc-7-17 + #ubuntu:20.04--gcc: + #image: duneci/ubuntu:18.04 + #script: + #- source /duneci/modules/dune-pip/bin/activate + # # issue with setup-dunepy: dune-fem-dg not yet build so dependency in dune-fem-dg fails + # # - python /duneci/modules/dune-python/bin/setup-dunepy.py --opts=$CI_PROJECT_DIR/scripts/opts/ci-gcc.opts install + #- duneci-standard-test + #variables: + #DUNECI_TOOLCHAIN: gcc-7-17 diff --git a/dune/fem-dg/algorithm/sub/evolution.hh b/dune/fem-dg/algorithm/sub/evolution.hh index 6ca3864cc9602a572528d5270956bc88b8eba6f8..054949055a5456fc5a0c45021d33d421eca1d4aa 100644 --- a/dune/fem-dg/algorithm/sub/evolution.hh +++ b/dune/fem-dg/algorithm/sub/evolution.hh @@ -296,6 +296,20 @@ namespace Fem diagnostics_.registerData( "OverallTimer", &overallTime_ ); diagnostics_.registerData( "NumberOfElements", &odeSolverMonitor_.numberOfElements_ ); } + +#ifdef BASEFUNCTIONSET_CODEGEN_GENERATE + { + const int polOrder = solution().space().order(); + const int maxOrder = 2 * polOrder + 1 ; + const int dim = GridType :: dimension; + std::vector< int > quadOrder( maxOrder ); + for( int i=2; i<maxOrder+2; ++i ) + quadOrder.push_back( i ); + std::string filename( "autogeneratedcode_"+std::to_string( dim ) + "d_k" + std::to_string( polOrder ) + ".hh" ); + Dune::Fem::generateCode( solution().space(), quadOrder, quadOrder, "./", filename ); + + } +#endif } virtual void doSolve ( const int loop, TimeProviderType& tp ) override diff --git a/dune/fem-dg/examples/advdiff/algorithmcreator.hh b/dune/fem-dg/examples/advdiff/algorithmcreator.hh index e5d4ca8e85ddf99138afa50d00fb2199b0c522a3..0aab62457f547439ee6ff4fb2e6c2ff29690aa77 100644 --- a/dune/fem-dg/examples/advdiff/algorithmcreator.hh +++ b/dune/fem-dg/examples/advdiff/algorithmcreator.hh @@ -56,7 +56,10 @@ namespace Fem typedef AlgorithmConfigurator< GridSelectorGridType, Galerkin::Enum::default_, Adaptivity::Enum::default_, - DiscreteFunctionSpaces::Enum::default_, //legendre + //DiscreteFunctionSpaces::Enum::gausslobatto, //legendre + //DiscreteFunctionSpaces::Enum::gausslegendre, //legendre + DiscreteFunctionSpaces::Enum::legendre, + //DiscreteFunctionSpaces::Enum::default_, Solver::Enum::default_, AdvectionLimiter::Enum::default_, Matrix::Enum::default_, diff --git a/dune/fem-dg/examples/advdiff/models.hh b/dune/fem-dg/examples/advdiff/models.hh index d69f9a8468da58f3b66b8b2a6cc2c830a7c7cf10..f9f2df0cf0dc9736f3a57313483fb08e9c73f884 100644 --- a/dune/fem-dg/examples/advdiff/models.hh +++ b/dune/fem-dg/examples/advdiff/models.hh @@ -103,8 +103,6 @@ namespace Fem using BaseType::time_; using BaseType::time; - HeatEqnModel(const HeatEqnModel& otehr); - const HeatEqnModel &operator=(const HeatEqnModel &other); public: /** * \brief Constructor diff --git a/dune/fem-dg/examples/advdiff/test/CMakeLists.txt b/dune/fem-dg/examples/advdiff/test/CMakeLists.txt index 93fbf1c8a06a968b57b1ece08518a63228dba330..7fb9a636f2e779880b211d2929acb616ede55e6e 100644 --- a/dune/fem-dg/examples/advdiff/test/CMakeLists.txt +++ b/dune/fem-dg/examples/advdiff/test/CMakeLists.txt @@ -1,13 +1,13 @@ include_directories("${CMAKE_SOURCE_DIR}/dune/fem-dg/examples/advdiff/") # specify type of grid implementation, dimension and polynomial order -set( GRIDTYPE ALUGRID_CUBE ) -#set( GRIDTYPE SPGRID ) +#set( GRIDTYPE ALUGRID_CUBE ) +set( GRIDTYPE SPGRID ) set( GRIDDIM 2 ) -set( POLORDER 2 ) +set( POLORDER 4 ) add_definitions( "-DGRIDDIM=${GRIDDIM}" ) -add_definitions( "-DDIMRANGE=5" ) +add_definitions( "-DDIMRANGE=3" ) dune_add_test_case( NAME advdiff SOURCES ../main.cc diff --git a/dune/fem-dg/examples/advdiff/test/parameters/advdiff b/dune/fem-dg/examples/advdiff/test/parameters/advdiff index fb3a7427fe8e27ec957be95fec4df826bb987f8c..a6390f72c02bb4696a463ded666b390b2cc011ba 100644 --- a/dune/fem-dg/examples/advdiff/test/parameters/advdiff +++ b/dune/fem-dg/examples/advdiff/test/parameters/advdiff @@ -15,7 +15,15 @@ gridsol.filename: heat-checkpoint # GENERAL #-------- -# femdg.stepper.printcount: 10 +fem.adaptation.method: none # none | generic | callback + +# coarsest level that should be present +fem.adaptation.coarsestLevel: 3 +# finest level that should be present +fem.adaptation.finestLevel: 6 + +fem.eoc.steps: 1 +femdg.stepper.printcount: 100 paramfile: ../../parameter/paramBase # PROBLEM SETUP @@ -24,7 +32,6 @@ paramfile: ../../parameter/paramBase # problem: heat, quasi, plaplace problem: pulse -fem.eoc.steps: 3 femdg.stepper.endtime: 0.15 femdg.stepper.diffusiontimestep: 1 epsilon: 0.001 diff --git a/dune/fem-dg/examples/euler/algorithmcreator.hh b/dune/fem-dg/examples/euler/algorithmcreator.hh index 9cbb4a9674e61dadb81e432972cde4344873769a..a2822b912793893e36846f9ac4a4525d6643e1b3 100644 --- a/dune/fem-dg/examples/euler/algorithmcreator.hh +++ b/dune/fem-dg/examples/euler/algorithmcreator.hh @@ -62,7 +62,11 @@ namespace Fem typedef AlgorithmConfigurator< GridSelectorGridType, Galerkin::Enum::dg, Adaptivity::Enum::yes, - DiscreteFunctionSpaces::Enum::orthonormal, + //DiscreteFunctionSpaces::Enum::orthonormal, + //DiscreteFunctionSpaces::Enum::lagrange, + DiscreteFunctionSpaces::Enum::gausslobatto, + //DiscreteFunctionSpaces::Enum::gausslegendre, + //DiscreteFunctionSpaces::Enum::hierarchic_legendre, Solver::Enum::fem, AdvectionLimiter::Enum::limited, Matrix::Enum::matrixfree, diff --git a/dune/fem-dg/examples/euler/test/CMakeLists.txt b/dune/fem-dg/examples/euler/test/CMakeLists.txt index 73005fd61a0aeca37523461dd51e16d027faefa3..61c78881f60a7ce2f28be904f2a25fd2d2797a0f 100644 --- a/dune/fem-dg/examples/euler/test/CMakeLists.txt +++ b/dune/fem-dg/examples/euler/test/CMakeLists.txt @@ -5,7 +5,7 @@ set( GRIDTYPE ALUGRID_CUBE ) #set( GRIDTYPE SPGRID_COUNT_FLOPS ) #set( GRIDTYPE SPGRID ) set( GRIDDIM 2 ) -set( POLORDER 2 ) +set( POLORDER 4 ) add_definitions( "-D${GRIDTYPE}" ) add_definitions( "-DGRIDDIM=${GRIDDIM}" ) diff --git a/dune/fem-dg/examples/euler/test/parameters/euler b/dune/fem-dg/examples/euler/test/parameters/euler index c9d661f379929602f730fc6d68b0c33639ddcccc..e0ed5802faaecb31175c5c8fb5e690964f6cace8 100644 --- a/dune/fem-dg/examples/euler/test/parameters/euler +++ b/dune/fem-dg/examples/euler/test/parameters/euler @@ -8,7 +8,7 @@ problem: sod # LIMITER SETTINGS #----------------- # 0 = only dg solution | 1 = only reconstruction | 2 = both -femdg.limiter.admissiblefunctions: 1 +#femdg.limiter.admissiblefunctions: 1 # tolerance for shock indicator femdg.limiter.tolerance: 1 # threshold for avoiding over-excessive limitation @@ -19,7 +19,7 @@ femdg.limiter.indicatoroutput: true # DATA WRITER #------------ fem.io.datafileprefix: RC -fem.io.savestep: 0.16 # SaveStep (write data every `saveStep' time period, <=0 deactivates) +fem.io.savestep: 0.01 # SaveStep (write data every `saveStep' time period, <=0 deactivates) fem.io.savecount: -1 # SaveCount (write data every saveCount time steps, <=0 deactivates) @@ -29,8 +29,11 @@ gridsol.savestep: 0.5 gridsol.firstwrite: 0.5 gridsol.filename: straka-checkpoint -fem.eoc.steps: 3 +fem.eoc.steps: 4 +femdg.stepper.printcount: 100 +# coarsest level that should be present (also initial refinement) +fem.adaptation.coarsestLevel: 0 # STEPPER #-------- @@ -65,13 +68,14 @@ r: 0.25 # radius of perturbation ball # coarsest level that should be present fem.adaptation.coarsestLevel: 0 # finest level that should be present -fem.adaptation.finestLevel: 0 +fem.adaptation.finestLevel: 6 # DOMAIN SETUP #------------- fem.io.macroGridFile_1d: ../../grids/unitcube1.dgf -fem.io.macroGridFile_2d: ../../grids/grid2d_str1d.dgf +#fem.io.macroGridFile_2d: ../../grids/grid2d_str1d.dgf +fem.io.macroGridFile_2d: ../../grids/grid2d_nonaffine.dgf fem.io.macroGridFile_3d: ../../grids/unitcube3.dgf diff --git a/dune/fem-dg/examples/euler/test/parameters/parameter b/dune/fem-dg/examples/euler/test/parameters/parameter index b5019cedc020a1cd71becbcc844d0bcf2c7771b2..d453d8d0ab311a0919c52940130f7f965a444fca 100644 --- a/dune/fem-dg/examples/euler/test/parameters/parameter +++ b/dune/fem-dg/examples/euler/test/parameters/parameter @@ -1,19 +1,19 @@ -# PROBLEM SELECTION +# PROBLEM SELECTION #------------------ # possible: "sod" , "withman", "withmansmooth", "smooth1d" , "ffs" , "diffraction" , "shockbubble" -problem: sod +problem: sod # problemflag: 0 # riemanndata: [1., -1., 1., 1., 1., 1.] # LIMITER SETTINGS #----------------- -# 0 = only dg solution | 1 = only reconstruction | 2 = both -femdg.limiter.admissiblefunctions: 1 -# tolerance for shock indicator +# 0 = only dg solution | 1 = only reconstruction | 2 = both +femdg.limiter.admissiblefunctions: 1 +# tolerance for shock indicator femdg.limiter.tolerance: 1 -# threshold for avoiding over-excessive limitation +# threshold for avoiding over-excessive limitation femdg.limiter.limiteps: 1e-8 -# add indicator to outputvariables +# add indicator to outputvariables femdg.limiter.indicatoroutput: true # DATA WRITER @@ -23,7 +23,7 @@ fem.io.savestep: 0.01 # SaveStep (write data every `saveStep' time period, <=0 d fem.io.savecount: -1 # SaveCount (write data every saveCount time steps, <=0 deactivates) -# GRID SOLUTION +# GRID SOLUTION #-------------- gridsol.savestep: 0.5 gridsol.firstwrite: 0.5 @@ -32,12 +32,17 @@ gridsol.filename: straka-checkpoint # GENERAL #-------- +# coarsest level that should be present +fem.adaptation.coarsestLevel: 3 +# finest level that should be present +fem.adaptation.finestLevel: 3 + paramfile: ../../parameter/paramBase # STEPPER #-------- -fem.eoc.steps: 4 +fem.eoc.steps: 1 femdg.stepper.starttime: 0. femdg.stepper.endtime: 0.15 femdg.stepper.maxtimestep: 0.1 diff --git a/dune/fem-dg/examples/grids/grid2d_nonaffine.dgf b/dune/fem-dg/examples/grids/grid2d_nonaffine.dgf new file mode 100644 index 0000000000000000000000000000000000000000..b6a197c7c60a2f971bbba38b5d8fcad878dce985 --- /dev/null +++ b/dune/fem-dg/examples/grids/grid2d_nonaffine.dgf @@ -0,0 +1,76 @@ +DGF +% Elements = 16 | Vertices = 27 + +VERTEX +1.2500000000000000e-01 0.0000000000000000e+00 +2.5000000000000000e-01 0.0000000000000000e+00 +1.2500000000000000e-01 1.5000000000000000e-01 +2.8000000000000000e-01 1.1000000000000000e-01 +0.0000000000000000e+00 0.0000000000000000e+00 +0.0000000000000000e+00 1.2500000000000000e-01 +3.7500000000000000e-01 0.0000000000000000e+00 +5.0000000000000000e-01 0.0000000000000000e+00 +3.4500000000000000e-01 1.4500000000000000e-01 +5.0000000000000000e-01 1.2500000000000000e-01 +6.2500000000000000e-01 0.0000000000000000e+00 +5.9000000000000000e-01 1.2000000000000000e-01 +7.5000000000000000e-01 0.0000000000000000e+00 +7.2000000000000000e-01 1.5000000000000000e-01 +8.7500000000000000e-01 0.0000000000000000e+00 +1.0000000000000000e+00 0.0000000000000000e+00 +8.7500000000000000e-01 1.1500000000000000e-01 +1.0000000000000000e+00 1.2500000000000000e-01 +5.0000000000000000e-01 2.5000000000000000e-01 +6.2500000000000000e-01 2.5000000000000000e-01 +7.5000000000000000e-01 2.5000000000000000e-01 +8.7500000000000000e-01 2.5000000000000000e-01 +1.0000000000000000e+00 2.5000000000000000e-01 +3.7500000000000000e-01 2.5000000000000000e-01 +2.5000000000000000e-01 2.5000000000000000e-01 +1.2500000000000000e-01 2.5000000000000000e-01 +0.0000000000000000e+00 2.5000000000000000e-01 +# + +CUBE +0 1 2 3 +4 0 5 2 +6 7 8 9 +1 6 3 8 +7 10 9 11 +10 12 11 13 +14 15 16 17 +12 14 13 16 +9 11 18 19 +11 13 19 20 +16 17 21 22 +13 16 20 21 +8 9 23 18 +3 8 24 23 +2 3 25 24 +5 2 26 25 +# + +BOUNDARYSEGMENTS +2 0 1 +2 4 5 +2 4 0 +2 6 7 +2 1 6 +2 7 10 +2 10 12 +2 15 17 +2 14 15 +2 12 14 +2 18 19 +2 19 20 +2 17 22 +2 21 22 +2 20 21 +2 23 18 +2 24 23 +2 25 24 +2 5 26 +2 26 25 +# + +# diff --git a/dune/fem-dg/examples/parameter/paramBase b/dune/fem-dg/examples/parameter/paramBase index d4ae230c80c9de82a34329b3942ff8ad078d0ce1..85894f3937b58d793be647f453b2af73213d7f3c 100644 --- a/dune/fem-dg/examples/parameter/paramBase +++ b/dune/fem-dg/examples/parameter/paramBase @@ -5,7 +5,7 @@ fem.verboserank: 0 # OMP THREADS #------------ # number of threads used in OMP program -fem.parallel.numberofthreads: 4 +fem.parallel.numberofthreads: 1 # write diagnostics file ( # 0 don't, 1 only speedup file, 2 write all runfiles # 3 only write 0, others at end, 4 all files at end for scaling) @@ -39,7 +39,7 @@ gridsol.usegridsolution: false # STEPPER #----------------- -fem.eoc.steps: 1 +fem.eoc.steps: 4 femdg.stepper.printcount: 10 # maximal number of timesteps done (for debugging) # femdg.stepper.maximaltimesteps: 10 diff --git a/dune/fem-dg/examples/parameter/paramSolver b/dune/fem-dg/examples/parameter/paramSolver index 9c63a9fca182da81a2af9ec975fad29b59137f9a..a1623f22afb21125509f79434f3043cfdbe17452 100644 --- a/dune/fem-dg/examples/parameter/paramSolver +++ b/dune/fem-dg/examples/parameter/paramSolver @@ -9,7 +9,7 @@ fem.ode.miniterations: 95 fem.ode.maxiterations: 105 fem.ode.cflStart: 1. #fem.ode.cflMax: 5 -fem.timeprovider.factor: 0.45 +fem.timeprovider.factor: 0.15 fem.timeprovider.updatestep: 1 # parameter for the implicit solvers diff --git a/dune/fem-dg/examples/poisson/test/parameters/parameter b/dune/fem-dg/examples/poisson/test/parameters/parameter index bb177d8eb7529097a5be48b02d7836498b5af79c..bdb9a0ab018a43ede088201926a4903c8d37fce3 100644 --- a/dune/fem-dg/examples/poisson/test/parameters/parameter +++ b/dune/fem-dg/examples/poisson/test/parameters/parameter @@ -1,4 +1,6 @@ -# prefix data data files +fem.io.verboserank: 0 + +# prefix data data files fem.io.datafileprefix: solution # if you want to add time stemp to eoc file name # # to avoid overwriting the eoc files @@ -19,7 +21,7 @@ zvelocity: 0. # the only advection part for the linear heat eqn fem.solver.verbose: 1 fem.solver.newton.verbose: 1 fem.ode.verbose: full - + # macro grid file fem.io.macroGridFile_2d: ../../grids/unitcube2.dgf #fem.io.macroGridFile_2d:../../grids/square2d.dgf @@ -31,11 +33,11 @@ fem.io.macroGridFile_2d: ../../grids/unitcube2.dgf nonConformOrigin: false # choises are: CDG2, CDG, IP, NIPG, BO, BR2 -dgdiffusionflux.method: CDG2 +dgdiffusionflux.method: CDG2 dgdiffusionflux.theoryparameters: 1 dgdiffusionflux.lifting: id_id #dgdiffusionflux.upwind: -1 -0.001 -#dgdiffusionflux.upwind: 0 0 +#dgdiffusionflux.upwind: 0 0 dgdiffusionflux.penalty: 0 # for CDG, CDG2, LDG dgdiffusionflux.liftfactor: 0 diff --git a/dune/fem-dg/misc/algorithmcreatorenums.hh b/dune/fem-dg/misc/algorithmcreatorenums.hh index e131cc4f0f93291333fb514594fb4e476c1dfc8b..bae2d3f72724c516f44c6a94ec78ef0bd2416502 100644 --- a/dune/fem-dg/misc/algorithmcreatorenums.hh +++ b/dune/fem-dg/misc/algorithmcreatorenums.hh @@ -77,7 +77,11 @@ namespace Fem //! Discrete function space with Lagrange Finite Elements lagrange, //! p-adaptive space from dune-fem, implementing dg and lagrange - padaptive + padaptive, + //! Lagrange space with GaussLobatto interpolation points + gausslobatto, + //! Lagrange space with GaussLegendre interpolation points + gausslegendre }; } diff --git a/dune/fem-dg/misc/algorithmcreatorselector.hh b/dune/fem-dg/misc/algorithmcreatorselector.hh index 7939eb4f5d8782ede372e047e9f9fdc40c4e6caf..d758b46154de6a268c3cc1dc006b77ab3035ac77 100644 --- a/dune/fem-dg/misc/algorithmcreatorselector.hh +++ b/dune/fem-dg/misc/algorithmcreatorselector.hh @@ -51,6 +51,7 @@ #include <dune/fem-dg/assemble/primalmatrix.hh> #include <dune/fem/space/discontinuousgalerkin.hh> +#include <dune/fem/space/lagrange.hh> #include <dune/fem-dg/operator/dg/operatortraits.hh> @@ -502,6 +503,13 @@ namespace Fem /////////////////////////////////////////////////////////////////////////// // DiscreteFunctionSpaceSelector /////////////////////////////////////////////////////////////////////////// +#ifdef USE_BASEFUNCTIONSET_CODEGEN + template <class T> + using Storage = Dune::Fem::CodegenStorage<T>; +#else + template <class T> + using Storage = Dune::Fem::CachingStorage<T>; +#endif template< class FunctionSpaceImp, class GridPartImp, int polOrder, DiscreteFunctionSpaces::Enum dfType, Galerkin::Enum opType > struct DiscreteFunctionSpaceSelector; @@ -509,34 +517,48 @@ namespace Fem template< class FunctionSpaceImp, class GridPartImp, int polOrder > struct DiscreteFunctionSpaceSelector< FunctionSpaceImp, GridPartImp, polOrder, DiscreteFunctionSpaces::Enum::lagrange, Galerkin::Enum::cg > { - typedef LagrangeDiscreteFunctionSpace< FunctionSpaceImp, GridPartImp, polOrder, CachingStorage > type; + typedef LagrangeDiscreteFunctionSpace< FunctionSpaceImp, GridPartImp, polOrder, Storage > type; }; template< class FunctionSpaceImp, class GridPartImp, int polOrder > struct DiscreteFunctionSpaceSelector< FunctionSpaceImp, GridPartImp, polOrder, DiscreteFunctionSpaces::Enum::legendre, Galerkin::Enum::dg > { - typedef LegendreDiscontinuousGalerkinSpace< FunctionSpaceImp, GridPartImp, polOrder, CachingStorage > type; + typedef LegendreDiscontinuousGalerkinSpace< FunctionSpaceImp, GridPartImp, polOrder, Storage > type; }; template< class FunctionSpaceImp, class GridPartImp, int polOrder > struct DiscreteFunctionSpaceSelector< FunctionSpaceImp, GridPartImp, polOrder, DiscreteFunctionSpaces::Enum::orthonormal, Galerkin::Enum::dg > { - typedef DiscontinuousGalerkinSpace< FunctionSpaceImp, GridPartImp, polOrder, CachingStorage > type; + typedef DiscontinuousGalerkinSpace< FunctionSpaceImp, GridPartImp, polOrder, Storage > type; }; template< class FunctionSpaceImp, class GridPartImp, int polOrder > struct DiscreteFunctionSpaceSelector< FunctionSpaceImp, GridPartImp, polOrder, DiscreteFunctionSpaces::Enum::lagrange, Galerkin::Enum::dg > { - typedef LagrangeDiscontinuousGalerkinSpace< FunctionSpaceImp, GridPartImp, polOrder, CachingStorage > type; + typedef LagrangeDiscontinuousGalerkinSpace< FunctionSpaceImp, GridPartImp, polOrder, Storage > type; }; template< class FunctionSpaceImp, class GridPartImp, int polOrder > struct DiscreteFunctionSpaceSelector< FunctionSpaceImp, GridPartImp, polOrder, DiscreteFunctionSpaces::Enum::hierarchic_legendre, Galerkin::Enum::dg > { - typedef HierarchicLegendreDiscontinuousGalerkinSpace< FunctionSpaceImp, GridPartImp, polOrder, CachingStorage > type; + typedef HierarchicLegendreDiscontinuousGalerkinSpace< FunctionSpaceImp, GridPartImp, polOrder, Storage > type; + }; + +#if HAVE_DUNE_LOCALFUNCTIONS + template< class FunctionSpaceImp, class GridPartImp, int polOrder > + struct DiscreteFunctionSpaceSelector< FunctionSpaceImp, GridPartImp, polOrder, DiscreteFunctionSpaces::Enum::gausslobatto, Galerkin::Enum::dg > + { + typedef FixedOrderDGLagrangeSpace< FunctionSpaceImp, GridPartImp, polOrder, Dune::GaussLobattoPointSet, Storage > type; }; + template< class FunctionSpaceImp, class GridPartImp, int polOrder > + struct DiscreteFunctionSpaceSelector< FunctionSpaceImp, GridPartImp, polOrder, DiscreteFunctionSpaces::Enum::gausslegendre, Galerkin::Enum::dg > + { + typedef FixedOrderDGLagrangeSpace< FunctionSpaceImp, GridPartImp, polOrder, Dune::GaussLegendrePointSet, Storage > type; + }; +#endif + template< class ModelImp, class DiscreteFunctionSpaceImp, DiffusionFlux::Enum diffFluxId, Formulation::Enum form > struct DiffusionFluxSelector; diff --git a/dune/fem-dg/misc/configurator.hh b/dune/fem-dg/misc/configurator.hh index f8bdbc553144c7786f3e2a4af9966c38345a2099..71bdf13a7ee58f926b42eb56cac99fdc7a68603a 100644 --- a/dune/fem-dg/misc/configurator.hh +++ b/dune/fem-dg/misc/configurator.hh @@ -75,6 +75,10 @@ namespace Fem DiscreteFunctionSpaces::Enum::lagrange; #elif DISCRETEFUNCTIONSPACESENUM == 5 DiscreteFunctionSpaces::Enum::padaptive; +#elif DISCRETEFUNCTIONSPACESENUM == 6 + DiscreteFunctionSpaces::Enum::gausslobatto; +#elif DISCRETEFUNCTIONSPACESENUM == 7 + DiscreteFunctionSpaces::Enum::gausslegendre; #else // DISCRETEFUNCTIONSPACESENUM == 1 DiscreteFunctionSpaces::Enum::orthonormal; #endif diff --git a/dune/fem-dg/misc/simulator.hh b/dune/fem-dg/misc/simulator.hh index 0ef5faa1ea7d273bfaa1acc00a28670e56f9d9bf..d70fff96aba6c6fd8a992095420893663fee70fe 100644 --- a/dune/fem-dg/misc/simulator.hh +++ b/dune/fem-dg/misc/simulator.hh @@ -49,12 +49,12 @@ #include <dune/fem-dg/misc/streams.hh> #if defined USE_BASEFUNCTIONSET_CODEGEN || defined BASEFUNCTIONSET_CODEGEN_GENERATE -#include <dune/fem/space/basisfunctionset/default_codegen.hh> #include <dune/fem/space/basisfunctionset/codegen.hh> #endif #ifdef USE_BASEFUNCTIONSET_CODEGEN #warning "Using autogenerated code" +#include <autogeneratedcode.hh> #endif #include <dune/fem-dg/pass/threadhandle.hh> @@ -269,7 +269,7 @@ namespace Fem static void apply( const AlgorithmCreator& algCreator, const int polynomialOrder, const bool computeAnyway ) { #ifdef BASEFUNCTIONSET_CODEGEN_GENERATE - Dune::Fem::CodegenInfo :: instance().setFileName( autoFilename( CODEDIM, polOrd ) ); + Dune::Fem::Codegen::CodegenInfo :: instance().setFileName( autoFilename( CODEDIM, polOrd ) ); #endif if( computeAnyway || polOrd == polynomialOrder ) { @@ -290,8 +290,9 @@ namespace Fem static void run( const AlgorithmCreator& algCreator ) { #ifdef BASEFUNCTIONSET_CODEGEN_GENERATE + using namespace Dune::Fem::Codegen; #if COUNT_FLOPS - Dune::Fem::CodegenInfo :: instance().setPath( + CodegenInfo :: instance().setPath( Dune::Fem::Parameter::commonInputPath() + "/autogeneratedcodeflops"); #endif std::cout << "Generating Code \n"; @@ -306,11 +307,11 @@ namespace Fem Dune::Fem::ForLoop< SimulatePolOrd, MIN_POLORD, MAX_POLORD > :: apply( algCreator, polOrder, bool(MIN_POLORD == MAX_POLORD) ); #ifdef BASEFUNCTIONSET_CODEGEN_GENERATE } - catch (const Dune::Fem::CodegenInfoFinished& ) {} + catch (const CodegenInfoFinished& ) {} std::cerr << "Code for k="<< MAX_POLORD << " generated!! " << std::endl; - Dune::Fem::CodegenInfo :: instance().dumpInfo(); - Dune::Fem::CodegenInfo :: instance().clear(); + CodegenInfo :: instance().dumpInfo(); + CodegenInfo :: instance().clear(); std::remove( autoFilename( CODEDIM, MAX_POLORD ).c_str() ); finalizeCodegen(); #endif diff --git a/dune/fem-dg/models/modelwrapper.hh b/dune/fem-dg/models/modelwrapper.hh index aed6d44469d37279f01d2f24fa9cc20bebecf5ef..2cabcf41971ec88485b869ea31d63316a2921c06 100644 --- a/dune/fem-dg/models/modelwrapper.hh +++ b/dune/fem-dg/models/modelwrapper.hh @@ -198,7 +198,7 @@ namespace Fem limitedRange_[ i ] = i; // if method has been filled then modified will be set differently - advection_.limitedRange( limitedRange_ ); + advection().limitedRange( limitedRange_ ); } #ifdef EULER_WRAPPER_TEST @@ -210,17 +210,15 @@ namespace Fem void setTime (const double t) { BaseType::setTime(t); -#if HAVE_DUNE_FEMPY // update model times (only if time method is available on these models) //! TODO problem without virtualization advection_.setTime(t); - //! TODO problem without virtualization diffusion_.setTime(t); + //! TODO problem without virtualization diffusion().setTime(t); ::detail::CallSetTime< AdvectionModelType, ::detail::CheckTimeMethod< AdvectionModelType >::value > - ::setTime( const_cast< AdvectionModelType& > (advection_), t ); + ::setTime( const_cast< AdvectionModelType& > (advection()), t ); ::detail::CallSetTime< DiffusionModelType, ::detail::CheckTimeMethod< DiffusionModelType >::value > - ::setTime( const_cast< DiffusionModelType& > (diffusion_), t ); -#endif + ::setTime( const_cast< DiffusionModelType& > (diffusion()), t ); } double gamma () const { return problem_.gamma(); } @@ -229,9 +227,9 @@ namespace Fem void setEntity( const Entity& entity ) const { if( hasAdvection ) - advection_.init( entity ); + advection().init( entity ); if( hasDiffusion ) - diffusion_.init( entity ); + diffusion().init( entity ); } inline bool hasStiffSource() const { return AdditionalType::hasStiffSource; } @@ -242,8 +240,8 @@ namespace Fem void obtainBounds( RangeType& globalMin, RangeType& globalMax) const { - globalMin = 0; - globalMax = std::numeric_limits<double>::max(); + assert( hasAdvection ); + advection().obtainBounds(globalMin, globalMax); } bool isConstant( const RangeType& min, const RangeType& max ) const @@ -259,7 +257,7 @@ namespace Fem RangeType & s) const { assert( hasDiffusion ); - diffusion_.source( local.quadraturePoint(), u, du, s ); + diffusion().source( local.quadraturePoint(), u, du, s ); return 0; } @@ -271,7 +269,7 @@ namespace Fem RangeType& s) const { assert( hasAdvection ); - advection_.source( local.quadraturePoint(), u, du, s ); + advection().source( local.quadraturePoint(), u, du, s ); return 0; } @@ -282,7 +280,7 @@ namespace Fem JacobianRangeType& result ) const { assert( hasAdvection ); - advection_.diffusiveFlux( local.quadraturePoint(), u, du, result ); + advection().diffusiveFlux( local.quadraturePoint(), u, du, result ); } template <class LocalEvaluation> @@ -292,7 +290,7 @@ namespace Fem { if( hasDiffusion ) { - maxValue = diffusion_.diffusionTimeStep( local.entity(), local.quadraturePoint(), 0.0, u ); + maxValue = diffusion().diffusionTimeStep( local.entity(), local.quadraturePoint(), 0.0, u ); } } @@ -301,7 +299,7 @@ namespace Fem const T& circumEstimate, const RangeType& u ) const { - return diffusion_.diffusionTimeStep( local.entity(), local.quadraturePoint(), circumEstimate, u ); + return diffusion().diffusionTimeStep( local.entity(), local.quadraturePoint(), circumEstimate, u ); } // is not used @@ -314,7 +312,7 @@ namespace Fem assert( hasAdvection ); assert( 0 ); // if this is used we have to check if this is correct // TODO: u != ubar and du != dubar - advection_.linDiffusiveFlux( u, du, local.quadraturePoint(), u, du, A); + advection().linDiffusiveFlux( u, du, local.quadraturePoint(), u, du, A); } template <class LocalEvaluation> @@ -329,7 +327,7 @@ namespace Fem RangeType u; // fake return variable const int id = getBoundaryId( local ); // the following fails since is is called with - return advection_.hasBoundaryValue(id, time(), local.entity(), local.position(), u, u); + return advection().hasBoundaryValue(id, time(), local.entity(), local.position(), u, u); } // return uRight for insertion into the numerical flux @@ -342,7 +340,7 @@ namespace Fem #ifndef NDEBUG const bool isDirichlet = #endif - advection_.boundaryValue(id, time(), local.entity(), local.quadraturePoint(), + advection().boundaryValue(id, time(), local.entity(), local.quadraturePoint(), local.intersection().unitOuterNormal( local.localPosition() ), uLeft, uRight); assert( isDirichlet ); @@ -363,7 +361,7 @@ namespace Fem #ifndef NDEBUG const bool isFluxBnd = #endif - advection_.boundaryFlux(id, time(), local.entity(), local.quadraturePoint(), normal, uLeft, gLeft); + advection().boundaryFlux(id, time(), local.entity(), local.quadraturePoint(), normal, uLeft, gLeft); gLeft *= len; assert( isFluxBnd ); return 0; // TODO: do something better here @@ -376,7 +374,7 @@ namespace Fem JacobianRangeType& diff ) const { assert( hasDiffusion ); - diffusion_.diffusiveFlux( local.quadraturePoint(), u, du, diff); + diffusion().diffusiveFlux( local.quadraturePoint(), u, du, diff); } @@ -395,7 +393,7 @@ namespace Fem #ifndef NDEBUG const bool isFluxBnd = #endif - diffusion_.diffusionBoundaryFlux(id, time(), local.entity(), local.quadraturePoint(), normal, uLeft, jacLeft, gLeft); + diffusion().diffusionBoundaryFlux(id, time(), local.entity(), local.quadraturePoint(), normal, uLeft, jacLeft, gLeft); gLeft *= len; assert( isFluxBnd ); return 0; // QUESTION: do something better here? Yes, return time step restriction if possible @@ -411,7 +409,7 @@ namespace Fem // TODO: add a max speed for the diffusion time step control // this needs to be added in diffusionTimeStep assert( hasAdvection ); - advspeed = advection_.maxSpeed( time(), local.entity(), local.quadraturePoint(), unitNormal, u ); + advspeed = advection().maxSpeed( time(), local.entity(), local.quadraturePoint(), unitNormal, u ); totalspeed = advspeed; } @@ -425,7 +423,7 @@ namespace Fem inline DomainType velocity (const LocalEvaluation& local, RangeType& u) const { - return advection_.velocity( time(), local.entity(), local.quadraturePoint(), u ); + return advection().velocity( time(), local.entity(), local.quadraturePoint(), u ); } ///////////////////////////////////////////////////////////////// @@ -437,7 +435,7 @@ namespace Fem const RangeType& u, DomainType& velocity) const { - velocity = advection_.velocity( time(), en, x, u ); + velocity = advection().velocity( time(), en, x, u ); } // we have physical check for this model @@ -452,7 +450,7 @@ namespace Fem const DomainType& x, const RangeType& u) const { - return advection_.physical( entity, x, u ) > 0; + return advection().physical( entity, x, u ) > 0; } // adjust average value if necessary @@ -463,7 +461,7 @@ namespace Fem RangeType& u ) const { // nothing to be done here for this test case - advection_.adjustAverageValue( entity, xLocal, u ); + advection().adjustAverageValue( entity, xLocal, u ); } // calculate jump between left and right value @@ -474,7 +472,7 @@ namespace Fem const RangeType& uRight, RangeType& jump) const { - jump = advection_.jump( it, x, uLeft, uRight ); + jump = advection().jump( it, x, uLeft, uRight ); } // calculate jump between left and right value @@ -485,7 +483,7 @@ namespace Fem const RangeType& uRight, RangeType& indicator) const { - indicator = advection_.jump( it, x, uLeft, uRight ); + indicator = advection().jump( it, x, uLeft, uRight ); } // misc for eoc calculation @@ -495,8 +493,13 @@ namespace Fem } protected: - const AdvectionModelType& advection_; - const DiffusionModelType& diffusion_; + const AdvectionModelType& advection () const { return advection_; } + const DiffusionModelType& diffusion () const { return diffusion_; } + + // store a copy of the models here for thread parallel runs + // where we need class variables to be thread safe + AdvectionModelType advection_; + DiffusionModelType diffusion_; const ProblemType& problem_; LimitedRangeType limitedRange_; diff --git a/dune/fem-dg/operator/dg/CMakeLists.txt b/dune/fem-dg/operator/dg/CMakeLists.txt index 32a1bc6768f3be52fa16629000f1e3e381d20171..504bdc9b28099bdd78985769e4b269981de0982d 100644 --- a/dune/fem-dg/operator/dg/CMakeLists.txt +++ b/dune/fem-dg/operator/dg/CMakeLists.txt @@ -1 +1 @@ -dune_install( discretemodelcommon.hh fluxdiscretemodel.hh fluxoperator.hh operatorbase.hh operatortraits.hh primaldiscretemodel.hh primaloperator.hh) +dune_install( defaultquadrature.hh discretemodelcommon.hh fluxdiscretemodel.hh fluxoperator.hh operatorbase.hh operatortraits.hh primaldiscretemodel.hh primaloperator.hh) diff --git a/dune/fem-dg/operator/dg/defaultquadrature.hh b/dune/fem-dg/operator/dg/defaultquadrature.hh new file mode 100644 index 0000000000000000000000000000000000000000..dd73d6af3ad848632dcdaaec05c69ef22b6a9b63 --- /dev/null +++ b/dune/fem-dg/operator/dg/defaultquadrature.hh @@ -0,0 +1,83 @@ +#ifndef DUNE_FEMDG_DEFAULTQUADRATURE_HH +#define DUNE_FEMDG_DEFAULTQUADRATURE_HH + +#include <dune/fem/space/lagrange.hh> +#include <dune/fem/quadrature/defaultquadratures.hh> +#include <dune/fem/quadrature/interpolationquadrature.hh> + +namespace Dune +{ + namespace Fem + { + + struct DefaultQuadratureGauss + { + template <class F, int d> + using DefaultQuadratureTraits = Dune::Fem::DefaultQuadratureTraits< F, d >; + + static int volumeOrder( const int polOrder ) { return 2 * polOrder; } + static int faceOrder( const int polOrder ) { return 2 * polOrder + 1; } + }; + + template < class Space > + struct DefaultQuadrature : public DefaultQuadratureGauss + { + }; + +#if HAVE_DUNE_LOCALFUNCTIONS + struct DefaultQuadratureGaussLobatto + { + template <class F, int d> + using DefaultQuadratureTraits = Dune::Fem::GaussLobattoQuadratureTraits< F, d >; + + static int volumeOrder( const int polOrder ) { return (polOrder > 0) ? (2 * polOrder - 1) : 0; } + static int faceOrder( const int polOrder ) { return (polOrder > 0) ? (2 * polOrder - 1) : 0; } + }; + + template < class FunctionSpace, class GridPart, unsigned int order, template< class > class Storage > + struct DefaultQuadrature< Dune::Fem::FixedOrderDGLagrangeSpace< FunctionSpace, GridPart, order, Dune::GaussLobattoPointSet, Storage > > + : public DefaultQuadratureGaussLobatto + { + }; + + template< class LFEMap > + struct DefaultQuadratureSpec : DefaultQuadratureGauss + {}; + + template< class FunctionSpace, class GridPart, unsigned int order > + struct DefaultQuadratureSpec< FixedOrderLagrangeFiniteElementMap< FunctionSpace, GridPart, order, Dune::GaussLobattoPointSet > > + : public DefaultQuadratureGaussLobatto + { + }; + + struct DefaultQuadratureGaussLegendre + { + template <class F, int d> + using DefaultQuadratureTraits = Dune::Fem::GaussLegendreQuadratureTraits< F, d >; + + static int volumeOrder( const int polOrder ) { return 2 * polOrder + 1; } + static int faceOrder( const int polOrder ) { return 2 * polOrder + 1; } + }; + + template < class FunctionSpace, class GridPart, unsigned int order, template< class > class Storage > + struct DefaultQuadrature< Dune::Fem::FixedOrderDGLagrangeSpace< FunctionSpace, GridPart, order, Dune::GaussLegendrePointSet, Storage > > + : public DefaultQuadratureGaussLegendre + {}; + + template< class FunctionSpace, class GridPart, unsigned int order > + struct DefaultQuadratureSpec< FixedOrderLagrangeFiniteElementMap< FunctionSpace, GridPart, order, Dune::GaussLegendrePointSet > > + : public DefaultQuadratureGaussLegendre + { + }; + + template< class LFEMap, class FunctionSpace, template< class > class Storage > + struct DefaultQuadrature< DiscontinuousLocalFiniteElementSpace< LFEMap, FunctionSpace, Storage > > + : public DefaultQuadratureSpec< LFEMap > + { + }; + +#endif + } +} + +#endif diff --git a/dune/fem-dg/operator/dg/dgpyoperator.hh b/dune/fem-dg/operator/dg/dgpyoperator.hh index 661ecd7d045393f3a2ff0b8679bb64346f23acea..7239d322390f4e9cb23946ecab812aaf288c5c30 100644 --- a/dune/fem-dg/operator/dg/dgpyoperator.hh +++ b/dune/fem-dg/operator/dg/dgpyoperator.hh @@ -8,6 +8,10 @@ #include <dune/fem/solver/timeprovider.hh> #include <dune/fem/operator/common/spaceoperatorif.hh> +#include <dune/fem/space/lagrange.hh> +#include <dune/fem/quadrature/interpolationquadrature.hh> + + #include <dune/fem-dg/algorithm/evolution.hh> // dune-fem-dg includes @@ -18,10 +22,10 @@ #include <dune/fem-dg/models/modelwrapper.hh> #include <dune/fem-dg/misc/algorithmcreatorselector.hh> #include <dune/fem-dg/operator/adaptation/estimator.hh> +#include <dune/fem-dg/operator/dg/defaultquadrature.hh> -#if HAVE_DUNE_FEMPY +// this is part of dune-fem now #include <dune/fempy/quadrature/fempyquadratures.hh> -#endif namespace Dune { @@ -79,14 +83,16 @@ namespace Fem typedef typename DiffusionFluxSelector< ModelType, DiscreteFunctionSpaceType, diffFluxId, formId >::type DiffusionFluxType; - typedef DefaultOperatorTraits< ModelType, DestinationType, AdvectionFluxType, DiffusionFluxType, - std::tuple<>, typename DiscreteFunctionSpaceType::FunctionSpaceType, -#if HAVE_DUNE_FEMPY - Dune::FemPy::FempyQuadratureTraits, // use quadratures from dune-fempy -#else - Dune::Fem::DefaultQuadratureTraits, -#endif - threading > OpTraits; + typedef typename std::conditional< Additional::defaultQuadrature, + DefaultOperatorTraits< ModelType, DestinationType, AdvectionFluxType, DiffusionFluxType, + std::tuple<>, typename DiscreteFunctionSpaceType::FunctionSpaceType, + DefaultQuadrature< DiscreteFunctionSpaceType >::template DefaultQuadratureTraits, + threading>, + // fempy quadratures + DefaultOperatorTraits< ModelType, DestinationType, AdvectionFluxType, DiffusionFluxType, + std::tuple<>, typename DiscreteFunctionSpaceType::FunctionSpaceType, + Dune::FemPy::FempyQuadratureTraits, + threading> > ::type OpTraits; typedef AdvectionDiffusionOperatorSelector< OpTraits, formId, limiterId > OperatorSelectorType ; @@ -98,6 +104,7 @@ namespace Fem typedef Estimator< DestinationType, typename ModelType::ProblemType > GradientIndicatorType ; typedef AdaptIndicator< IndicatorType, GradientIndicatorType > AdaptIndicatorType; + typedef typename FullOperatorType :: TroubledCellIndicatorType TroubledCellIndicatorType; // solver selection, available fem, istl, petsc, ... typedef typename MatrixFreeSolverSelector< solverId, symmetric > :: template LinearInverseOperatorType< DiscreteFunctionSpaceType, DiscreteFunctionSpaceType > LinearSolverType ; @@ -114,9 +121,9 @@ namespace Fem model_( advectionModel, diffusionModel, problem_ ), advFluxPtr_(), advFlux_( advectionFlux( parameter, std::integral_constant< bool, fluxIsUserDefined >() )), - fullOperator_( space.gridPart(), model_, advFlux_, extra_, name(), parameter ), - explOperator_( space.gridPart(), model_, advFlux_, extra_, name(), parameter ), - implOperator_( space.gridPart(), model_, advFlux_, extra_, name(), parameter ), + fullOperator_( space.gridPart(), model_, advFlux_, extra_, "full", parameter ), + explOperator_( space.gridPart(), model_, advFlux_, extra_, "expl", parameter ), + implOperator_( space.gridPart(), model_, advFlux_, extra_, "impl", parameter ), adaptIndicator_( space, model_, advFlux_, extra_, name()+"_adaptind", parameter ) { } @@ -132,9 +139,9 @@ namespace Fem model_( advectionModel, diffusionModel, problem_ ), advFluxPtr_(), advFlux_( advFlux ), - fullOperator_( space.gridPart(), model_, advFlux_, extra_, name(), parameter ), - explOperator_( space.gridPart(), model_, advFlux_, extra_, name(), parameter ), - implOperator_( space.gridPart(), model_, advFlux_, extra_, name(), parameter ), + fullOperator_( space.gridPart(), model_, advFlux_, extra_, "full", parameter ), + explOperator_( space.gridPart(), model_, advFlux_, extra_, "expl", parameter ), + implOperator_( space.gridPart(), model_, advFlux_, extra_, "impl", parameter ), adaptIndicator_( space, model_, advFlux_, extra_, name()+"_adaptind", parameter ) { } @@ -183,6 +190,13 @@ namespace Fem } } + void setTroubledCellIndicator(TroubledCellIndicatorType indicator) + { + fullOperator_.setTroubledCellIndicator(indicator); + explOperator_.setTroubledCellIndicator(indicator); + } + + /** \copydoc SpaceOperatorInterface::setTime */ void setTime( const double time ) { @@ -191,6 +205,23 @@ namespace Fem double timeStepEstimate() const { return fullOperator_.timeStepEstimate(); } + //! return number of interior elements visited by the operator + inline size_t gridSizeInterior() const + { + size_t elem = std::max( fullOperator_.numberOfElements(), + explOperator_.numberOfElements() ); + + // this can occur if element size if requested + // before operator had been applied + if( elem == 0 ) + { + const auto end = space_.end(); + size_t elem = 0; + for( auto it = space_.begin(); it != end; ++it, ++elem ); + } + return elem; + } + //// End Methods from SpaceOperatorInterface ///// protected: @@ -222,7 +253,6 @@ namespace Fem mutable double fixedTimeStep_ ; mutable bool initialized_; - }; } // end namespace Fem diff --git a/dune/fem-dg/operator/dg/discretemodelcommon.hh b/dune/fem-dg/operator/dg/discretemodelcommon.hh index cdf1686e2fff36189940333fd02e41adcc8ec058..92006147073e8dc6dbc75b94b935accc5366636f 100644 --- a/dune/fem-dg/operator/dg/discretemodelcommon.hh +++ b/dune/fem-dg/operator/dg/discretemodelcommon.hh @@ -304,7 +304,11 @@ namespace Fem return hasBndValue; } - const ModelType& model_; + // store an instance here so that for thread parallel + // runs class variables are thread private since discrete models + // are thread private + ModelType model_; + const AdvectionFluxType& numflux_; mutable RangeType uBnd_; }; /*@LST0E@*/ diff --git a/dune/fem-dg/operator/dg/operatorbase.hh b/dune/fem-dg/operator/dg/operatorbase.hh index 1a9521a7dfa5f169ccdc3f0dfd07dcf255204f59..74bef4e86e2ae64098cf3dda5ac5f80653ea9ceb 100644 --- a/dune/fem-dg/operator/dg/operatorbase.hh +++ b/dune/fem-dg/operator/dg/operatorbase.hh @@ -92,6 +92,11 @@ namespace Fem public: using BaseType::operator () ; + // dummy method for a troubled cell indicator to be passed to the + // limited advection operator + typedef void* TroubledCellIndicatorType; + void setTroubledCellIndicator(TroubledCellIndicatorType indicator) {} + typedef typename Traits::ModelType ModelType; typedef typename ModelType::ProblemType ProblemType ; diff --git a/dune/fem-dg/operator/dg/operatortraits.hh b/dune/fem-dg/operator/dg/operatortraits.hh index 55b21a764661416243bda9653c1f6f7df2dc2c52..23f4ac9a2cfd4f12e4d554ecb4ffe00f0c9b5363 100644 --- a/dune/fem-dg/operator/dg/operatortraits.hh +++ b/dune/fem-dg/operator/dg/operatortraits.hh @@ -1,56 +1,29 @@ #ifndef DUNE_FEM_DG_OPERATORTRAITS_HH #define DUNE_FEM_DG_OPERATORTRAITS_HH +#include <dune/fem/quadrature/dunequadratures.hh> #include <dune/fem/quadrature/cachingquadrature.hh> +#include <dune/fem/quadrature/interpolationquadrature.hh> #include <dune/fem-dg/operator/fluxes/diffusion/fluxes.hh> #include <dune/fem-dg/operator/adaptation/adaptation.hh> #include <dune/fem/space/finitevolume/space.hh> #include <dune/fem/function/adaptivefunction/adaptivefunction.hh> + #include <dune/fem-dg/operator/fluxes/diffusion/parameters.hh> + +#if HAVE_DUNE_POLYGONGRID +#include <dune/polygongrid/declaration.hh> +#endif + +#if HAVE_OPM_GRID +#include <opm/grid/polyhedralgrid/declaration.hh> +#endif // #if HAVE_OPM_GRID + namespace Dune { namespace Fem { - - // traits for the operator passes - template< class GridPart, - int polOrd, - class ModelImp, - class DiscreteFunctionImp, - class AdvectionFluxImp, - class DiffusionFluxImp, - class LimiterIndicatorFunctionImp, - class AdaptationHandlerImp, - class ExtraParameterTupleImp = std::tuple<>, - template <class F, int d> class QuadratureTraits = Dune::Fem::DefaultQuadratureTraits - > - struct OperatorTraits - { - typedef GridPart GridPartType; - typedef typename GridPartType::GridType GridType; - - typedef ModelImp ModelType; - typedef AdvectionFluxImp AdvectionFluxType; - typedef DiffusionFluxImp DiffusionFluxType; - - // polynomial order of ansatz space - static const int polynomialOrder = polOrd; - - typedef DiscreteFunctionImp DestinationType ; - //static_assert( std::is_same<typename ModelType::RangeType, typename DiscreteFunctionType::RangeType>::value, "range type does not fit."); - typedef typename DestinationType::DiscreteFunctionSpaceType DiscreteFunctionSpaceType; - - typedef Fem::CachingQuadrature< GridPartType, 0, QuadratureTraits > VolumeQuadratureType; - typedef Fem::CachingQuadrature< GridPartType, 1, QuadratureTraits > FaceQuadratureType; - - typedef LimiterIndicatorFunctionImp LimiterIndicatorType; - - typedef AdaptationHandlerImp AdaptationHandlerType ; - - typedef ExtraParameterTupleImp ExtraParameterTupleType; - }; - // traits for the operator passes template< class ModelImp, class DiscreteFunctionImp, @@ -58,7 +31,7 @@ namespace Fem class DiffusionFluxImp, class ExtraParameterTupleImp = std::tuple<>, class AdaptationHandlerFunctionSpaceImp = typename DiscreteFunctionImp::DiscreteFunctionSpaceType::FunctionSpaceType, - template <class F, int d> class QuadratureTraits = Dune::Fem::DefaultQuadratureTraits, + template <class F, int d> class QuadratureTraits = DefaultQuadrature< typename DiscreteFunctionImp::DiscreteFunctionSpaceType >::template DefaultQuadratureTraits, bool enableThreaded = // static cmake variables provided by dune-fem #ifdef USE_SMP_PARALLEL @@ -89,9 +62,8 @@ namespace Fem static_assert( std::is_same<typename ModelType::RangeType, typename DestinationType::RangeType>::value, "range type does not fit."); - // default quadrature selection should be CachingQuadrature - template <class DFS> + template <class Grid, bool caching> struct SelectQuadrature { typedef Fem::CachingQuadrature< GridPartType, 0, QuadratureTraits > VolumeQuadratureType; @@ -100,15 +72,46 @@ namespace Fem // if selected discrete function space has no caching storage, // then select ElementQuadrature, and not CachingQuadrature - template <class FS, class GP, int polOrd, - template <class, class, int, template <class> class> class DFS> - struct SelectQuadrature< DFS< FS, GP, polOrd, Dune::Fem::SimpleStorage > > + // also, if the grid is polygonal or polyhedral + // CachingQuadarature cannot be used + template <class Grid> + struct SelectQuadrature< Grid, false > { typedef Fem::ElementQuadrature< GridPartType, 0, QuadratureTraits > VolumeQuadratureType; typedef Fem::ElementQuadrature< GridPartType, 1, QuadratureTraits > FaceQuadratureType; }; - typedef SelectQuadrature< DiscreteFunctionSpaceType > SelectQuadratureType; + template <class Grid> + struct CheckGrid { static const bool value = true; }; + + // also, if the grid is polygonal or polyhedral + // CachingQuadarature cannot be used +#if HAVE_DUNE_POLYGONGRID + template <class ct> + struct CheckGrid< Dune::PolygonGrid< ct > > { static const bool value = false; }; +#endif + +#if HAVE_OPM_GRID + template <int dim, int dimworld, class ct> + struct CheckGrid< Dune::PolyhedralGrid< dim, dimworld, ct > > { static const bool value = false; }; +#endif + + template <class DFS> + struct CheckSpace { static const bool value = true; }; + + // if selected discrete function space has no caching storage, + // then select ElementQuadrature, and not CachingQuadrature + template <class FS, class GP, int polOrd, + template <class, class, int, template <class> class> class DFS> + struct CheckSpace< DFS< FS, GP, polOrd, Dune::Fem::SimpleStorage > > + { + static const bool value = false; + }; + + // define quad selector which contains the correct types for quadratures + typedef SelectQuadrature< GridType, + CheckSpace< DiscreteFunctionSpaceType > :: value && + CheckGrid < GridType > :: value > SelectQuadratureType; typedef typename SelectQuadratureType::VolumeQuadratureType VolumeQuadratureType; typedef typename SelectQuadratureType::FaceQuadratureType FaceQuadratureType; diff --git a/dune/fem-dg/operator/dg/primaloperator.hh b/dune/fem-dg/operator/dg/primaloperator.hh index 8bd6882b824d5beebe45ac481bd40a1ef5e5470e..8946d663ec9b7344b2aab3627f21d1bfc9c47e79 100644 --- a/dune/fem-dg/operator/dg/primaloperator.hh +++ b/dune/fem-dg/operator/dg/primaloperator.hh @@ -320,6 +320,7 @@ namespace Fem // Destination of Limiter can differ from the operators destination type depending on FV or DG // standard limiter and scaling limiter typedef Limiter< DestinationType, LimiterDestinationType, LimiterDiscreteModelType, threading, ModelType::scalingLimiter > LimiterType; + typedef typename LimiterType :: TroubledCellIndicatorType TroubledCellIndicatorType; // select non-blocking communication handle typedef typename @@ -382,17 +383,20 @@ namespace Fem , indicator_() , diffFlux_( gridPart_, model_, DGPrimalDiffusionFluxParameters( ParameterKey::generate( name, "dgdiffusionflux." ), parameter ) ) , discreteModel1_( model_, advFlux_, diffFlux_ ) - , limiter_( space_, limiterSpace_, model_ ) + , limiter_( space_, limiterSpace_, model_, parameter ) , pass0_() , pass2_( discreteModel1_, pass0_, space_ ) , counter_(0) , limitTime_( 0 ) , computeTime_( 0 ) + , name_( name ) + , verbose_( Dune::Fem::Parameter::verbose() ) // ||parameter.verbose() ) { } virtual ~DGLimitedAdvectionOperator() { - std::cout << "~DGLimitedAdvectionOperator: op calls = " << counter_ << " T_l = " << limitTime_ << " T_op = " << computeTime_ << std::endl; + if( verbose_ ) + std::cout << "~DGLimitedAdvectionOperator("<<name_<<"): op calls = " << counter_ << " T_l = " << limitTime_ << " T_op = " << computeTime_ << std::endl; } void activateLinear() const { @@ -460,7 +464,7 @@ namespace Fem inline size_t numberOfElements () const { - return pass2_.numberOfElements(); + return std::max( pass2_.numberOfElements(), limiter_.numberOfElements() ); } /* @@ -481,6 +485,11 @@ namespace Fem LimiterCall< LimiterType, polOrd >::limit( limiter_, arg, U ); } + void setTroubledCellIndicator(TroubledCellIndicatorType indicator) + { + limiter_.setTroubledCellIndicator(indicator); + } + void printmyInfo(std::string filename) const { std::ostringstream filestream; @@ -513,11 +522,11 @@ namespace Fem } protected: - GridPartType& gridPart_; - const ModelType& model_; - const AdvectionFluxType& advFlux_; + GridPartType& gridPart_; + const ModelType& model_; + const AdvectionFluxType& advFlux_; - SpaceType space_; + SpaceType space_; LimiterSpaceType limiterSpace_; mutable LimiterDestinationType limitedU_; @@ -539,6 +548,9 @@ namespace Fem mutable double limitTime_; mutable double computeTime_; + + std::string name_; + const bool verbose_; }; diff --git a/dune/fem-dg/operator/fluxes/advection/llfadvflux.hh b/dune/fem-dg/operator/fluxes/advection/llfadvflux.hh index 593ac493f3d775a14eb9a75ae36de79a8a4e1e0e..f7326d377c5c1db5070a92035901b840eacf1391 100644 --- a/dune/fem-dg/operator/fluxes/advection/llfadvflux.hh +++ b/dune/fem-dg/operator/fluxes/advection/llfadvflux.hh @@ -70,20 +70,26 @@ namespace Fem const auto faceArea = normal.two_norm(); normal *= 1./faceArea; + double maxspeedl, maxspeedr; + double viscparal, viscparar; + FluxRangeType anaflux; + // assume that model is set to left entity + model_.setEntity( left.entity() ); + model_.advection( left, uLeft, jacLeft, anaflux ); // set gLeft anaflux.mv( normal, gLeft ); + model_.maxSpeed( left, normal, uLeft, viscparal, maxspeedl ); + + model_.setEntity( right.entity() ); + model_.advection( right, uRight, jacRight, anaflux ); // add to gLeft anaflux.umv( normal, gLeft ); - double maxspeedl, maxspeedr; - double viscparal, viscparar; - - model_.maxSpeed( left, normal, uLeft, viscparal, maxspeedl ); model_.maxSpeed( right, normal, uRight, viscparar, maxspeedr ); const double maxspeed = std::max( maxspeedl, maxspeedr); @@ -99,6 +105,8 @@ namespace Fem // conservation property gRight = gLeft; + model_.setEntity( left.entity() ); + return maxspeed * faceArea; } }; diff --git a/dune/fem-dg/operator/fluxes/diffusion/dgprimalfluxes.hh b/dune/fem-dg/operator/fluxes/diffusion/dgprimalfluxes.hh index 764fd1bc05798bc7028a9acdc92f6ba779293b54..f9c7e4be3c626a4c4c0011889c1f6f6c3e04c154 100644 --- a/dune/fem-dg/operator/fluxes/diffusion/dgprimalfluxes.hh +++ b/dune/fem-dg/operator/fluxes/diffusion/dgprimalfluxes.hh @@ -11,6 +11,8 @@ #include <dune/fem/storage/dynamicarray.hh> #include <dune/fem-dg/pass/dgmasspass.hh> +#include <dune/fem-dg/operator/dg/defaultquadrature.hh> + #include "fluxbase.hh" namespace Dune @@ -62,7 +64,8 @@ namespace Fem typedef typename DiscreteGradientSpaceType::RangeType GradientType; typedef Fem::TemporaryLocalFunction< DiscreteGradientSpaceType > LiftingFunctionType; - typedef Fem::CachingQuadrature< GridPartType, 0> VolumeQuadratureType ; + typedef Fem::CachingQuadrature< GridPartType, 0, + DefaultQuadrature<DiscreteGradientSpaceType>::template DefaultQuadratureTraits> VolumeQuadratureType ; typedef Fem::LocalMassMatrix < DiscreteGradientSpaceType, VolumeQuadratureType > LocalMassMatrixType; @@ -96,7 +99,7 @@ namespace Fem #ifdef USE_CACHED_INVERSE_MASSMATRIX , localMassMatrix_( InverseMassProviderType :: getObject( KeyType( gradSpc_.gridPart() ) ) ) #else - , localMassMatrix_( gradSpc_, 2*gradSpc_.order() ) + , localMassMatrix_( gradSpc_, [this](const int order) { return DefaultQuadrature<DiscreteGradientSpaceType>::volumeOrder(order); } ) #endif , isInitialized_( 0 ) { diff --git a/dune/fem-dg/operator/limiter/indicatorbase.hh b/dune/fem-dg/operator/limiter/indicatorbase.hh new file mode 100644 index 0000000000000000000000000000000000000000..10edaf26ce387cf429454cb1a5ea2dbffdc4ae0a --- /dev/null +++ b/dune/fem-dg/operator/limiter/indicatorbase.hh @@ -0,0 +1,13 @@ +#pragma once +namespace Dune +{ + namespace Fem + { + template< class DiscreteFunction > + struct TroubledCellIndicatorBase + { + typedef typename DiscreteFunction::LocalFunctionType LocalFunctionType; + virtual double operator()( const DiscreteFunction& U, const LocalFunctionType& uEn ) const = 0; + }; + } +} diff --git a/dune/fem-dg/operator/limiter/limiter.hh b/dune/fem-dg/operator/limiter/limiter.hh index 5dafcdb848d263c6282abcc0e8f4bd4a663081ab..804e089f180a37385a0449b78f179f6fae7a2e92 100644 --- a/dune/fem-dg/operator/limiter/limiter.hh +++ b/dune/fem-dg/operator/limiter/limiter.hh @@ -115,9 +115,12 @@ namespace Fem ThreadPass < InnerPassType, ThreadIteratorType, true>, InnerPassType > :: type LimitPassType; - typedef typename LimiterDiscreteModelType::IndicatorType IndicatorType; + typedef typename LimiterDiscreteModelType :: IndicatorType IndicatorType; typedef typename IndicatorType :: DiscreteFunctionSpaceType IndicatorSpaceType; + // InnerPassType == LimitPass in case of threading + typedef typename InnerPassType :: TroubledCellIndicatorType TroubledCellIndicatorType; + public: Limiter( const DomainSpaceType& domainSpace, const double lowerBound, const double upperBound ) @@ -133,15 +136,16 @@ namespace Fem Limiter( const DomainSpaceType& domainSpace, const RangeSpaceType& rangeSpace, - const ModelType& model ) + const ModelType& model, + const Dune::Fem::ParameterReader ¶meter = Dune::Fem::Parameter::container() ) : domainSpace_( domainSpace ) , rangeSpace_( rangeSpace ) , indicatorSpace_( domainSpace_.gridPart() ) , indicator_("indicator", indicatorSpace_ ) , model_( model ) - , discreteModel_( model_, domainSpace_.order() ) + , discreteModel_( model_, domainSpace_.order(), parameter ) , startPass_() - , limitPass_( discreteModel_ , startPass_, rangeSpace_ ) + , limitPass_( discreteModel_ , startPass_, rangeSpace_, parameter ) { discreteModel_.setIndicator( &indicator_ ); @@ -159,6 +163,11 @@ namespace Fem limitPass_( arg, dest ); } + void setTroubledCellIndicator(TroubledCellIndicatorType indicator) + { + limitPass_.setTroubledCellIndicator(indicator); + } + bool activated( const EntityType& entity ) const { return std::abs( indicator_.localFunction( entity )[ 0 ] ) > 0.0; @@ -173,6 +182,11 @@ namespace Fem return limitPass_.computeTimeSteps(); } + inline size_t numberOfElements () const + { + return limitPass_.numberOfElements(); + } + private: Limiter( const Limiter& ); diff --git a/dune/fem-dg/operator/limiter/limiterdiscretemodel.hh b/dune/fem-dg/operator/limiter/limiterdiscretemodel.hh index 2601492793459f8a753939ea42b9fb1c498f9be7..a8796ff78f8e03511340243af2bfcec504538e8e 100644 --- a/dune/fem-dg/operator/limiter/limiterdiscretemodel.hh +++ b/dune/fem-dg/operator/limiter/limiterdiscretemodel.hh @@ -439,12 +439,13 @@ namespace Fem //! returns true, if we have an inflow boundary template <class ArgumentTuple> bool checkDirection(const IntersectionType& it, - const double time, const FaceLocalDomainType& x, + const FaceLocalDomainType& xFace, + const LocalDomainType& xLocal, const ArgumentTuple& uLeft) const { // evaluate velocity - model_.velocity(this->inside(), this->inside().geometry().local( it.geometry().global(x) ), uLeft[ uVar ], velocity_); - return checkDirection(it, x, velocity_); + model_.velocity(this->inside(), xLocal, uLeft[ uVar ], velocity_); + return checkDirection(it, xFace, velocity_); } protected: diff --git a/dune/fem-dg/operator/limiter/limiterutility.hh b/dune/fem-dg/operator/limiter/limiterutility.hh index 899c33368a9c6e70b76c1fb3e0b805b99bc31a75..1043f1c155c9d6d2c4def8ccd182dce7e17828f3 100644 --- a/dune/fem-dg/operator/limiter/limiterutility.hh +++ b/dune/fem-dg/operator/limiter/limiterutility.hh @@ -287,13 +287,14 @@ namespace Fem } - template <class GridPart, class Entity, class EvalAverage> + template <class GridPart, class Entity, class EvalAverage, class LFEn> static void setupNeighborValues( const GridPart& gridPart, const Entity& entity, const EvalAverage& average, const DomainType& entityCenter, const RangeType& entityValue, + const LFEn& lfEn, const bool StructuredGrid, Flags& flags, std::vector< DomainType >& baryCenters, @@ -320,7 +321,7 @@ namespace Fem const auto endit = gridPart.iend( entity ); - const bool cartesianGrid = flags.cartesian; + //const bool cartesianGrid = flags.cartesian; // loop over all neighbors for (auto it = gridPart.ibegin( entity ); it != endit; ++it ) @@ -394,7 +395,12 @@ namespace Fem point -= entityCenter; const double length = (point * lambda); - const double factorLength = (cartesianGrid) ? 2.0 * length : length ; + // this version mirrors the point outside of the domain but only + // for Cartesian grids - I think having different behaviour + // depending on the grid not so satisfactory + // const double factorLength = (cartesianGrid) ? 2.0 * length : length ; + // instead put the point onto the boundary + const double factorLength = length ; lambda *= factorLength; assert( lambda.two_norm () > 0 ); @@ -409,7 +415,13 @@ namespace Fem const DomainType pointOnBoundary = lambda + entityCenter; // evaluate data on boundary - if( average.boundaryValue( entity, intersection, interGeo, pointOnBoundary, entityValue, jumpNeighborEntity ) ) + // This version uses the bary center value to construct the + // boundary value + // if( average.boundaryValue( entity, intersection, interGeo, pointOnBoundary, entityValue, jumpNeighborEntity ) ) + // instead evaluate the discrete function directly on the boundary + RangeType enBnd(entityValue); + lfEn.evaluate(entity.geometry().local(pointOnBoundary), enBnd); + if( average.boundaryValue( entity, intersection, interGeo, pointOnBoundary, enBnd, jumpNeighborEntity ) ) { jumpNeighborEntity -= entityValue; } @@ -924,9 +936,9 @@ namespace Fem protected: void printInfo(const std::string& name ) const { - //if( Parameter::verbose() ) + if( Parameter::verbose() ) { - std::cout << "LimiterFunction: " << name << " with epsilon = " << epsilon_ << std::endl; + std::cout << "LimiterFunction (" << name << ") with femdg.limiter.epsilon: " << epsilon_ << std::endl; } } }; diff --git a/dune/fem-dg/operator/limiter/limitpass.hh b/dune/fem-dg/operator/limiter/limitpass.hh index cf1ee086d2a557348177c20a22f4c59d595ec0c4..5605e0e8f3b81c43946a7151fd6adfacdd7e8c2e 100644 --- a/dune/fem-dg/operator/limiter/limitpass.hh +++ b/dune/fem-dg/operator/limiter/limitpass.hh @@ -13,8 +13,6 @@ #include <dune/fem/quadrature/cornerpointset.hh> #include <dune/fem/io/parameter.hh> -#include <dune/fem/operator/1order/localmassmatrix.hh> - #include <dune/fem/space/common/adaptationmanager.hh> #include <dune/fem/space/common/basesetlocalkeystorage.hh> #include <dune/fem/space/common/capabilities.hh> @@ -23,6 +21,7 @@ #include <dune/fem/space/finitevolume.hh> #include <dune/fem/function/adaptivefunction.hh> +#include <dune/fem/function/localfunction/bindable.hh> #include <dune/fem/misc/compatibility.hh> #include <dune/fem/misc/threads/threadmanager.hh> @@ -36,10 +35,10 @@ #include <dune/fem-dg/operator/limiter/limiterdiscretemodel.hh> #include <dune/fem-dg/operator/limiter/lpreconstruction.hh> -#if HAVE_DUNE_OPTIM -#define WANT_DUNE_OPTIM 1 -//#define WANT_DUNE_OPTIM 0 -#endif +#include <dune/fem-dg/operator/limiter/smoothness.hh> +#include <dune/fem-dg/operator/limiter/indicatorbase.hh> + +#include <dune/fem-dg/operator/dg/defaultquadrature.hh> //************************************************************* @@ -88,7 +87,8 @@ namespace Fem // call problem checkDirection const typename BaseType::EntityType &entity = intersection.inside(); - return discreteModel().checkPhysical( entity, entity.geometry().local( intersection.geometry().global( quadrature.localPoint( qp ) ) ), ranges_ ); + //return discreteModel().checkPhysical( entity, entity.geometry().local( intersection.geometry().global( quadrature.localPoint( qp ) ) ), ranges_ ); + return discreteModel().checkPhysical( entity, quadrature.point( qp ), ranges_ ); } // check whether we have inflow or outflow direction @@ -102,7 +102,7 @@ namespace Fem assert( quadPoint_ == qp ); // call checkDirection() on discrete model - return discreteModel().checkDirection( intersection, time(), quadrature.localPoint( qp ), ranges_ ); + return discreteModel().checkDirection( intersection, quadrature.localPoint( qp ), quadrature.point( qp ), ranges_ ); } protected: using BaseType::discreteModel; @@ -253,7 +253,8 @@ namespace Fem typedef AdaptationMethod<GridType> AdaptationMethodType; //! id for choosing admissible linear functions - enum AdmissibleFunctions { DGFunctions = 0, ReconstructedFunctions = 1 , BothFunctions = 2 }; + //! _default refers to muscl(1) on simplices and LP limiter (3) on cubes and polygons + enum AdmissibleFunctions { dgonly = 0, muscl = 1 , muscldg = 2, lp = 3, _default = 4 }; //! returns true if pass is currently active in the pass tree using BaseType :: active ; @@ -261,8 +262,10 @@ namespace Fem //! type of Cartesian grid checker typedef CheckCartesian< GridPartType > CheckCartesianType; + //! function describing an external troubled cell indicator + typedef std::shared_ptr< TroubledCellIndicatorBase<ArgumentFunctionType> > TroubledCellIndicatorType; + protected: -#if WANT_DUNE_OPTIM typedef typename GridPartType :: GridViewType GridViewType ; struct BoundaryValue @@ -280,7 +283,78 @@ namespace Fem }; typedef Dune::FV::LPReconstruction< GridViewType, RangeType, BoundaryValue > LinearProgramming; -#endif + + struct ConstantFunction : + public Dune::Fem::BindableGridFunction< GridPartType, Dune::Dim<dimRange> > + { + typedef Dune::Fem::BindableGridFunction<GridPartType, Dune::Dim<dimRange> > Base; + typedef typename Base::RangeType RangeType; + using Base::Base; + + RangeType value_; + + template <class Quadrature, class RangeArray> + void evaluateQuadrature(const Quadrature& quadrature, RangeArray &values) const + { + const int nop = quadrature.nop(); + values.resize( nop ); + std::fill( values.begin(), values.end(), value_ ); + } + + template <class Point> + void evaluate(const Point &x, typename Base::RangeType &ret) const + { + ret = value_; + } + + bool isConstant() const { return true; } + + unsigned int order() const { return 0; } + std::string name() const { return "LimmitPass::ConstantFunction"; } // needed for output + }; + + struct LinearFunction : public ConstantFunction + { + DomainType center_; + GradientType gradient_; + + typedef ConstantFunction Base; + typedef typename Base::RangeType RangeType; + using Base::Base; + using Base::value_; + + template <class Quadrature, class RangeArray> + void evaluateQuadrature(const Quadrature& quadrature, RangeArray &values) const + { + const int nop = quadrature.nop(); + values.resize( nop ); + for( int qp = 0; qp<nop; ++qp ) + { + evaluate( quadrature[ qp ], values[ qp ] ); + } + } + + template <class Point> + void evaluate(const Point &x, RangeType &ret) const + { + Base::evaluate( x, ret ); + + // get global coordinate + auto point = Base::global( x ); + point -= center_; + + // evaluate linear function + for( int r = 0; r < dimRange; ++r ) + { + ret[ r ] += (gradient_[ r ] * point); + } + } + + bool isConstant() const { return gradient_.infinity_norm() < 1e-10; } + + unsigned int order() const { return 1; } + std::string name() const { return "LimmitPass::LinearFunction"; } // needed for output + }; public: @@ -297,20 +371,39 @@ namespace Fem PreviousPassType& pass, const DiscreteFunctionSpaceType& spc, const int vQ = -1, - const int fQ = -1 ) : + const int fQ = -1, + const bool verbose = Dune::Fem::Parameter::verbose() ) + : LimitDGPass(problem, pass, spc, Dune::Fem::Parameter::container(), vQ, fQ, verbose ) + {} + + //- Public methods + /** \brief constructor + * + * \param problem Actual problem definition (see problem.hh) + * \param pass Previous pass + * \param spc Space belonging to the discrete function local to this pass + * \param parameter Parameter reader for dynamic parameters + * \param vQ order of volume quadrature + * \param fQ order of face quadrature + */ + + LimitDGPass(DiscreteModelType& problem, + PreviousPassType& pass, + const DiscreteFunctionSpaceType& spc, + const Dune::Fem::ParameterReader ¶meter = Dune::Fem::Parameter::container(), + const int vQ = -1, + const int fQ = -1, + const bool verbose = Dune::Fem::Parameter::verbose() ) : BaseType(pass, spc), - caller_( 0 ), + caller_(), discreteModel_(problem), currentTime_(0.0), arg_(0), dest_(0), spc_(spc), gridPart_(spc_.gridPart()), -#if WANT_DUNE_OPTIM - linProg_( static_cast< GridViewType > (gridPart_), BoundaryValue( *this ), - Dune::Fem::Parameter::getValue<double>("finitevolume.linearprogramming.tol", 1e-8 ) - ), -#endif + linearFunction_( gridPart_ ), + linProg_(), indexSet_( gridPart_.indexSet() ), localIdSet_( gridPart_.grid().localIdSet()), cornerPointSetContainer_(), @@ -322,32 +415,46 @@ namespace Fem argOrder_( spc_.order() ), storedComboSets_(), tolFactor_( getTolFactor() ), - tol_1_( 1.0/getTol() ), + indicator_( getIndicator(parameter) ), + tol_1_( 2./ parameter.getValue("femdg.limiter.tolerance", double(1.0) ) ), geoInfo_( gridPart_.indexSet() ), faceGeoInfo_( geoInfo_.geomTypes(1) ), phi0_( 0 ), matrixCacheVec_( gridPart_.grid().maxLevel() + 1 ), factors_(), numbers_(), - localMassMatrix_( spc_ , 2*spc_.order() ), adaptive_((AdaptationMethodType(gridPart_.grid())).adaptive()), cartesianGrid_( CheckCartesianType::check( gridPart_ ) ), stepTime_(3, 0.0), calcIndicator_(discreteModel_.calculateIndicator()), reconstruct_(false), - admissibleFunctions_( getAdmissibleFunctions() ), - usedAdmissibleFunctions_( admissibleFunctions_ ), + admissibleFunctions_( getAdmissibleFunctions( parameter ) ), + usedAdmissibleFunctions_( usedAdmissibleFunctions() ), + extTroubledCellIndicator_( indicator_ == 3 + ? new ModalSmoothnessIndicator< ArgumentFunctionType >() : nullptr ), counter_( 0 ) { - if( Parameter :: verbose () ) + if( usedAdmissibleFunctions_ == lp ) { - std::cout << "LimitPass: Grid is "; + linProg_.reset( new LinearProgramming( static_cast< GridViewType > (gridPart_), BoundaryValue( *this ), + parameter.getValue<double>("finitevolume.linearprogramming.tol", 1e-8 )) ); + } + + if( verbose ) + { + std::cout << "LimitDGPass (Grid is "; if( cartesianGrid_ ) - std::cout << "cartesian"; + std::cout << "cartesian) "; else - std::cout << "unstructured"; - //std::cout << "! LimitEps: "<< limitEps_ << ", LimitTol: "<< 1./tol_1_ << std::endl; - std::cout << "! Limiter.tolerance: "<< 1./tol_1_ << std::endl; + std::cout << "unstructured) "; + + std::cout << "parameters: " << std::endl; + std::cout << " femdg.limiter.tolerance: " << 1./tol_1_ << std::endl; + std::cout << " femdg.limiter.indicator: " << indicator_ << std::endl; + std::string adFctName( admissibleFctNames()[ admissibleFunctions_ ] ); + if( admissibleFunctions_ != usedAdmissibleFunctions_ ) + adFctName += "("+admissibleFctNames()[ usedAdmissibleFunctions_ ] + ")"; + std::cout << " femdg.limiter.admissiblefunctions: " << adFctName << std::endl; } // we need the flux here @@ -356,19 +463,24 @@ namespace Fem //! Destructor virtual ~LimitDGPass() { - std::cout << "~LimitDGPass: op calls " << counter_ << std::endl; + // std::cout << "~LimitDGPass: op calls " << counter_ << std::endl; + } + + void setTroubledCellIndicator(TroubledCellIndicatorType indicator) + { + extTroubledCellIndicator_ = indicator; } //! return default face quadrature order static int defaultVolumeQuadratureOrder( const DiscreteFunctionSpaceType& space, const EntityType& entity ) { - return (2 * space.order( entity )); + return DefaultQuadrature< DiscreteFunctionSpaceType >::volumeOrder( space.order( entity ) ); } //! return default face quadrature order static int defaultFaceQuadratureOrder( const DiscreteFunctionSpaceType& space, const EntityType& entity ) { - return (2 * space.order( entity )) + 1; + return DefaultQuadrature< DiscreteFunctionSpaceType >::faceOrder( space.order( entity ) ); } protected: @@ -384,7 +496,6 @@ namespace Fem return ( faceQuadOrd_ < 0 ) ? defaultFaceQuadratureOrder( spc_, entity ) : faceQuadOrd_ ; } - //! get tolerance factor for shock detector double getTolFactor() const { @@ -395,21 +506,43 @@ namespace Fem } //! get tolerance for shock detector - double getTol() const + double getIndicator( const Dune::Fem::ParameterReader ¶meter ) const { - double tol = 1.0; - tol = Parameter::getValue("femdg.limiter.tolerance", tol ); - return tol; + static const std::string indicators[] = { "user", "none", "jump" ,"modal", "always" }; + std::string key( "femdg.limiter.indicator" ); + return parameter.getEnum( key, indicators, 2); + } + + static const std::string (&admissibleFctNames())[5] + { + static const std::string admissiblefct[] = { "dgonly" , "muscl", "muscl+dg", "lp", "default" }; + return admissiblefct; } //! get tolerance for shock detector - AdmissibleFunctions getAdmissibleFunctions() const + AdmissibleFunctions getAdmissibleFunctions( const Dune::Fem::ParameterReader ¶meter ) const + { + std::string key( "femdg.limiter.admissiblefunctions" ); + return (AdmissibleFunctions) parameter.getEnum( key, admissibleFctNames(), _default ); + } + + AdmissibleFunctions usedAdmissibleFunctions() const { - // default value - int val = 1; - val = Parameter::getValue("femdg.limiter.admissiblefunctions", val); - assert( val >= DGFunctions || val <= BothFunctions ); - return (AdmissibleFunctions) val; + if( admissibleFunctions_ == _default ) + { + if( ! geoInfo_.multipleGeomTypes() && geoInfo_.geomTypes(0)[0].isSimplex() ) + { + // default for simplices is muscl reconstruction because it + // seems to work better for simplex grids + return muscl; + } + else + { + // default for all other element types is lp reconstruction + return lp; + } + } + return admissibleFunctions_; } template <class S1, class S2> @@ -551,7 +684,7 @@ namespace Fem return tmp; } - size_t leafElements() const + size_t numberOfElements() const { return elementCounter_; } @@ -578,12 +711,16 @@ namespace Fem assign( U , dest, firstThread ); // if case of finite volume scheme set admissible functions to reconstructions - usedAdmissibleFunctions_ = reconstruct_ ? ReconstructedFunctions : admissibleFunctions_; + if( reconstruct_ && ! linProg_ ) + { + // if linProg is not available then the only other FV reconstruction is muscl + usedAdmissibleFunctions_ = muscl; + } // in case of reconstruction if( reconstruct_ ) { - // in case of non-adaptive scheme indicator not needed + // for FV scheme in case of non-adaptive scheme indicator not needed calcIndicator_ = adaptive_; // adjust quadrature orders @@ -602,7 +739,7 @@ namespace Fem currentTime_ = this->time(); // initialize caller - caller_ = new DiscreteModelCallerType( *arg_, discreteModel_ ); + caller_.reset( new DiscreteModelCallerType( *arg_, discreteModel_ ) ); caller_->setTime(currentTime_); // calculate maximal indicator (if necessary) @@ -624,21 +761,12 @@ namespace Fem matrixCacheVec_.resize( numLevels ); } -#if WANT_DUNE_OPTIM - // helper class for evaluation of average value of discrete function - EvalAverage average( *this, U, discreteModel_); - - values_.resize( size ); - // evaluate average values on all cells - for( const auto& element : Dune::elements( gridPart_ ) ) + if( linProg_ ) { - average.evaluate( element, values_[ gridPart_.indexSet().index( element ) ] ); + values_.resize( size ); + valuesComputed_.resize( size ); + std::fill( valuesComputed_.begin(), valuesComputed_.end(), false ); } - - gradients_.resize( size ); - // get reconstructions - linProg_( gridPart_.indexSet(), values_, gradients_ ); -#endif } //! Some management (interface version) @@ -667,11 +795,9 @@ namespace Fem } // finalize caller - if( caller_ ) - { - delete caller_; - caller_ = 0; - } + caller_.reset(); + // reset usedAdmissibleFunction value to class default + usedAdmissibleFunctions_ = usedAdmissibleFunctions(); } //! apply local is virtual @@ -739,9 +865,6 @@ namespace Fem // timer for shock detection Dune::Timer indiTime; - // extract types - enum { dim = EntityType :: dimension }; - // check argument is not zero assert( arg_ ); @@ -749,6 +872,9 @@ namespace Fem // set entity to caller caller().setEntity( en ); + // initialize linear function + linearFunction_.bind( en ); + // get function to limit const ArgumentFunctionType &U = *(std::get< argumentPosition >( *arg_ )); @@ -756,13 +882,17 @@ namespace Fem const LocalFunctionType uEn = U.localFunction(en); // get geometry - const Geometry& geo = en.geometry(); + const Geometry& geo = linearFunction_.geometry(); // cache geometry type const GeometryType geomType = geo.type(); // get bary center of element - const LocalDomainType& x = geoInfo_.localCenter( geomType ); - const DomainType enBary = geo.global( x ); + const LocalDomainType& wLocal = geoInfo_.localCenter( geomType ); + + DomainType& enBary = linearFunction_.center_; + + // compute barycenter of element + enBary = geomType.isNone() ? geo.center() : geo.global( wLocal ); const IntersectionIteratorType endnit = gridPart_.iend( en ); IntersectionIteratorType niter = gridPart_.ibegin(en); @@ -774,7 +904,7 @@ namespace Fem RangeType shockIndicator(0); RangeType adaptIndicator(0); - RangeType enVal; + RangeType& enVal = linearFunction_.value_; // if limiter is true then limitation is done // when we want to reconstruct in any case then @@ -796,9 +926,8 @@ namespace Fem // otherwise everything may be corrupted { // get barycenter of entity - const DomainType& enBaryLocal = (int(dimGrid) == int(dimDomain)) ? - geoInfo_.localCenter( geomType ) : - geo.local( enBary ) ; + const DomainType& enBaryLocal = (int(dimGrid) == int(dimDomain) && ! geomType.isNone() ) ? + wLocal : geo.local( enBary ) ; // check that average value is physical if( discreteModel_.hasPhysical() && @@ -824,8 +953,8 @@ namespace Fem else if ( calcIndicator_ ) // otherwise compute shock indicator { // check shock indicator - limiter = calculateIndicator(en, uEn, geo, limiter, // parameter - limit, shockIndicator, adaptIndicator); // return values + limiter = calculateIndicator(U, uEn, geo, limiter, // parameter + limit, shockIndicator, adaptIndicator); // return values } else if( !reconstruct_ ) { @@ -879,10 +1008,12 @@ namespace Fem EvalAverage average( *this, U, discreteModel_, geo.volume() ); // setup neighbors barycenter and mean value for all neighbors - LimiterUtilityType::setupNeighborValues( gridPart_, en, average, enBary, enVal, + LimiterUtilityType::setupNeighborValues( gridPart_, en, average, enBary, enVal, uEn, StructuredGrid, flags, barys_, nbVals_ ); } + const unsigned int enIndex = indexSet_.index( en ); + // mark entity as finished, even if not limited everything necessary was done assert( indexSet_.index( en ) < int(visited_.size()) ); visited_[ indexSet_.index( en ) ] = true ; @@ -893,15 +1024,18 @@ namespace Fem // increase number of limited elements ++limitedElements_; - const unsigned int enIndex = indexSet_.index( en ); -#if WANT_DUNE_OPTIM - bool useLinProg = true ; - if( useLinProg ) + GradientType& gradient = linearFunction_.gradient_; + + // use linear function from LP reconstruction + if( usedAdmissibleFunctions_ == lp ) { - deoMod_ = gradients_[ enIndex ]; + // compute average values on neighboring elements + fillAverageValues( en, enIndex, U, enVal ); + assert( linProg_ ); + // compute optimal linear reconstruction + linProg_->applyLocal( en, gridPart_.indexSet(), values_, gradient ); } else -#endif { // obtain combination set ComboSetType& comboSet = storedComboSets_[ nbVals_.size() ]; @@ -912,26 +1046,26 @@ namespace Fem } // reset values - deoMods_.clear(); + gradients_.clear(); comboVec_.clear(); - if( usedAdmissibleFunctions_ >= ReconstructedFunctions ) + if( usedAdmissibleFunctions_ == muscl || usedAdmissibleFunctions_ == muscldg ) { // level is only needed for Cartesian grids to access the matrix caches const int matrixCacheLevel = ( flags.cartesian ) ? en.level() : 0 ; assert( matrixCacheLevel < (int) matrixCacheVec_.size() ); MatrixCacheType& matrixCache = matrixCacheVec_[ matrixCacheLevel ]; - // calculate linear functions, stored in deoMods_ and comboVec_ + // calculate linear functions, stored in gradients_ and comboVec_ LimiterUtilityType::calculateLinearFunctions( comboSet, geomType, flags, barys_, nbVals_, matrixCache, - deoMods_, + gradients_, comboVec_ ); } // add DG Function - if( (usedAdmissibleFunctions_ % 2) == DGFunctions ) + if( usedAdmissibleFunctions_ == dgonly || usedAdmissibleFunctions_ == muscldg ) { addDGFunction( en, geo, uEn, enVal, enBary ); } @@ -939,10 +1073,10 @@ namespace Fem // Limiting std::vector< RangeType > factors; LimiterUtilityType::limitFunctions( - discreteModel_.limiterFunction(), comboVec_, barys_, nbVals_, deoMods_, factors ); + discreteModel_.limiterFunction(), comboVec_, barys_, nbVals_, gradients_, factors ); // take maximum of limited functions - LimiterUtilityType::getMaxFunction(deoMods_, deoMod_, factors_[ enIndex ], numbers_[ enIndex ], factors ); + LimiterUtilityType::getMaxFunction(gradients_, gradient, factors_[ enIndex ], numbers_[ enIndex ], factors ); } // end if linProg //////////////////////////////////////////////////////////////////// @@ -954,8 +1088,8 @@ namespace Fem // get local funnction for limited values DestLocalFunctionType limitEn = dest_->localFunction(en); - // project deoMod_ to limitEn - L2project(en, geo, enBary, enVal, limit, deoMod_, limitEn ); + // project linearFunction onto limitEn + interpolate( en, geo, limit, linearFunction_, limitEn ); assert( checkPhysical(en, geo, limitEn) ); @@ -965,6 +1099,34 @@ namespace Fem } protected: + void fillAverageValues( const EntityType& en, const unsigned int enIndex, + const ArgumentFunctionType &U, const RangeType& enVal ) const + { + // helper class for evaluation of average value of discrete function + EvalAverage average( *this, U, discreteModel_); + + if( ! valuesComputed_[ enIndex ] ) + { + values_[ enIndex ] = enVal; + valuesComputed_[ enIndex ] = true; + } + + const auto& indexSet = gridPart_.indexSet(); + for (const auto& intersection : intersections(gridPart_, en) ) + { + if( intersection.neighbor() ) + { + const auto neighbor = intersection.outside(); + const unsigned int nbIndex = indexSet.index( neighbor ); + if( ! valuesComputed_[ nbIndex ] ) + { + average.evaluate( neighbor, values_[ nbIndex ] ); + valuesComputed_[ nbIndex ] = true; + } + } + } + } + // add linear components of the DG function void addDGFunction(const EntityType& en, const Geometry& geo, @@ -1014,7 +1176,7 @@ namespace Fem A.mv( rhs, D[ r ]); } - deoMods_.push_back( D ); + gradients_.push_back( D ); std::vector<int> comb( nbVals_.size() ); const size_t combSize = comb.size(); for (size_t i=0;i<combSize; ++i) comb[ i ] = i; @@ -1050,7 +1212,6 @@ namespace Fem const Geometry& geo, const LocalFunctionImp& uEn) const { - enum { dim = dimGrid }; if( discreteModel_.hasPhysical() ) { if( en.type().isNone() ) @@ -1104,63 +1265,42 @@ namespace Fem } }; + // L2 projection template <class LocalFunctionImp> - void L2project(const EntityType& en, - const Geometry& geo, - const DomainType& enBary, - const RangeType& enVal, - const FieldVector<bool,dimRange>& limit, - const GradientType& deoMod, - LocalFunctionImp& limitEn, - const bool constantValue = false ) const + void interpolate(const EntityType& en, + const Geometry& geo, + const FieldVector<bool,dimRange>& limit, + const LinearFunction& linearFunction, + LocalFunctionImp& limitEn ) const { - enum { dim = dimGrid }; - // true if geometry mapping is affine - const bool affineMapping = localMassMatrix_.affine(); + const bool affineMapping = geo.affine(); // set zero dof to zero uTmpLocal_.init( en ); uTmpLocal_.clear(); - // get quadrature for destination space order - VolumeQuadratureType quad( en, spc_.order() + 1 ); + const auto interpolation = spc_.interpolation( en ); - const int quadNop = quad.nop(); - for(int qP = 0; qP < quadNop ; ++qP) + const bool constantValue = linearFunction.isConstant(); + if( constantValue ) { - // get quadrature weight - const double intel = (affineMapping) ? - quad.weight(qP) : // affine case - quad.weight(qP) * geo.integrationElement( quad.point(qP) ); // general case - - RangeType retVal( enVal ); - // if we don't have only constant value then evaluate function - if( !constantValue ) - { - // get global coordinate - DomainType point = geo.global( quad.point( qP ) ); - point -= enBary; - - // evaluate linear function - for( int r = 0; r < dimRange; ++r ) - retVal[ r ] += (deoMod[ r ] * point); - } - - retVal *= intel; - uTmpLocal_.axpy( quad[ qP ], retVal ); + const ConstantFunction& constFct = linearFunction; + interpolation( constFct, uTmpLocal_.localDofVector() ); + } + else + { + interpolation( linearFunction, uTmpLocal_.localDofVector() ); } - - if( !affineMapping ) - localMassMatrix_.applyInverse( en, uTmpLocal_ ); // check physicality of projected data if ( (! constantValue) && (! checkPhysical(en, geo, uTmpLocal_)) ) { // for affine mapping we only need to set higher moments to zero - if( affineMapping ) - { + if( Dune::Fem::Capabilities::isHierarchic< DiscreteFunctionSpaceType > :: v && + affineMapping ) + { // note: the following assumes an ONB made up of moments and affine mapping const int numBasis = uTmpLocal_.numDofs()/dimRange; for(int i=1; i<numBasis; ++i) { @@ -1173,9 +1313,9 @@ namespace Fem } else { - // if not physical project to mean value - L2project(en,geo,enBary,enVal,limit,deoMod_, limitEn, true); - return ; + // general interpolation of constant value + const ConstantFunction& constFct = linearFunction; + interpolation( constFct, uTmpLocal_.localDofVector() ); } } @@ -1189,7 +1329,7 @@ namespace Fem { // copy to limitEn skipping components that should not be limited const int numBasis = uTmpLocal_.numDofs()/dimRange; - for(int i=1; i<numBasis; ++i) + for(int i=0; i<numBasis; ++i) { for( const auto& r : discreteModel_.model().limitedRange() ) { @@ -1202,7 +1342,7 @@ namespace Fem template <class BasisFunctionSetType, class PointType> const RangeType& evaluateConstantBasis( const BasisFunctionSetType& basisSet, - const PointType& x ) const + const PointType& x ) const { // calculate constant part of the basis functions if( ! (phi0_[ 0 ] > 0 ) ) @@ -1231,8 +1371,9 @@ namespace Fem RangeType& val) const { bool notphysical = false; - if( Dune::Fem::Capabilities::isHierarchic< DiscreteFunctionSpaceType > :: v - && localMassMatrix_.affine() ) + const Geometry& geo = en.geometry(); + + if( Dune::Fem::Capabilities::isHierarchic< DiscreteFunctionSpaceType > :: v && geo.affine() ) { // get point quadrature VolumeQuadratureType quad( en, 0 ); @@ -1253,8 +1394,6 @@ namespace Fem } else { - const Geometry& geo = en.geometry(); - // get quadrature VolumeQuadratureType quad( en, volumeQuadratureOrder( en ) ); @@ -1287,11 +1426,22 @@ namespace Fem return notphysical; } - template <bool conforming> bool integrateIntersection(const IntersectionType & intersection, const EntityType& nb, RangeType& shockIndicator, RangeType& adaptIndicator) const + { + if( ! conformingGridPart && ! intersection.conforming() ) + return integrateIntersectionImpl< false >(intersection, nb, shockIndicator, adaptIndicator); + else + return integrateIntersectionImpl< true >(intersection, nb, shockIndicator, adaptIndicator); + } + + template <bool conforming> + bool integrateIntersectionImpl(const IntersectionType & intersection, + const EntityType& nb, + RangeType& shockIndicator, + RangeType& adaptIndicator) const { // make sure we got the right conforming statement assert( intersection.conforming() == conforming ); @@ -1381,15 +1531,15 @@ namespace Fem } // calculate shock detector - bool calculateIndicator(const EntityType& en, + bool calculateIndicator(const ArgumentFunctionType& U, const LocalFunctionType& uEn, const Geometry& geo, const bool initLimiter, FieldVector<bool,dimRange>& limit, RangeType& shockIndicator, - RangeType& adaptIndicator) const + RangeType& adaptIndicator ) const { - enum { dim = EntityType :: dimension }; + const EntityType& en = uEn.entity(); // calculate circume during neighbor check double circume = 0.0; @@ -1442,7 +1592,6 @@ namespace Fem shockIndicator = -1; return true; } - } else { // non-conforming case @@ -1496,52 +1645,46 @@ namespace Fem // add face vol to circume circume += vol; - // order of quadrature - const int jumpQuadOrd = spc_.order(); - - // check all neighbors - if (intersection.neighbor()) + // internal shock indicator based on Krivodonova et al. + if( ! extTroubledCellIndicator_ ) { - // get neighbor entity - const EntityType& nb = intersection.outside(); + // order of quadrature + const int jumpQuadOrd = spc_.order(); - // conforming case - if( ! conformingGridPart && ! intersection.conforming() ) - { // non-conforming case - if (integrateIntersection< false > (intersection, nb, shockIndicator, adaptIndicator)) + // check all neighbors + if (intersection.neighbor()) + { + // get neighbor entity + const EntityType& nb = intersection.outside(); + + if (integrateIntersection(intersection, nb, shockIndicator, adaptIndicator)) { shockIndicator = -1; return true; } } - else + + // check all neighbors + if ( intersection.boundary() ) { - if (integrateIntersection< true > (intersection, nb, shockIndicator, adaptIndicator)) + FaceQuadratureType faceQuadInner(gridPart_,intersection, jumpQuadOrd, FaceQuadratureType::INSIDE); + + // initialize intersection + caller().initializeBoundary( intersection, faceQuadInner ); + + if (integrateBoundary(en, intersection, faceQuadInner, shockIndicator, adaptIndicator)) { shockIndicator = -1; return true; } } } - - // check all neighbors - if ( intersection.boundary() ) - { - FaceQuadratureType faceQuadInner(gridPart_,intersection, jumpQuadOrd, FaceQuadratureType::INSIDE); - - // initialize intersection - caller().initializeBoundary( intersection, faceQuadInner ); - - if (integrateBoundary(en, intersection, faceQuadInner, shockIndicator, adaptIndicator)) - { - shockIndicator = -1; - return true; - } - } } - } // end intersection iterator + if (indicator_ == 1) + return false; + // calculate max face volume { // min faceVol @@ -1566,11 +1709,34 @@ namespace Fem // multiply h pol ord with circume const double circFactor = (circume > 0.0) ? (hPowPolOrder/(circume * tolFactor_ )) : 0.0; + assert(indicator_!=0 || extTroubledCellIndicator_); + if( extTroubledCellIndicator_ ) // also true for indicator_=3 + { + shockIndicator = ( tol_1_ * (*extTroubledCellIndicator_)( U, uEn ) ); + } + else if( indicator_ == 2 ) + { + for(int r=0; r<dimRange; ++r) + { + shockIndicator[r] = std::abs(shockIndicator[r]) * circFactor * tol_1_; + } + } + else if ( indicator_ == 4 ) + { + // always limit on each cell + shockIndicator = 2.; + } + else + { + std::cout << "wrong indicator selection\n"; + assert(0); + abort(); + } + for(int r=0; r<dimRange; ++r) { - // only scale shock indicator with tolerance - shockIndicator[r] = std::abs(shockIndicator[r]) * circFactor * tol_1_; adaptIndicator[r] = std::abs(adaptIndicator[r]) * circFactor; + if(shockIndicator[r] > 1.) { limit[r] = true; @@ -1589,10 +1755,10 @@ namespace Fem { // check whether we have an inflow intersection or not const int quadNop = quad.nop(); - for(int l=0; l<quadNop; ++l) + for(int qp=0; qp<quadNop; ++qp) { // check physicality of value - const bool physical = caller().checkPhysical( intersection, quad, l ); + const bool physical = caller().checkPhysical( intersection, quad, qp ); if( checkPhysical && ! physical ) { @@ -1603,7 +1769,7 @@ namespace Fem if( ! inflowIntersection ) { // check intersection - if( physical && caller().checkDirection(intersection, quad, l) ) + if( physical && caller().checkDirection(intersection, quad, qp) ) { inflowIntersection = true; // in case of physicality check is disabled @@ -1634,7 +1800,7 @@ namespace Fem } private: - mutable DiscreteModelCallerType *caller_; + mutable std::unique_ptr< DiscreteModelCallerType > caller_; DiscreteModelType& discreteModel_; mutable double currentTime_; @@ -1644,9 +1810,9 @@ namespace Fem const DiscreteFunctionSpaceType& spc_; GridPartType& gridPart_; -#if WANT_DUNE_OPTIM - mutable LinearProgramming linProg_; -#endif + mutable LinearFunction linearFunction_; + + std::unique_ptr< LinearProgramming > linProg_; const IndexSetType& indexSet_; const LocalIdSetType& localIdSet_; @@ -1665,16 +1831,16 @@ namespace Fem // tolerance to scale shock indicator const double tolFactor_; + std::size_t indicator_; const double tol_1_; // if true scheme is TVD const GeometryInformationType geoInfo_; const FaceGeometryInformationType faceGeoInfo_; - mutable GradientType deoMod_; mutable RangeType phi0_ ; - mutable std::vector< GradientType > deoMods_; + mutable std::vector< GradientType > gradients_; mutable std::vector< CheckType > comboVec_; mutable std::vector< DomainType > barys_; @@ -1687,7 +1853,6 @@ namespace Fem // vector for stroing the information which elements have been computed already mutable std::vector< bool > visited_; - LocalMassMatrixType localMassMatrix_; //! true if limiter is used in adaptive scheme const bool adaptive_; //! true if grid is cartesian like @@ -1696,18 +1861,21 @@ namespace Fem mutable std::vector<double> stepTime_; mutable size_t elementCounter_; - //! true if indicator should be calculated + //! true if troubled cell indicator should be calculated mutable bool calcIndicator_; //! true if limiter is used as finite volume scheme of higher order mutable bool reconstruct_; // choice of admissible linear functions - const AdmissibleFunctions admissibleFunctions_; - mutable AdmissibleFunctions usedAdmissibleFunctions_ ; + const AdmissibleFunctions admissibleFunctions_; + mutable AdmissibleFunctions usedAdmissibleFunctions_ ; mutable std::vector< RangeType > values_; - mutable std::vector< GradientType > gradients_; + mutable std::vector< bool > valuesComputed_; + + // function pointer to external troubled cell indicator, can be nullptr + TroubledCellIndicatorType extTroubledCellIndicator_; mutable int counter_; }; // end DGLimitPass diff --git a/dune/fem-dg/operator/limiter/lpreconstruction.hh b/dune/fem-dg/operator/limiter/lpreconstruction.hh index fff7baeac5fb6882b25459163fca823da9098ebd..c6269e30ce9d81d9a1993506d43e00234b5f70b7 100644 --- a/dune/fem-dg/operator/limiter/lpreconstruction.hh +++ b/dune/fem-dg/operator/limiter/lpreconstruction.hh @@ -83,6 +83,7 @@ namespace Dune typedef Optim::GaussJordanSolver< FieldMatrix< Field, GlobalCoordinate::dimension, GlobalCoordinate::dimension > > Solver; typedef Optim::LinearProgramming< Solver, false > LP; + typedef std::vector< std::pair< GlobalCoordinate, StateVector > > DifferencesVectorType; public: LPReconstruction ( const GridView &gridView, BoundaryValue boundaryValue, Real tolerance ) : gridView_( gridView ), @@ -105,119 +106,127 @@ namespace Dune } } - template< class Mapper, class Vector > - void operator () ( const Mapper &mapper, const Vector &u, std::vector< Jacobian > &du ) const + template< class Entity, class Mapper, class Vector > + void applyLocal ( const Entity& element, + const Mapper &mapper, + const Vector &u, + Jacobian& du ) const { - du.resize( u.size() ); + DifferencesVectorType& differences = differences_; + differences.clear(); - std::vector< std::pair< GlobalCoordinate, StateVector > > differences; Constraints constraints; - const auto end = gridView().template end< 0, Dune::InteriorBorder_Partition >(); - for( auto it = gridView().template begin< 0, Dune::InteriorBorder_Partition>(); it != end; ++it ) + const std::size_t elIndex = mapper.index( element ); + const GlobalCoordinate elCenter = element.geometry().center(); + + std::array< unsigned int, dimension+1 > select; + const std::vector< unsigned int > &faceAxes = faceAxes_[ LocalGeometryTypeIndex::index( element.type() ) ]; + if( !faceAxes.empty() ) { - const auto element = *it; + const auto iend = gridView().iend( element ); + for( auto iit = gridView().ibegin( element ); iit != iend; ++iit ) + { + const auto intersection = *iit; - const std::size_t elIndex = mapper.index( element ); - const GlobalCoordinate elCenter = element.geometry().center(); + select[ faceAxes[ intersection.indexInInside() ] ] = differences.size(); - std::array< unsigned int, dimension+1 > select; - const std::vector< unsigned int > &faceAxes = faceAxes_[ LocalGeometryTypeIndex::index( element.type() ) ]; - if( !faceAxes.empty() ) - { - differences.clear(); - const auto iend = gridView().iend( element ); - for( auto iit = gridView().ibegin( element ); iit != iend; ++iit ) + if( intersection.boundary() ) + { + const GlobalCoordinate iCenter = intersection.geometry().center(); + const GlobalCoordinate iNormal = intersection.centerUnitOuterNormal(); + const StateVector uBnd = boundaryValue_( intersection, iCenter, iNormal, u[ elIndex ] ); + differences.emplace_back( iCenter - elCenter, uBnd - u[ elIndex ] ); + } + else if( intersection.neighbor() ) { - const auto intersection = *iit; - - select[ faceAxes[ intersection.indexInInside() ] ] = differences.size(); - - if( intersection.boundary() ) - { - const GlobalCoordinate iCenter = intersection.geometry().center(); - const GlobalCoordinate iNormal = intersection.centerUnitOuterNormal(); - const StateVector uBnd = boundaryValue_( intersection, iCenter, iNormal, u[ elIndex ] ); - differences.emplace_back( iCenter - elCenter, uBnd - u[ elIndex ] ); - } - else if( intersection.neighbor() ) - { - const auto neighbor = intersection.outside(); - const GlobalCoordinate nbCenter = neighbor.geometry().center(); - differences.emplace_back( nbCenter - elCenter, u[ mapper.index( neighbor ) ] - u[ elIndex ] ); - } + const auto neighbor = intersection.outside(); + const GlobalCoordinate nbCenter = neighbor.geometry().center(); + differences.emplace_back( nbCenter - elCenter, u[ mapper.index( neighbor ) ] - u[ elIndex ] ); } } - else + } + else + { + Dune::ReservedVector< GlobalCoordinate, dimension > onb; + + const auto iend = gridView().iend( element ); + for( auto iit = gridView().ibegin( element ); iit != iend; ++iit ) { - Dune::ReservedVector< GlobalCoordinate, dimension > onb; + const auto intersection = *iit; + + select[ onb.size() ] = differences.size(); - differences.clear(); - const auto iend = gridView().iend( element ); - for( auto iit = gridView().ibegin( element ); iit != iend; ++iit ) + if( intersection.boundary() ) { - const auto intersection = *iit; - - select[ onb.size() ] = differences.size(); - - if( intersection.boundary() ) - { - const GlobalCoordinate iCenter = intersection.geometry().center(); - const GlobalCoordinate iNormal = intersection.centerUnitOuterNormal(); - const StateVector uBnd = boundaryValue_( intersection, iCenter, iNormal, u[ elIndex ] ); - differences.emplace_back( iCenter - elCenter, uBnd - u[ elIndex ] ); - } - else if( intersection.neighbor() ) - { - const auto neighbor = intersection.outside(); - const GlobalCoordinate nbCenter = neighbor.geometry().center(); - differences.emplace_back( nbCenter - elCenter, u[ mapper.index( neighbor ) ] - u[ elIndex ] ); - } - - if( onb.size() < dimension ) - { - GlobalCoordinate dx = differences.back().first; - for( const GlobalCoordinate &v : onb ) - dx.axpy( -(dx*v), v ); - - const Real dxNorm = dx.two_norm(); - if( dxNorm >= tolerance_ ) - onb.push_back( dx /= dxNorm ); - } + const GlobalCoordinate iCenter = intersection.geometry().center(); + const GlobalCoordinate iNormal = intersection.centerUnitOuterNormal(); + const StateVector uBnd = boundaryValue_( intersection, iCenter, iNormal, u[ elIndex ] ); + differences.emplace_back( iCenter - elCenter, uBnd - u[ elIndex ] ); + } + else if( intersection.neighbor() ) + { + const auto neighbor = intersection.outside(); + const GlobalCoordinate nbCenter = neighbor.geometry().center(); + differences.emplace_back( nbCenter - elCenter, u[ mapper.index( neighbor ) ] - u[ elIndex ] ); } - } - // reserve memory for constraints - const std::size_t numConstraints = differences.size(); - constraints.resize( 2u*numConstraints ); - Optim::ActiveIndexMapper< SmallObjectAllocator< unsigned int > > active( GlobalCoordinate::dimension, constraints.size() ); - for( int j = 0; j < StateVector::dimension; ++j ) - { - GlobalCoordinate negGradient( 0 ); - for( std::size_t i = 0u; i < numConstraints; ++i ) + if( onb.size() < dimension ) { - const Field sign = (differences[ i ].second[ j ] >= 0 ? 1 : -1); + GlobalCoordinate dx = differences.back().first; + for( const GlobalCoordinate &v : onb ) + dx.axpy( -(dx*v), v ); - negGradient.axpy( sign, differences[ i ].first ); + const Real dxNorm = dx.two_norm(); + if( dxNorm >= tolerance_ ) + onb.push_back( dx /= dxNorm ); + } + } + } - constraints[ 2*i ].normal() = differences[ i ].first; - constraints[ 2*i ].normal() *= sign; - constraints[ 2*i ].rhs() = sign*differences[ i ].second[ j ]; + // reserve memory for constraints + const std::size_t numConstraints = differences.size(); + constraints.resize( 2u*numConstraints ); + Optim::ActiveIndexMapper< SmallObjectAllocator< unsigned int > > active( GlobalCoordinate::dimension, constraints.size() ); + for( int j = 0; j < StateVector::dimension; ++j ) + { + GlobalCoordinate negGradient( 0 ); + for( std::size_t i = 0u; i < numConstraints; ++i ) + { + const Field sign = (differences[ i ].second[ j ] >= 0 ? 1 : -1); - constraints[ 2*i+1 ].normal() = constraints[ 2*i ].normal(); - constraints[ 2*i+1 ].normal() *= Field( -1 ); - constraints[ 2*i+1 ].rhs() = 0; - } + negGradient.axpy( sign, differences[ i ].first ); - // activate GlobalCoordinate::dimension constraints active in the origin - active.clear(); - for( int i = 0; i < dimension; ++i ) - active.activate( 2*select[ i ]+1 ); + constraints[ 2*i ].normal() = differences[ i ].first; + constraints[ 2*i ].normal() *= sign; + constraints[ 2*i ].rhs() = sign*differences[ i ].second[ j ]; - // solve - du[ elIndex ][ j ] = 0; - lp_( negGradient, constraints, du[ elIndex ][ j ], active ); + constraints[ 2*i+1 ].normal() = constraints[ 2*i ].normal(); + constraints[ 2*i+1 ].normal() *= Field( -1 ); + constraints[ 2*i+1 ].rhs() = 0; } + + // activate GlobalCoordinate::dimension constraints active in the origin + active.clear(); + for( int i = 0; i < dimension; ++i ) + active.activate( 2*select[ i ]+1 ); + + // solve + du[ j ] = 0; + lp_( negGradient, constraints, du[ j ], active ); + } + } + + template< class Mapper, class Vector > + void operator () ( const Mapper &mapper, const Vector &u, std::vector< Jacobian > &du ) const + { + du.resize( u.size() ); + + const auto end = gridView().template end< 0, Dune::InteriorBorder_Partition >(); + for( auto it = gridView().template begin< 0, Dune::InteriorBorder_Partition>(); it != end; ++it ) + { + const auto element = *it; + applyLocal( element, mapper, u, du[ mapper.index( element ) ] ); } //auto handle = vectorCommDataHandle( mapper, du, [] ( Jacobian a, Jacobian b ) { return b; } ); @@ -232,6 +241,7 @@ namespace Dune Real tolerance_; LP lp_; std::vector< std::vector< unsigned int > > faceAxes_; + mutable DifferencesVectorType differences_; }; diff --git a/dune/fem-dg/operator/limiter/scalinglimitpass.hh b/dune/fem-dg/operator/limiter/scalinglimitpass.hh index 9f0825ac4510f4a6cbf9af406bb7aba77f877153..c4d1d8d7934d78c79d388f934c0ae208b5405f13 100644 --- a/dune/fem-dg/operator/limiter/scalinglimitpass.hh +++ b/dune/fem-dg/operator/limiter/scalinglimitpass.hh @@ -116,24 +116,9 @@ namespace Fem //! type of cartesian grid checker typedef CheckCartesian< GridPartType > CheckCartesianType; - protected: - template <class DiscreteSpace> - struct HierarchicalBasis - { - static const bool v = false ; - }; - - template < class FunctionSpace, class GridPart, int polOrder, template< class > class Storage > - struct HierarchicalBasis< DiscontinuousGalerkinSpace< FunctionSpace, GridPart, polOrder, Storage > > - { - static const bool v = true ; - }; + //! function describing an external troubled cell indicator + typedef std::shared_ptr< TroubledCellIndicatorBase<ArgumentFunctionType> > TroubledCellIndicatorType; - template < class FunctionSpace, class GridPart, int polOrder, template< class > class Storage > - struct HierarchicalBasis< HierarchicLegendreDiscontinuousGalerkinSpace< FunctionSpace, GridPart, polOrder, Storage > > - { - static const bool v = true ; - }; public: //- Public methods @@ -146,10 +131,30 @@ namespace Fem * \param fQ order of face quadrature */ ScalingLimitDGPass(DiscreteModelType& problem, - PreviousPassType& pass, - const DiscreteFunctionSpaceType& spc, - const int vQ = -1, - const int fQ = -1 ) : + PreviousPassType& pass, + const DiscreteFunctionSpaceType& spc, + const int vQ = -1, + const int fQ = -1, + const bool verbose = Dune::Fem::Parameter::verbose()) : + ScalingLimitDGPass( problem, pass, spc, Dune::Fem::Parameter::container() ) + {} + + //- Public methods + /** \brief constructor + * + * \param problem Actual problem definition (see problem.hh) + * \param pass Previous pass + * \param spc Space belonging to the discrete function local to this pass + * \param vQ order of volume quadrature + * \param fQ order of face quadrature + */ + ScalingLimitDGPass(DiscreteModelType& problem, + PreviousPassType& pass, + const DiscreteFunctionSpaceType& spc, + const Dune::Fem::ParameterReader ¶meter = Dune::Fem::Parameter::container(), + const int vQ = -1, + const int fQ = -1, + const bool verbose = Dune::Fem::Parameter::verbose()) : BaseType(pass, spc), caller_( 0 ), discreteModel_(problem), @@ -158,6 +163,7 @@ namespace Fem dest_(0), spc_(spc), gridPart_(spc_.gridPart()), + scaledFunction_( gridPart_, discreteModel_.model(), spc_.order() ), indexSet_( gridPart_.indexSet() ), cornerPointSetContainer_(), dofConversion_(dimRange), @@ -166,7 +172,7 @@ namespace Fem argOrder_( spc_.order() ), geoInfo_( gridPart_.indexSet() ), phi0_( 0 ), - localMassMatrix_( spc_ , 2*spc_.order()+3 ), + localMassMatrix_( spc_, [this](const int order) { return DefaultQuadrature<DiscreteFunctionSpaceType >::volumeOrder(order); } ), stepTime_(3, 0.0) { // we need the flux here @@ -182,31 +188,25 @@ namespace Fem //! return default face quadrature order static int defaultVolumeQuadratureOrder( const DiscreteFunctionSpaceType& space, const EntityType& entity ) { - return (2 * space.order( entity )); + return DefaultQuadrature<DiscreteFunctionSpaceType >::volumeOrder( space.order( entity ) ); } //! return default face quadrature order static int defaultFaceQuadratureOrder( const DiscreteFunctionSpaceType& space, const EntityType& entity ) { - return (2 * space.order( entity )) + 1; + return DefaultQuadrature<DiscreteFunctionSpaceType >::faceOrder( space.order( entity ) ); } //! return appropriate quadrature order, default is 2 * order(entity) int volumeQuadratureOrder( const EntityType& entity ) const { - return ( volumeQuadOrd_ < 0 ) ? ( 2*spc_.order( entity )+3 ) : volumeQuadOrd_ ; - } - - //! return default face quadrature order - int defaultFaceQuadOrder( const EntityType& entity ) const - { - return (2 * spc_.order( entity )) + 3; + return ( volumeQuadOrd_ < 0 ) ? defaultVolumeQuadratureOrder( spc_, entity ) : volumeQuadOrd_ ; } //! return appropriate quadrature order, default is 2 * order( entity ) + 1 int faceQuadratureOrder( const EntityType& entity ) const { - return ( faceQuadOrd_ < 0 ) ? defaultFaceQuadOrder( entity ) : faceQuadOrd_ ; + return ( faceQuadOrd_ < 0 ) ? defaultFaceQuadratureOrder( spc_, entity ) : faceQuadOrd_ ; } template <class S1, class S2> @@ -339,6 +339,117 @@ namespace Fem } }; + + struct ScaledFunction : + public Dune::Fem::BindableGridFunction< GridPartType, Dune::Dim<dimRange> > + { + typedef Dune::Fem::BindableGridFunction<GridPartType, Dune::Dim<dimRange> > Base; + typedef typename Base::RangeType RangeType; + typedef typename Base::EntityType EntityType; + using Base::Base; + + typedef typename DiscreteModelType :: ModelType ModelType; + + protected: + const ModelType& model_; + int order_; + + mutable unsigned int quadId_; + mutable std::vector< RangeType > tmpVal_ ; + mutable RangeType theta_; + public: + using Base::bind; + mutable RangeType enVal_; + mutable int count_ ; + + ScaledFunction( const GridPartType& gridPart, + const ModelType& model, const int order ) + : Base( gridPart ), + model_( model ), + order_( order ), + quadId_( -1 ), + tmpVal_(), theta_(1), enVal_(0), count_(0) + {} + + void bind( const EntityType& entity, const int order ) + { + Base::bind( entity ); + order_ = order; + } + + template <class Quadrature> + std::vector< RangeType >& getValues( const Quadrature& quadrature ) const + { + // adjust size if necessary + tmpVal_.resize( quadrature.nop() ); + + // store quadrature id for later check during evaluate + quadId_ = quadrature.id(); + count_ = 0; + return tmpVal_; + } + + // return reference to scaling factor + RangeType& resetTheta () const + { + // reset theta to default value which does no scaling + theta_ = 1; + return theta_; + } + + template <class Quadrature, class RangeArray> + void evaluateQuadrature(const Quadrature& quadrature, RangeArray &values) const + { + assert( quadrature.id() == quadId_ ); + const int quadNop = quadrature.nop(); + assert( quadNop == int(tmpVal_.size()) ); + + for(int qP = 0; qP < quadNop ; ++qP) + { + evaluate( qP, values[ qP ] ); + } + } + + template <class Point> + void evaluate(const Point &x, typename Base::RangeType &value) const + { + evaluate( count_, value ); + ++count_; + return ; + + std::cout << "Wrong quadrature " << std::endl; + assert( false ); + std::abort(); + } + + template <class Quadrature> + void evaluate(const QuadraturePointWrapper< Quadrature > &x, typename Base::RangeType &value) const + { + assert( x.quadrature().id() == quadId_ ); + evaluate( x.index(), value ); + } + + unsigned int order() const { return order_; } + std::string name() const { return "ScalingLimmitPass::ScaledFunction"; } // needed for output + + protected: + void evaluate(const int qP, typename Base::RangeType &value) const + { + assert( qP < int(tmpVal_.size() )); + // copy value + value = tmpVal_[ qP ]; + + // \tilde{p}(x) = \theta (p(x) - \bar{u}) + \bar{u} + // limitedRange contains all components that should be modified + // default is 0,...,dimRange-1 + for( const auto& d : model_.limitedRange() ) + { + value[ d ] = theta_[ d ] * ( value[ d ] - enVal_[ d ]) + enVal_[ d ]; + } + } + }; + + public: virtual std::vector<double> computeTimeSteps () const { @@ -348,7 +459,7 @@ namespace Fem return tmp; } - size_t leafElements() const + size_t numberOfElements() const { return elementCounter_; } @@ -485,17 +596,17 @@ namespace Fem applyLocalImp( entity ); } + void setTroubledCellIndicator(TroubledCellIndicatorType indicator) + { // don't need a troubled cell indicator here + } + protected: //! Perform the limitation on all elements. void applyLocalImp(const EntityType& en) const { - //std::cout << "ScalingPass::applyLocalImp" << std::endl; // timer for shock detection Dune::Timer indiTime; - // extract types - enum { dim = EntityType :: dimension }; - // check argument is not zero assert( arg_ ); @@ -503,6 +614,9 @@ namespace Fem // set entity to caller caller().setEntity( en ); + // bind function to entity + scaledFunction_.bind( en, spc_.order( en ) ); + // get function to limit const ArgumentFunctionType &U = *(std::get< argumentPosition >( *arg_ )); @@ -512,7 +626,8 @@ namespace Fem // get geometry const Geometry& geo = en.geometry(); - RangeType enVal ; + // get reference to cell average + RangeType& enVal = scaledFunction_.enVal_; bool limiter = false; @@ -523,7 +638,7 @@ namespace Fem limiter = true; } - RangeType theta( 1 ); + RangeType& theta = scaledFunction_.resetTheta(); CornerPointSetType cornerquad( en ); if( ! checkPhysicalQuad( cornerquad, uEn, enVal, theta ) ) @@ -554,14 +669,23 @@ namespace Fem limiter = true; } + for (auto t : theta) + { + if (t<1) // if scaling would be done + limiter = true; + } + // scale function if( limiter ) { // get local funnction for limited values DestLocalFunctionType limitEn = dest_->localFunction(en); - // project scaled function to limitEn - L2project(en, geo, enVal, uEn, theta, limitEn); + // set all dofs to zero + limitEn.clear(); + + const auto interpolation = spc_.interpolation( en ); + interpolation( scaledFunction_, limitEn.localDofVector() ); // set indicator 1 discreteModel_.markIndicator(); @@ -583,20 +707,19 @@ namespace Fem RangeType& theta ) const { // geometry and also use caching - const int quadNop = quad.nop(); const EntityType& en = uEn.entity(); - tmpVal_.resize( quadNop ); + auto& tmpVal = scaledFunction_.getValues( quad ); bool physical = true; // evaluate uEn on all quadrature points - uEn.evaluateQuadrature( quad , tmpVal_ ); + uEn.evaluateQuadrature( quad , tmpVal ); - //const Geometry& geo = en.geometry(); + const int quadNop = quad.nop(); for(int l=0; l<quadNop; ++l) { - const RangeType& u = tmpVal_[ l ]; + const RangeType& u = tmpVal[ l ]; for( const auto& d : discreteModel_.model().limitedRange() ) { @@ -609,8 +732,6 @@ namespace Fem theta[ d ] = std::min( std::min( upper, lower ), theta[d ]); } - // warning!!! caching of geo can be more efficient - //const DomainType& xgl = geo.global( quad[l] ); // check data if ( ! discreteModel_.physical( en, quad.point(l), u ) ) { @@ -623,78 +744,6 @@ namespace Fem return physical; } - // check physicality on given quadrature - template <class QuadratureType, class LocalFunctionImp> - bool checkPhysicalQuad(const QuadratureType& quad, - const LocalFunctionImp& uEn) const - { - // geometry and also use caching - const int quadNop = quad.nop(); - const EntityType& en = uEn.entity(); - - tmpVal_.resize( quadNop ); - - // evaluate uEn on all quadrature points - uEn.evaluateQuadrature( quad , tmpVal_ ); - - //const Geometry& geo = en.geometry(); - for(int l=0; l<quadNop; ++l) - { - const RangeType& u = tmpVal_[ l ]; - - // warning!!! caching of geo can be more efficient - //const DomainType& xgl = geo.global( quad[l] ); - // check data - if ( ! discreteModel_.physical( en, quad.point(l), u ) ) - { - // notPhysical - return false ; - } - } - } - - //! check physicallity of data - template <class LocalFunctionImp> - bool checkPhysical(const EntityType& en, - const Geometry& geo, - const LocalFunctionImp& uEn) const - { - enum { dim = dimGrid }; - if( discreteModel_.hasPhysical() ) - { -#if 1 - // use LagrangePointSet to evaluate on corners of the - // geometry and also use caching - return checkPhysicalQuad( CornerPointSetType( en ), uEn ); -#else - { - VolumeQuadratureType volQuad(en, volumeQuadOrd_ ); - if( ! checkPhysicalQuad(volQuad, uEn) ) return false; - } - - const IntersectionIteratorType endnit = gridPart_.iend(en); - for (IntersectionIteratorType nit = gridPart_.ibegin(en); - nit != endnit; ++nit) - { - const IntersectionType& intersection = *nit; - if( intersection.neighbor() && ! intersection.conforming() ) - { - typedef typename FaceQuadratureType :: NonConformingQuadratureType NonConformingQuadratureType; - NonConformingQuadratureType faceQuadInner(gridPart_,intersection, faceQuadOrd_, FaceQuadratureType::INSIDE); - if( ! checkPhysicalQuad( faceQuadInner, uEn ) ) return false; - } - else - { - // conforming case - FaceQuadratureType faceQuadInner(gridPart_,intersection, faceQuadOrd_, FaceQuadratureType::INSIDE); - if( ! checkPhysicalQuad( faceQuadInner, uEn ) ) return false; - } - } -#endif - } // end physical - return true; - } - template <class LocalFunctionImp, class SpaceImp> struct NumLinearBasis { @@ -732,82 +781,6 @@ namespace Fem } } - // L2 projection - template <class LocalFunctionImp> - void L2project(const EntityType& en, - const Geometry& geo, - const RangeType& enVal, - const LocalFunctionType& uEn, - const RangeType& theta, - LocalFunctionImp& limitEn ) const - { - enum { dim = dimGrid }; - - // true if geometry mapping is affine - const bool affineMapping = localMassMatrix_.affine(); - - // set all dofs to zero - limitEn.clear(); - - // get quadrature for destination space order - VolumeQuadratureType quad( en, volumeQuadratureOrder( en ) ); - - //std::cout << globalMin << " " << globalMax << std::endl; - //std::cout << minVal << " " << maxVal << std::endl; - - //old version that did not work well - /* - for( const auto& d : discreteModel_.model().limitedRange() ) - { - double fst = 1.0; - double sec = 1.0; - if( std::abs( maxVal[ d ] - enVal[ d ] ) > 1e-10 ) - fst = (globalMax[ d ] - enVal[ d ])/(maxVal[ d ] - enVal[ d ]); - - if( std::abs( minVal[ d ] - enVal[ d ] ) > 1e-10 ) - sec = (globalMin[ d ] - enVal[ d ])/(minVal[ d ] - enVal[ d ]); - - theta[ d ] = std::min( std::min( std::abs( fst ), std::abs( sec ) ), double(1) ); - if( std::abs( theta[d ] ) < 1e-12 ) - theta[ d ] = 0; - } - */ - - const int quadNop = tmpVal_.size();// quad.nop(); - assert( quadNop == int(quad.nop()) ); - - // this has been done previously in checkPhysicalQuad - // uEn.evaluateQuadrature( quad, tmpVal_ ); - - for(int qP = 0; qP < quadNop ; ++qP) - { - RangeType &value = tmpVal_[ qP ]; - - // \tilde{p}(x) = \theta (p(x) - \bar{u}) + \bar{u} - // limitedRange contains all components that should be modified - // default is 0,...,dimRange-1 - for( const auto& d : discreteModel_.model().limitedRange() ) - { - value[ d ] = theta[ d ] * ( value[ d ] - enVal[ d ]) + enVal[ d ]; - } - - // get quadrature weight - const double intel = (affineMapping) ? - quad.weight(qP) : // affine case - quad.weight(qP) * geo.integrationElement( quad.point(qP) ); // general case - - // quadrature scaling - value *= intel; - } - - // add all value to limitEn - limitEn.axpyQuadrature( quad, tmpVal_ ); - - // apply local inverse mass matrix for non-linear mappings - if( !affineMapping ) - localMassMatrix_.applyInverse( en, limitEn ); - } - template <class BasisFunctionSetType, class PointType> const RangeType& evaluateConstantBasis( const BasisFunctionSetType& basisSet, const PointType& x ) const @@ -839,7 +812,7 @@ namespace Fem RangeType& val) const { bool notphysical = false; - if( HierarchicalBasis< DiscreteFunctionSpaceType > :: v + if( Dune::Fem::Capabilities::isHierarchic< DiscreteFunctionSpaceType > :: v && localMassMatrix_.affine() ) { // get point quadrature @@ -928,6 +901,8 @@ namespace Fem const DiscreteFunctionSpaceType& spc_; GridPartType& gridPart_; + mutable ScaledFunction scaledFunction_; + const IndexSetType& indexSet_; CornerPointSetContainerType cornerPointSetContainer_; @@ -945,8 +920,6 @@ namespace Fem mutable RangeType globalMin_; mutable RangeType globalMax_ ; - mutable std::vector< RangeType > tmpVal_ ; - mutable std::vector< RangeType > aver_ ; // vector for stroing the information which elements have been computed already diff --git a/dune/fem-dg/operator/limiter/smoothness.hh b/dune/fem-dg/operator/limiter/smoothness.hh new file mode 100644 index 0000000000000000000000000000000000000000..b4e44959f0f45bceb9220cdf84d43a8dd0965302 --- /dev/null +++ b/dune/fem-dg/operator/limiter/smoothness.hh @@ -0,0 +1,115 @@ +#include <cmath> +#include <dune/common/fvector.hh> +#include <dune/common/fmatrix.hh> +#include <dune/common/dynvector.hh> +#include <dune/common/dynmatrix.hh> +#include <dune/fem/function/localfunction/const.hh> +#include <dune/fem/space/shapefunctionset/orthonormal.hh> +#include <dune/fem-dg/operator/limiter/indicatorbase.hh> + +template <class LF> +double smoothnessIndicator(const LF& uLocal) +{ + using ONB = Dune::Fem::OrthonormalShapeFunctions<LF::dimDomain>; + const std::size_t R = LF::dimRange; // will be using density + const std::size_t P = uLocal.order(); + assert(uLocal.size()/double(R) == ONB::size(P)); + // actually some inverse mass matrix needed here + const double area = uLocal.entity().geometry().volume(); + const double factor = 1/std::sqrt( area ); + // 1D monoments vector + double q[P+1]; + double b2[P+1]; + double f = 0; + std::size_t k = ONB::size(0); + q[0] = uLocal[0]*uLocal[0]; // constant part not used + double l2norm2 = 0; // q[0]; + for (std::size_t i=1;i<=P;++i) + { + q[i] = 0; + b2[i] = 0; + double nofMoments = ONB::size(i)-k; + assert(nofMoments == 1.); + for (;k<ONB::size(i);++k) + { + q[i] += uLocal[k*R]*uLocal[k*R] / nofMoments; + l2norm2 += uLocal[k*R]*uLocal[k*R] / nofMoments; + b2[i] += pow(1/double(i),2*P) / nofMoments; + f += pow(1/double(i),2*P) / nofMoments; + } + } +#if 0 + for (std::size_t i=0;i<=P;++i) + q[i] = std::sqrt( q[i] ) / factor; +#endif + for (std::size_t i=1;i<=P;++i) + { + /* + std::cout << "====: " << i << " " << q[i] << " " + << l2norm2 << " " << b2[i]/f << " " << l2norm2*b2[i]/f + << " -> " << std::sqrt( q[i] + l2norm2*b2[i]/f ) / factor + << std::endl; */ + q[i] = std::sqrt( q[i] + l2norm2*b2[i]/f ) / factor; + } + double maxQ = std::max( q[P], q[P-1] ); + // find first 'significant' mode + std::size_t significant = 0; + for (std::size_t i=P;i>=1;--i) + { + maxQ = std::max(maxQ, q[i]); + if (maxQ>1e-14) + { + significant = i; + break; + } + } + if (significant==0) // constant, i.e., very smooth indeed + return 100; + if (significant==1) // not quite clear if this needs to be fixed - + // solution is linear and we do not have enough info to fit + return 10; + + Dune::DynamicMatrix<double> matrix(significant,2); + Dune::DynamicVector<double> rhs(significant); + for (std::size_t r=significant; r-->0; ) + { + maxQ = std::max(maxQ, q[r+1]); + rhs[r] = std::log( maxQ ); + matrix[r][0] = 1; + matrix[r][1] = -std::log(double(r+1)); + } + Dune::FieldMatrix<double,2,2> A; + Dune::FieldVector<double,2> b; + for (std::size_t r=0;r<2;++r) + { + for (std::size_t c=0;c<2;++c) + { + A[r][c] = 0; + for (std::size_t k=0;k<significant;++k) + A[r][c] += matrix[k][r]*matrix[k][c]; + } + b[r] = 0; + for (std::size_t k=0;k<significant;++k) + b[r] += matrix[k][r]*rhs[k]; + } + Dune::FieldVector<double,2> x; + A.solve(x,b); + double s = x[1]; + assert(s==s); + // std::cout << " indicator= " << s << std::endl; + return s; +} +template <class DiscreteFunction> +struct ModalSmoothnessIndicator +: public Dune::Fem::TroubledCellIndicatorBase<DiscreteFunction> +{ + typedef typename DiscreteFunction :: LocalFunctionType LocalFunctionType; + double operator()( const DiscreteFunction& U, const LocalFunctionType& uEn) const override + { + double modalInd = smoothnessIndicator( uEn ); + if( std::abs( modalInd ) > 1e-14 ) + return 1.0 / modalInd ; + else + return 0.0; + } +}; diff --git a/dune/fem-dg/pass/dginversemass.hh b/dune/fem-dg/pass/dginversemass.hh index fcad09174fffe61041796a3a06f3cbebb4e1ade0..112838c274488e02d64010d262613ea466e50c7f 100644 --- a/dune/fem-dg/pass/dginversemass.hh +++ b/dune/fem-dg/pass/dginversemass.hh @@ -13,6 +13,8 @@ #include <dune/fem-dg/pass/pass.hh> #include <dune/fem-dg/pass/discretemodel.hh> +#include <dune/fem-dg/operator/dg/defaultquadrature.hh> + namespace Dune { @@ -94,7 +96,7 @@ namespace Dune explicit DGInverseMassPass ( PreviousPass &previousPass, const DiscreteFunctionSpaceType &space ) : BaseType( previousPass, space, "DGInverseMassPass" ), - localMassMatrix_( space, 2*space.order() ), + localMassMatrix_( space, [this](const int order) { return DefaultQuadrature<DiscreteFunctionSpaceType >::volumeOrder(order); } ), arg_( 0 ), dest_( 0 ) {} @@ -106,7 +108,8 @@ namespace Dune const int volQuadOrd = -1, const int faceQuadOrd = -1) : BaseType( previousPass, space, "DGInverseMassPass" ), - localMassMatrix_( space, ( volQuadOrd == -1 ) ? (2*space.order()) : volQuadOrd ), + localMassMatrix_( space, [this,volQuadOrd](const int order) { return + ( volQuadOrd == -1 ) ? DefaultQuadrature<DiscreteFunctionSpaceType >::volumeOrder(order) : volQuadOrd; } ), arg_( 0 ), dest_( 0 ) {} diff --git a/dune/fem-dg/pass/dgmasspass.hh b/dune/fem-dg/pass/dgmasspass.hh index e405b602d69cfb7f6c36ce71bb47d43e3618798e..467867f7db73418406381876fc87dcec50d084fd 100644 --- a/dune/fem-dg/pass/dgmasspass.hh +++ b/dune/fem-dg/pass/dgmasspass.hh @@ -14,6 +14,7 @@ #include <dune/fem-dg/pass/dginversemass.hh> #include <dune/fem-dg/misc/crs.hh> +#include <dune/fem-dg/operator/dg/defaultquadrature.hh> namespace Dune { @@ -107,7 +108,8 @@ namespace Dune : scalarSpace_( const_cast< GridPartType& > (key.gridPart()) ), volumeQuadratureOrder_( 2 * scalarSpace_.order() ), matrices_( Fem :: ThreadManager :: maxThreads() ), - localMassMatrix_( scalarSpace_ ), + localMassMatrix_( scalarSpace_, [this](const int order) { return + DefaultQuadrature< ScalarDiscreteFunctionSpaceType >::volumeOrder(order); } ), sequence_( -1 ) { assert( Fem::ThreadManager::singleThreadMode() ); diff --git a/dune/fem-dg/pass/dgpass.hh b/dune/fem-dg/pass/dgpass.hh index 0db741f100bedd1081496a4495a9375c97215c72..7a5e7fafc025ced5d39a19f230e619f159a7d4b7 100644 --- a/dune/fem-dg/pass/dgpass.hh +++ b/dune/fem-dg/pass/dgpass.hh @@ -19,6 +19,9 @@ #include <dune/fem-dg/pass/modelcaller.hh> #include <dune/fem-dg/pass/discretemodel.hh> #include <dune/fem/misc/compatibility.hh> +#include <dune/fem-dg/operator/dg/defaultquadrature.hh> + +#include <dune/fem/io/parameter.hh> namespace Dune { @@ -135,16 +138,34 @@ namespace Fem PreviousPassType& pass, const DiscreteFunctionSpaceType& spc, const int volumeQuadOrd = -1, - const int faceQuadOrd = -1 ) + const int faceQuadOrd = -1, + const bool verbose = Dune::Fem::Parameter::verbose() ) + : LocalCDGPass( discreteModel, pass, spc, Dune::Fem::Parameter::container(), volumeQuadOrd, faceQuadOrd, verbose ) + {} + + //- Public methods + //! Constructor + //! \param discreteModel Actual discrete model definition (see dgdiscretemodels.hh) + //! \param pass Previous pass + //! \param spc Space belonging to the discrete function local to this pass + //! \param volumeQuadOrd defines the order of the volume quadrature which is by default 2* space polynomial order + //! \param faceQuadOrd defines the order of the face quadrature which is by default 2* space polynomial order + LocalCDGPass( DiscreteModelType& discreteModel, + PreviousPassType& pass, + const DiscreteFunctionSpaceType& spc, + const Dune::Fem::ParameterReader& /* parameter */, + const int volumeQuadOrd = -1, + const int faceQuadOrd = -1, + const bool verbose = Dune::Fem::Parameter::verbose() ) : BaseType(pass, spc), caller_(), discreteModel_(discreteModel), - arg_(0), - dest_(0), + arg_( nullptr ), + dest_( nullptr ), spc_(spc), gridPart_(spc_.gridPart()), indexSet_(gridPart_.indexSet()), - visited_(0), + visited_(), updEn_(spc_), updNeigh_(spc_), valEnVec_( 20 ), @@ -159,7 +180,7 @@ namespace Fem #ifdef USE_CACHED_INVERSE_MASSMATRIX localMassMatrix_( InverseMassProviderType :: getObject( MassKeyType( gridPart_ ) ) ), #else - localMassMatrix_( spc_ , volumeQuadOrd_ ), + localMassMatrix_( spc_ , [this](const int order) { return DefaultQuadrature<DiscreteFunctionSpaceType >::volumeOrder(order); } ), #endif reallyCompute_( true ) { @@ -642,10 +663,10 @@ namespace Fem // eval boundary Flux wspeedS += caller().boundaryFlux(intersection, - faceQuadInner, - l, - fluxEn, - diffFluxEn) + faceQuadInner, + l, + fluxEn, + diffFluxEn) * faceQuadInner.weight(l); // apply weights @@ -751,6 +772,7 @@ namespace Fem flux *= intel; } + // add values to local function updEn.axpyQuadrature( volQuad, valJacEn_ ); } @@ -921,13 +943,13 @@ namespace Fem //! return default face quadrature order static int defaultVolumeQuadratureOrder( const DiscreteFunctionSpaceType& space, const EntityType& entity ) { - return (2 * space.order( entity )); + return DefaultQuadrature< DiscreteFunctionSpaceType >::volumeOrder( space.order( entity ) ); } - //! return default face quadrature order + //! return default face quadrature static int defaultFaceQuadratureOrder( const DiscreteFunctionSpaceType& space, const EntityType& entity ) { - return (2 * space.order( entity )) + 1; + return DefaultQuadrature< DiscreteFunctionSpaceType >::faceOrder( space.order( entity ) ); } protected: diff --git a/dune/fem-dg/pass/threadpass.hh b/dune/fem-dg/pass/threadpass.hh index 4f63f708cca26917b5e017949730fb288d8b3e0d..0aa7fa4c8492d43a7b2064aead4e8eec53ba18fa 100644 --- a/dune/fem-dg/pass/threadpass.hh +++ b/dune/fem-dg/pass/threadpass.hh @@ -213,6 +213,22 @@ namespace Fem PreviousPassType& pass, const DiscreteFunctionSpaceType& spc, const int volumeQuadOrd = -1, + const int faceQuadOrd = -1) + : ThreadPass( discreteModel, pass, spc, Dune::Fem::Parameter::container(), volumeQuadOrd, faceQuadOrd ) + {} + + /** \brief Constructor + * \param discreteModel Actual discrete model + * \param pass Previous pass + * \param spc Space belonging to the discrete function local to this pass + * \param volumeQuadOrd defines the order of the volume quadrature which is by default 2* space polynomial order + * \param faceQuadOrd defines the order of the face quadrature which is by default 2* space polynomial order + */ + ThreadPass(const DiscreteModelType& discreteModel, + PreviousPassType& pass, + const DiscreteFunctionSpaceType& spc, + const Dune::Fem::ParameterReader ¶meter, + const int volumeQuadOrd = -1, const int faceQuadOrd = -1) : BaseType(pass, spc), delDofs_( spc ), @@ -229,7 +245,8 @@ namespace Fem faceQuadOrd_( faceQuadOrd ), firstCall_( true ), requireCommunication_( true ), - sumComputeTime_( Fem :: Parameter :: getValue<bool>("fem.parallel.sumcomputetime", false ) ) + parameter_( ¶meter ), + sumComputeTime_( parameter.getValue<bool>("fem.parallel.sumcomputetime", false ) ) { // initialize quadratures before entering multithread mode initializeQuadratures( spc, volumeQuadOrd, faceQuadOrd ); @@ -254,6 +271,17 @@ namespace Fem #endif // get information about communication requireCommunication_ = passes_[ 0 ]->requireCommunication(); + parameter_ = nullptr; + } + + template <class TroubledCellIndicatorType> + void setTroubledCellIndicator( TroubledCellIndicatorType indicator ) + { + const int maxThreads = Fem::ThreadManager::maxThreads(); + for(int i=0; i<maxThreads; ++i) + { + passes_[ i ]->setTroubledCellIndicator( indicator ); + } } static void initializeQuadratures( const DiscreteFunctionSpaceType& space, const int volQuadOrder, const int faceQuadOrder ) @@ -595,8 +623,17 @@ namespace Fem { // use separate discrete discrete model for each thread discreteModels_[ thread ] = new DiscreteModelType( singleDiscreteModel_ ); - // create dg passes, the last bool disables communication in the pass itself - passes_[ thread ] = new InnerPassType( *discreteModels_[ thread ], previousPass_, space(), volumeQuadOrd_, faceQuadOrd_ ); + const bool verbose = Dune::Fem::Parameter::verbose() && Fem::ThreadManager::isMaster(); + if( parameter_ ) + { + // create dg passes, the last bool disables communication in the pass itself + passes_[ thread ] = new InnerPassType( *discreteModels_[ thread ], previousPass_, space(), *parameter_, volumeQuadOrd_, faceQuadOrd_, verbose ); + } + else + { + // create dg passes, the last bool disables communication in the pass itself + passes_[ thread ] = new InnerPassType( *discreteModels_[ thread ], previousPass_, space(), volumeQuadOrd_, faceQuadOrd_, verbose ); + } return ; } @@ -732,6 +769,9 @@ namespace Fem const int faceQuadOrd_; mutable bool firstCall_; bool requireCommunication_; + + const Dune::Fem::ParameterReader* parameter_; + const bool sumComputeTime_; }; //! @} diff --git a/dune/fem-dg/python/operator.hh b/dune/fem-dg/python/operator.hh index 9f0f46c15905bbc27a765d1100c0c38448cbd51a..cb66e247b3425155600b00c61d624c4b9a599cf1 100644 --- a/dune/fem-dg/python/operator.hh +++ b/dune/fem-dg/python/operator.hh @@ -73,7 +73,7 @@ namespace Dune cls.def( "applyLimiter", []( Operator &self, DF &u) { self.applyLimiter(u); } ); // cls.def( "setTime", &Operator::setTime); cls.def( "_setTime", &Operator::setTime); - cls.def_property_readonly("timeStepEstimate", + cls.def_property_readonly("localTimeStepEstimate", [](const Operator &self) -> std::tuple<double,double,double> { return {self.timeStepEstimate(), self.explicitOperator().timeStepEstimate(), diff --git a/dune/fem-dg/solver/rungekuttasolver.hh b/dune/fem-dg/solver/rungekuttasolver.hh index 37fc487dad112b1c4373066028e6237374077118..b6261c0216f9f625e5ca31226221904a4dd296f0 100644 --- a/dune/fem-dg/solver/rungekuttasolver.hh +++ b/dune/fem-dg/solver/rungekuttasolver.hh @@ -291,7 +291,6 @@ namespace Fem // create implicit or explicit ode solver if( odeSolverType_ == 0 ) { - std::cout << "Creating explicit ode solver" << std::endl; solver = OdeSolversType :: createExplicitSolver( operator_, tp, rkSteps_, *param_, parameter, name_ ); } else if (odeSolverType_ == 1) @@ -346,7 +345,11 @@ namespace Fem else tpPtr_->init(); tpPtr_->init(); - std::cout << "cfl = " << double(tpPtr_->factor()) << ", T_0 = " << tpPtr_->time() << std::endl; + + if( Dune::Fem::Parameter::verbose() ) + { + std::cout << "cfl = " << double(tpPtr_->factor()) << ", T_0 = " << tpPtr_->time() << std::endl; + } } void initialize( const DestinationType& U ) diff --git a/dune/optim/common/smallobject.hh b/dune/optim/common/smallobject.hh index f210d2fffb47c86f8370f07ed558d088c15d9c5f..c0b85477c1fb3743b565acdf6f88a5b3cc27e024 100644 --- a/dune/optim/common/smallobject.hh +++ b/dune/optim/common/smallobject.hh @@ -74,7 +74,7 @@ namespace Dune static SmallObjectPool &instance () { - static SmallObjectPool inst; + static thread_local SmallObjectPool inst; return inst; } diff --git a/pydemo/euler/euler.py b/pydemo/euler/euler.py index 93be7d81c6264bd923f389cb761c37fc6190227b..b70c3376ebc2a4bc98735822840803d4f06e2561 100644 --- a/pydemo/euler/euler.py +++ b/pydemo/euler/euler.py @@ -1,5 +1,6 @@ from ufl import * from dune.common import FieldVector +from dune.grid import reader from dune.ufl import Space, GridFunction from dune.fem.function import gridFunction import numpy @@ -128,7 +129,8 @@ def sod(dim=2,gamma=1.4): #Model.domain=[[0, 0], [1, 0.25], [256, 64]] #Model.domain=[[0, 0], [1, 0.25], [128, 32]] Model.domain=[[0, 0], [1, 0.25], [64, 16]] - Model.endTime=0.15 + Model.domain=(reader.dgf, "grid2d_nonaffine.dgf") + Model.endTime=0.25 def chorin(gv,t): gf = gv.function("chorin","chorin.hh", Vl,Vr,gamma,x0,t,name="chorin") lgf = gf.localFunction() # this seems to fail? @@ -137,7 +139,7 @@ def sod(dim=2,gamma=1.4): lgf.bind(e) return FieldVector( Model.toCons(lgf(x)) ) # return Model.toCons(gf(e,x)) - lf.plot() + # lf.plot() return lf Model.exact = lambda gv,t: chorin(gv,t) Model.name="sod" diff --git a/pydemo/euler/main.py b/pydemo/euler/main.py index 6861621b6ca3c71208d6396cf615c37403f0fcdd..577bc3cd62d141409c577a2a26efd0c799315dee 100644 --- a/pydemo/euler/main.py +++ b/pydemo/euler/main.py @@ -1,6 +1,7 @@ -import mpi4py.rc +#import mpi4py.rc # mpi4py.rc.threaded = False from dune.fem import parameter +from dune.alugrid import aluCubeGrid from dune.femdg.testing import run # from euler import constant as problem @@ -12,15 +13,13 @@ from euler import sod as problem dim = 2 gamma = 1.4 -parameter.append({"fem.verboserank": -1}) +parameter.append({"fem.verboserank": 0}) primitive=lambda Model,uh: {"pressure": Model.toPrim(uh)[2]} parameters = {"fem.ode.odesolver": "EX", - "fem.timeprovider.factor": 0.25, "fem.ode.order": 3, - "femdg.limiter.admissiblefunctions": 1, - "femdg.limiter.tolerance": 1, - "femdg.limiter.epsilon": 1e-8} + "femdg.limiter.tolerance":1 } + #----------------- # "dgadvectionflux.method": "EULER-HLLC", "EULER-HLL", "LLF" # default value is 'LLF' @@ -31,10 +30,16 @@ parameters = {"fem.ode.odesolver": "EX", # 0 = only dg solution | 1 = only reconstruction | 2 = both #----------------- -run(problem(), - startLevel=0, polOrder=2, limiter="default", - primitive=primitive, saveStep=0.16, subsamp=2, - dt=None,threading=False,grid="alucube", space="dgonb", +Model = problem() +Model.domain = aluCubeGrid(Model.domain,dimgrid=2) + +run(Model, + startLevel=3, polOrder=4, limiter="default", + primitive=primitive, saveStep=0.05, subsamp=2, + dt=None,threading=False,grid="alucube", + space="dglagrange", + # space=("dglagrange","lobatto"), + # space=("dglagrange","gauss"), parameters=parameters) # print(str(parameter)) diff --git a/pydemo/euler/testdg.py b/pydemo/euler/testdg.py index ec0e7a639a3f5ecf8b22dd6717da87ccd0c7206a..d4c914d9a546cdd44db294aaf34b6f823f9f71cb 100644 --- a/pydemo/euler/testdg.py +++ b/pydemo/euler/testdg.py @@ -1,5 +1,7 @@ -import mpi4py.rc +# import mpi4py.rc # mpi4py.rc.threaded = False +help("modules") + from dune.fem import parameter from dune.femdg.testing import run diff --git a/pydemo/euler/testfv0.py b/pydemo/euler/testfv0.py index 04b78d05429677547f50f46a89da44b277162723..1befbcbb8d850f6542191f11049a0d2b202949d3 100644 --- a/pydemo/euler/testfv0.py +++ b/pydemo/euler/testfv0.py @@ -1,4 +1,4 @@ -import mpi4py.rc +# import mpi4py.rc # mpi4py.rc.threaded = False from dune.fem import parameter from dune.femdg.testing import run diff --git a/pydemo/euler/testfv1.py b/pydemo/euler/testfv1.py index 9b186a3043d2416037c3c6c9232cee32c5245f3c..b1123c08c32d1d246b242788ab012f40f6735b00 100644 --- a/pydemo/euler/testfv1.py +++ b/pydemo/euler/testfv1.py @@ -1,4 +1,4 @@ -import mpi4py.rc +# import mpi4py.rc # mpi4py.rc.threaded = False from dune.fem import parameter from dune.femdg.testing import run diff --git a/pydemo/euler/testpolyfv1.py b/pydemo/euler/testpolyfv1.py index b72cb5134f347554773018a2771492c28e24f8e6..ec88912ae4e536262b99502887decefc451fc506 100644 --- a/pydemo/euler/testpolyfv1.py +++ b/pydemo/euler/testpolyfv1.py @@ -1,4 +1,4 @@ -import mpi4py.rc +# import mpi4py.rc # mpi4py.rc.threaded = False from dune.fem import parameter from dune.femdg.testing import run @@ -38,7 +38,7 @@ Model.exact = None run(Model, startLevel=0, limiter="default", - primitive=primitive, saveStep=0.16, subsamp=2, + primitive=primitive, saveStep=0.16, dt=None,threading=False,grid="polygon", space="finitevolume", parameters=parameters) diff --git a/python/dune/femdg/_operators.py b/python/dune/femdg/_operators.py index fd06811049bcb742c7033789bf0fdfd8aa7c229a..b182b6c5706716d545a606a04b7179e468e97a8c 100644 --- a/python/dune/femdg/_operators.py +++ b/python/dune/femdg/_operators.py @@ -1,12 +1,15 @@ from __future__ import absolute_import, division, print_function, unicode_literals -import sys +import sys, hashlib import logging logger = logging.getLogger(__name__) +from io import StringIO from dune.common.checkconfiguration import assertHave, preprocessorAssert, ConfigurationError +from dune.typeregistry import generateTypeName from dune.generator import Constructor, Method +from dune.generator.importclass import load as classLoad from dune.common.hashit import hashIt from dune.fem.operator import load from dune.fem import parameter as parameterReader @@ -83,31 +86,10 @@ def createOrderRedcution(domainSpace): return load(includes, typeName, constructor).Operator( domainSpace ) ##################################################### -## fem-dg Operator +## fem-dg models ##################################################### from dune.femdg.patch import transform -# create DG operator + solver (limiter = none,minmod,vanleer,superbee), -# (diffusionScheme = cdg2,br2,ip,nipg,...) -def femDGOperator(Model, space, - limiter="minmod", - advectionFlux="default", - diffusionScheme = "cdg2", threading=False, - initialTime=0.0, parameters=None): - virtualize = False - import dune.create as create - - includes = [] - - if limiter is None or limiter is False: - limiter = "unlimited" - - if limiter.lower() == "default": - limiter = "minmod" - - # TODO: does this make sense - if there is no diffusion then it doesn't - # matter and with diffusion using 'none' seems a bad idea? - if diffusionScheme is None or diffusionScheme is False: - diffusionScheme = "none" +def femDGModels(Model, space, initialTime=0): u = TrialFunction(space) v = TestFunction(space) @@ -144,13 +126,124 @@ def femDGOperator(Model, space, diffModel += inner(as_vector(Model.S_impl(t,x,u,grad(u))),v)*dx print("Model.S_s is deprecated. Use S_i instead!") - advModel = create.model("elliptic",space.grid, advModel, + from dune.fem.model import elliptic + virtualize = False + + advModel = elliptic(space.grid, advModel, modelPatch=transform(Model,space,t,"Adv"), virtualize=virtualize) - diffModel = create.model("elliptic",space.grid, diffModel, + diffModel = elliptic(space.grid, diffModel, modelPatch=transform(Model,space,t,"Diff"), virtualize=virtualize) + Model._ufl = {"u":u,"v":v,"n":n,"x":x,"t":t} + + return [Model,advModel,diffModel] + +##################################################### +## fem-dg Operator +##################################################### +# create DG operator + solver (limiter = none,default,minmod,vanleer,superbee,lp,scaling), +# (diffusionScheme = cdg2,cdg,br2,ip,nipg,bo) +def femDGOperator(Model, space, + limiter="default", + advectionFlux="default", + diffusionScheme = "cdg2", + threading=False, + defaultQuadrature=True, + codegen=True, + initialTime=0.0, parameters=None): + """ create DG operator + ODE solver + + Args: + Model: analytical model describing the PDE and auxiliary functionality + space: discrete function space (DG space) + limiter: choice of limiter stabilization, possible values are + none,default,minmod,vanleer,superbee,lp,scaling + advectionFlux: choice of numerical flux for advective parts + default is local Lax-Friedrichs + diffusionScheme: choice of numerical flux for diffusive parts + possible choices are cdg2(default),cdg,br2,ip,nipg,bo + threading: enable shared memory parallelization + defaultQuadrature: use quadratures that generically fit to the space + codegen: enable optimized code for evaluation and interpolation + initialTime: T_0, default is 0.0 + parameters: Additional parameter passed to the DG operator, limiter and ODE solvers + Returns: + DGOperator + """ + + includes = [] + + # obtain information about limiter interface before Model + # is augmented with default implementations + hasScalingInterface = hasattr(Model,"lowerBound") or hasattr(Model,"upperBound") or hasattr(Model,"physical") + hasLimiterInterface = (hasattr(Model,"jump") and hasattr(Model,"velocity")) or hasattr(Model,"physical") + + if type(Model)==list or type(Model)==tuple: + advModel = Model[1] + diffModel = Model[2] + Model = Model[0] + else: + Model, advModel, diffModel = femDGModels(Model,space,initialTime) + + hasAdvFlux = hasattr(Model,"F_c") + hasDiffFlux = hasattr(Model,"F_v") + hasStiffSource = hasattr(Model,"S_i") or hasattr(Model,"S_s") + hasNonStiffSource = hasattr(Model,"S_e") or hasattr(Model,"S_ns") + + virtualize = False + + defaultLimiter = limiter == "default" + + if limiter is None or limiter is False: + limiter = "unlimited" + + if type(limiter) in [list,tuple]: + limiterIndicator = limiter[1] + limiter = limiter[0] + else: + limiterIndicator = None + + limiterstr = limiter + if limiter.lower() == "default": + # check for limiter interface implementation + if not hasLimiterInterface: + print("\nfemDGOperator: Limiter selected but limiter interface (jump,velocity,physical) missing in Model!", flush=True) + print("femDGOperator: Falling back to unlimited!\n", flush=True) + limiter = "unlimited" + else: + # default is minmod which can be either lp-minmod or muscl-minmod + limiter = "minmod" + limiterstr = limiter if space.grid.type.isSimplex else "lp" + # force default values for how reconstruction is done + parameters["femdg.limiter.admissiblefunctions"] = "default" + + if limiter.lower() == "lp": + limiter = "minmod" + # force default values for how reconstruction is done + parameters["femdg.limiter.admissiblefunctions"] = "lp" + + if limiter.lower() == "scaling": + # check for scaling limiter interface + if not hasScalingInterface: + raise KeyError(\ + "femDGOperator: ScalingLimiter selected but scaling limiter interface (lowerBound,upperBound,physical) missing in Model!\n") + elif limiter.lower() != "unlimited": + # check for scaling limiter interface + if not hasScalingInterface: + raise KeyError(\ + "femDGOperator: MUSCL type stabilization selected but limiter interface (jump,velocity,physical) missing in Model!\n") + + if space.grid.comm.rank == 0: + limiterstr = "default(" + limiterstr + ")" if defaultLimiter else limiterstr + print("femDGOperator: Limiter =",limiterstr) + + # TODO: does this make sense - if there is no diffusion then it doesn't + # matter and with diffusion using 'none' seems a bad idea? + if diffusionScheme is None or diffusionScheme is False: + diffusionScheme = "none" + spaceType = space._typeName if virtualize: @@ -197,13 +290,13 @@ def femDGOperator(Model, space, # at the moment this is always the same type (depending on # model._typeName) so could be done by only providing the header # file in the dg operator construction method - from dune.typeregistry import generateTypeName clsName,includes = generateTypeName("Dune::Fem::DGAdvectionFlux",advModel._typeName,"Dune::Fem::AdvectionFlux::Enum::userdefined") advectionFlux = advectionFlux(advModel,clsName,includes) includes += advectionFlux._includes - #elif advectionFlux.lower().find(".h") >= 0: - # advFluxId = "Dune::Fem::AdvectionFlux::Enum::userdefined" - # includes += [ advectionFlux ] + elif hasattr(advectionFlux,"_typeName"): + advFluxId = "Dune::Fem::AdvectionFlux::Enum::userdefined" + advectionFluxIsCallable = True + includes += advectionFlux._includes else: # if dgadvectionflux.method has been selected, then use general flux, # otherwise default to LLF flux @@ -242,7 +335,8 @@ def femDGOperator(Model, space, elif limiter.lower() != "minmod": raise ValueError("limiter "+limiter+" not recognised") - signature = (advFluxId,diffusionScheme,threading,solverId,formId,limiterId,limiterFctId,advFluxId,diffFluxId,) + signature = (advFluxId,diffusionScheme,threading,solverId,formId, + limiterId,limiterFctId,advFluxId,diffFluxId,str(defaultQuadrature)) additionalClass = "Additional_"+hashIt(str(signature)) struct = Struct(additionalClass, targs=['class FunctionSpace']) struct.append(TypeAlias('DomainType','typename FunctionSpace::DomainType')) @@ -258,8 +352,7 @@ def femDGOperator(Model, space, limitedDimRange = "FunctionSpace :: dimRange" else: limiterModified = {} - count = 0 - for id,f in limiterModifiedDict.items(): count += 1 + count = len( limiterModifiedDict.items() ) limitedDimRange = str(count) struct.append([Declaration( Variable("const int", "limitedDimRange = " + limitedDimRange), @@ -303,6 +396,9 @@ def femDGOperator(Model, space, struct.append([Declaration( Variable("const Dune::Fem::DiffusionFlux::Enum", "diffFluxId = " + diffFluxId), static=True)]) + struct.append([Declaration( + Variable("const bool", "defaultQuadrature"), initializer=defaultQuadrature, + static=True)]) writer = SourceWriter(StringWriter()) writer.emit([struct]) @@ -329,33 +425,50 @@ def femDGOperator(Model, space, _, domainFunctionIncludes, domainFunctionType, _, _, _ = space.storage base = 'Dune::Fem::SpaceOperatorInterface< ' + domainFunctionType + '>' - estimateMark = Method('estimateMark', '''[]( DuneType &self, const typename DuneType::DestinationType &u, const double dt) { self.estimateMark(u, dt); }''' ); + estimateMark = Method('estimateMark', '''[]( DuneType &self, const typename DuneType::DestinationType &u, const double dt) { self.estimateMark(u, dt); }''' ) + + includes += ["dune/fem-dg/operator/limiter/indicatorbase.hh"] + setIndicator = Method('setTroubledCellIndicator', + args=['DuneType &self, typename DuneType::TroubledCellIndicatorType indicator'], + body=['self.setTroubledCellIndicator(indicator);'], + extra=['pybind11::keep_alive<0,1>()']) + gridSizeInterior = Method('gridSizeInterior', '&DuneType::gridSizeInterior') + + order = space.order + if codegen: + codegen = [space,range(2,2*order+2),range(2,2*order+2)] + else: + codegen = None if parameters is not None: if advectionFluxIsCallable: - op = load(includes, typeName, estimateMark, - baseClasses = [base], + op = load(includes, typeName, estimateMark, setIndicator, gridSizeInterior, + baseClasses=[base], + codegen=codegen, preamble=writer.writer.getvalue()).\ Operator( space, advModel, diffModel, advectionFlux, parameters=parameters ) else: - op = load(includes, typeName, estimateMark, + op = load(includes, typeName, estimateMark, setIndicator, gridSizeInterior, baseClasses = [base], + codegen=codegen, preamble=writer.writer.getvalue()).\ Operator( space, advModel, diffModel, parameters=parameters ) else: if advectionFluxIsCallable: - op = load(includes, typeName, estimateMark, + op = load(includes, typeName, estimateMark, setIndicator, gridSizeInterior, baseClasses = [base], + codegen=codegen, preamble=writer.writer.getvalue()).\ Operator( space, advModel, diffModel, advectionFlux ) else: - op = load(includes, typeName, estimateMark, + op = load(includes, typeName, estimateMark, setIndicator, gridSizeInterior, baseClasses = [base], + codegen=codegen, preamble=writer.writer.getvalue()).\ Operator( space, advModel, diffModel ) - op._t = t - op.time = t.value + op._t = Model._ufl["t"] + op.time = Model._ufl["t"].value op.models = [advModel,diffModel] op.space = space def setTime(self,time): @@ -371,8 +484,40 @@ def femDGOperator(Model, space, op.stepTime = stepTime.__get__(op) op._hasAdvFlux = hasAdvFlux op._hasDiffFlux = hasDiffFlux + if limiterIndicator is not None: + op.setTroubledCellIndicator(limiterIndicator) return op +def smoothnessIndicator(clsName, includes, u_h, ctorArgs=None): + if ctorArgs is None: ctorArgs=[] + baseName,_ = generateTypeName("Dune::Fem::TroubledCellIndicatorBase",u_h) + return classLoad(clsName, includes,*ctorArgs, baseClasses=[baseName], + holder="std::shared_ptr") +def advectionNumericalFlux(clsName ,includes, advModel, additionalArgs=None): + if additionalArgs is None: additionalArgs=[] + code = ''' +namespace Dune +{ + namespace Fem + { + template <> + struct DGAdvectionFlux< XXXADV_MODELXXX, AdvectionFlux::Enum::userdefined > + : public XXXIMPL_MODELXXX + { + template< class ... Args> + DGAdvectionFlux( Args&&... args ) + : XXXIMPL_MODELXXX( std::forward<Args>(args)... ) {} + std::string name() const {return "user defined flux";} + }; + } +} +''' + code = code.replace("XXXADV_MODELXXX",advModel._typeName) + code = code.replace("XXXIMPL_MODELXXX",clsName) + clsName,includesA = generateTypeName("Dune::Fem::DGAdvectionFlux",advModel, + "Dune::Fem::AdvectionFlux::Enum::userdefined") + return classLoad(clsName, includes+includesA+[StringIO(code)], advModel, *additionalArgs) + # RungeKutta solvers def rungeKuttaSolver( fullOperator, imex='EX', butchertable=None, parameters={} ): @@ -410,9 +555,11 @@ def rungeKuttaSolver( fullOperator, imex='EX', butchertable=None, parameters={} setTimeStepSize = Method('setTimeStepSize', '&DuneType::setTimeStepSize') deltaT = Method('deltaT', '&DuneType::deltaT') - return load(includes, typeName, constructor, solve, setTimeStepSize, deltaT).Operator( - fullOperator.fullOperator, - fullOperator.explicitOperator, - fullOperator.implicitOperator, - imexId, - parameters=parameters) + return load(includes, typeName, + constructor, solve, setTimeStepSize, deltaT, + codegen=fullOperator.codegen).\ + Operator( fullOperator.fullOperator, + fullOperator.explicitOperator, + fullOperator.implicitOperator, + imexId, + parameters=parameters ) diff --git a/python/dune/femdg/patch.py b/python/dune/femdg/patch.py index 599091f293d8a23cb2687ed494f0a05a2ffea78f..65d132fb0efd5ee1feb963da3d05138ac0e1a38d 100644 --- a/python/dune/femdg/patch.py +++ b/python/dune/femdg/patch.py @@ -1,9 +1,12 @@ -from __future__ import division, print_function, unicode_literals -# from dune.ufl.codegen import generateMethod -from ufl import grad, TrialFunction, SpatialCoordinate, FacetNormal, Coefficient, replace, diff, as_vector +from functools import reduce + +from ufl import grad, TrialFunction, SpatialCoordinate, FacetNormal,\ + Coefficient, replace, diff, as_vector,\ + conditional from ufl.core.expr import Expr -from dune.source.cplusplus import Variable, UnformattedExpression, AccessModifier, Declaration +from dune.source.cplusplus import Variable, UnformattedExpression,\ + AccessModifier, Declaration, Method from ufl.algorithms import expand_compounds, expand_derivatives, expand_indices, expand_derivatives def uflExpr(Model,space,t): @@ -11,6 +14,30 @@ def uflExpr(Model,space,t): n = FacetNormal(space.cell()) x = SpatialCoordinate(space.cell()) + physicalBound = None + lowerBound = getattr(Model,"lowerBound",None) + if lowerBound is None: + lowerBound = space.dimRange*["std::numeric_limits<double>::min()"] + else: + lowerCond = [conditional(u[i]>=lowerBound[i],1,0) + for i in range(len(lowerBound)) + if lowerBound[i] is not None ] + if lowerCond != []: + physicalBound = reduce( (lambda x,y: x*y), lowerCond ) + else: lowerBound=space.dimRange*["std::numeric_limits<double>::min()"] + upperBound = getattr(Model,"upperBound",None) + if upperBound is None: + upperBound = space.dimRange*["std::numeric_limits<double>::max()"] + else: + upperCond = [conditional(u[i]<=upperBound[i],1,0) + for i in range(len(upperBound)) + if upperBound[i] is not None ] + if upperCond != []: + physicalBound_ = reduce( (lambda x,y: x*y), upperCond ) + physicalBound = physicalBound_ if physicalBound is None else\ + physicalBound*physicalBound_ + else: upperBound=space.dimRange*["std::numeric_limits<double>::min()"] + maxSpeed = getattr(Model,"maxLambda",None) if maxSpeed is not None: maxSpeed = maxSpeed(t,x,u,n) @@ -20,9 +47,14 @@ def uflExpr(Model,space,t): diffusionTimeStep = getattr(Model,"maxDiffusion",None) if diffusionTimeStep is not None: diffusionTimeStep = diffusionTimeStep(t,x,u) - physical = getattr(Model,"physical",None) - if physical is not None: + physical = getattr(Model,"physical",True) + if not isinstance(physical,bool): physical = physical(t,x,u) + if physicalBound is not None: + physical = physical*physicalBound + else: + if physicalBound is not None: + physical = physical*physicalBound # TODO: jump is problematic since the coefficient 'w' causes issues - # no predefined when extracting required Coefficients so needs fixing # So jump is not returned by this method and is constructed again in @@ -61,7 +93,7 @@ def uflExpr(Model,space,t): elif not hasAdvFlux and hasDiffFlux: boundaryDFlux.update( [ (kk,method) for kk in ids] ) else: - assert not (hasAdvFlux and hasDiffFlux), "one boundary fluxes provided for id "+str(k)+" but two bulk flux given" + assert not (hasAdvFlux and hasDiffFlux), "one boundary fluxes provided for id "+str(k)+" but two bulk fluxes given" except TypeError: try: method = f(t,x,u) @@ -78,12 +110,13 @@ def uflExpr(Model,space,t): limitedDimRange = "DFunctionSpace :: dimRange" else: limiterModified = {} - count = 0 - for id,f in limiterModifiedDict.items(): count += 1 + count = len(limiterModifiedDict.items()) + # for id,f in limiterModifiedDict.items(): count += 1 limitedDimRange = str(count) # jump = None # TODO: see comment above return maxSpeed, velocity, diffusionTimeStep, physical, jump,\ - boundaryAFlux, boundaryDFlux, boundaryValue, hasBoundaryValue + boundaryAFlux, boundaryDFlux, boundaryValue, hasBoundaryValue,\ + physicalBound def codeFemDg(self): code = self._code() @@ -100,6 +133,30 @@ def codeFemDg(self): n = FacetNormal(space.cell()) x = SpatialCoordinate(space.cell()) + physicalBound = None + lowerBound = getattr(Model,"lowerBound",None) + if lowerBound is None: + lowerBound = space.dimRange*["std::numeric_limits<double>::min()"] + else: + lowerCond = [conditional(u[i]>=lowerBound[i],1,0) + for i in range(len(lowerBound)) + if lowerBound[i] is not None ] + if lowerCond != []: + physicalBound = reduce( (lambda x,y: x*y), lowerCond ) + else: lowerBound=space.dimRange*["std::numeric_limits<double>::min()"] + upperBound = getattr(Model,"upperBound",None) + if upperBound is None: + upperBound = space.dimRange*["std::numeric_limits<double>::max()"] + else: + upperCond = [conditional(u[i]<=upperBound[i],1,0) + for i in range(len(upperBound)) + if upperBound[i] is not None ] + if upperCond != []: + physicalBound_ = reduce( (lambda x,y: x*y), upperCond ) + physicalBound = physicalBound_ if physicalBound is None else\ + physicalBound*physicalBound_ + else: upperBound=space.dimRange*["std::numeric_limits<double>::min()"] + # TODO come up with something better! hasGamma = getattr(Model,"gamma",None) code.append([Declaration( @@ -158,10 +215,15 @@ def codeFemDg(self): targs=['class Entity, class Point, class T'], const=True, predefined=predefined) - # QUESTION: should `physical` actually depend on x? Perhaps even t? physical = getattr(Model,"physical",True) if not isinstance(physical,bool): physical = physical(t,x,u) + if physicalBound is not None: + physical = physical*physicalBound + else: + if physicalBound is not None: + physical = physical*physicalBound + self.generateMethod(code, physical, 'double', 'physical', args=['const Entity &entity', 'const Point &x', @@ -285,15 +347,24 @@ def codeFemDg(self): limitedDimRange = "DFunctionSpace :: dimRange" else: limiterModified = {} - count = 0 - for id,f in limiterModifiedDict.items(): count += 1 + count = len(limiterModifiedDict.items()) + # for id,f in limiterModifiedDict.items(): count += 1 limitedDimRange = str(count) self.generateMethod(code, limiterModified, 'void', 'limitedRange', args=['LimitedRange& limRange'], targs=['class LimitedRange'], const=True, evalSwitch=False, predefined=predefined) - + obtainBounds = Method("void","obtainBounds", + targs=['class LimitedRange'], + args=["LimitedRange& globalMin","LimitedRange& globalMax"],const=True) + obtainBounds.append("globalMin = {" + + ', '.join(map(str, lowerBound)) + +"};") + obtainBounds.append("globalMax = {" + + ', '.join(map(str, upperBound)) + +"};") + code.append( [obtainBounds] ) return code def transform(Model,space,t, name="" ): diff --git a/python/dune/femdg/rk.py b/python/dune/femdg/rk.py index 4db0e984509e393761d192e0277f79fae8ca6a32..9514364b10d2a1678f27a181d4cf106f49145e28 100644 --- a/python/dune/femdg/rk.py +++ b/python/dune/femdg/rk.py @@ -12,11 +12,17 @@ class FemDGStepper: self.rkScheme.setTimeStepSize(dt) self.rkScheme.solve(u) return self.rkScheme.deltaT() -def femdgStepper(*,order=None,rkType=None,operator=None,cfl=None,parameters=True): - if parameters is True: - parameters = {} - elif parameters is False: - parameters = None + @property + def deltaT(self): + return self.rkScheme.deltaT() + @deltaT.setter + def deltaT(self,dt): + self.rkScheme.setTimeStepSize(dt) + +def femdgStepper(*,order=None,rkType=None,operator=None,cfl=0.45,parameters=True): + if parameters is True: parameters = {} + elif parameters is False: parameters = None + if rkType == "default": rkType = None def _femdgStepper(op,cfl=None): if parameters is not None: if not "fem.timeprovider.factor" in parameters: @@ -148,7 +154,7 @@ class RungeKutta: self.op.stepTime(0,0) self.op(u,self.k[0]) if dt is None and self.dt is None: - dt = self.op.timeStepEstimate[0]*self.cfl + dt = self.op.localTimeStepEstimate[0]*self.cfl elif dt is None: dt = self.dt self.dt = 1e10 @@ -158,12 +164,12 @@ class RungeKutta: self.tmp.axpy(dt*self.A[i][j],self.k[j]) self.op.stepTime(self.c[i],dt) self.op(self.tmp,self.k[i]) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) else: if dt is None and self.dt is None: self.op.stepTime(0,0) self.op(u,self.k[0]) - dt = self.op.timeStepEstimate[0]*self.cfl + dt = self.op.localTimeStepEstimate[0]*self.cfl elif dt is None: dt = self.dt self.dt = 1e10 @@ -173,7 +179,7 @@ class RungeKutta: self.tmp.axpy(dt*self.A[i][j],self.k[j]) self.op.stepTime(self.c[i],dt) self.op(self.tmp,self.k[i]) # this seems like a good initial guess for dt small - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) self.helmholtz.alpha = dt*self.A[i][i] self.helmholtz.solve(baru=self.tmp,target=self.k[i]) @@ -181,7 +187,7 @@ class RungeKutta: u.axpy(dt*self.b[i],self.k[i]) self.op.applyLimiter( u ) self.op.stepTime(0,0) - return dt + return self.op.space.grid.comm.min(dt) class Heun(RungeKutta): def __init__(self, op, cfl=None): A = [[0,0], @@ -225,7 +231,7 @@ class ImplSSP2: # with stages=1 same as above - increasing stages does not impro if dt is None and self.dt is None: self.op.stepTime(0,0) self.op(u, self.tmp) - dt = self.op.timeStepEstimate[0]*self.cfl + dt = self.op.localTimeStepEstimate[0]*self.cfl elif dt is None: dt = self.dt self.dt = 1e10 @@ -237,18 +243,18 @@ class ImplSSP2: # with stages=1 same as above - increasing stages does not impro for i in range(2,self.stages+1): self.op.stepTime(self.c(i),dt) self.op(self.q2, self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) self.q2.axpy(dt*self.mu21, self.tmp) self.q2.assgin(tmp) self.helmholtz.solve(self.tmp, self.q2) u.as_numpy[:] *= (1-self.lamsps) u.axpy(self.lamsps, self.q2) self.op(self.q2, self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) u.axpy(dt*self.musps, self.tmp) self.op.applyLimiter( u ) self.op.stepTime(0,0) - return dt + return self.op.space.grid.comm.min(dt) class ExplSSP2: def __init__(self,stages,op,cfl=None): self.op = op @@ -263,7 +269,7 @@ class ExplSSP2: if dt is None and self.dt is None: self.op.stepTime(0,0) self.op(u, self.tmp) - dt = self.op.timeStepEstimate[0]*self.cfl + dt = self.op.localTimeStepEstimate[0]*self.cfl elif dt is None: dt = self.dt self.dt = 1e10 @@ -272,17 +278,17 @@ class ExplSSP2: for i in range(1,self.stages): self.op.stepTime(self.c(i),dt) self.op(u,self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) u.axpy(fac, self.tmp) self.op.stepTime(self.c(i),dt) self.op(u,self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) u.as_numpy[:] *= (self.stages-1)/self.stages u.axpy(dt/self.stages, self.tmp) u.axpy(1/self.stages, self.q2) self.op.applyLimiter( u ) self.op.stepTime(0,0) - return dt + return self.op.space.grid.comm.min(dt) def ssp2(stages,explicit=True): if explicit: return lambda op,cfl=None: ExplSSP2(stages,op,cfl) @@ -313,7 +319,7 @@ class ExplSSP3: if dt is None and self.dt is None: self.op.stepTime(0,0) self.op(u, self.tmp) - dt = self.op.timeStepEstimate[0]*self.cfl + dt = self.op.localTimeStepEstimate[0]*self.cfl elif dt is None: dt = self.dt self.dt = 1e10 @@ -322,14 +328,14 @@ class ExplSSP3: while i <= (self.n-1)*(self.n-2)/2: self.op.stepTime(self.c(i),dt) self.op(u,self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) u.axpy(fac, self.tmp) i += 1 self.q2.assign(u) while i <= self.n*(self.n+1)/2: self.op.stepTime(self.c(i),dt) self.op(u,self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) u.axpy(fac, self.tmp) i += 1 u.as_numpy[:] *= (self.n-1)/(2*self.n-1) @@ -337,12 +343,12 @@ class ExplSSP3: while i <= self.stages: self.op.stepTime(self.c(i),dt) self.op(u,self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) u.axpy(fac, self.tmp) i += 1 self.op.applyLimiter( u ) self.op.stepTime(0,0) - return dt + return self.op.space.grid.comm.min(dt) class ImplSSP3: def __init__(self,stages,op,cfl=None): self.stages = stages @@ -372,7 +378,7 @@ class ImplSSP3: if dt is None and self.dt is None: # self.op.stepTime(0,0) self.op(u, self.tmp) - dt = self.op.timeStepEstimate[0]*self.cfl + dt = self.op.localTimeStepEstimate[0]*self.cfl elif dt is None: dt = self.dt self.dt = 1e10 @@ -383,18 +389,18 @@ class ImplSSP3: for i in range(2,self.stages+1): # self.op.stepTime(self.c(i),dt) self.op(self.q2, self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) self.q2.axpy(dt*self.mu21, self.tmp) self.helmholtz.solve(self.q2,self.tmp) self.q2.assign(self.tmp) u.as_numpy[:] *= (1-self.lamsps) u.axpy(self.lamsps, self.q2) self.op(self.q2, self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) u.axpy(dt*self.musps, self.tmp) self.op.applyLimiter( u ) self.op.stepTime(0,0) - return dt + return self.op.space.grid.comm.min(dt) def ssp3(stages,explicit=True): if explicit: return lambda op,cfl=None: ExplSSP3(stages,op,cfl) @@ -415,7 +421,7 @@ class ExplSSP4_10: if dt is None and self.dt is None: self.op.stepTime(0,0) self.op(u, self.tmp) - dt = self.op.timeStepEstimate[0]*self.cfl + dt = self.op.localTimeStepEstimate[0]*self.cfl elif dt is None: dt = self.dt self.dt = 1e10 @@ -425,7 +431,7 @@ class ExplSSP4_10: while i <= 5: self.op.stepTime(self.c(i), dt) self.op(u, self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) u.axpy(dt/6, self.tmp) i += 1 @@ -437,16 +443,16 @@ class ExplSSP4_10: while i <= 9: self.op.stepTime(self.c(i), dt) self.op(u, self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) u.axpy(dt/6, self.tmp) i += 1 self.op.stepTime(self.c(i), dt) self.op(u, self.tmp) - self.dt = min(self.dt, self.op.timeStepEstimate[0]*self.cfl) + self.dt = min(self.dt, self.op.localTimeStepEstimate[0]*self.cfl) u.as_numpy[:] *= 3/5 u.axpy(1, self.q2) u.axpy(dt/10, self.tmp) self.op.applyLimiter( u ) self.op.stepTime(0,0) - return dt + return self.op.space.grid.comm.min(dt) diff --git a/python/dune/femdg/testing.py b/python/dune/femdg/testing.py index 69f63f4b42a0d18dcba8f13530456e5bc3f59b0e..1c85ebb191c0a2126cdc22510190ab39904b669b 100644 --- a/python/dune/femdg/testing.py +++ b/python/dune/femdg/testing.py @@ -21,6 +21,11 @@ def run(Model, Stepper=None, exact = Model.exact except: exact = None + + if grid == "polygon": + subsamp=None + print('Disabling subsampling for PolygonGrid') + print("*************************************") print("**** Running simulation",Model.name) print("*************************************") @@ -58,7 +63,10 @@ def run(Model, Stepper=None, # create discrete function space try: - if space.lower() == "finitevolume": + if type(space) in [list,tuple]: + space = create.space( space[0], grid, dimRange=dimR, order=polOrder, + pointType=space[1] ) + elif space.lower() == "finitevolume": space = create.space( space, grid, dimRange=dimR) else: space = create.space( space, grid, order=polOrder, dimRange=dimR) @@ -67,7 +75,10 @@ def run(Model, Stepper=None, if modifyModel is not None: Model = modifyModel(Model,space) - operator = femDGOperator(Model, space, limiter=limiter, threading=threading, parameters=parameters ) + operator = femDGOperator(Model, space, + limiter=limiter, threading=threading, parameters=parameters, + defaultQuadrature=True + ) stepper = Stepper(operator, cfl) # create and initialize solution u_h = space.interpolate(Model.initial, name='u_h') @@ -120,7 +131,7 @@ def run(Model, Stepper=None, sys.exit(1) if t > saveTime: print('[',tcount,']','dt = ', dt, 'time = ',t, - 'dtEst = ',operator.timeStepEstimate, + 'dtEst = ',operator.localTimeStepEstimate, 'elements = ',grid.size(0), flush=True ) try: velo0.setConstant("time",[t])