From b24516ea83d60810992fad9f648f6958b174af57 Mon Sep 17 00:00:00 2001 From: Susanne Date: Wed, 7 Aug 2019 12:18:00 +0300 Subject: [PATCH 1/3] actual ConvectionDiffusion Plugin with separated cutElement fv1 disc --- CMakeLists.txt | 1 + convection_diffusion_plugin.cpp | 99 +- convection_diffusion_plugin_Kopie.cpp | 271 ++ .../convection_diffusion_fv1 Kopie.cpp | 2617 +++++++++++++++++ fv1_cutElem/convection_diffusion_fv1 Kopie.h | 363 +++ .../convection_diffusion_fv1_cutElem.cpp | 1711 +++++++++++ .../convection_diffusion_fv1_cutElem.h | 264 ++ .../___immersed_bnd_cond_diffusion_impl.h | 952 ++++++ .../diffusion_interface Kopie.h | 235 ++ .../diffusion_interface/diffusion_interface.h | 242 ++ .../diffusion_interface_impl Kopie.h | 371 +++ .../diffusion_interface_impl.h | 372 +++ .../loc_to_glob_mapper_diffusion.h | 130 + .../loc_to_glob_mapper_diffusion_impl.h | 579 ++++ .../convection_diffusion_fv1_Nitsche_Juli.cpp | 2165 ++++++++++++++ .../convection_diffusion_fv1_Nitsche_Juli.h | 326 ++ .../convection_diffusion_fv1_last.cpp | 2377 +++++++++++++++ .../convection_diffusion_fv1_last.h | 325 ++ .../convection_diffusion_fv1_mitJump.cpp | 1828 ++++++++++++ .../convection_diffusion_fv1_mitJump.h | 316 ++ 20 files changed, 15541 insertions(+), 3 deletions(-) create mode 100644 convection_diffusion_plugin_Kopie.cpp create mode 100644 fv1_cutElem/convection_diffusion_fv1 Kopie.cpp create mode 100644 fv1_cutElem/convection_diffusion_fv1 Kopie.h create mode 100644 fv1_cutElem/convection_diffusion_fv1_cutElem.cpp create mode 100644 fv1_cutElem/convection_diffusion_fv1_cutElem.h create mode 100644 fv1_cutElem/diffusion_interface/___immersed_bnd_cond_diffusion_impl.h create mode 100644 fv1_cutElem/diffusion_interface/diffusion_interface Kopie.h create mode 100644 fv1_cutElem/diffusion_interface/diffusion_interface.h create mode 100644 fv1_cutElem/diffusion_interface/diffusion_interface_impl Kopie.h create mode 100644 fv1_cutElem/diffusion_interface/diffusion_interface_impl.h create mode 100644 fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion.h create mode 100644 fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion_impl.h create mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.cpp create mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.h create mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.cpp create mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.h create mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.cpp create mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f30d82c..6359a24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ set(pluginName ConvectionDiffusion) set(SOURCES convection_diffusion_base.cpp fv1/convection_diffusion_fv1.cpp + fv1_cutElem/convection_diffusion_fv1_cutElem.cpp fe/convection_diffusion_fe.cpp fvcr/convection_diffusion_fvcr.cpp fv/convection_diffusion_fv.cpp diff --git a/convection_diffusion_plugin.cpp b/convection_diffusion_plugin.cpp index eaf61c9..c5169fc 100644 --- a/convection_diffusion_plugin.cpp +++ b/convection_diffusion_plugin.cpp @@ -36,12 +36,18 @@ #include "bridge/util.h" #include "bridge/util_domain_dependent.h" +#include "bridge/util_domain_algebra_dependent.h" #include "convection_diffusion_base.h" #include "fv1/convection_diffusion_fv1.h" +#include "fv1_cutElem/convection_diffusion_fv1_cutElem.h" #include "fe/convection_diffusion_fe.h" #include "fvcr/convection_diffusion_fvcr.h" #include "fv/convection_diffusion_fv.h" +#include "fv1_cutElem/diffusion_interface/diffusion_interface.h" + +//#include "lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion.h" + #include "lib_disc/spatial_disc/elem_disc/sss.h" using namespace std; @@ -183,7 +189,20 @@ static void Domain(Registry& reg, string grp) .set_construct_as_smart_pointer(true); reg.add_class_to_group(name, "ConvectionDiffusionFV1", tag); } - + +// Convection Diffusion FV1 non-conforming Boundary + { + typedef ConvectionDiffusionFV1_cutElem T; + typedef ConvectionDiffusionBase TBase; + string name = string("ConvectionDiffusionFV1_cutElem").append(suffix); + reg.add_class_(name, grp) + .template add_constructor("Function(s)#Subset(s)") + .add_method("set_upwind", &T::set_upwind) + .add_method("set_singular_sources_and_sinks", &T::set_sss, "", "Singular Sources and Sinks") + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "ConvectionDiffusionFV1_cutElem", tag); + } + // Convection Diffusion FE { typedef ConvectionDiffusionFE T; @@ -221,13 +240,61 @@ static void Domain(Registry& reg, string grp) } } + /** + * Function called for the registration of Domain and Algebra dependent parts + * of the plugin. All Functions and Classes depending on both Domain and Algebra + * are to be placed here when registering. The method is called for all + * available Domain and Algebra types, based on the current build options. + * + * @param reg registry + * @param parentGroup group for sorting of functionality + */ + template + static void DomainAlgebra(Registry& reg, string grp) + { + string suffix = GetDomainAlgebraSuffix(); + string tag = GetDomainAlgebraTag(); + + typedef ApproximationSpace approximation_space_type; + typedef GridFunction function_type; + + + // MovingInterfaceDiffusion + { + + typedef MovingInterfaceDiffusion T; + typedef IMovingInterface TBase; + string name = string("MovingInterfaceDiffusion").append(suffix); + reg.add_class_(name, grp) + .template add_constructor > ass, + SmartPtr > spMaster, + SmartPtr > interfaceProvider, + SmartPtr > cutElementHandler)>("domain disc, global handler") + .add_method("init", &T::init) + .add_method("set_source_data", &T::set_source_data) + .add_method("set_jump_data", &T::set_jump_data) + .add_method("set_jump_grad_data", &T::set_jump_grad_data) + .add_method("set_diffusion_data", &T::set_diffusion_data) + .add_method("get_integral", &T::get_integral) + .add_method("get_numDoFs", &T::get_numDoFs) + .add_method("set_Nitsche", &T::set_Nitsche) + .add_method("adjust_for_error", &T::adjust_for_error) + .add_method("initialize_threshold", &T::initialize_threshold) + .add_method("set_threshold", &T::set_threshold, "", "Set Threshold") + .add_method("set_analytic_solution", &T::set_analytic_solution, "", "Set Threshold") + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "MovingInterfaceDiffusion", tag); + } + } + + template static void Dimension(Registry& reg, string grp) { string dimSuffix = GetDimensionSuffix(); string dimTag = GetDimensionTag(); - - // singular sources and sinks + + // singular sources and sinks { typedef SingularSourcesAndSinks T; string name = string("CdSingularSourcesAndSinks").append(dimSuffix); @@ -242,6 +309,30 @@ static void Dimension(Registry& reg, string grp) .set_construct_as_smart_pointer(true); reg.add_class_to_group(name, "CdSingularSourcesAndSinks", dimTag); } + + // CutElementHandlerImmersed + { + typedef CutElementHandlerImmersed T; + string name = string("CutElementHandlerImmersed").append(dimSuffix); + reg.add_class_(name, grp) + .template add_constructor mg, const char*, SmartPtr >)>("multigrid, fct names") + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "CutElementHandlerImmersed", dimTag); + } + + // DiffusionInterfaceProvider + { + typedef DiffusionInterfaceProvider T; + string name = string("DiffusionInterfaceProvider").append(dimSuffix); + reg.add_class_(name, grp) + .template add_constructor("") + .add_method("print", &T::print) + .add_method("add", &T::add) + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "DiffusionInterfaceProvider", dimTag); + } + + } }; // end Functionality @@ -264,6 +355,8 @@ InitUGPlugin_ConvectionDiffusion(Registry* reg, string grp) try{ RegisterDimensionDependent(*reg,grp); RegisterDomainDependent(*reg,grp); + RegisterDomainAlgebraDependent(*reg,grp); + } UG_REGISTRY_CATCH_THROW(grp); } diff --git a/convection_diffusion_plugin_Kopie.cpp b/convection_diffusion_plugin_Kopie.cpp new file mode 100644 index 0000000..eaf61c9 --- /dev/null +++ b/convection_diffusion_plugin_Kopie.cpp @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2012-2015: G-CSC, Goethe University Frankfurt + * Author: Andreas Vogel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +/** + * File for registration of ConvectionDiffusion routines. + */ + +#include "bridge/util.h" +#include "bridge/util_domain_dependent.h" +#include "convection_diffusion_base.h" +#include "fv1/convection_diffusion_fv1.h" +#include "fe/convection_diffusion_fe.h" +#include "fvcr/convection_diffusion_fvcr.h" +#include "fv/convection_diffusion_fv.h" + +#include "lib_disc/spatial_disc/elem_disc/sss.h" + +using namespace std; +using namespace ug::bridge; + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +/** + * \defgroup convection_diffusion Convection Diffusion + * \ingroup plugins + * This plugin provides the discretization of convection and diffusion problems. + * \{ + */ + +/** + * Class exporting the functionality of the plugin. All functionality that is to + * be used in scripts or visualization must be registered here. + */ +struct Functionality +{ + +/** + * Function called for the registration of Domain dependent parts + * of the plugin. All Functions and Classes depending on the Domain + * are to be placed here when registering. The method is called for all + * available Domain types, based on the current build options. + * + * @param reg registry + * @param parentGroup group for sorting of functionality + */ +template +static void Domain(Registry& reg, string grp) +{ + static const int dim = TDomain::dim; + string suffix = GetDomainSuffix(); + string tag = GetDomainTag(); + +// Convection Diffusion Base + { + typedef ConvectionDiffusionBase T; + typedef IElemDisc TBase; + string name = string("ConvectionDiffusionBase").append(suffix); + reg.add_class_(name, grp) + .add_method("set_diffusion", static_cast, dim> >)>(&T::set_diffusion), "", "Diffusion") + .add_method("set_diffusion", static_cast(&T::set_diffusion), "", "Diagonal Diffusion") +#ifdef UG_FOR_LUA + .add_method("set_diffusion", static_cast(&T::set_diffusion), "", "Diffusion") + .add_method("set_diffusion", static_cast(&T::set_diffusion), "", "Diffusion") +#endif + + .add_method("set_velocity", static_cast, dim> >)>(&T::set_velocity), "", "Velocity Field") + .add_method("set_velocity", static_cast&)>(&T::set_velocity), "", "Velocity Field") +#ifdef UG_FOR_LUA + .add_method("set_velocity", static_cast(&T::set_velocity), "", "Velocity Field") + .add_method("set_velocity", static_cast(&T::set_velocity), "", "Velocity Field") +#endif + + .add_method("set_flux", static_cast, dim> >)>(&T::set_flux), "", "Flux") + .add_method("set_flux", static_cast&)>(&T::set_flux), "", "Flux") +#ifdef UG_FOR_LUA + .add_method("set_flux", static_cast(&T::set_flux), "", "Flux") + .add_method("set_flux", static_cast(&T::set_flux), "", "Flux") +#endif + + .add_method("set_reaction_rate", static_cast >)>(&T::set_reaction_rate), "", "Reaction Rate") + .add_method("set_reaction_rate", static_cast(&T::set_reaction_rate), "", "Reaction Rate") +#ifdef UG_FOR_LUA + .add_method("set_reaction_rate", static_cast(&T::set_reaction_rate), "", "Reaction Rate") + .add_method("set_reaction_rate", static_cast(&T::set_reaction_rate), "", "Reaction Rate") +#endif + + .add_method("set_reaction", static_cast >)>(&T::set_reaction), "", "Reaction") + .add_method("set_reaction", static_cast(&T::set_reaction), "", "Reaction") +#ifdef UG_FOR_LUA + .add_method("set_reaction", static_cast(&T::set_reaction), "", "Reaction") + .add_method("set_reaction", static_cast(&T::set_reaction), "", "Reaction") +#endif + + .add_method("set_reaction_rate_explicit", static_cast >)>(&T::set_reaction_rate_explicit), "", "Reaction Rate Explicit") + .add_method("set_reaction_rate_explicit", static_cast(&T::set_reaction_rate_explicit), "", "Reaction Rate Explicit") +#ifdef UG_FOR_LUA + .add_method("set_reaction_rate_explicit", static_cast(&T::set_reaction_rate_explicit), "", "Reaction Rate Explicit") +#endif + + .add_method("set_reaction_explicit", static_cast >)>(&T::set_reaction_explicit), "", "Reaction Explicit") + .add_method("set_reaction_explicit", static_cast(&T::set_reaction_explicit), "", "Reaction Explicit") +#ifdef UG_FOR_LUA + .add_method("set_reaction_explicit", static_cast(&T::set_reaction_explicit), "", "Reaction Explicit") +#endif + + .add_method("set_source_explicit", static_cast >)>(&T::set_source_explicit), "", "Source Explicit") + .add_method("set_source_explicit", static_cast(&T::set_source_explicit), "", "Source Explicit") + #ifdef UG_FOR_LUA + .add_method("set_source_explicit", static_cast(&T::set_source_explicit), "", "Source Explicit") + #endif + + .add_method("set_source", static_cast >)>(&T::set_source), "", "Source") + .add_method("set_source", static_cast(&T::set_source), "", "Source") +#ifdef UG_FOR_LUA + .add_method("set_source", static_cast(&T::set_source), "", "Source") + .add_method("set_source", static_cast(&T::set_source), "", "Source") +#endif + + .add_method("set_vector_source", static_cast, dim> >)>(&T::set_vector_source), "", "Vector Source") +#ifdef UG_FOR_LUA + .add_method("set_vector_source", static_cast(&T::set_vector_source), "", "Vector Source") + .add_method("set_vector_source", static_cast(&T::set_vector_source), "", "Vector Source") +#endif + + .add_method("set_mass_scale", static_cast >)>(&T::set_mass_scale), "", "Mass Scale") + .add_method("set_mass_scale", static_cast(&T::set_mass_scale), "", "Mass Scale") +#ifdef UG_FOR_LUA + .add_method("set_mass_scale", static_cast(&T::set_mass_scale), "", "Mass Scale") + .add_method("set_mass_scale", static_cast(&T::set_mass_scale), "", "Mass Scale") +#endif + + .add_method("set_mass", static_cast >)>(&T::set_mass), "", "Mass") + .add_method("set_mass", static_cast(&T::set_mass), "", "Mass") +#ifdef UG_FOR_LUA + .add_method("set_mass", static_cast(&T::set_mass), "", "Mass") + .add_method("set_mass", static_cast(&T::set_mass), "", "Mass") +#endif + + .add_method("value", &T::value) + .add_method("gradient", &T::gradient); + reg.add_class_to_group(name, "ConvectionDiffusionBase", tag); + } + +// Convection Diffusion FV1 + { + typedef ConvectionDiffusionFV1 T; + typedef ConvectionDiffusionBase TBase; + string name = string("ConvectionDiffusionFV1").append(suffix); + reg.add_class_(name, grp) + .template add_constructor("Function(s)#Subset(s)") + .add_method("set_upwind", &T::set_upwind) + .add_method("set_singular_sources_and_sinks", &T::set_sss, "", "Singular Sources and Sinks") + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "ConvectionDiffusionFV1", tag); + } + +// Convection Diffusion FE + { + typedef ConvectionDiffusionFE T; + typedef ConvectionDiffusionBase TBase; + string name = string("ConvectionDiffusionFE").append(suffix); + reg.add_class_(name, grp) + .template add_constructor("Function(s)#Subset(s)") + .add_method("set_quad_order", &T::set_quad_order) + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "ConvectionDiffusionFE", tag); + } + +// Convection Diffusion FVCR + { + typedef ConvectionDiffusionFVCR T; + typedef ConvectionDiffusionBase TBase; + string name = string("ConvectionDiffusionFVCR").append(suffix); + reg.add_class_(name, grp) + .template add_constructor("Function(s)#Subset(s)") + .add_method("set_upwind", &T::set_upwind) + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "ConvectionDiffusionFVCR", tag); + } + +// Convection Diffusion FV + { + typedef ConvectionDiffusionFV T; + typedef ConvectionDiffusionBase TBase; + string name = string("ConvectionDiffusionFV").append(suffix); + reg.add_class_(name, grp) + .template add_constructor("Function(s)#Subset(s)") + .add_method("set_quad_order", &T::set_quad_order) + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "ConvectionDiffusionFV", tag); + } +} + +template +static void Dimension(Registry& reg, string grp) +{ + string dimSuffix = GetDimensionSuffix(); + string dimTag = GetDimensionTag(); + + // singular sources and sinks + { + typedef SingularSourcesAndSinks T; + string name = string("CdSingularSourcesAndSinks").append(dimSuffix); + reg.add_class_(name, grp) + .add_constructor() + .add_method("addps", static_cast&, const std::vector&)>(&T::addps)) + .add_method("addls", static_cast&, const std::vector&, const std::vector&)>(&T::addls)) +#ifdef UG_FOR_LUA + .add_method("addps", static_cast&, LuaFunctionHandle)>(&T::addps)) + .add_method("addls", static_cast&, const std::vector&, LuaFunctionHandle)>(&T::addls)) +#endif + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "CdSingularSourcesAndSinks", dimTag); + } +} + +}; // end Functionality + +// end group convection_diffusion +/// \} + +} // end namespace ConvectionDiffusionPlugin + + +/** + * This function is called when the plugin is loaded. + */ +extern "C" void +InitUGPlugin_ConvectionDiffusion(Registry* reg, string grp) +{ + grp.append("/SpatialDisc/ElemDisc"); + typedef ConvectionDiffusionPlugin::Functionality Functionality; + + try{ + RegisterDimensionDependent(*reg,grp); + RegisterDomainDependent(*reg,grp); + } + UG_REGISTRY_CATCH_THROW(grp); +} + +}// namespace ug diff --git a/fv1_cutElem/convection_diffusion_fv1 Kopie.cpp b/fv1_cutElem/convection_diffusion_fv1 Kopie.cpp new file mode 100644 index 0000000..ef04ceb --- /dev/null +++ b/fv1_cutElem/convection_diffusion_fv1 Kopie.cpp @@ -0,0 +1,2617 @@ +/* + * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt + * Author: Andreas Vogel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + + +#include "convection_diffusion_fv1.h" + +#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" +#include "lib_disc/spatial_disc/disc_util/geom_provider.h" + +//#include "lib_disc/spatial_disc/disc_util/fv1_geom.h" +//#include "lib_disc/spatial_disc/disc_util/hfv1_geom.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape.h" +#include "../../NavierStokes/incompressible/fv1/diffusion_interface/interface_handler_diffusion.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +DebugID DID_CONV_DIFF_FV1("CONV_DIFF_FV1"); + +//////////////////////////////////////////////////////////////////////////////// +// general +//////////////////////////////////////////////////////////////////////////////// + +template +ConvectionDiffusionFV1:: +ConvectionDiffusionFV1(const char* functions, const char* subsets) + : ConvectionDiffusionBase(functions,subsets), + m_spConvShape(new ConvectionShapesNoUpwind), + m_bNonRegularGrid(false) +{ + register_all_funcs(m_bNonRegularGrid); +} + +template +void ConvectionDiffusionFV1:: +prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid) +{ +// check number + if(vLfeID.size() != 1) + UG_THROW("ConvectionDiffusion: Wrong number of functions given. " + "Need exactly "<<1); + + if(vLfeID[0].order() != 1 || vLfeID[0].type() != LFEID::LAGRANGE) + UG_THROW("ConvectionDiffusion FV Scheme only implemented for 1st order."); + + m_LFEID = vLfeID[0]; + +// remember + m_bNonRegularGrid = bNonRegularGrid; + +// update assemble functions + register_all_funcs(m_bNonRegularGrid); +} + +template +bool ConvectionDiffusionFV1:: +use_hanging() const +{ + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Assembling functions +//////////////////////////////////////////////////////////////////////////////// + +template +void ConvectionDiffusionFV1:: +prep_assemble_loop() +{ + if (m_sss.valid()) + m_sss->clear_markers(); +} + +template +template +void ConvectionDiffusionFV1:: +prep_elem_loop(const ReferenceObjectID roid, const int si) +{ + +// check, that upwind has been set + if(m_spConvShape.invalid()) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Upwind has not been set."); + +// set local positions +// if(!TFVGeom::usesHangingNodes) + if(!TFVGeom::usesHangingNodes && TFVGeom::staticLocalData) + { + static const int refDim = TElem::dim; +// TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID, 1); + const MathVector* vSCVFip = geo.scvf_local_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_local_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip, false); + m_imVelocity.template set_local_ips(vSCVFip,numSCVFip, false); + m_imFlux.template set_local_ips(vSCVFip,numSCVFip, false); + m_imSource.template set_local_ips(vSCVip,numSCVip, false); + m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip, false); + m_imReactionRate.template set_local_ips(vSCVip,numSCVip, false); + m_imReaction.template set_local_ips(vSCVip,numSCVip, false); + m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imReactionExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imSourceExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imMassScale.template set_local_ips(vSCVip,numSCVip, false); + m_imMass.template set_local_ips(vSCVip,numSCVip, false); + + // init upwind for element type + if(!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Cannot init upwind for element type."); + } +} + +template +template +void ConvectionDiffusionFV1:: +fsh_elem_loop() +{} + +template +template +void ConvectionDiffusionFV1:: +prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) +{ +// Update Geometry for this element + //static TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + //TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); + +// fix: set orientation initially globally! + geo.set_orientation(1); + + + try{ + UG_DLOG(DID_CONV_DIFF_FV1, 2, ">>OCT_DISC_DEBUG: " << "convection_diffusion_fv1.cpp: " << "prep_elem(): update(): "<< roid << std::endl); +// geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); + geo.update(elem, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::prep_elem:" + " Cannot update Finite Volume Geometry."); + +// set local positions +// if(TFVGeom::usesHangingNodes) + if(TFVGeom::usesHangingNodes || !TFVGeom::staticLocalData) + { + const int refDim = TElem::dim; + const MathVector* vSCVFip = geo.scvf_local_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_local_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip); + m_imVelocity.template set_local_ips(vSCVFip,numSCVFip); + m_imFlux.template set_local_ips(vSCVFip,numSCVFip); + m_imSource.template set_local_ips(vSCVip,numSCVip); + m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip); + m_imReactionRate.template set_local_ips(vSCVip,numSCVip); + m_imReaction.template set_local_ips(vSCVip,numSCVip); + m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip); + m_imReactionExpl.template set_local_ips(vSCVip,numSCVip); + m_imSourceExpl.template set_local_ips(vSCVip,numSCVip); + m_imMassScale.template set_local_ips(vSCVip,numSCVip); + m_imMass.template set_local_ips(vSCVip,numSCVip); +/* + if(m_spConvShape.valid()) + if(!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Cannot init upwind for element type."); + */ + } + + // set global positions + const MathVector* vSCVFip = geo.scvf_global_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_global_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion. set_global_ips(vSCVFip, numSCVFip); + m_imVelocity. set_global_ips(vSCVFip, numSCVFip); + m_imFlux. set_global_ips(vSCVFip, numSCVFip); + m_imSource. set_global_ips(vSCVip, numSCVip); + m_imVectorSource. set_global_ips(vSCVFip, numSCVFip); + m_imReactionRate. set_global_ips(vSCVip, numSCVip); + m_imReactionRateExpl. set_global_ips(vSCVip, numSCVip); + m_imReactionExpl. set_global_ips(vSCVip, numSCVip); + m_imSourceExpl. set_global_ips(vSCVip, numSCVip); + m_imReaction. set_global_ips(vSCVip, numSCVip); + m_imMassScale. set_global_ips(vSCVip, numSCVip); + m_imMass. set_global_ips(vSCVip, numSCVip); +} + +template +static TVector CalculateCenter(GridObject* o, const TVector* coords) +{ + TVector v; + VecSet(v, 0); + + size_t numCoords = 0; + switch(o->base_object_id()){ + case VERTEX: numCoords = 1; break; + case EDGE: numCoords = static_cast(o)->num_vertices(); break; + case FACE: numCoords = static_cast(o)->num_vertices(); break; + case VOLUME: numCoords = static_cast(o)->num_vertices(); break; + default: UG_THROW("Unknown element type."); break; + } + + for(size_t i = 0; i < numCoords; ++i) + VecAdd(v, v, coords[i]); + + if(numCoords > 0) + VecScale(v, v, 1. / (number)numCoords); + + return v; +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + + bool debug = false; + bool boundary = false; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + const bool bElementIsCut = geo.get_element_modus(); + const bool bElementIsOutside = geo.get_boolian_for_diffusion(); + + // First call with orientation = 1: + int orientation = 1; + geo.set_orientation(orientation); + + geo.init_integral(); + + // normal assembling if not cut by interface: + if ( !bElementIsCut ) + { + LocalVector dummyU; + LocalIndices ind = u.get_indices(); + dummyU.resize(ind); + dummyU = 0; + + this->template add_jac_A_elem_local (geo, J, u, dummyU, elem, vCornerCoords, bElementIsOutside); + return; + } + + // get data: + geo.resize_local_data(u); + LocalMatrix& locJ_tri = geo.get_jacobian_tri(); + LocalMatrix& locJ_quad = geo.get_jacobian_quad(); + + LocalVector& locU_tri = geo.get_solution_tri(); + LocalVector& locU_quad = geo.get_solution_quad(); + + // reset data: + locJ_tri = 0; + locJ_quad = 0; + + LocalIndices ind = u.get_indices(); + + // call elem disc twice: + + if ( debug ) geo.print_InterfaceIDdata(); + + ReferenceObjectID roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + + this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, false); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_tri, 3); + this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords, false); + } + + geo.set_jacobian_tri(locJ_tri); + geo.set_DoF_tag_tri(false); + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + + this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, false); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_quad, 4); + this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords, false); + } + + geo.set_jacobian_quad(locJ_quad); + geo.set_DoF_tag_quad(false); + } + + + // Second call with orientation = 1: + bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! + + orientation *= -1; + geo.set_orientation(orientation); + try{ + geo.update(elem, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" + " Cannot update Finite Volume Geometry."); + + if ( debug ) geo.print_InterfaceIDdata(); + + roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + + this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, true); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_tri, 3); + this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords, true); + } + + geo.set_jacobian_tri(locJ_tri); + geo.set_DoF_tag_tri(shiftTag); + + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + + this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, true); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_quad, 4); + this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords, true); + } + + geo.set_jacobian_quad(locJ_quad); + geo.set_DoF_tag_quad(shiftTag); + } + + +} + + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + ug::MathMatrix diffusion = m_imDiffusion[0]; + diffusion *= 10.0; + + if ( bElementIsOutside ) // = inside circle line!! + diffusion *= 0.1; + +// Diff. Tensor times Gradient + MathVector Dgrad; + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// Diffusion and Velocity Term + if(m_imDiffusion.data_given() || m_imVelocity.data_given()) + { + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + //////////////////////////////////////////////////// + // Diffusive Term + //////////////////////////////////////////////////// + if(m_imDiffusion.data_given()) + { + // DID_CONV_DIFF_FV1 + number D_diff_flux_sum = 0.0; + + // loop shape functions + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + // Compute Diffusion Tensor times Gradient + MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); + + // Compute flux at IP + const number D_diff_flux = VecDot(Dgrad, scvf.normal()); + UG_DLOG(DID_CONV_DIFF_FV1, 2, ">>OCT_DISC_DEBUG: " << "convection_diffusion_fv1.cpp: " << "add_jac_A_elem(): " << "sh # " << sh << " ; normalSize scvf # " << ip << ": " << VecLength(scvf.normal()) << "; \t from "<< scvf.from() << "; to " << scvf.to() << "; D_diff_flux: " << D_diff_flux << "; scvf.global_grad(sh): " << scvf.global_grad(sh) << std::endl); + + // Add flux term to local matrix // HIER MATRIXINDIZES!!! + UG_ASSERT((scvf.from() < J.num_row_dof(_C_)) && (scvf.to() < J.num_col_dof(_C_)), + "Bad local dof-index on element with object-id " << elem->base_object_id() + << " with center: " << CalculateCenter(elem, vCornerCoords)); + + J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; + J(_C_, scvf.to() , _C_, sh) += D_diff_flux; + + // DID_CONV_DIFF_FV1 + D_diff_flux_sum += D_diff_flux; + } + + UG_DLOG(DID_CONV_DIFF_FV1, 2, "D_diff_flux_sum = " << D_diff_flux_sum << std::endl << std::endl); + } + + + ///////////////////////////////////////////////////////////////////////////// + // Additional diffusive Term due to jump in solution at the interface + // u^+ - u^- = jump + ///////////////////////////////////////////////////////////////////////////// + if ( 0 ) + { + // loop shape functions + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + // Compute Diffusion Tensor times Gradient + MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); + + // Compute flux at IP + const number D_diff_flux = jump(_C_,sh) * VecDot(Dgrad, scvf.normal()); + + J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; + J(_C_, scvf.to() , _C_, sh) += D_diff_flux; + } + + } + + //////////////////////////////////////////////////// + // Convective Term + //////////////////////////////////////////////////// + if(m_imVelocity.data_given()) + { + // Add Flux contribution + for(size_t sh = 0; sh < convShape.num_sh(); ++sh) + { + const number D_conv_flux = convShape(ip, sh); + + // Add flux term to local matrix + J(_C_, scvf.from(), _C_, sh) += D_conv_flux; + J(_C_, scvf.to(), _C_, sh) -= D_conv_flux; + } + } + + // no explicit dependency on flux import + } + } + + //UG_LOG("Local Matrix is: \n"<domain()->position_accessor(); + const typename TDomain::grid_type& grid = *this->domain()->grid(); + const number time = this->time(); + MathVector<1> out; + for(size_t i = 0; i < geo.num_scv(); i++) { + const typename TFVGeom::SCV& scv = geo.scv(i); + const int co = scv.node_id(); + const number len = m_sss->get_contrib_of_scv((TElem*)elem, (Grid&)grid, aaPos, geo, co, time, out); + if (len == 0.0) continue; + out[0] *= len; + if (out[0] < 0.0) + // sink + J(_C_, co, _C_, co) -= out[0]; + } + } +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + double diffusion = 10.0; + + if ( bElementIsOutside ) + diffusion = 1.0; + + std::vector& vBF = geo.get_boundary_faces(); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + + // loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + + // loop trial space + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + { + UG_LOG("bf.node_id(): " << bf.node_id() << "\n"); + UG_LOG("bf.global_grad(sh): " << bf.global_grad(sh) << "\n"); + UG_LOG("normal(): " << bf.normal() << "\n"); + + // add to local matrix + J(_C_, bf.node_id(), _C_, sh) += VecDot(bf.global_grad(sh), bf.normal()); + J(_C_, bf.node_id(), _C_, sh) *= diffusion; + } + } + +} + + +template +template +void ConvectionDiffusionFV1:: +add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + if(!m_imMassScale.data_given()) return; + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local matrix + J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip]; + } + +// m_imMass part does not explicitly depend on associated unknown function +} + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + bool output = false; + bool output_integral = false; + + bool debug = false; + bool boundary = false; + bool add = true; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + const bool bElementIsCut = geo.get_element_modus(); + const bool bElementIsOutside = geo.get_boolian_for_diffusion(); + + // First call with orientation = 1: + int orientation = 1; + geo.set_orientation(orientation); + + // necessary for call of 'get_solution_tri' an 'get_solution_quad': + geo.resize_local_data(u); + std::vector imSource; + if ( m_imSource.data_given() ) { + for ( size_t i = 0; i < 3; ++i ) + imSource.push_back(m_imSource[i]); + } + + // normal assembling if not cut by interface: + if ( !bElementIsCut ) + { + LocalVector dummyU; + LocalIndices ind = d.get_indices(); + dummyU.resize(ind); + dummyU = 0; + LocalVector source = geo.set_source(imSource, ind, 3, false); + + if ( output ) + { + for ( size_t i = 0; i < 3; ++i) + UG_LOG("*** corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); + UG_LOG("\n" ); + } + + this->template add_def_A_elem_local (geo, d, u, dummyU, dummyU, source, elem, vCornerCoords, bElementIsOutside); + + number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, d, u, elem); + geo.add_to_integral(intValElem); + if ( output_integral ) + UG_LOG("------------------> usual: integral = " << sqrt(geo.get_integral()) << "\n"); + + return; + } + + // get data: + LocalVector& locD_tri = geo.get_defect_tri(); + LocalVector& locD_quad = geo.get_defect_quad(); + + LocalVector& locU_tri = geo.get_solution_tri(); + LocalVector& locU_quad = geo.get_solution_quad(); + + // reset data: + locD_tri = 0; + locD_quad = 0; + + // call elem disc twice: + + if ( debug ) geo.print_InterfaceIDdata(); + + LocalIndices ind = d.get_indices(); + + ReferenceObjectID roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + + LocalVector jump_tri = geo.set_jump_values(ind, 3); + LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); + LocalVector source_tri = geo.set_source(imSource, ind, 3, true); + + if ( output ) UG_LOG(" tri 1: orientaten: " << orientation << "\n"); + + this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords, false); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_tri, 3); + this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords, false); + } + + if ( output ) + { + for ( size_t i = 0; i < 3; ++i) + UG_LOG("corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); + UG_LOG("\n" ); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output_integral ) UG_LOG("------------------> tri1: integral = " << sqrt(geo.get_integral()) << "\n"); + + geo.set_defect_tri(locD_tri); + geo.set_DoF_tag_tri(false); + + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + + LocalVector jump_quad = geo.set_jump_values(ind, 4); + LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); + LocalVector source_quad = geo.set_source(imSource, ind, 4, true); + + if ( output ) UG_LOG(" quad 1: orientaten: " << orientation << "\n"); + this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem, vCornerCoords, false); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_quad, 4); + this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords, false); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output_integral ) UG_LOG("------------------> quad1: integral = " << sqrt(geo.get_integral()) << "\n"); + + + geo.set_defect_quad(locD_quad); + geo.set_DoF_tag_quad(false); + + } + + + // Second call with orientation = -1: + bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! + + orientation *= -1; + if ( output ) UG_LOG(" ____2: orientaten: " << orientation << "\n"); + + geo.set_orientation(orientation); + try{ + geo.update(elem, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" + " Cannot update Finite Volume Geometry."); + + if ( debug ) geo.print_InterfaceIDdata(); + + roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); + LocalVector source_tri = geo.set_source(imSource, ind, 3, true); + + if ( output ) UG_LOG(" tri 2: orientaten: " << orientation << "\n"); + + this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords,true); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_tri, 3); + this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords, true); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output ) UG_LOG("------------------> tri2: integral = " << sqrt(geo.get_integral()) << "\n"); + + + geo.set_defect_tri(locD_tri); + geo.set_DoF_tag_tri(shiftTag); + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); + LocalVector source_quad = geo.set_source(imSource, ind, 4, true); + + if ( output ) UG_LOG(" quad 2: orientaten: " << orientation << "\n"); + + this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem,vCornerCoords, true); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_quad, 4); + this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords, true); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output_integral ) UG_LOG("------------------> quad2: integral = " << sqrt(geo.get_integral()) << "\n"); + + geo.set_defect_quad(locD_quad); + geo.set_DoF_tag_quad(shiftTag); + + } +} + + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + ug::MathMatrix diffusion = m_imDiffusion[0]; + diffusion *= 10.0; + double diffCoeff = 10.0; + + if ( bElementIsOutside ) // = inside circle line!! + { diffusion *= 0.1; diffCoeff = 0.1;} + + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + + if(m_imDiffusion.data_given() || m_imVelocity.data_given() || m_imFlux.data_given()) + { + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + ///////////////////////////////////////////////////// + // Diffusive Term + ///////////////////////////////////////////////////// + if(m_imDiffusion.data_given()) + { + // to compute D \nabla c + MathVector Dgrad_c, grad_c; + + // compute gradient and shape at ip + VecSet(grad_c, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad_c, u(_C_,sh), scvf.global_grad(sh)); + + // scale by diffusion tensor + MatVecMult(Dgrad_c, diffusion, grad_c); + + // Compute flux + const number diff_flux = VecDot(Dgrad_c, scvf.normal()); + + // Add to local defect + d(_C_, scvf.from()) -= diff_flux; + d(_C_, scvf.to() ) += diff_flux; + } + + ///////////////////////////////////////////////////////////////////////////// + // Additional diffusive Term due to jump in solution at the interface + // u^+ - u^- = jump + ///////////////////////////////////////////////////////////////////////////// + if ( 1 ) + { + // scale diffusion by jump in solution: + // const double jump = 2.0; + // diffusion *= jump; + + // to compute D \nabla c=Id_interface + MathVector Dgrad, grad; + + // compute gradient and shape at ip + VecSet(grad, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad, jump(_C_,sh), scvf.global_grad(sh)); + + // scale by diffusion tensor + MatVecMult(Dgrad, diffusion, grad); + + // Compute flux + const number diff_flux = VecDot(Dgrad, scvf.normal()); + + // Add to local defect + d(_C_, scvf.from()) -= diff_flux; + d(_C_, scvf.to() ) += diff_flux; + + } + } + + } + + ///////////////////////////////////////////////////// + // add rhs during same method! + // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! + ///////////////////////////////////////////////////// + + if ( 1 ) + { //m_imSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); + + // get associated node + int co = scv.node_id(); + d(_C_, co) -= source(_C_, co) * scv.volume(); + + // Add to local rhs + /* if ( co > 2 ) + { + d(_C_, co) -= m_imSource[2] * scv.volume(); + UG_LOG("m_imSource[2] * scv.volume(): " << m_imSource[2] << "\n"); + UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); + } + else + { + d(_C_, co) -= m_imSource[co] * scv.volume(); + UG_LOG("m_imSource[co] * scv.volume(): " << m_imSource[co] << "\n"); + UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); + } + + */ + } + } + + ///////////////////////////////////////////////////////////////////////////// + // Additional source Term due to jump in gradient at the interface + // (\nabla u^+ - \nabla u^-)\cdot n = h(x) * |n| + ///////////////////////////////////////////////////////////////////////////// + if ( 1 ) + { + std::vector& vBF = geo.get_boundary_faces(); + MathVector Dgrad; + VecSet(Dgrad, 0.0); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + // loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + // Add to local rhs + d(_C_, bf.node_id()) += jump_grad(_C_,bf.node_id()) * bf.Vol; + } + } + +//////////////////////////////// +// Singular sources and sinks +//////////////////////////////// + + if (m_sss.valid()) { + const typename TDomain::position_accessor_type& aaPos = this->domain()->position_accessor(); + const typename TDomain::grid_type& grid = *this->domain()->grid(); + const number time = this->time(); + MathVector<1> out; + for(size_t i = 0; i < geo.num_scv(); i++) { + const typename TFVGeom::SCV& scv = geo.scv(i); + const int co = scv.node_id(); + const number len = m_sss->get_contrib_of_scv((TElem*)elem, (Grid&)grid, aaPos, geo, co, time, out); + if (len == 0.0) continue; + out[0] *= len; + if (out[0] > 0.0) + // source + d(_C_, co) -= out[0]; + else + // sink + d(_C_, co) -= out[0] * u(_C_, co); + } + } +} + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + double diffusion = 10.0; + + if ( bElementIsOutside ) + diffusion = 1.0; + + std::vector& vBF = geo.get_boundary_faces(); + MathVector Dgrad; + VecSet(Dgrad, 0.0); + + UG_LOG("---------- vBF.size(): " << vBF.size() << "\n"); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + + // set solution + /* for(size_t sh = 0; sh < geo.num_sh(); ++sh) + { + u(_C_, sh) = 1.0; + u(_C_, sh) -= corners[sh][0]*(2*corners[sh][0] - 1.0); + u(_C_, sh) -= corners[sh][1]*(2*corners[sh][1] - 1.0); + } + */ + // u(_C_, sh) = 1 - 2*(corners[sh][0]*corners[sh][0] + corners[sh][1]*corners[sh][1]) - (corners[sh][0]+corners[sh][1]); + // u(_C_, sh) = corners[sh][1]*(2*corners[sh][1] - 1.0); + // u(_C_, sh) = (1.0 - corners[sh][0] - corners[sh][1]) * (1.0 - 2*corners[sh][0] - 2*corners[sh][1]); + // u(_C_, sh) = corners[sh][1]; + // for(size_t sh = 0; sh < geo.num_sh(); ++sh) + // u(_C_, sh) = corners[sh][0]*(2*corners[sh][0] - 1.0); //corners[sh][0]; + // u(_C_, sh) = corners[sh][0]*(2* corners[sh][0]-1); + + //////////////////////////////////////////////////////////////////////////////// + // NO loop integration points! + // /* for(size_t ip = 0; ip < vBF.size(); ++ip) */ + // Reason: the length of the normal is already the length of the total face (NOT the scvf!) + //////////////////////////////////////////////////////////////////////////////// + + // loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + VecSet(Dgrad, 0.0); + + // loop trial space + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + { + // Diffusion + UG_LOG("bf.num_sh(): " << bf.num_sh() << "\n"); + UG_LOG("Dgrad: " << Dgrad << "\n"); + UG_LOG("bf.normal(): " << bf.normal() << "\n"); + UG_LOG("bf.global_grad(ip, sh): " << bf.global_grad(sh) << "\n"); + + UG_LOG("u(_C_, sh): " << u(_C_, sh) << "\n"); + + VecScaleAppend(Dgrad, diffusion * u(_C_, sh), bf.global_grad(sh)); + } + + // add to local vector + d(_C_, bf.node_id()) += VecDot(Dgrad, bf.normal()); + + } + + UG_LOG("---------- end ----------- \n\n"); + +} + + +//////////////////////////////////////////////////////////////////////////////// +/// +/// methods for cut element error computation via 'add_l2error_A_elem()' +/// +//////////////////////////////////////////////////////////////////////////////// + +template +number get_exact_sol_test(MathVector position) +{ + return sin(2*M_PI*position[0]) + sin(2*M_PI*position[1]); +} + +template +number get_exact_sol_Gangl(MathVector position) +{ + double kappa_2 = 10.0; + double dist_x = position[0] - 0.0; + double dist_y = position[1] - 0.0; + double sqR = 0.4*0.4; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = -4*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_2 - 1); + + if ( dist >= 0.4 ) + returnValue = -2*kappa_2*sqDist*sqDist; + + return returnValue; +} + +template +MathVector get_exact_grad_Gangl(MathVector position) +{ + double kappa_2 = 10.0; + double dist_x = position[0] - 0.0; + double dist_y = position[1] - 0.0; + double sqR = 0.4*0.4; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double factor = -8*kappa_2*kappa_2*sqR; + + if ( dist >= 0.4 ) + factor = -8*kappa_2*sqDist; + + MathVector returnVector; + returnVector[0] = factor*dist_x; + returnVector[1] = factor*dist_y; + + return returnVector; +} + +template +MathVector get_exact_grad_FedkiwEx5(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + double radius = 0.5; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double absValue = position[0]*position[0] + position[1]* position[1]; + + MathVector returnVector; + returnVector[0] = 0.0; + returnVector[1] = 0.0; + + double factor = 1.0/absValue; + if ( dist >= radius ) + { + returnVector[0] = factor*position[0]; + returnVector[1] = factor*position[1]; + } + + return returnVector; + +} + +template +number get_exact_sol_FedkiwEx6(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + double radius = 0.5; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = 0.0; + + if ( dist <= radius ) + returnValue = exp(position[0])*cos(position[1]); + + return returnValue; +} + +template +number get_exact_sol_FedkiwEx5(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + + double dist_x = position[0]-center_x; + double dist_y = position[1]-center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = 1.0; + + if ( dist > 0.5 ) + returnValue = 1.0 + log(2*dist); + + return returnValue; +} + +template +number get_exact_sol_FedkiwEx3(MathVector position) +{ + double center_x = 0.5; + double center_y = 0.5; + double radius = 0.25; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double absValue = position[0]*position[0] + position[1]* position[1]; + + double returnValue = 0.0; + + if ( dist <= radius ) + returnValue = exp(-absValue); + + return returnValue; +} + +template +MathVector get_exact_grad(MathVector position) +{ + +} + +////////////////////////////////////////////////////////////////////// +// code see ugbase/lib_disc/function_spaces/integrate.h: evaluate() for +// --> L2ErrorIntegrand (for value) +// --> H1ErrorIntegrand (for gradient): lines 1873-1910 +// +// called bei Integrate() via method 'integrand.values': +// integrand.values(&(vValue[0]), &(vGlobIP[0]), +// pElem, &vCorner[0], rQuadRule.points(), +// &(vJT[0]), +// numIP); +// +////////////////////////////////////////////////////////////////////// +template +template +number ConvectionDiffusionFV1:: +add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem) +{ + bool output = false; + + // number integral = 0; + + std::vector > vCorner; + std::vector > vGlobIP; + std::vector > vLocIP; + std::vector > vJT; + std::vector vValue; + std::vector vValueGrad; + + QuadType type = GetQuadratureType("best"); + + const QuadratureRule& rQuadRule + = QuadratureRuleProvider::get(roid, 1, type); + + // get reference element mapping by reference object id + DimReferenceMapping& mapping + = ReferenceMappingProvider::get(roid); + + // number of integration points + const size_t numIP = rQuadRule.size(); + + // get all corner coordinates + // CollectCornerCoordinates(vCorner, *pElem, aaPos, true); + + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(roid); + + vCorner.clear(); + // remember global position of nodes + for(size_t i = 0; i < rRefElem.num(0); ++i) + vCorner.push_back(geo.get_corner(i)); + + if ( output ) + { + for ( size_t i = 0; i < rRefElem.num(0); ++i) + UG_LOG("vCorner" << vCorner[i][0] << " and " << vCorner[i][1] << "\n" ); + UG_LOG("\n" ); + } + + // update the reference mapping for the corners + mapping.update(vCorner); + + // compute global integration points + vGlobIP.resize(numIP); + mapping.local_to_global(&(vGlobIP[0]), rQuadRule.points(), numIP); + + if ( output ) UG_LOG("vGlobIP" << vGlobIP[0][0] << " and " << vGlobIP[0][1] << "\n" ); + if ( output ) UG_LOG("\n" ); + + // compute local integration points + vLocIP.resize(numIP); + for(size_t ip = 0; ip < numIP; ++ip) + vLocIP[ip] = rQuadRule.points()[ip]; + + if ( output ) UG_LOG("vLocIP" << vLocIP[0][0] << " and " << vLocIP[0][1] << "\n" ); + if ( output ) UG_LOG("\n" ); + + + // compute transformation matrices + vJT.resize(numIP); + mapping.jacobian_transposed(&(vJT[0]), rQuadRule.points(), numIP); + + const size_t num_sh = geo.num_scvf(); + + if ( num_sh != rRefElem.num(0) ) + UG_THROW("wrong number of corners: sh = " << num_sh << ", but rRefElem.num(0) = " << rRefElem.num(0) << "\n"); + + // compute integrand values at integration points + vValue.resize(numIP); + vValueGrad.resize(numIP); + + try + { + // loop all integration points + for(size_t ip = 0; ip < numIP; ++ip) + { + // compute exact solution at integration point +// number exactSolIP = get_exact_sol_FedkiwEx5(vGlobIP[ip]); + number exactSolIP = get_exact_sol_Gangl(vGlobIP[ip]); + + // compute exact gradient at integration point + MathVector exactGradIP = get_exact_grad_FedkiwEx5(vGlobIP[ip]); + + // compute approximated solution at integration point + number approxSolIP = 0.0; + MathVector locTmp; VecSet(locTmp, 0.0); + + const typename TFVGeom::SCV& scv = geo.scv(ip); + + for(size_t sh = 0; sh < num_sh; ++sh) + { + // add shape fct at ip * value at shape + approxSolIP += u(_C_,sh) * geo.get_shape(sh, vLocIP[ip], roid); + + // add gradient at ip + VecScaleAppend(locTmp, u(_C_,sh), scv.local_grad(sh)); + } + + // get squared of difference + vValue[ip] = (exactSolIP - approxSolIP); + vValue[ip] *= vValue[ip]; + + // compute global gradient + MathVector approxGradIP; + MathMatrix JTInv; + Inverse(JTInv, vJT[ip]); + MatVecMult(approxGradIP, JTInv, locTmp); + + // get error of gradient + vValueGrad[ip] = VecDistanceSq(approxGradIP, exactGradIP); + + + } + /* integrand.values(&(vValue[0]), &(vGlobIP[0]), + pElem, &vCorner[0], rQuadRule.points(), + &(vJT[0]), + numIP); + */ + } + UG_CATCH_THROW("Unable to compute values of integrand at integration point."); + + // reset contribution of this element + number intValElem = 0; + + // loop integration points + for(size_t ip = 0; ip < numIP; ++ip) + { + // get quadrature weight + const number weightIP = rQuadRule.weight(ip); + + // get determinate of mapping + const number det = SqrtGramDeterminant(vJT[ip]); + + // add contribution of integration point + intValElem += vValue[ip] * weightIP * det; + // intValElem += vValueGrad[ip] * weightIP * det; + + } + + // add to global sum + + if ( output ) UG_LOG("added: " << intValElem << "\n\n"); + + return intValElem; +} + + +template +template +void ConvectionDiffusionFV1:: +add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + +// reaction rate + if(m_imReactionRateExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local defect + d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume(); + } + } + +// reaction + if(m_imReactionExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local defect + d(_C_, co) += m_imReactionExpl[ip] * scv.volume(); + } + } + + if(m_imSourceExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) -= m_imSourceExpl[ip] * scv.volume(); + } + } +} + +template +template +void ConvectionDiffusionFV1:: +add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + if(!m_imMassScale.data_given() && !m_imMass.data_given()) return; + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // mass value + number val = 0.0; + + // multiply by scaling + if(m_imMassScale.data_given()) + val += m_imMassScale[ip] * u(_C_, co); + + // add mass + if(m_imMass.data_given()) + val += m_imMass[ip]; + + // Add to local defect + d(_C_, co) += val * scv.volume(); + } +} + + +template +template +void ConvectionDiffusionFV1:: +add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) +{ + ///////////////////////////////////////////////////// + // add rhs ALLREADY(!) during 'add_def_A_elem_local()' method! + // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! + ///////////////////////////////////////////////////// + + return; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + // loop Sub Control Volumes (SCV) + if ( m_imSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) += m_imSource[ip] * scv.volume(); + //UG_LOG("d(_C_, co) = " << d(_C_, co) << "; \t ip " << ip << "; \t co " << co << "; \t scv_vol " << scv.volume() << "; \t m_imSource[ip] " << m_imSource[ip] << std::endl); + } + } + + // loop Sub Control Volumes (SCVF) + if ( m_imVectorSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); + + // Add to local rhs + d(_C_, scvf.from()) -= VecDot(m_imVectorSource[ip], scvf.normal() ); + d(_C_, scvf.to() ) += VecDot(m_imVectorSource[ip], scvf.normal() ); + } + } +} + + +// //////////////////////////////// +// error estimation (begin) /// + +// prepares the loop over all elements of one type for the computation of the error estimator +template +template +void ConvectionDiffusionFV1:: +prep_err_est_elem_loop(const ReferenceObjectID roid, const int si) +{ + // get the error estimator data object and check that it is of the right type + // we check this at this point in order to be able to dispense with this check later on + // (i.e. in prep_err_est_elem and compute_err_est_A_elem()) + if (this->m_spErrEstData.get() == NULL) + { + UG_THROW("No ErrEstData object has been given to this ElemDisc!"); + } + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (!err_est_data) + { + UG_THROW("Dynamic cast to SideAndElemErrEstData failed." + << std::endl << "Make sure you handed the correct type of ErrEstData to this discretization."); + } + + +// check that upwind has been set + if (m_spConvShape.invalid()) + UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " + "Upwind has not been set."); + +// set local positions + if (!TFVGeom::usesHangingNodes) + { + static const int refDim = TElem::dim; + + // get local IPs + size_t numSideIPs, numElemIPs; + const MathVector* sideIPs; + const MathVector* elemIPs; + try + { + numSideIPs = err_est_data->num_all_side_ips(roid); + numElemIPs = err_est_data->num_elem_ips(roid); + sideIPs = err_est_data->template side_local_ips(roid); + elemIPs = err_est_data->template elem_local_ips(roid); + + if (!sideIPs || !elemIPs) return; // are NULL if TElem is not of the same dim as TDomain + } + UG_CATCH_THROW("Integration points for error estimator cannot be set."); + + // set local IPs in imports + m_imDiffusion.template set_local_ips(sideIPs, numSideIPs, false); + m_imVelocity.template set_local_ips(sideIPs, numSideIPs, false); + m_imFlux.template set_local_ips(sideIPs, numSideIPs, false); + m_imSource.template set_local_ips(elemIPs, numElemIPs, false); + m_imVectorSource.template set_local_ips(sideIPs, numSideIPs, false); + m_imReactionRate.template set_local_ips(elemIPs, numElemIPs, false); + m_imReaction.template set_local_ips(elemIPs, numElemIPs, false); + m_imMassScale.template set_local_ips(elemIPs, numElemIPs, false); + m_imMass.template set_local_ips(elemIPs, numElemIPs, false); + + // init upwind for element type + TFVGeom& geo = GeomProvider::get(); + if (!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " + "Cannot init upwind for element type."); + + // store values of shape functions in local IPs + LagrangeP1::reference_element_type> trialSpace + = Provider::reference_element_type> >::get(); + + m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh()); + for (size_t ip = 0; ip < numElemIPs; ip++) + trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]); + for (size_t ip = 0; ip < numSideIPs; ip++) + trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]); + } +} + +template +template +void ConvectionDiffusionFV1:: +prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + +// update geometry for this element + static TFVGeom& geo = GeomProvider::get(); + try + { + geo.update(elem, vCornerCoords, &(this->subset_handler())); + } + UG_CATCH_THROW("ConvectionDiffusionFV1::prep_err_est_elem: Cannot update Finite Volume Geometry."); + +// roid + ReferenceObjectID roid = elem->reference_object_id(); + +// set local positions + if (TFVGeom::usesHangingNodes) + { + static const int refDim = TElem::dim; + + size_t numSideIPs, numElemIPs; + const MathVector* sideIPs; + const MathVector* elemIPs; + try + { + numSideIPs = err_est_data->num_all_side_ips(roid); + numElemIPs = err_est_data->num_elem_ips(roid); + sideIPs = err_est_data->template side_local_ips(roid); + elemIPs = err_est_data->template elem_local_ips(roid); + + if (!sideIPs || !elemIPs) return; // are NULL if TElem is not of the same dim as TDomain + } + UG_CATCH_THROW("Integration points for error estimator cannot be set."); + + m_imDiffusion.template set_local_ips(sideIPs, numSideIPs); + m_imVelocity.template set_local_ips(sideIPs, numSideIPs); + m_imFlux.template set_local_ips(sideIPs, numSideIPs); + m_imSource.template set_local_ips(elemIPs, numElemIPs); + m_imVectorSource.template set_local_ips(sideIPs, numSideIPs); + m_imReactionRate.template set_local_ips(elemIPs, numElemIPs); + m_imReaction.template set_local_ips(elemIPs, numElemIPs); + m_imMassScale.template set_local_ips(elemIPs, numElemIPs); + m_imMass.template set_local_ips(elemIPs, numElemIPs); + + // init upwind for element type + TFVGeom& geo = GeomProvider::get(); + if (!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " + "Cannot init upwind for element type."); + + // store values of shape functions in local IPs + LagrangeP1::reference_element_type> trialSpace + = Provider::reference_element_type> >::get(); + + m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh()); + for (size_t ip = 0; ip < numElemIPs; ip++) + trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]); + for (size_t ip = 0; ip < numSideIPs; ip++) + trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]); + } + +// set global positions + size_t numSideIPs, numElemIPs; + const MathVector* sideIPs; + const MathVector* elemIPs; + + try + { + numSideIPs = err_est_data->num_all_side_ips(roid); + numElemIPs = err_est_data->num_elem_ips(roid); + + sideIPs = err_est_data->all_side_global_ips(elem, vCornerCoords); + elemIPs = err_est_data->elem_global_ips(elem, vCornerCoords); + } + UG_CATCH_THROW("Global integration points for error estimator cannot be set."); + + m_imDiffusion. set_global_ips(&sideIPs[0], numSideIPs); + m_imVelocity. set_global_ips(&sideIPs[0], numSideIPs); + m_imFlux. set_global_ips(&sideIPs[0], numSideIPs); + m_imSource. set_global_ips(&elemIPs[0], numElemIPs); + m_imVectorSource. set_global_ips(&sideIPs[0], numSideIPs); + m_imReactionRate. set_global_ips(&elemIPs[0], numElemIPs); + m_imReaction. set_global_ips(&elemIPs[0], numElemIPs); + m_imMassScale. set_global_ips(&elemIPs[0], numElemIPs); + m_imMass. set_global_ips(&elemIPs[0], numElemIPs); +} + +// computes the error estimator contribution (stiffness part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ + typedef typename reference_element_traits::reference_element_type ref_elem_type; + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + +// request geometry + static const TFVGeom& geo = GeomProvider::get(); + + +// SIDE TERMS // + +// get the sides of the element + // We have to cast elem to a pointer of type SideAndElemErrEstData::elem_type + // for the SideAndElemErrEstData::operator() to work properly. + // This cannot generally be achieved by casting to TElem*, since this method is also registered for + // lower-dimensional types TElem, and must therefore be compilable, even if it is never EVER to be executed. + // The way we achieve this here, is by calling associated_elements_sorted() which has an implementation for + // all possible types. Whatever comes out of it is of course complete nonsense if (and only if) + // SideAndElemErrEstData::elem_type != TElem. To be on the safe side, we throw an error if the number of + // entries in the list is not as it should be. + + typename MultiGrid::traits::side_type>::secure_container side_list; + pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); + if (side_list.size() != (size_t) ref_elem_type::numSides) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// some help variables + MathVector fluxDensity, gradC, normal; + + // FIXME: The computation of the gradient has to be reworked. + // In the case of P1 shape functions, it is valid. For Q1 shape functions, however, + // the gradient is not constant (but bilinear) on the element - and along the sides. + // We cannot use the FVGeom here. Instead, we need to calculate the gradient in each IP! + + // calculate grad u (take grad from first scvf ip (grad u is constant on the entire element)) +/* if (geo.num_scvf() < 1) {UG_THROW("Element has no SCVFs!");} + const typename TFVGeom::SCVF& scvf = geo.scvf(0); + + VecSet(gradC, 0.0); + for (size_t j=0; j(normal, side, vCornerCoords); + VecNormalize(normal, normal); + + try + { + for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) + { + size_t ip = passedIPs + sip; + + VecSet(fluxDensity, 0.0); + + // diffusion // + if (m_imDiffusion.data_given()) + MatVecScaleMultAppend(fluxDensity, -1.0, m_imDiffusion[ip], gradC); + + // convection // + if (m_imVelocity.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtSideIP(sh,sip); + + VecScaleAppend(fluxDensity, val, m_imVelocity[ip]); + } + + // general flux // + if (m_imFlux.data_given()) + VecAppend(fluxDensity, m_imFlux[ip]); + + (*err_est_data)(side_list[side],sip) += scale * VecDot(fluxDensity, normal); + } + + passedIPs += err_est_data->num_side_ips(side_list[side]); + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); + } + +// VOLUME TERMS // + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + { + number total = 0.0; + + // diffusion // TODO ONLY FOR (PIECEWISE) CONSTANT DIFFUSION TENSOR SO FAR! + // div(D*grad(c)) + // nothing to do, as c is piecewise linear and div(D*grad(c)) disappears + // if D is diagonal and c bilinear, this should also vanish (confirm this!) + + // convection // TODO ONLY FOR (PIECEWISE) CONSTANT OR DIVERGENCE-FREE + // VELOCITY FIELDS SO FAR! + // div(v*c) = div(v)*c + v*grad(c) -- gradC has been calculated above + if (m_imVelocity.data_given()) + total += VecDot(m_imVelocity[ip], gradC); + + // general flux // TODO ONLY FOR DIVERGENCE-FREE FLUX FIELD SO FAR! + // nothing to do + + // reaction // + if (m_imReactionRate.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < geo.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); + + total += m_imReactionRate[ip] * val; + } + + if (m_imReaction.data_given()) + { + total += m_imReaction[ip]; + } + + (*err_est_data)(elem_list[0],ip) += scale * total; + } + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// computes the error estimator contribution (mass part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ +// note: mass parts only enter volume term + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// request geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop integration points + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + { + number total = 0.0; + + // mass scale // + if (m_imMassScale.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < geo.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); + + total += m_imMassScale[ip] * val; + } + + // mass // + if (m_imMass.data_given()) + { + total += m_imMass[ip]; + } + + (*err_est_data)(elem_list[0],ip) += scale * total; + } + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// computes the error estimator contribution (rhs part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ + typedef typename reference_element_traits::reference_element_type ref_elem_type; + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + +// SIDE TERMS // + +// get the sides of the element + typename MultiGrid::traits::side_type>::secure_container side_list; + pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); + if (side_list.size() != (size_t) ref_elem_type::numSides) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// loop sides + size_t passedIPs = 0; + for (size_t side = 0; side < (size_t) ref_elem_type::numSides; side++) + { + // normal on side + MathVector normal; + SideNormal(normal, side, vCornerCoords); + VecNormalize(normal, normal); + + try + { + for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) + { + size_t ip = passedIPs + sip; + + // vector source // + if (m_imVectorSource.data_given()) + (*err_est_data)(side_list[side],sip) += scale * VecDot(m_imVectorSource[ip], normal); + } + + passedIPs += err_est_data->num_side_ips(side_list[side]); + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); + } + +// VOLUME TERMS // + + if (!m_imSource.data_given()) return; + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// source // + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + (*err_est_data)(elem_list[0],ip) += scale * m_imSource[ip]; + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// postprocesses the loop over all elements of one type in the computation of the error estimator +template +template +void ConvectionDiffusionFV1:: +fsh_err_est_elem_loop() +{ +// finish the element loop in the same way as the actual discretization + this->template fsh_elem_loop (); +}; + +// error estimation (end) /// +// ///////////////////////////////// + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +lin_def_velocity(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // sum up contributions of convection shapes + MathVector linDefect; + VecSet(linDefect, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(linDefect, u(_C_,sh), convShape.D_vel(ip, sh)); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] += linDefect; + vvvLinDef[ip][_C_][scvf.to()] -= linDefect; + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +lin_def_diffusion(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // compute gradient at ip + MathVector grad_u; VecSet(grad_u, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad_u, u(_C_,sh), scvf.global_grad(sh)); + + // compute the lin defect at this ip + MathMatrix linDefect; + + // part coming from -\nabla u * \vec{n} + for(size_t k=0; k < (size_t)dim; ++k) + for(size_t j = 0; j < (size_t)dim; ++j) + linDefect(j,k) = (scvf.normal())[j] * grad_u[k]; + + // add contribution from convection shapes + if(convShape.non_zero_deriv_diffusion()) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + MatAdd(linDefect, convShape.D_diffusion(ip, sh), u(_C_, sh)); + + // add contributions + vvvLinDef[ip][_C_][scvf.from()] -= linDefect; + vvvLinDef[ip][_C_][scvf.to() ] += linDefect; + } +} + +template +template +void ConvectionDiffusionFV1:: +lin_def_flux(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] += scvf.normal(); + vvvLinDef[ip][_C_][scvf.to()] -= scvf.normal(); + } +} +// computes the linearized defect w.r.t to the reaction rate +template +template +void ConvectionDiffusionFV1:: +lin_def_reaction_rate(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = u(_C_, co) * scv.volume(); + } +} + +// computes the linearized defect w.r.t to the reaction +template +template +void ConvectionDiffusionFV1:: +lin_def_reaction(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the source +template +template +void ConvectionDiffusionFV1:: +lin_def_source(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the vector source +// (in analogy to velocity) +template +template +void ConvectionDiffusionFV1:: +lin_def_vector_source(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ + // get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + + // loop Sub Control Volumes Faces (SCVF) + for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] -= scvf.normal(); + vvvLinDef[ip][_C_][scvf.to()] += scvf.normal(); + } +} + +// computes the linearized defect w.r.t to the mass scale +template +template +void ConvectionDiffusionFV1:: +lin_def_mass_scale(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t co = 0; co < geo.num_scv(); ++co) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(co); + + // Check associated node + UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); + + // set lin defect + vvvLinDef[co][_C_][co] = u(_C_, co) * scv.volume(); + } +} + +// computes the linearized defect w.r.t to the mass scale +template +template +void ConvectionDiffusionFV1:: +lin_def_mass(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t co = 0; co < geo.num_scv(); ++co) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(co); + + // Check associated node + UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); + + // set lin defect + vvvLinDef[co][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +ex_value(number vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > vvvDeriv[]) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reference element + typedef typename reference_element_traits::reference_element_type + ref_elem_type; + +// number of shape functions + static const size_t numSH = ref_elem_type::numCorners; + + +// FV1 SCVF ip + if(vLocIP == geo.scvf_local_ips()) + { + // Loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // Get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // compute concentration at ip + vValue[ip] = 0.0; + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vValue[ip] += u(_C_, sh) * scvf.shape(sh); + + // compute derivative w.r.t. to unknowns iff needed + if(bDeriv) + { + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vvvDeriv[ip][_C_][sh] = scvf.shape(sh); + + // do not forget that number of DoFs (== vvvDeriv[ip][_C_]) + // might be > scvf.num_sh() in case of hanging nodes! + size_t ndof = vvvDeriv[ip][_C_].size(); + for (size_t sh = scvf.num_sh(); sh < ndof; ++sh) + vvvDeriv[ip][_C_][sh] = 0.0; + } + } + } +// FV1 SCV ip + else if(vLocIP == geo.scv_local_ips()) + { + // Loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // Get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get corner of SCV + const size_t co = scv.node_id(); + + // solution at ip + vValue[ip] = u(_C_, co); + + // set derivatives if needed + if(bDeriv) + { + size_t ndof = vvvDeriv[ip][_C_].size(); + for(size_t sh = 0; sh < ndof; ++sh) + vvvDeriv[ip][_C_][sh] = (sh==co) ? 1.0 : 0.0; + } + } + } +// general case + else + { + // get trial space + LagrangeP1& rTrialSpace = Provider >::get(); + + // storage for shape function at ip + number vShape[numSH]; + + // loop ips + for(size_t ip = 0; ip < nip; ++ip) + { + // evaluate at shapes at ip + rTrialSpace.shapes(vShape, vLocIP[ip]); + + // compute concentration at ip + vValue[ip] = 0.0; + for(size_t sh = 0; sh < numSH; ++sh) + vValue[ip] += u(_C_, sh) * vShape[sh]; + + // compute derivative w.r.t. to unknowns iff needed + // \todo: maybe store shapes directly in vvvDeriv + if(bDeriv) + { + for(size_t sh = 0; sh < numSH; ++sh) + vvvDeriv[ip][_C_][sh] = vShape[sh]; + + // beware of hanging nodes! + size_t ndof = vvvDeriv[ip][_C_].size(); + for (size_t sh = numSH; sh < ndof; ++sh) + vvvDeriv[ip][_C_][sh] = 0.0; + } + } + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +ex_grad(MathVector vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > > vvvDeriv[]) +{ +// Get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reference element + typedef typename reference_element_traits::reference_element_type + ref_elem_type; + +// reference dimension + static const int refDim = ref_elem_type::dim; + +// number of shape functions + static const size_t numSH = ref_elem_type::numCorners; + + +// FV1 SCVF ip + if(vLocIP == geo.scvf_local_ips()) + { + // Loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // Get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + VecSet(vValue[ip], 0.0); + + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(vValue[ip], u(_C_, sh), scvf.global_grad(sh)); + + if(bDeriv) + { + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vvvDeriv[ip][_C_][sh] = scvf.global_grad(sh); + + // beware of hanging nodes! + size_t ndof = vvvDeriv[ip][_C_].size(); + for (size_t sh = scvf.num_sh(); sh < ndof; ++sh) + vvvDeriv[ip][_C_][sh] = 0.0; + } + } + } +// general case + else + { + // get trial space + LagrangeP1& rTrialSpace = Provider >::get(); + + // storage for shape function at ip + MathVector vLocGrad[numSH]; + MathVector locGrad; + + // Reference Mapping + MathMatrix JTInv; + ReferenceMapping mapping(vCornerCoords); + + // loop ips + for(size_t ip = 0; ip < nip; ++ip) + { + // evaluate at shapes at ip + rTrialSpace.grads(vLocGrad, vLocIP[ip]); + + // compute grad at ip + VecSet(locGrad, 0.0); + for(size_t sh = 0; sh < numSH; ++sh) + VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]); + + // compute global grad + mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]); + MatVecMult(vValue[ip], JTInv, locGrad); + + // compute derivative w.r.t. to unknowns iff needed + if(bDeriv) + { + for(size_t sh = 0; sh < numSH; ++sh) + MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); + + // beware of hanging nodes! + size_t ndof = vvvDeriv[ip][_C_].size(); + for (size_t sh = numSH; sh < ndof; ++sh) + vvvDeriv[ip][_C_][sh] = 0.0; + } + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// upwind +//////////////////////////////////////////////////////////////////////////////// + +template +void ConvectionDiffusionFV1:: +set_upwind(SmartPtr > shapes) {m_spConvShape = shapes;} + +// computes the linearized defect w.r.t to the velocity +template +const typename ConvectionDiffusionFV1::conv_shape_type& +ConvectionDiffusionFV1:: +get_updated_conv_shapes(const FVGeometryBase& geo) +{ +// compute upwind shapes for transport equation +// \todo: we should move this computation into the preparation part of the +// disc, to only compute the shapes once, reusing them several times. + if(m_imVelocity.data_given()) + { + // get diffusion at ips + const MathMatrix* vDiffusion = NULL; + if(m_imDiffusion.data_given()) vDiffusion = m_imDiffusion.values(); + + // update convection shapes + if(!m_spConvShape->update(&geo, m_imVelocity.values(), vDiffusion, true)) + { + UG_LOG("ERROR in 'ConvectionDiffusionFV1::get_updated_conv_shapes': " + "Cannot compute convection shapes.\n"); + } + } + +// return a const (!!) reference to the upwind + return *const_cast*>(m_spConvShape.get()); +} + +//////////////////////////////////////////////////////////////////////////////// +// register assemble functions +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + +/* +// switch assemble functions + if(!bHang) + { + register_func >(); + } + else + { + register_func >(); + } + */ +} +#endif + +#ifdef UG_DIM_2 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + +/* +// switch assemble functions + if(!bHang) + { + register_func >(); + register_func >(); + register_func >(); + } + else + { + register_func >(); + register_func >(); + register_func >(); + } + */ +} +#endif + +#ifdef UG_DIM_3 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + /* + +// switch assemble functions + if(!bHang) + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + } + else + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + } +*/ +} +#endif + +template +template +void ConvectionDiffusionFV1:: +register_func() +{ + ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; + typedef this_type T; + static const int refDim = reference_element_traits::dim; + + this->clear_add_fct(id); + this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); + this->set_prep_elem_fct( id, &T::template prep_elem); + this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); + this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem); + this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem); + this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem); + this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem); + this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem); + this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); + +// error estimator parts + this->set_prep_err_est_elem_loop(id, &T::template prep_err_est_elem_loop); + this->set_prep_err_est_elem(id, &T::template prep_err_est_elem); + this->set_compute_err_est_A_elem(id, &T::template compute_err_est_A_elem); + this->set_compute_err_est_M_elem(id, &T::template compute_err_est_M_elem); + this->set_compute_err_est_rhs_elem(id, &T::template compute_err_est_rhs_elem); + this->set_fsh_err_est_elem_loop(id, &T::template fsh_err_est_elem_loop); + +// set computation of linearized defect w.r.t velocity + m_imDiffusion.set_fct(id, this, &T::template lin_def_diffusion); + m_imVelocity. set_fct(id, this, &T::template lin_def_velocity); + m_imFlux.set_fct(id, this, &T::template lin_def_flux); + m_imReactionRate. set_fct(id, this, &T::template lin_def_reaction_rate); + m_imReaction. set_fct(id, this, &T::template lin_def_reaction); + m_imSource. set_fct(id, this, &T::template lin_def_source); + m_imVectorSource.set_fct(id, this, &T::template lin_def_vector_source); + m_imMassScale.set_fct(id, this, &T::template lin_def_mass_scale); + m_imMass. set_fct(id, this, &T::template lin_def_mass); + +// exports + m_exValue-> template set_fct(id, this, &T::template ex_value); + m_exGrad->template set_fct(id, this, &T::template ex_grad); +} + +//////////////////////////////////////////////////////////////////////////////// +// explicit template instantiations +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template class ConvectionDiffusionFV1; +#endif +#ifdef UG_DIM_2 +template class ConvectionDiffusionFV1; +#endif +#ifdef UG_DIM_3 +template class ConvectionDiffusionFV1; +#endif + +} // end namespace ConvectionDiffusionPlugin +} // namespace ug + diff --git a/fv1_cutElem/convection_diffusion_fv1 Kopie.h b/fv1_cutElem/convection_diffusion_fv1 Kopie.h new file mode 100644 index 0000000..71d988b --- /dev/null +++ b/fv1_cutElem/convection_diffusion_fv1 Kopie.h @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2013-2015: G-CSC, Goethe University Frankfurt + * Author: Andreas Vogel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ +#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ + + +// ug4 headers +#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" +#include "lib_disc/spatial_disc/elem_disc/sss.h" + +// plugin's internal headers +#include "../convection_diffusion_base.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +// \ingroup lib_disc_elem_disc +/// \addtogroup convection_diffusion +/// \{ + +/// Discretization for the Convection-Diffusion Equation +/** + * This class implements the IElemDisc interface to provide element local + * assemblings for the convection diffusion equation. + * The Equation has the form + * \f[ + * \partial_t (m1*c + m2) - \nabla \left( D \nabla c - \vec{v} c - \vec{F} \right ) + * + r1 \cdot c + r2 = f + f2 + * \f] + * with + *
    + *
  • \f$ c \f$ is the unknown solution + *
  • \f$ m1 \equiv m(\vec{x},t) \f$ is the Mass Scaling Term + *
  • \f$ m2 \equiv m(\vec{x},t) \f$ is the Mass Term + *
  • \f$ D \equiv D(\vec{x},t) \f$ is the Diffusion Tensor + *
  • \f$ v \equiv \vec{v}(\vec{x},t) \f$ is the Velocity Field + *
  • \f$ F \equiv \vec{F}(\vec{x},t) \f$ is the Flux + *
  • \f$ r1 \equiv r(\vec{x},t) \f$ is the Reaction Rate + *
  • \f$ r2 \equiv r(\vec{x},t) \f$ is a Reaction Term + *
  • \f$ f \equiv f(\vec{x},t) \f$ is a Source Term + *
  • \f$ f2 \equiv f_2(\vec{x},t) \f$ is a Vector Source Term + *
+ * + * \tparam TDomain Domain + */ +template< typename TDomain> +class ConvectionDiffusionFV1 : public ConvectionDiffusionBase +{ + private: + /// Base class type + typedef ConvectionDiffusionBase base_type; + + /// Own type + typedef ConvectionDiffusionFV1 this_type; + + /// error estimator type + typedef SideAndElemErrEstData err_est_type; + + public: + /// World dimension + static const int dim = base_type::dim; + + public: + /// Constructor + ConvectionDiffusionFV1(const char* functions, const char* subsets); + + /// set the upwind method + /** + * This method sets the upwind method used to upwind the convection. + * + * \param shapes upwind method + */ + void set_upwind(SmartPtr > shapes); + + /// set singular sources and sinks + void set_sss(SmartPtr > sss) { m_sss = sss; } + + private: + /// prepares assembling + virtual void prep_assemble_loop(); + + /// prepares the loop over all elements + /** + * This method prepares the loop over all elements. It resizes the Position + * array for the corner coordinates and schedules the local ip positions + * at the data imports. + */ + template + void prep_elem_loop(const ReferenceObjectID roid, const int si); + + /// prepares the element for assembling + /** + * This methods prepares an element for the assembling. The Positions of + * the Element Corners are read and the Finite Volume Geometry is updated. + * The global ip positions are scheduled at the data imports. + */ + template + void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]); + + /// finishes the loop over all elements + template + void fsh_elem_loop(); + + /// assembles the local stiffness matrix using a finite volume scheme + template + void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + template + void add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + + + /// assembles the local mass matrix using a finite volume scheme + template + void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + + /// assembles the stiffness part of the local defect + template + void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + /// assembles the stiffness part of the local defect + template + void add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + template + void add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + template + number add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem); + + + /// assembles the stiffness part of the local defect explicit reaction, reaction_rate and source + template + void add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the mass part of the local defect + template + void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the local right hand side + template + void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_rhs_elem_local(TFVGeom& geo, LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); + + + /// prepares the loop over all elements of one type for the computation of the error estimator + template + void prep_err_est_elem_loop(const ReferenceObjectID roid, const int si); + + /// prepares the element for assembling the error estimator + template + void prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// computes the error estimator contribution for one element + template + void compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// computes the error estimator contribution for one element + template + void compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// computes the error estimator contribution for one element + template + void compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// postprocesses the loop over all elements of one type in the computation of the error estimator + template + void fsh_err_est_elem_loop(); + + protected: + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_velocity(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_diffusion(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_flux(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the reaction + template + void lin_def_reaction(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the reaction + template + void lin_def_reaction_rate(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the source term + template + void lin_def_source(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the vector source term + template + void lin_def_vector_source(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the mass scale term + template + void lin_def_mass_scale(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the mass scale term + template + void lin_def_mass(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + private: + /// abbreviation for the local solution + static const size_t _C_ = 0; + + /// singular sources and sinks + SmartPtr > m_sss; + + using base_type::m_imDiffusion; + using base_type::m_imVelocity; + using base_type::m_imFlux; + using base_type::m_imSource; + using base_type::m_imSourceExpl; + using base_type::m_imVectorSource; + using base_type::m_imReactionRate; + using base_type::m_imReactionRateExpl; + using base_type::m_imReaction; + using base_type::m_imReactionExpl; + using base_type::m_imMassScale; + using base_type::m_imMass; + + using base_type::m_exGrad; + using base_type::m_exValue; + + protected: + /// method to compute the upwind shapes + SmartPtr > m_spConvShape; + + /// returns the updated convection shapes + typedef IConvectionShapes conv_shape_type; + const IConvectionShapes& get_updated_conv_shapes(const FVGeometryBase& geo); + + /// computes the concentration + template + void ex_value(number vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > vvvDeriv[]); + + /// computes the gradient of the concentration + template + void ex_grad(MathVector vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > > vvvDeriv[]); + + public: + /// type of trial space for each function used + virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid); + + /// returns if hanging nodes are needed + virtual bool use_hanging() const; + + protected: + /// current regular grid flag + bool m_bNonRegularGrid; + + /// current shape function set (needed for GeomProvider::get()) + LFEID m_LFEID; + + /// register utils + /// \{ + void register_all_funcs(bool bHang); + template void register_func(); + /// \} + + private: + /// struct holding values of shape functions in IPs + struct ShapeValues + { + public: + void resize(std::size_t nEip, std::size_t nSip, std::size_t _nSh) + { + nSh = _nSh; + elemVals.resize(nEip); + sideVals.resize(nSip); + for (std::size_t i = 0; i < nEip; i++) elemVals[i].resize(nSh); + for (std::size_t i = 0; i < nSip; i++) sideVals[i].resize(nSh); + } + number& shapeAtElemIP(std::size_t sh, std::size_t ip) {return elemVals[ip][sh];} + number& shapeAtSideIP(std::size_t sh, std::size_t ip) {return sideVals[ip][sh];} + number* shapesAtElemIP(std::size_t ip) {return &elemVals[ip][0];} + number* shapesAtSideIP(std::size_t ip) {return &sideVals[ip][0];} + std::size_t num_sh() {return nSh;} + private: + std::size_t nSh; + std::vector > elemVals; + std::vector > sideVals; + } m_shapeValues; +}; + +// end group convection_diffusion +/// \} + +} // end ConvectionDiffusionPlugin +} // end namespace ug + + +#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__*/ diff --git a/fv1_cutElem/convection_diffusion_fv1_cutElem.cpp b/fv1_cutElem/convection_diffusion_fv1_cutElem.cpp new file mode 100644 index 0000000..aa54da0 --- /dev/null +++ b/fv1_cutElem/convection_diffusion_fv1_cutElem.cpp @@ -0,0 +1,1711 @@ +/* + * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt + * Author: Andreas Vogel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + + +#include "convection_diffusion_fv1_cutElem.h" + +#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + + +DebugID DID_CONV_DIFF_FV1_CUTELEM("CONV_DIFF_FV1_CUTELEM"); + +//////////////////////////////////////////////////////////////////////////////// +// helper function +//////////////////////////////////////////////////////////////////////////////// + +/// helper function to prepare data for 'add_def_A_elem_local()' and 'add_jac_A_elem_local()' +template +template +void ConvectionDiffusionFV1_cutElem:: +get_local_data(TFVGeom& geo, const LocalVector& u, LocalVector& locUOut, MathMatrix diffusionOut, LocalVector& jumpOut, LocalVector& jump_gradOut, LocalVector& sourceOut) +{ + const bool bElementIsCut = geo.get_element_modus(); + + LocalIndices ind = u.get_indices(); + jumpOut.resize(ind); jump_gradOut.resize(ind); sourceOut.resize(ind); + + const int orientation = geo.get_orientation(); + + std::vector imSource; + if ( m_imSource.data_given() ) { + for ( size_t i = 0; i < 3; ++i ) + imSource.push_back(m_imSource[i]); + } + +// A. set data for non-cut elements + if ( !bElementIsCut ) + { + // set diffusion + diffusionOut *= geo.get_diffusion(geo.get_boolian_for_diffusion()); + + // set boundary condition values source, jump, jump_grad + jumpOut = 0.0; jump_gradOut = 0.0; + sourceOut = geo.set_source(imSource, ind, 3, false); + LocalVector source = geo.set_source(imSource, ind, 3, false); + + int s = 0; + } +// B. set data for cut element + else + { + // set diffusion + diffusionOut *= geo.get_diffusion(); + + // set boundary condition values source, jump, jump_grad + int indexSize = 3; + if ( geo.get_roid() == ROID_QUADRILATERAL ) + indexSize = 4; + + geo.set_local_sol(locUOut, indexSize, u, orientation); + + jumpOut = geo.set_jump_values(ind, indexSize); + jump_gradOut = geo.set_jump_grad_values(ind, indexSize); + sourceOut = geo.set_source(imSource, ind, indexSize, true); + } + +} + +//////////////////////////////////////////////////////////////////////////////// +// general +//////////////////////////////////////////////////////////////////////////////// + +template +ConvectionDiffusionFV1_cutElem:: +ConvectionDiffusionFV1_cutElem(const char* functions, const char* subsets) + : ConvectionDiffusionBase(functions,subsets), + m_spConvShape(new ConvectionShapesNoUpwind), + m_bNonRegularGrid(false) +{ + register_all_funcs(m_bNonRegularGrid); +} + +template +void ConvectionDiffusionFV1_cutElem:: +prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid) +{ +// check number + if(vLfeID.size() != 1) + UG_THROW("ConvectionDiffusion: Wrong number of functions given. " + "Need exactly "<<1); + + if(vLfeID[0].order() != 1 || vLfeID[0].type() != LFEID::LAGRANGE) + UG_THROW("ConvectionDiffusion FV Scheme only implemented for 1st order."); + + m_LFEID = vLfeID[0]; + +// remember + m_bNonRegularGrid = bNonRegularGrid; + +// update assemble functions + register_all_funcs(m_bNonRegularGrid); +} + +template +bool ConvectionDiffusionFV1_cutElem:: +use_hanging() const +{ + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Assembling functions +//////////////////////////////////////////////////////////////////////////////// + +template +void ConvectionDiffusionFV1_cutElem:: +prep_assemble_loop() +{ + if (m_sss.valid()) + m_sss->clear_markers(); +} + +template +template +void ConvectionDiffusionFV1_cutElem:: +prep_elem_loop(const ReferenceObjectID roid, const int si) +{ + +// check, that upwind has been set + if(m_spConvShape.invalid()) + UG_THROW("ConvectionDiffusionFV1_cutElem::prep_elem_loop:" + " Upwind has not been set."); + +// set local positions +// if(!TFVGeom::usesHangingNodes) + if(!TFVGeom::usesHangingNodes && TFVGeom::staticLocalData) + { + static const int refDim = TElem::dim; +// TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID, 1); + const MathVector* vSCVFip = geo.scvf_local_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_local_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip, false); + m_imVelocity.template set_local_ips(vSCVFip,numSCVFip, false); + m_imFlux.template set_local_ips(vSCVFip,numSCVFip, false); + m_imSource.template set_local_ips(vSCVip,numSCVip, false); + m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip, false); + m_imReactionRate.template set_local_ips(vSCVip,numSCVip, false); + m_imReaction.template set_local_ips(vSCVip,numSCVip, false); + m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imReactionExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imSourceExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imMassScale.template set_local_ips(vSCVip,numSCVip, false); + m_imMass.template set_local_ips(vSCVip,numSCVip, false); + + // init upwind for element type + if(!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1_cutElem::prep_elem_loop:" + " Cannot init upwind for element type."); + } +} + +template +template +void ConvectionDiffusionFV1_cutElem:: +fsh_elem_loop() +{} + +template +template +void ConvectionDiffusionFV1_cutElem:: +prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) +{ +// Update Geometry for this element + //static TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + //TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); + +// fix: set orientation initially globally! + geo.set_orientation(1); + + + try{ + UG_DLOG(DID_CONV_DIFF_FV1_CUTELEM, 2, ">>OCT_DISC_DEBUG: " << "convection_diffusion_fv1.cpp: " << "prep_elem(): update(): "<< roid << std::endl); +// geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); + geo.update(elem, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1_cutElem::prep_elem:" + " Cannot update Finite Volume Geometry."); + +// set local positions +// if(TFVGeom::usesHangingNodes) + if(TFVGeom::usesHangingNodes || !TFVGeom::staticLocalData) + { + const int refDim = TElem::dim; + const MathVector* vSCVFip = geo.scvf_local_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_local_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip); + m_imVelocity.template set_local_ips(vSCVFip,numSCVFip); + m_imFlux.template set_local_ips(vSCVFip,numSCVFip); + m_imSource.template set_local_ips(vSCVip,numSCVip); + m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip); + m_imReactionRate.template set_local_ips(vSCVip,numSCVip); + m_imReaction.template set_local_ips(vSCVip,numSCVip); + m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip); + m_imReactionExpl.template set_local_ips(vSCVip,numSCVip); + m_imSourceExpl.template set_local_ips(vSCVip,numSCVip); + m_imMassScale.template set_local_ips(vSCVip,numSCVip); + m_imMass.template set_local_ips(vSCVip,numSCVip); +/* + if(m_spConvShape.valid()) + if(!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1_cutElem::prep_elem_loop:" + " Cannot init upwind for element type."); + */ + } + + // set global positions + const MathVector* vSCVFip = geo.scvf_global_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_global_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion. set_global_ips(vSCVFip, numSCVFip); + m_imVelocity. set_global_ips(vSCVFip, numSCVFip); + m_imFlux. set_global_ips(vSCVFip, numSCVFip); + m_imSource. set_global_ips(vSCVip, numSCVip); + m_imVectorSource. set_global_ips(vSCVFip, numSCVFip); + m_imReactionRate. set_global_ips(vSCVip, numSCVip); + m_imReactionRateExpl. set_global_ips(vSCVip, numSCVip); + m_imReactionExpl. set_global_ips(vSCVip, numSCVip); + m_imSourceExpl. set_global_ips(vSCVip, numSCVip); + m_imReaction. set_global_ips(vSCVip, numSCVip); + m_imMassScale. set_global_ips(vSCVip, numSCVip); + m_imMass. set_global_ips(vSCVip, numSCVip); +} + +template +static TVector CalculateCenter(GridObject* o, const TVector* coords) +{ + TVector v; + VecSet(v, 0); + + size_t numCoords = 0; + switch(o->base_object_id()){ + case VERTEX: numCoords = 1; break; + case EDGE: numCoords = static_cast(o)->num_vertices(); break; + case FACE: numCoords = static_cast(o)->num_vertices(); break; + case VOLUME: numCoords = static_cast(o)->num_vertices(); break; + default: UG_THROW("Unknown element type."); break; + } + + for(size_t i = 0; i < numCoords; ++i) + VecAdd(v, v, coords[i]); + + if(numCoords > 0) + VecScale(v, v, 1. / (number)numCoords); + + return v; +} + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + + bool debug = false; + bool boundary = false; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + const bool bElementIsCut = geo.get_element_modus(); + + // First call with orientation = 1: + int orientation = 1; + geo.set_orientation(orientation); + + geo.init_integral(); + + // normal assembling if not cut by interface: + if ( !bElementIsCut ) + { + LocalVector dummyU; + LocalIndices ind = u.get_indices(); + dummyU.resize(ind); + dummyU = 0; + + this->template add_jac_A_elem_local (geo, u, J, dummyU, elem, vCornerCoords); + return; + } + + // get data: + geo.resize_local_data(u); + LocalMatrix& locJ_tri = geo.get_jacobian_tri(); + LocalMatrix& locJ_quad = geo.get_jacobian_quad(); + + LocalVector& locU_tri = geo.get_solution_tri(); + LocalVector& locU_quad = geo.get_solution_quad(); + + // reset data: + locJ_tri = 0; + locJ_quad = 0; + + LocalIndices ind = u.get_indices(); + + // call elem disc twice: + + if ( debug ) geo.print_InterfaceIDdata(); + + ReferenceObjectID roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + + this->template add_jac_A_elem_local (geo, u, locJ_tri, locU_tri, elem, vCornerCoords); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_tri, 3); + this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords); + } + + geo.set_jacobian_tri(locJ_tri); + geo.set_DoF_tag_tri(false); + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + + this->template add_jac_A_elem_local (geo, u, locJ_quad, locU_quad, elem, vCornerCoords); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_quad, 4); + this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords); + } + + geo.set_jacobian_quad(locJ_quad); + geo.set_DoF_tag_quad(false); + } + + + // Second call with orientation = 1: + bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! + + orientation *= -1; + geo.set_orientation(orientation); + try{ + geo.update(elem, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1_cutElem::update:" + " Cannot update Finite Volume Geometry."); + + if ( debug ) geo.print_InterfaceIDdata(); + + roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + + this->template add_jac_A_elem_local (geo, u, locJ_tri, locU_tri, elem, vCornerCoords); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_tri, 3); + this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords); + } + + geo.set_jacobian_tri(locJ_tri); + geo.set_DoF_tag_tri(shiftTag); + + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + + this->template add_jac_A_elem_local (geo, u, locJ_quad, locU_quad, elem, vCornerCoords); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_quad, 4); + this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords); + } + + geo.set_jacobian_quad(locJ_quad); + geo.set_DoF_tag_quad(shiftTag); + } + + +} + + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_jac_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalMatrix& J, LocalVector& locU, GridObject* elem, const MathVector vCornerCoords[]) +{ + MathMatrix diffusion; + MatSet(diffusion, 0); + MatDiagSet(diffusion, 1.0); + + LocalVector source, jump; + + get_local_data(geo, u, locU, diffusion, jump, jump, jump); + + +// Diff. Tensor times Gradient + MathVector Dgrad; + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// Diffusion and Velocity Term + if(m_imDiffusion.data_given() || m_imVelocity.data_given()) + { + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + //////////////////////////////////////////////////// + // Diffusive Term + //////////////////////////////////////////////////// + if(m_imDiffusion.data_given()) + { + // DID_CONV_DIFF_FV1_CUTELEM + number D_diff_flux_sum = 0.0; + + // loop shape functions + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + // Compute Diffusion Tensor times Gradient + MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); + + // Compute flux at IP + const number D_diff_flux = VecDot(Dgrad, scvf.normal()); + UG_DLOG(DID_CONV_DIFF_FV1_CUTELEM, 2, ">>OCT_DISC_DEBUG: " << "convection_diffusion_fv1.cpp: " << "add_jac_A_elem(): " << "sh # " << sh << " ; normalSize scvf # " << ip << ": " << VecLength(scvf.normal()) << "; \t from "<< scvf.from() << "; to " << scvf.to() << "; D_diff_flux: " << D_diff_flux << "; scvf.global_grad(sh): " << scvf.global_grad(sh) << std::endl); + + // Add flux term to local matrix // HIER MATRIXINDIZES!!! + UG_ASSERT((scvf.from() < J.num_row_dof(_C_)) && (scvf.to() < J.num_col_dof(_C_)), + "Bad local dof-index on element with object-id " << elem->base_object_id() + << " with center: " << CalculateCenter(elem, vCornerCoords)); + + J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; + J(_C_, scvf.to() , _C_, sh) += D_diff_flux; + + // DID_CONV_DIFF_FV1_CUTELEM + D_diff_flux_sum += D_diff_flux; + } + + UG_DLOG(DID_CONV_DIFF_FV1_CUTELEM, 2, "D_diff_flux_sum = " << D_diff_flux_sum << std::endl << std::endl); + } + + + ///////////////////////////////////////////////////////////////////////////// + // Additional diffusive Term due to jump in solution at the interface + // u^+ - u^- = jump + ///////////////////////////////////////////////////////////////////////////// + if ( 0 ) + { + // loop shape functions + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + // Compute Diffusion Tensor times Gradient + MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); + + // Compute flux at IP + const number D_diff_flux = jump(_C_,sh) * VecDot(Dgrad, scvf.normal()); + + J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; + J(_C_, scvf.to() , _C_, sh) += D_diff_flux; + } + + } + + //////////////////////////////////////////////////// + // Convective Term + //////////////////////////////////////////////////// + if(m_imVelocity.data_given()) + { + // Add Flux contribution + for(size_t sh = 0; sh < convShape.num_sh(); ++sh) + { + const number D_conv_flux = convShape(ip, sh); + + // Add flux term to local matrix + J(_C_, scvf.from(), _C_, sh) += D_conv_flux; + J(_C_, scvf.to(), _C_, sh) -= D_conv_flux; + } + } + + // no explicit dependency on flux import + } + } + + //UG_LOG("Local Matrix is: \n"<domain()->position_accessor(); + const typename TDomain::grid_type& grid = *this->domain()->grid(); + const number time = this->time(); + MathVector<1> out; + for(size_t i = 0; i < geo.num_scv(); i++) { + const typename TFVGeom::SCV& scv = geo.scv(i); + const int co = scv.node_id(); + const number len = m_sss->get_contrib_of_scv((TElem*)elem, (Grid&)grid, aaPos, geo, co, time, out); + if (len == 0.0) continue; + out[0] *= len; + if (out[0] < 0.0) + // sink + J(_C_, co, _C_, co) -= out[0]; + } + } +} + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + double diffusion = 0.0; + + if ( !geo.get_element_modus() ) + diffusion = geo.get_diffusion(geo.get_boolian_for_diffusion()); + else + diffusion = geo.get_diffusion(); + + std::vector& vBF = geo.get_boundary_faces(); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + + // loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + + // loop trial space + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + { + UG_LOG("bf.node_id(): " << bf.node_id() << "\n"); + UG_LOG("bf.global_grad(sh): " << bf.global_grad(sh) << "\n"); + UG_LOG("normal(): " << bf.normal() << "\n"); + + // add to local matrix + J(_C_, bf.node_id(), _C_, sh) += VecDot(bf.global_grad(sh), bf.normal()); + J(_C_, bf.node_id(), _C_, sh) *= diffusion; + } + } + +} + + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + if(!m_imMassScale.data_given()) return; + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local matrix + J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip]; + } + +// m_imMass part does not explicitly depend on associated unknown function +} + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + bool output = false; + bool output_integral = false; + + bool debug = false; + bool boundary = false; + bool add = true; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + const bool bElementIsCut = geo.get_element_modus(); + + // First call with orientation = 1: + int orientation = 1; + geo.set_orientation(orientation); + + // necessary for call of 'get_solution_tri' an 'get_solution_quad': + geo.resize_local_data(u); + std::vector imSource; + if ( m_imSource.data_given() ) { + for ( size_t i = 0; i < 3; ++i ) + imSource.push_back(m_imSource[i]); + } + + // normal assembling if not cut by interface: + if ( !bElementIsCut ) + { + LocalVector dummyU; + LocalIndices ind = d.get_indices(); + dummyU.resize(ind); + dummyU = 0; + LocalVector source = geo.set_source(imSource, ind, 3, false); + + if ( output ) + { + for ( size_t i = 0; i < 3; ++i) + UG_LOG("*** corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); + UG_LOG("\n" ); + } + + this->template add_def_A_elem_local (geo, u, d, dummyU, elem, vCornerCoords); + + number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, d, u, elem); + geo.add_to_integral(intValElem); + if ( output_integral ) + UG_LOG("------------------> usual: integral = " << sqrt(geo.get_integral()) << "\n"); + + return; + } + + // get data: + LocalVector& locD_tri = geo.get_defect_tri(); + LocalVector& locD_quad = geo.get_defect_quad(); + + LocalVector& locU_tri = geo.get_solution_tri(); + LocalVector& locU_quad = geo.get_solution_quad(); + + // reset data: + locD_tri = 0; + locD_quad = 0; + + // call elem disc twice: + + if ( debug ) geo.print_InterfaceIDdata(); + + LocalIndices ind = d.get_indices(); + + ReferenceObjectID roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + + LocalVector jump_tri = geo.set_jump_values(ind, 3); + LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); + LocalVector source_tri = geo.set_source(imSource, ind, 3, true); + + if ( output ) UG_LOG(" tri 1: orientaten: " << orientation << "\n"); + + this->template add_def_A_elem_local (geo, u, locD_tri, locU_tri, elem, vCornerCoords); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_tri, 3); + this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords); + } + + if ( output ) + { + for ( size_t i = 0; i < 3; ++i) + UG_LOG("corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); + UG_LOG("\n" ); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output_integral ) UG_LOG("------------------> tri1: integral = " << sqrt(geo.get_integral()) << "\n"); + + geo.set_defect_tri(locD_tri); + geo.set_DoF_tag_tri(false); + + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + + LocalVector jump_quad = geo.set_jump_values(ind, 4); + LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); + LocalVector source_quad = geo.set_source(imSource, ind, 4, true); + + if ( output ) UG_LOG(" quad 1: orientaten: " << orientation << "\n"); + this->template add_def_A_elem_local (geo, u, locD_quad, locU_quad, elem, vCornerCoords); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_quad, 4); + this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output_integral ) UG_LOG("------------------> quad1: integral = " << sqrt(geo.get_integral()) << "\n"); + + + geo.set_defect_quad(locD_quad); + geo.set_DoF_tag_quad(false); + + } + + + // Second call with orientation = -1: + bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! + + orientation *= -1; + if ( output ) UG_LOG(" ____2: orientaten: " << orientation << "\n"); + + geo.set_orientation(orientation); + try{ + geo.update(elem, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1_cutElem::update:" + " Cannot update Finite Volume Geometry."); + + if ( debug ) geo.print_InterfaceIDdata(); + + roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); + LocalVector source_tri = geo.set_source(imSource, ind, 3, true); + + if ( output ) UG_LOG(" tri 2: orientaten: " << orientation << "\n"); + + this->template add_def_A_elem_local (geo, u, locD_tri, locU_tri, elem, vCornerCoords); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_tri, 3); + this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output ) UG_LOG("------------------> tri2: integral = " << sqrt(geo.get_integral()) << "\n"); + + + geo.set_defect_tri(locD_tri); + geo.set_DoF_tag_tri(shiftTag); + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); + LocalVector source_quad = geo.set_source(imSource, ind, 4, true); + + if ( output ) UG_LOG(" quad 2: orientaten: " << orientation << "\n"); + + this->template add_def_A_elem_local (geo, u, locD_quad, locU_quad, elem, vCornerCoords); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_quad, 4); + this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output_integral ) UG_LOG("------------------> quad2: integral = " << sqrt(geo.get_integral()) << "\n"); + + geo.set_defect_quad(locD_quad); + geo.set_DoF_tag_quad(shiftTag); + + } +} + + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_def_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalVector& d, LocalVector& locU, GridObject* elem, const MathVector vCornerCoords[]) +{ + + MathMatrix diffusion; + MatSet(diffusion, 0); + MatDiagSet(diffusion, 1.0); + + LocalVector jump, jump_grad, source; + + get_local_data(geo, u, locU, diffusion, jump, jump_grad, source); + + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + + if(m_imDiffusion.data_given() || m_imVelocity.data_given() || m_imFlux.data_given()) + { + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + ///////////////////////////////////////////////////// + // Diffusive Term + ///////////////////////////////////////////////////// + if(m_imDiffusion.data_given()) + { + // to compute D \nabla c + MathVector Dgrad_c, grad_c; + + // compute gradient and shape at ip + VecSet(grad_c, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad_c, locU(_C_,sh), scvf.global_grad(sh)); + + // scale by diffusion tensor + MatVecMult(Dgrad_c, diffusion, grad_c); + + // Compute flux + const number diff_flux = VecDot(Dgrad_c, scvf.normal()); + + // Add to local defect + d(_C_, scvf.from()) -= diff_flux; + d(_C_, scvf.to() ) += diff_flux; + } + + ///////////////////////////////////////////////////////////////////////////// + // Additional diffusive Term due to jump in solution at the interface + // u^+ - u^- = jump + ///////////////////////////////////////////////////////////////////////////// + if ( 1 ) + { + // scale diffusion by jump in solution: + // const double jump = 2.0; + // diffusion *= jump; + + // to compute D \nabla c=Id_interface + MathVector Dgrad, grad; + + // compute gradient and shape at ip + VecSet(grad, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad, jump(_C_,sh), scvf.global_grad(sh)); + + // scale by diffusion tensor + MatVecMult(Dgrad, diffusion, grad); + + // Compute flux + const number diff_flux = VecDot(Dgrad, scvf.normal()); + + // Add to local defect + d(_C_, scvf.from()) -= diff_flux; + d(_C_, scvf.to() ) += diff_flux; + + } + } + + } + + ///////////////////////////////////////////////////// + // add rhs during same method! + // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! + ///////////////////////////////////////////////////// + + if ( 1 ) + { //m_imSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); + + // get associated node + int co = scv.node_id(); + d(_C_, co) -= source(_C_, co) * scv.volume(); + + // Add to local rhs + /* if ( co > 2 ) + { + d(_C_, co) -= m_imSource[2] * scv.volume(); + UG_LOG("m_imSource[2] * scv.volume(): " << m_imSource[2] << "\n"); + UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); + } + else + { + d(_C_, co) -= m_imSource[co] * scv.volume(); + UG_LOG("m_imSource[co] * scv.volume(): " << m_imSource[co] << "\n"); + UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); + } + + */ + } + } + + ///////////////////////////////////////////////////////////////////////////// + // Additional source Term due to jump in gradient at the interface + // (\nabla u^+ - \nabla u^-)\cdot n = h(x) * |n| + ///////////////////////////////////////////////////////////////////////////// + if ( 1 ) + { + std::vector& vBF = geo.get_boundary_faces(); + MathVector Dgrad; + VecSet(Dgrad, 0.0); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + // loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + // Add to local rhs + d(_C_, bf.node_id()) += jump_grad(_C_,bf.node_id()) * bf.Vol; + } + } + +//////////////////////////////// +// Singular sources and sinks +//////////////////////////////// + + if (m_sss.valid()) { + const typename TDomain::position_accessor_type& aaPos = this->domain()->position_accessor(); + const typename TDomain::grid_type& grid = *this->domain()->grid(); + const number time = this->time(); + MathVector<1> out; + for(size_t i = 0; i < geo.num_scv(); i++) { + const typename TFVGeom::SCV& scv = geo.scv(i); + const int co = scv.node_id(); + const number len = m_sss->get_contrib_of_scv((TElem*)elem, (Grid&)grid, aaPos, geo, co, time, out); + if (len == 0.0) continue; + out[0] *= len; + if (out[0] > 0.0) + // source + d(_C_, co) -= out[0]; + else + // sink + d(_C_, co) -= out[0] * locU(_C_, co); + } + } +} + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + double diffusion = 0.0; + + if ( !geo.get_element_modus() ) + diffusion = geo.get_diffusion(geo.get_boolian_for_diffusion()); + else + diffusion = geo.get_diffusion(); + + std::vector& vBF = geo.get_boundary_faces(); + MathVector Dgrad; + VecSet(Dgrad, 0.0); + + UG_LOG("---------- vBF.size(): " << vBF.size() << "\n"); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + + // set solution + /* for(size_t sh = 0; sh < geo.num_sh(); ++sh) + { + u(_C_, sh) = 1.0; + u(_C_, sh) -= corners[sh][0]*(2*corners[sh][0] - 1.0); + u(_C_, sh) -= corners[sh][1]*(2*corners[sh][1] - 1.0); + } + */ + // u(_C_, sh) = 1 - 2*(corners[sh][0]*corners[sh][0] + corners[sh][1]*corners[sh][1]) - (corners[sh][0]+corners[sh][1]); + // u(_C_, sh) = corners[sh][1]*(2*corners[sh][1] - 1.0); + // u(_C_, sh) = (1.0 - corners[sh][0] - corners[sh][1]) * (1.0 - 2*corners[sh][0] - 2*corners[sh][1]); + // u(_C_, sh) = corners[sh][1]; + // for(size_t sh = 0; sh < geo.num_sh(); ++sh) + // u(_C_, sh) = corners[sh][0]*(2*corners[sh][0] - 1.0); //corners[sh][0]; + // u(_C_, sh) = corners[sh][0]*(2* corners[sh][0]-1); + + //////////////////////////////////////////////////////////////////////////////// + // NO loop integration points! + // /* for(size_t ip = 0; ip < vBF.size(); ++ip) */ + // Reason: the length of the normal is already the length of the total face (NOT the scvf!) + //////////////////////////////////////////////////////////////////////////////// + + // loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + VecSet(Dgrad, 0.0); + + // loop trial space + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + { + // Diffusion + UG_LOG("bf.num_sh(): " << bf.num_sh() << "\n"); + UG_LOG("Dgrad: " << Dgrad << "\n"); + UG_LOG("bf.normal(): " << bf.normal() << "\n"); + UG_LOG("bf.global_grad(ip, sh): " << bf.global_grad(sh) << "\n"); + + UG_LOG("u(_C_, sh): " << u(_C_, sh) << "\n"); + + VecScaleAppend(Dgrad, diffusion * u(_C_, sh), bf.global_grad(sh)); + } + + // add to local vector + d(_C_, bf.node_id()) += VecDot(Dgrad, bf.normal()); + + } + + UG_LOG("---------- end ----------- \n\n"); + +} + + +//////////////////////////////////////////////////////////////////////////////// +/// +/// methods for cut element error computation via 'add_l2error_A_elem()' +/// +//////////////////////////////////////////////////////////////////////////////// + +template +number get_exact_sol_test(MathVector position) +{ + return sin(2*M_PI*position[0]) + sin(2*M_PI*position[1]); +} + +template +number get_exact_sol_Gangl(MathVector position) +{ + double kappa_2 = 10.0; + double dist_x = position[0] - 0.0; + double dist_y = position[1] - 0.0; + double sqR = 0.4*0.4; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = -4*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_2 - 1); + + if ( dist >= 0.4 ) + returnValue = -2*kappa_2*sqDist*sqDist; + + return returnValue; +} + +template +MathVector get_exact_grad_Gangl(MathVector position) +{ + double kappa_2 = 10.0; + double dist_x = position[0] - 0.0; + double dist_y = position[1] - 0.0; + double sqR = 0.4*0.4; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double factor = -8*kappa_2*kappa_2*sqR; + + if ( dist >= 0.4 ) + factor = -8*kappa_2*sqDist; + + MathVector returnVector; + returnVector[0] = factor*dist_x; + returnVector[1] = factor*dist_y; + + return returnVector; +} + +template +MathVector get_exact_grad_FedkiwEx5(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + double radius = 0.5; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double absValue = position[0]*position[0] + position[1]* position[1]; + + MathVector returnVector; + returnVector[0] = 0.0; + returnVector[1] = 0.0; + + double factor = 1.0/absValue; + if ( dist >= radius ) + { + returnVector[0] = factor*position[0]; + returnVector[1] = factor*position[1]; + } + + return returnVector; + +} + +template +number get_exact_sol_FedkiwEx6(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + double radius = 0.5; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = 0.0; + + if ( dist <= radius ) + returnValue = exp(position[0])*cos(position[1]); + + return returnValue; +} + +template +number get_exact_sol_FedkiwEx5(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + + double dist_x = position[0]-center_x; + double dist_y = position[1]-center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = 1.0; + + if ( dist > 0.5 ) + returnValue = 1.0 + log(2*dist); + + return returnValue; +} + +template +number get_exact_sol_FedkiwEx3(MathVector position) +{ + double center_x = 0.5; + double center_y = 0.5; + double radius = 0.25; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double absValue = position[0]*position[0] + position[1]* position[1]; + + double returnValue = 0.0; + + if ( dist <= radius ) + returnValue = exp(-absValue); + + return returnValue; +} + +template +MathVector get_exact_grad(MathVector position) +{ + +} + +////////////////////////////////////////////////////////////////////// +// code see ugbase/lib_disc/function_spaces/integrate.h: evaluate() for +// --> L2ErrorIntegrand (for value) +// --> H1ErrorIntegrand (for gradient): lines 1873-1910 +// +// called bei Integrate() via method 'integrand.values': +// integrand.values(&(vValue[0]), &(vGlobIP[0]), +// pElem, &vCorner[0], rQuadRule.points(), +// &(vJT[0]), +// numIP); +// +////////////////////////////////////////////////////////////////////// +template +template +number ConvectionDiffusionFV1_cutElem:: +add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem) +{ + bool output = false; + + // number integral = 0; + + std::vector > vCorner; + std::vector > vGlobIP; + std::vector > vLocIP; + std::vector > vJT; + std::vector vValue; + std::vector vValueGrad; + + QuadType type = GetQuadratureType("best"); + + const QuadratureRule& rQuadRule + = QuadratureRuleProvider::get(roid, 1, type); + + // get reference element mapping by reference object id + DimReferenceMapping& mapping + = ReferenceMappingProvider::get(roid); + + // number of integration points + const size_t numIP = rQuadRule.size(); + + // get all corner coordinates + // CollectCornerCoordinates(vCorner, *pElem, aaPos, true); + + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(roid); + + vCorner.clear(); + // remember global position of nodes + for(size_t i = 0; i < rRefElem.num(0); ++i) + vCorner.push_back(geo.get_corner(i)); + + if ( output ) + { + for ( size_t i = 0; i < rRefElem.num(0); ++i) + UG_LOG("vCorner" << vCorner[i][0] << " and " << vCorner[i][1] << "\n" ); + UG_LOG("\n" ); + } + + // update the reference mapping for the corners + mapping.update(vCorner); + + // compute global integration points + vGlobIP.resize(numIP); + mapping.local_to_global(&(vGlobIP[0]), rQuadRule.points(), numIP); + + if ( output ) UG_LOG("vGlobIP" << vGlobIP[0][0] << " and " << vGlobIP[0][1] << "\n" ); + if ( output ) UG_LOG("\n" ); + + // compute local integration points + vLocIP.resize(numIP); + for(size_t ip = 0; ip < numIP; ++ip) + vLocIP[ip] = rQuadRule.points()[ip]; + + if ( output ) UG_LOG("vLocIP" << vLocIP[0][0] << " and " << vLocIP[0][1] << "\n" ); + if ( output ) UG_LOG("\n" ); + + + // compute transformation matrices + vJT.resize(numIP); + mapping.jacobian_transposed(&(vJT[0]), rQuadRule.points(), numIP); + + const size_t num_sh = geo.num_scvf(); + + if ( num_sh != rRefElem.num(0) ) + UG_THROW("wrong number of corners: sh = " << num_sh << ", but rRefElem.num(0) = " << rRefElem.num(0) << "\n"); + + // compute integrand values at integration points + vValue.resize(numIP); + vValueGrad.resize(numIP); + + try + { + // loop all integration points + for(size_t ip = 0; ip < numIP; ++ip) + { + // compute exact solution at integration point +// number exactSolIP = get_exact_sol_FedkiwEx5(vGlobIP[ip]); + number exactSolIP = get_exact_sol_Gangl(vGlobIP[ip]); + + // compute exact gradient at integration point + MathVector exactGradIP = get_exact_grad_FedkiwEx5(vGlobIP[ip]); + + // compute approximated solution at integration point + number approxSolIP = 0.0; + MathVector locTmp; VecSet(locTmp, 0.0); + + const typename TFVGeom::SCV& scv = geo.scv(ip); + + for(size_t sh = 0; sh < num_sh; ++sh) + { + // add shape fct at ip * value at shape + approxSolIP += u(_C_,sh) * geo.get_shape(sh, vLocIP[ip], roid); + + // add gradient at ip + VecScaleAppend(locTmp, u(_C_,sh), scv.local_grad(sh)); + } + + // get squared of difference + vValue[ip] = (exactSolIP - approxSolIP); + vValue[ip] *= vValue[ip]; + + // compute global gradient + MathVector approxGradIP; + MathMatrix JTInv; + Inverse(JTInv, vJT[ip]); + MatVecMult(approxGradIP, JTInv, locTmp); + + // get error of gradient + vValueGrad[ip] = VecDistanceSq(approxGradIP, exactGradIP); + + + } + /* integrand.values(&(vValue[0]), &(vGlobIP[0]), + pElem, &vCorner[0], rQuadRule.points(), + &(vJT[0]), + numIP); + */ + } + UG_CATCH_THROW("Unable to compute values of integrand at integration point."); + + // reset contribution of this element + number intValElem = 0; + + // loop integration points + for(size_t ip = 0; ip < numIP; ++ip) + { + // get quadrature weight + const number weightIP = rQuadRule.weight(ip); + + // get determinate of mapping + const number det = SqrtGramDeterminant(vJT[ip]); + + // add contribution of integration point + intValElem += vValue[ip] * weightIP * det; + // intValElem += vValueGrad[ip] * weightIP * det; + + } + + // add to global sum + + if ( output ) UG_LOG("added: " << intValElem << "\n\n"); + + return intValElem; +} + + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + +// reaction rate + if(m_imReactionRateExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local defect + d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume(); + } + } + +// reaction + if(m_imReactionExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local defect + d(_C_, co) += m_imReactionExpl[ip] * scv.volume(); + } + } + + if(m_imSourceExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) -= m_imSourceExpl[ip] * scv.volume(); + } + } +} + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + if(!m_imMassScale.data_given() && !m_imMass.data_given()) return; + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // mass value + number val = 0.0; + + // multiply by scaling + if(m_imMassScale.data_given()) + val += m_imMassScale[ip] * u(_C_, co); + + // add mass + if(m_imMass.data_given()) + val += m_imMass[ip]; + + // Add to local defect + d(_C_, co) += val * scv.volume(); + } +} + + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) +{ + ///////////////////////////////////////////////////// + // add rhs ALLREADY(!) during 'add_def_A_elem_local()' method! + // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! + ///////////////////////////////////////////////////// + + return; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + // loop Sub Control Volumes (SCV) + if ( m_imSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) += m_imSource[ip] * scv.volume(); + //UG_LOG("d(_C_, co) = " << d(_C_, co) << "; \t ip " << ip << "; \t co " << co << "; \t scv_vol " << scv.volume() << "; \t m_imSource[ip] " << m_imSource[ip] << std::endl); + } + } + + // loop Sub Control Volumes (SCVF) + if ( m_imVectorSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); + + // Add to local rhs + d(_C_, scvf.from()) -= VecDot(m_imVectorSource[ip], scvf.normal() ); + d(_C_, scvf.to() ) += VecDot(m_imVectorSource[ip], scvf.normal() ); + } + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +// upwind +//////////////////////////////////////////////////////////////////////////////// + +template +void ConvectionDiffusionFV1_cutElem:: +set_upwind(SmartPtr > shapes) {m_spConvShape = shapes;} + +// computes the linearized defect w.r.t to the velocity +template +const typename ConvectionDiffusionFV1_cutElem::conv_shape_type& +ConvectionDiffusionFV1_cutElem:: +get_updated_conv_shapes(const FVGeometryBase& geo) +{ +// compute upwind shapes for transport equation +// \todo: we should move this computation into the preparation part of the +// disc, to only compute the shapes once, reusing them several times. + if(m_imVelocity.data_given()) + { + // get diffusion at ips + const MathMatrix* vDiffusion = NULL; + if(m_imDiffusion.data_given()) vDiffusion = m_imDiffusion.values(); + + // update convection shapes + if(!m_spConvShape->update(&geo, m_imVelocity.values(), vDiffusion, true)) + { + UG_LOG("ERROR in 'ConvectionDiffusionFV1_cutElem::get_updated_conv_shapes': " + "Cannot compute convection shapes.\n"); + } + } + +// return a const (!!) reference to the upwind + return *const_cast*>(m_spConvShape.get()); +} + +//////////////////////////////////////////////////////////////////////////////// +// register assemble functions +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template<> +void ConvectionDiffusionFV1_cutElem:: +register_all_funcs(bool bHang) +{ + register_func > >(); + +/* +// switch assemble functions + if(!bHang) + { + register_func >(); + } + else + { + register_func >(); + } + */ +} +#endif + +#ifdef UG_DIM_2 +template<> +void ConvectionDiffusionFV1_cutElem:: +register_all_funcs(bool bHang) +{ + register_func > >(); + +/* +// switch assemble functions + if(!bHang) + { + register_func >(); + register_func >(); + register_func >(); + } + else + { + register_func >(); + register_func >(); + register_func >(); + } + */ +} +#endif + +#ifdef UG_DIM_3 +template<> +void ConvectionDiffusionFV1_cutElem:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + /* + +// switch assemble functions + if(!bHang) + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + } + else + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + } +*/ +} +#endif + +template +template +void ConvectionDiffusionFV1_cutElem:: +register_func() +{ + ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; + typedef this_type T; + static const int refDim = reference_element_traits::dim; + + this->clear_add_fct(id); + this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); + this->set_prep_elem_fct( id, &T::template prep_elem); + this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); + this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem); + this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem); + this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem); + this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem); + this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem); + this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); + +} + +//////////////////////////////////////////////////////////////////////////////// +// explicit template instantiations +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template class ConvectionDiffusionFV1_cutElem; +#endif +#ifdef UG_DIM_2 +template class ConvectionDiffusionFV1_cutElem; +#endif +#ifdef UG_DIM_3 +template class ConvectionDiffusionFV1_cutElem; +#endif + +} // end namespace ConvectionDiffusionPlugin +} // namespace ug + diff --git a/fv1_cutElem/convection_diffusion_fv1_cutElem.h b/fv1_cutElem/convection_diffusion_fv1_cutElem.h new file mode 100644 index 0000000..3715e46 --- /dev/null +++ b/fv1_cutElem/convection_diffusion_fv1_cutElem.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2013-2015: G-CSC, Goethe University Frankfurt + * Author: Andreas Vogel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1_CUTELEM_ +#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1_CUTELEM_ + + +// ug4 headers +#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" +#include "lib_disc/spatial_disc/elem_disc/sss.h" + +// plugin's internal headers +#include "../convection_diffusion_base.h" + +#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" +#include "lib_disc/spatial_disc/disc_util/geom_provider.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +// \ingroup lib_disc_elem_disc +/// \addtogroup convection_diffusion +/// \{ + +/// Discretization for the Convection-Diffusion Equation +/** + * This class implements the IElemDisc interface to provide element local + * assemblings for the convection diffusion equation. + * The Equation has the form + * \f[ + * \partial_t (m1*c + m2) - \nabla \left( D \nabla c - \vec{v} c - \vec{F} \right ) + * + r1 \cdot c + r2 = f + f2 + * \f] + * with + *
    + *
  • \f$ c \f$ is the unknown solution + *
  • \f$ m1 \equiv m(\vec{x},t) \f$ is the Mass Scaling Term + *
  • \f$ m2 \equiv m(\vec{x},t) \f$ is the Mass Term + *
  • \f$ D \equiv D(\vec{x},t) \f$ is the Diffusion Tensor + *
  • \f$ v \equiv \vec{v}(\vec{x},t) \f$ is the Velocity Field + *
  • \f$ F \equiv \vec{F}(\vec{x},t) \f$ is the Flux + *
  • \f$ r1 \equiv r(\vec{x},t) \f$ is the Reaction Rate + *
  • \f$ r2 \equiv r(\vec{x},t) \f$ is a Reaction Term + *
  • \f$ f \equiv f(\vec{x},t) \f$ is a Source Term + *
  • \f$ f2 \equiv f_2(\vec{x},t) \f$ is a Vector Source Term + *
+ * + * \tparam TDomain Domain + */ +template< typename TDomain> +class ConvectionDiffusionFV1_cutElem : public ConvectionDiffusionBase +{ + private: + /// Base class type + typedef ConvectionDiffusionBase base_type; + + /// Own type + typedef ConvectionDiffusionFV1_cutElem this_type; + + /// error estimator type + typedef SideAndElemErrEstData err_est_type; + + public: + /// World dimension + static const int dim = base_type::dim; + + public: + /// Constructor + ConvectionDiffusionFV1_cutElem(const char* functions, const char* subsets); + + /// set the upwind method + /** + * This method sets the upwind method used to upwind the convection. + * + * \param shapes upwind method + */ + void set_upwind(SmartPtr > shapes); + + /// set singular sources and sinks + void set_sss(SmartPtr > sss) { m_sss = sss; } + + private: + /// prepares assembling + virtual void prep_assemble_loop(); + + /// prepares the loop over all elements + /** + * This method prepares the loop over all elements. It resizes the Position + * array for the corner coordinates and schedules the local ip positions + * at the data imports. + */ + template + void prep_elem_loop(const ReferenceObjectID roid, const int si); + + /// prepares the element for assembling + /** + * This methods prepares an element for the assembling. The Positions of + * the Element Corners are read and the Finite Volume Geometry is updated. + * The global ip positions are scheduled at the data imports. + */ + template + void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]); + + /// finishes the loop over all elements + template + void fsh_elem_loop(); + + /// assembles the local stiffness matrix using a finite volume scheme + template + void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_jac_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalMatrix& J, LocalVector& locU, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + + /// assembles the local mass matrix using a finite volume scheme + template + void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + + /// assembles the stiffness part of the local defect + template + void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + /// assembles the stiffness part of the local defect + template + void add_def_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalVector& d, LocalVector& locU, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + template + number add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem); + + + /// assembles the stiffness part of the local defect explicit reaction, reaction_rate and source + template + void add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the mass part of the local defect + template + void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the local right hand side + template + void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_rhs_elem_local(TFVGeom& geo, LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); + + /// helper function to prepare data for 'add_def_A_elem_local()' and 'add_jac_A_elem_local()' + template + void get_local_data(TFVGeom& geo, const LocalVector& u, LocalVector& locUOut, MathMatrix diffusionOut, LocalVector& jumpOut, LocalVector& jump_gradOut, LocalVector& sourceOut); + + private: + /// abbreviation for the local solution + static const size_t _C_ = 0; + + /// singular sources and sinks + SmartPtr > m_sss; + + using base_type::m_imDiffusion; + using base_type::m_imVelocity; + using base_type::m_imFlux; + using base_type::m_imSource; + using base_type::m_imSourceExpl; + using base_type::m_imVectorSource; + using base_type::m_imReactionRate; + using base_type::m_imReactionRateExpl; + using base_type::m_imReaction; + using base_type::m_imReactionExpl; + using base_type::m_imMassScale; + using base_type::m_imMass; + + using base_type::m_exGrad; + using base_type::m_exValue; + + protected: + /// method to compute the upwind shapes + SmartPtr > m_spConvShape; + + /// returns the updated convection shapes + typedef IConvectionShapes conv_shape_type; + const IConvectionShapes& get_updated_conv_shapes(const FVGeometryBase& geo); + + public: + /// type of trial space for each function used + virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid); + + /// returns if hanging nodes are needed + virtual bool use_hanging() const; + + protected: + /// current regular grid flag + bool m_bNonRegularGrid; + + /// current shape function set (needed for GeomProvider::get()) + LFEID m_LFEID; + + /// register utils + /// \{ + void register_all_funcs(bool bHang); + template void register_func(); + /// \} + + private: + /// struct holding values of shape functions in IPs + struct ShapeValues + { + public: + void resize(std::size_t nEip, std::size_t nSip, std::size_t _nSh) + { + nSh = _nSh; + elemVals.resize(nEip); + sideVals.resize(nSip); + for (std::size_t i = 0; i < nEip; i++) elemVals[i].resize(nSh); + for (std::size_t i = 0; i < nSip; i++) sideVals[i].resize(nSh); + } + number& shapeAtElemIP(std::size_t sh, std::size_t ip) {return elemVals[ip][sh];} + number& shapeAtSideIP(std::size_t sh, std::size_t ip) {return sideVals[ip][sh];} + number* shapesAtElemIP(std::size_t ip) {return &elemVals[ip][0];} + number* shapesAtSideIP(std::size_t ip) {return &sideVals[ip][0];} + std::size_t num_sh() {return nSh;} + private: + std::size_t nSh; + std::vector > elemVals; + std::vector > sideVals; + } m_shapeValues; +}; + +// end group convection_diffusion +/// \} + +} // end ConvectionDiffusionPlugin +} // end namespace ug + + +#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1_CUTELEM_*/ diff --git a/fv1_cutElem/diffusion_interface/___immersed_bnd_cond_diffusion_impl.h b/fv1_cutElem/diffusion_interface/___immersed_bnd_cond_diffusion_impl.h new file mode 100644 index 0000000..75b1a15 --- /dev/null +++ b/fv1_cutElem/diffusion_interface/___immersed_bnd_cond_diffusion_impl.h @@ -0,0 +1,952 @@ +/* + * particle_bnd_cond_impl.h + * + * Created on: 30.01.2015 + * Author: suze + */ + +#ifndef DIFFUSION_BND_COND_IMPL_H_ +#define DIFFUSION_BND_COND_IMPL_H_ + + + +namespace ug{ +namespace MovingInterfaceDiffusion{ + +//////////////////////////////////////////////////////////////////////////////// +// Constructor - set default values +//////////////////////////////////////////////////////////////////////////////// +// see 'no_normal_stress_outflow.cpp': +template +ParticleBndCondDiffusion:: +ParticleBndCondDiffusion(SmartPtr > spMaster, + SmartPtr > localHandler) + : MovingInterface::IInterfaceBndCond(spMaster->symb_fcts(), spMaster->symb_subsets(), localHandler), + m_spMaster(spMaster), + m_spInterfaceHandlerLocal(localHandler) +{ +// update assemble functions + register_all(false); +} + +template +void ParticleBndCondDiffusion:: +prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid) +{ +// write delta t to data + number dt = 0.13; + if(this->is_time_dependent()) + { + UG_LOG("ParticleBndCondDiffusion::prepare_setting(): vorher: m_dt = " << get_time_step() << "\n"); + + set_time_dependent(true); + + // get and check current and old solution + const LocalVectorTimeSeries* vLocSol = this->local_time_solutions(); + dt = vLocSol->time(0) - vLocSol->time(1); + + set_time_step(dt); + } + +} + +// see 'NavierStokesNoNormalStressOutflowFV1::prep_elem()' +template +template +void ParticleBndCondDiffusion:: +prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) +{ + +// Update Geometry for this element + static TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + + geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); + +} + + +//////////////////////////////////////////////////////////////////////////////// +// jacobian methods +//////////////////////////////////////////////////////////////////////////////// +// removes the equations with IDs in 'vFctID' locally assembled in the corners of 'vDofID' +template +void ParticleBndCondDiffusion:: +remove_equations(LocalMatrix& J, std::vector vFctID, std::vector vDofID) +{ + + UG_THROW("in ParticleBndCondDiffusion::remove_equations(): vFctID.size() = " << vFctID.size() << "\n"); + + for(size_t i = 0; i < vDofID.size(); ++i) + for(size_t j = 0; j < vFctID.size(); ++j) + for(size_t fct = 0; fct < J.num_all_row_fct(); ++fct) + for(size_t dof = 0; dof < J.num_all_row_dof(fct); ++dof) + J(vFctID[j], vDofID[i], fct, dof) = 0.0; + +} + + + + +// see 'NavierStokesNoNormalStressOutflowFV1::diffusive_flux_Jac()' +template +void ParticleBndCondDiffusion:: +diffusive_flux_Jac(const size_t ip, const interfaceBF& bf, LocalMatrix& J, const LocalVector& u) +{ + + MathMatrix diffFlux, tang_diffFlux; + MathVector normalStress; + + for(size_t sh = 0; sh < bf.num_sh(); ++sh) // loop shape functions + { + // 1. Compute the total flux + // - add \nabla u + MatSet (diffFlux, 0); + MatDiagSet (diffFlux, VecDot (bf.global_grad(sh), bf.normal())); + + + // - add (\nabla u)^T + if( !m_spMaster->laplace()) + for (size_t d1 = 0; d1 < (size_t)dim; ++d1) + for (size_t d2 = 0; d2 < (size_t)dim; ++d2) + diffFlux(d1,d2) += bf.global_grad(sh)[d1] * bf.normal()[d2]; + + // 2. Scale by viscosity + diffFlux *= get_kinVisc_fluid(); + + // 3. Change sign, since force acts onto particle in inverse direction: + //diffFlux *= -1.0; + + // 4. Add flux to local Jacobian + for(size_t d1 = 0; d1 < (size_t)dim; ++d1) + for(size_t d2 = 0; d2 < (size_t)dim; ++d2){ + J(d1, bf.node_id(), d2, sh) += diffFlux (d1, d2); + // if ( sh < 2 ) UG_LOG("bf.node_id(): " << bf.node_id() << "sh: " << sh << ": diff_flux added: " << diffFlux (d1, d2) << "\n"); + } + + // 5. Add pressure term to local Jacobian + for(size_t d1 = 0; d1 < (size_t)dim; ++d1) + J(d1, bf.node_id(), _P_, sh) -= bf.shape(sh) * bf.normal()[d1]; + + } + +} + + + +void copy_and_reset(LocalMatrix& cpJ, LocalMatrix& J) +{ + + UG_THROW("oha!!...in ParticleBndCondDiffusion: copy_and_reset()\n"); + + for(size_t fct1 = 0; fct1 < J.num_all_row_fct(); ++fct1) + for(size_t dof1 = 0; dof1 < J.num_all_row_dof(fct1); ++dof1) + for(size_t fct2 = 0; fct2 < J.num_all_row_fct(); ++fct2) + for(size_t dof2 = 0; dof2 < J.num_all_row_dof(fct2); ++dof2) + { + cpJ(fct1, dof1, fct2, dof2) = J(fct1, dof1, fct2, dof2); + J(fct1, dof1, fct2, dof2) = 0.0; + } +} + + +template +template +void ParticleBndCondDiffusion:: +add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + ElementModus elemModus = m_spInterfaceHandlerLocal->get_element_modus(elem); // computed via 'compute_element_modus()' during 'update_marker()' + + const LocalIndices& rowInd = J.get_row_indices(); + + //////////////////////////////////////////////////////////////////////////////// + // Remove local impuls equations for interface-corners + if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling + { + + if ( elemModus != INSIDE_DOM ) + { + // all impulse equations will be removed + std::vector vFctID(dim); + for(size_t i = 0; i < dim; ++i) vFctID[i] = i; + + // equations for interface nodes will be removed + std::vector vDoFID; vDoFID.clear(); + for(size_t i = 0; i < m_spInterfaceHandlerLocal->m_vInterfaceID.size(); ++i) + { + size_t interfaceID = m_spInterfaceHandlerLocal->m_vInterfaceID[i]; + size_t indexToRemove = interfaceID; //m_spInterfaceHandlerLocal->m_vOriginalCornerID[interfaceID]; + vDoFID.push_back(indexToRemove); + } + + remove_equations(J, vFctID, vDoFID); + } + + } + + +//////////////////////////////////////////////////////////////////////////////// +// see 'ParticleFlatTop::add_jac_A_elem_interface()' +//////////////////////////////////////////////////////////////////////////////// + +// Loop the boundary faces for new impuls equations +// --> IFF INSIDE_DOM: vBF.size() = 0 ;-) + SmartPtr > fluidDensity = m_spMaster->density(); + std::vector& vBF = m_spInterfaceHandlerLocal->get_boundary_faces(); + +// initialize data (written during call of 'diffusive_flux_Jac()': + LocalIndices ind = u.get_indices(); + rotJ_ind.resize(ind); rotJ_ind = 0.0; + rotJ_rot.resize(ind); rotJ_rot = 0.0; + + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + + interfaceBF bf = vBF[ip]; + + if ( fluidDensity->value(0, ip) != fluidDensity->value(1, ip) ) + UG_THROW("ParticleBndCondDiffusion::add_jac_M_elem(): density different for series 0 and 1: " + << fluidDensity->value(0, ip) << " != " << fluidDensity->value(1, ip) << "\n"); + + number importDensity = fluidDensity->value(0, ip); + + // The momentum equation: + if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling + diffusive_flux_Jac(ip, bf, J, u); + + // scale with deltaT ( = 1.0 for non-time-dependent) + // buffJ *= deltaT; + // ToDo --> NOT necessary, since add_def_A_elem() will be multiplied by 'dt' + // during elem_dis_assemble_util.h ??? + + // The continuity equation + if ( 1 ) //! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling + { + for(size_t sh = 0; sh < bf.num_sh(); ++sh) // loop shape functions + for (size_t d2 = 0; d2 < (size_t)dim; ++d2) + J(_P_, bf.node_id(), d2, sh) += bf.shape(sh) * bf.normal()[d2] + * importDensity; + } + + } // end vBF + + // copy rotJ_ind/rotJ_rot to m_spInterfaceHandlerLocal data for access from mapper + if ( vBF.size() > 0 ) + copy_local_couplings_jac(); + + +} + + +//////////////////////////////////////////////////////////////////////////////// +// defect methods +//////////////////////////////////////////////////////////////////////////////// + +// removes the defects with IDs in 'vFctID' locally assembled in the corners of 'vDofID' +template +void ParticleBndCondDiffusion:: +remove_equations(LocalVector& d, std::vector vFctID, std::vector vDofID) +{ + for(size_t i = 0; i < vDofID.size(); ++i) + for(size_t j = 0; j < vFctID.size(); ++j) + d(vFctID[j], vDofID[i]) = 0.0; + +} + + + +// see 'NavierStokesNoNormalStressOutflowFV1::diffusive_flux_defect()' +template +void ParticleBndCondDiffusion:: +diffusive_flux_defect(const size_t ip, const interfaceBF& bf, LocalVector& d, const LocalVector& u) +{ + MathMatrix gradVel; + MathVector diffFlux; + +// 1. Get the gradient of the velocity at ip + for(size_t d1 = 0; d1 < (size_t)dim; ++d1) + for(size_t d2 = 0; d2 < (size_t)dim; ++d2) + { + // sum up contributions of each shape + gradVel(d1, d2) = 0.0; + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + gradVel(d1, d2) += bf.global_grad(sh)[d2] * u(d1, sh); + } + +// 2. Compute the total flux + +// - add (\nabla u) \cdot \vec{n} + MatVecMult(diffFlux, gradVel, bf.normal()); + +// - add (\nabla u)^T \cdot \vec{n} + if( !m_spMaster->laplace()) + TransposedMatVecMultAdd(diffFlux, gradVel, bf.normal()); + +// 3. Scale by viscosity + diffFlux *= get_kinVisc_fluid(); + +// 4. Change sign, since force acts onto particle in inverse direction: + //diffFlux *= -1.0; + +// 5. Add flux to local defect + for(size_t d1 = 0; d1 < (size_t)dim; ++d1) + d(d1, bf.node_id()) += diffFlux[d1]; + + +// 6. Add pressure term to local defect + number pressure = 0.0; + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + pressure += bf.shape(sh) * u(_P_, sh); + + for(size_t d1 = 0; d1 < (size_t)dim; ++d1) + d(d1, bf.node_id()) -= pressure * bf.normal()[d1]; + +} + +template +void ParticleBndCondDiffusion:: +add_def_A_elem_Quadri_for2(LocalVector& locD, const LocalVector locU) +{ +// Loop the boundary faces to assemble impulse equations + SmartPtr > fluidDensity = m_spMaster->density(); + std::vector& vBF = m_spInterfaceHandlerLocal->get_boundary_faces(); + + if ( vBF.size() != 4 ) + UG_THROW("in 'ParticleBndCondDiffusion::add_def_A_elem_Quadri_for2(): vBF.size() should be 4 but is " << vBF.size() << "\n"); + + UG_LOG("vBF.size(): " << vBF.size() << "\n"); + +// get density + number importDensity = fluidDensity->value(0, 0); + if ( fluidDensity->value(0, 0) != fluidDensity->value(1, 0) ) + UG_THROW("ParticleBndCondDiffusion::add_def_A_elem_Quadri_for2(): density different for series 0 and 1: " + << fluidDensity->value(0, 0) << " != " << fluidDensity->value(1, 0) << "\n"); + if ( importDensity != get_density_fluid() ) + UG_THROW("ParticleBndCondDiffusion::add_def_A_elem_Quadri_for2(): importDensity = " << importDensity << " = " + "fluidDensity = " << get_density_fluid() << "\n"); + +// loop all boundary faces + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + UG_LOG("---- ip = " << ip << "\n"); + + interfaceBF bf = vBF[ip]; + + // Compute Velocity at ip + MathVector stdVel(0.0); + for(size_t d1 = 0; d1 < (size_t)dim; ++d1) + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + stdVel[d1] += locU(d1, sh) * bf.shape(sh); + + // Momentum equation: + if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling + diffusive_flux_defect(ip, bf, locD, locU); + + // Continuity equation: + if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling + locD(_P_, bf.node_id()) += VecDot(stdVel, bf.normal()) * importDensity; + + } // end vBF-loop + +} + +template +void ParticleBndCondDiffusion:: +write_QuadriSol(const LocalVector origU) +{ + UG_LOG("start write_QuadriSol\n"); + +// initialize data + LocalIndices ind = origU.get_indices(); + LocalVector quadriU; + + UG_LOG("1 start write_QuadriSol\n"); + + if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 2 ) + { + for(size_t fct = 0; fct < ind.num_fct(); ++fct) + ind.resize_dof(fct, 5); + + if ( ind.num_dof(0) != 5 ) + UG_THROW("hmm: ind.num_dof(0) = " << ind.num_dof(0) << "\n"); + } + quadriU.resize(ind); + + UG_LOG("2 start write_QuadriSol\n"); + + // A. remap solution (velocity AND pressure!) of inside node + if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 2 ) + { + size_t copyID = m_spInterfaceHandlerLocal->m_vNOInterfaceID[0]; + for(size_t fct = 0; fct < dim+1; ++fct) + {quadriU(fct,4) = origU(fct,copyID); + UG_LOG("origU(fct,copyID) = " << origU(fct,copyID) << "\n");} + } + + UG_LOG("3 start write_QuadriSol: quadriU \n" << quadriU << "\n"); + + if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 2 ) + { + for ( size_t i = 0; i < m_spInterfaceHandlerLocal->m_vNOInterfaceID.size(); ++i ) + UG_THROW("m_vNOInterfaceID[" << i << "]: " << m_spInterfaceHandlerLocal->m_vNOInterfaceID[i] << "\n"); + + } + for ( size_t i = 0; i < m_spInterfaceHandlerLocal->m_vInterfaceID.size(); ++i ) + UG_LOG("m_vInterfaceID[" << i << "]: " << m_spInterfaceHandlerLocal->m_vInterfaceID[i] << "\n"); + for ( size_t i = 0; i < m_spInterfaceHandlerLocal->m_vQuadriOrigID.size(); ++i ) + UG_LOG("m_vQuadriOrigID[" << i << "]: " << m_spInterfaceHandlerLocal->m_vQuadriOrigID[i] << "\n"); + + std::vector testV; + for(size_t dof = 0; dof < 4; ++dof) + testV.push_back(1.0+0.1*dof); + + // B. remap pressure solution in all interface nodes + for(size_t fct = 0; fct < dim+1; ++fct) + for(size_t dof = 0; dof < 4; ++dof) + { + quadriU(fct,dof) = testV[m_spInterfaceHandlerLocal->m_vQuadriOrigID[dof]]; //origU(fct,m_spInterfaceHandlerLocal->m_vQuadriOrigID[dof]); + UG_LOG("quadriU(fct,dof): " << quadriU(fct,dof) << "\n"); + UG_LOG("testV[" << m_spInterfaceHandlerLocal->m_vQuadriOrigID[dof] << "]: " << testV[m_spInterfaceHandlerLocal->m_vQuadriOrigID[dof]] << "\n"); + } + + UG_LOG("start write_QuadriSol: quadriU = \n" << quadriU << "\n"); + UG_THROW("4 start write_QuadriSol\n"); + +// C. write velocities of the 2 particles: + MathVector transSol1 = m_spInterfaceHandlerLocal->get_transSol(0, 0); + MathVector rotSol1 = m_spInterfaceHandlerLocal->get_rotSol(0, 0); + MathVector transSol2 = m_spInterfaceHandlerLocal->get_transSol(1, 0); + MathVector rotSol2 = m_spInterfaceHandlerLocal->get_rotSol(1, 0); + + UG_LOG("transSol1 = " << transSol1 << "\n"); + UG_LOG("transSol2 = " << transSol2 << "\n"); + UG_LOG("rotSol1 = " << rotSol1 << "\n"); + UG_LOG("rotSol2 = " << rotSol2 << "\n"); + +// resize local data as done during 'modify_LocalSol' +// --> but there with num_co = 3 for the Triangle with inside node! + for(size_t fct = 0; fct < ind.num_fct(); ++fct) + for(size_t dof = 0; dof < 4; ++dof) + { + MathMatrix rotationMatCo = m_spInterfaceHandlerLocal->get_rotationMat(m_spInterfaceHandlerLocal->radial_at_co(dof)); + UG_LOG("write_QuadriSol: radial(" << dof << ": " << m_spInterfaceHandlerLocal->radial_at_co(dof) << "\n"); + + // write solution of particle with prtIndex = 0: + if ( dof < 2 ) + { + quadriU(fct,dof) = transSol1[fct]; + for ( int d = 0; d < dim; ++d ) + quadriU(fct,dof) += rotationMatCo[fct][d]*rotSol1[d]; + } + // write solution of particle with prtIndex = 1: + else + { + quadriU(fct,dof) = transSol2[fct]; + for ( int d = 0; d < dim; ++d ) + quadriU(fct,dof) += rotationMatCo[fct][d]*rotSol2[d]; + } + } + + + UG_LOG("after write_QuadriSol: quadriU = \n" << quadriU << "\n"); + +} + +template +void ParticleBndCondDiffusion:: +add_quadri_to_defect(LocalVector& d, const LocalVector& quadriD) +{ + const LocalIndices& ind = quadriD.get_indices(); + UG_LOG("START add_quadri_to_defect \n"); + + for ( size_t i = 0; i < m_spInterfaceHandlerLocal->m_vQuadriOrigID.size(); ++i ) + UG_LOG("m_vOrig[" << i << "] = " << m_spInterfaceHandlerLocal->m_vQuadriOrigID[i] << "\n"); + + UG_LOG("d: \n" << d << "\n"); + UG_LOG("quadriD: \n" << quadriD << "\n"); + for(size_t fct=0; fct < quadriD.num_all_fct(); ++fct) + { + UG_LOG("fct = " << fct << "quadriD.num_all_dof(fct) = " << quadriD.num_all_dof(fct) << "\n"); + + for(size_t dof=0; dof < quadriD.num_all_dof(fct); ++dof) + { + UG_LOG("0 -> dof = " << dof << "\n"); + + if ( quadriD.value(fct,dof) != quadriD.value(fct,dof)) + UG_THROW("NAN in 'add_quadri_to_defect()'!...\n"); + + bool isPrtNode = m_spInterfaceHandlerLocal->lies_onInterface(dof); + // usual assembling for fluid-dof and pressure-fct + if ( isPrtNode ) + { + size_t _dof = m_spInterfaceHandlerLocal->m_vQuadriOrigID[dof]; + UG_LOG("dof = " << dof << ", _dof = " << _dof << "\n"); + + d.value(fct,_dof) += quadriD.value(fct,dof); + UG_LOG("d = \n" << d << "\n"); + + } + + } + } + +} + + + +template +template +void ParticleBndCondDiffusion:: +add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +//////////////////////////////////////////////////////////////////////////////// +// Remove local impulse equations for interface-corners + + ElementModus elemModus = m_spInterfaceHandlerLocal->get_element_modus(elem); // computed via 'compute_element_modus()' during 'update_marker()' + if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling + { + if ( elemModus != INSIDE_DOM ) + { + // all impulse equations will be removed + std::vector vFctID(dim); + for(size_t i = 0; i < dim; ++i) vFctID[i] = i; + + // equations for interface nodes will be removed + std::vector vDoFID; vDoFID.clear(); + for(size_t i = 0; i < m_spInterfaceHandlerLocal->m_vInterfaceID.size(); ++i) + { + size_t interfaceID = m_spInterfaceHandlerLocal->m_vInterfaceID[i]; + size_t indexToRemove = interfaceID; //m_spInterfaceHandlerLocal->m_vOriginalCornerID[interfaceID]; + vDoFID.push_back(indexToRemove); + } + + remove_equations(d, vFctID, vDoFID); + + } + } + + + if ( elemModus == CUT_BY_2_INTERFACE && !m_spInterfaceHandlerLocal->StdFV_assembling()) + { + write_QuadriSol(u); + + if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 2 ) + + // case == 4: all entries (also for pressure eq) will be written newly, since only boundary faces are relevant + // => during remove_equations() only velocity equations were removed! + if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 4 ) + d = 0.0; + + // locU was written during 'ParticleMapper::modify_LocalData()': + if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 4 || m_spInterfaceHandlerLocal->interface_id_all().size() == 2 ) + add_def_A_elem_Quadri_for2(d, u); + else + UG_THROW("in ParticleBndCondDiffusion::add_def_A_elem(): wrong amount of interface.size() for CUT_BY_2_INTERFACE: " << m_spInterfaceHandlerLocal->interface_id_all().size() << " ( should be 2!)\n"); + + return; + } + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// initialize data (written during call of 'diffusive_flux_Jac()': + LocalIndices ind = u.get_indices(); + rotD.resize(ind); rotD = 0.0; + + + // ToDo: if ( CUT_BY_2 && m_spInterfaceHandlerLocal->m_vInterfaceID.size() == 2 ) + // => TRIANGLE/5-Eck! => write u( , ) neu!! + +// Loop the boundary faces to assemble impulse equations + SmartPtr > fluidDensity = m_spMaster->density(); + std::vector& vBF = m_spInterfaceHandlerLocal->get_boundary_faces(); + + + if ( dim == 2 && vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + interfaceBF bf = vBF[ip]; + + // Compute Velocity at ip + MathVector stdVel(0.0); + for(size_t d1 = 0; d1 < (size_t)dim; ++d1) + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + stdVel[d1] += u(d1, sh) * bf.shape(sh); + + // Momentum equation: + if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling + diffusive_flux_defect(ip, bf, d, u); + + // scale with deltaT ( = 1.0 for non-time-dependent) + // d *= deltaT; + // ToDo --> NOT necessary, since add_def_A_elem() will be multiplied by 'dt' + // during elem_dis_assemble_util.h ??? + + if ( fluidDensity->value(0, ip) != fluidDensity->value(1, ip) ) + UG_THROW("ParticleBndCondDiffusion::add_jac_M_elem(): density different for series 0 and 1: " + << fluidDensity->value(0, ip) << " != " << fluidDensity->value(1, ip) << "\n"); + number importDensity = fluidDensity->value(0, ip); + if ( importDensity != get_density_fluid() ) + UG_THROW("ParticleBndCondDiffusion::add_def_A_elem(): importDensity = " << importDensity << " != " + "fluidDensity = " << get_density_fluid() << "\n"); + + + // Continuity equation: + if ( 1 ) //! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling + d(_P_, bf.node_id()) += VecDot(stdVel, bf.normal()) * importDensity; + // ToDo m_massDefect += VecDot(stdVel, bf.normal()); + } + +/* if ( elemModus == CUT_BY_INTERFACE ) + if ( m_spInterfaceHandlerLocal->m_vInterfaceID.size() == 2 ) + UG_THROW("vBF.size() = " << vBF.size() << "\n"); +*/ + // copy rotJ_ind/rotJ_rot to m_spInterfaceHandlerLocal data for access from mapper + + copy_local_couplings_def(); + + +//////////////////////////////////////////////////////////////////////////////// +// instead of 'set_gravity()' during 'add_local_vec_to_global()' +//////////////////////////////////////////////////////////////////////////////// + + + //ToDo... + + +} + + +// instead of calling 'set_mass_and_inertia()' during 'add_local_mat_to_global_interface()' +template +template +void ParticleBndCondDiffusion:: +add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); + +// A. do nothing for inside elements + if ( modus == INSIDE_DOM ) + return; + +// B. for outside elements: geo.num_scv() = 0 +// => nothing added during NavierStokesFV1::add_jac_M_elem +// => nothing will be subtracted here :) + + +/////////////////////////////////////////////////////////////////////////////// +// substract part added by NavierStokesFV1::add_jac_M_elem(): +// (instead of setting scv.volume() to zero) +//////////////////////////////////////////////////////////////////////////////// + +// Only first order implementation + UG_ASSERT((TFVGeom::order == 1), "Only first order implemented."); + +// get finite volume geometry + static TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + + SmartPtr > fluidDensity = m_spMaster->density(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int sh = scv.node_id(); + + if ( !m_spInterfaceHandlerLocal->lies_onInterface(sh) ) + continue; + + if ( fluidDensity->value(0, ip) != fluidDensity->value(1, ip) ) + UG_THROW("ParticleBndCondDiffusion::add_jac_M_elem(): density different for series 0 and 1: " + << fluidDensity->value(0, ip) << " != " << fluidDensity->value(1, ip) << "\n"); + + number importDensity = fluidDensity->value(0, ip); + + // loop velocity components + for(int d1 = 0; d1 < dim; ++d1) + { + // Add to local matrix + J(d1, sh, d1, sh) -= scv.volume() * importDensity; + } + } + + return; + + + const int prtIndex = get_prtIndex(); + const number prtDensity = get_density(prtIndex); + +// if INSIDE_DOM: do nothing! + if ( modus != INSIDE_DOM ) + { + // get data + const ReferenceObjectID roid = elem->reference_object_id(); + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(roid); + + // OUTSIDE_DOM + if ( modus == OUTSIDE_DOM ) + { + // loop corners of reference element + for(size_t sh = 0; sh < rRefElem.num(0); ++sh) + { + // loop velocity components + for(int d1 = 0; d1 < dim; ++d1) + { + // Add to local matrix + J(d1, sh, d1, sh) += geo.volume_fem_elem() * prtDensity; + // rescale volume fraction + J(d1, sh, d1, sh) *= 1.0/rRefElem.num(0); + } + } + } + // CUT_BY_INTERFACE + else if ( modus == CUT_BY_INTERFACE ) + { + // loop corners of reference element + for(size_t sh = 0; sh < rRefElem.num(0); ++sh) + { + // loop velocity components + for(int d1 = 0; d1 < dim; ++d1) + { + // Add to local matrix + J(d1, sh, d1, sh) += geo.volume_fem_elem() * prtDensity; + UG_THROW("geo.volume_fem_elem() = " << geo.volume_fem_elem() << "\n"); + // rescale volume fraction + J(d1, sh, d1, sh) *= 1.0/rRefElem.num(0); + } + } + } + else + UG_THROW("ParticleBndCondDiffusion::add_jac_M_elem()..."); + + } // end 'if ( !is_inside_elem() )' + + +} + + +template +template +void ParticleBndCondDiffusion:: +add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); + +// A. do nothing for inside elements + if ( modus == INSIDE_DOM ) + return; + +// B. for outside elements: geo.num_scv() = 0 +// => nothing added during NavierStokesFV1::add_jac_M_elem +// => nothing will be subtracted here :) + + +/////////////////////////////////////////////////////////////////////////////// +// substract part added by NavierStokesFV1::add_jac_M_elem(): +// (instead of setting scv.volume() to zero) +//////////////////////////////////////////////////////////////////////////////// + +// Only first order implementation + UG_ASSERT((TFVGeom::order == 1), "Only first order implemented."); + +// get finite volume geometry + static TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + + SmartPtr > fluidDensity = m_spMaster->density(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int sh = scv.node_id(); + + if ( !m_spInterfaceHandlerLocal->lies_onInterface(sh) ) + continue; + + if ( fluidDensity->value(0, ip) != fluidDensity->value(1, ip) ) + UG_THROW("ParticleBndCondDiffusion::add_jac_M_elem(): density different for series 0 and 1: " + << fluidDensity->value(0, ip) << " != " << fluidDensity->value(1, ip) << "\n"); + + number importDensity = fluidDensity->value(0, ip); + + // loop velocity components + for(int d1 = 0; d1 < dim; ++d1) + { + // Add to local matrix + d(d1, sh) -= u(d1, sh) * scv.volume() * importDensity; + } + } + + +} + + +// here gravity force -> independent of velocity solution! +template +template +void ParticleBndCondDiffusion:: +add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) +{ + return; + + + ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); + +// A. do nothing for inside elements + if ( modus == INSIDE_DOM ) + return; + +// B. for outside elements: geo.num_scv() = 0 +// => nothing added during NavierStokesFV1::add_jac_M_elem +// => nothing will be subtracted here :) + + +/////////////////////////////////////////////////////////////////////////////// +// substract part added by NavierStokesFV1::add_rgh_elem(): +// (instead of setting scv.volume() to zero) +//////////////////////////////////////////////////////////////////////////////// + +// Only first order implementation + UG_ASSERT((TFVGeom::order == 1), "Only first order implemented."); + +// get finite volume geometry + static TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int sh = scv.node_id(); + + if ( !m_spInterfaceHandlerLocal->lies_onInterface(sh) ) + continue; + + // Add to local matrix + d(0, sh) -= scv.volume() * (-9.81); + + } + + +} + + + +//////////////////////////////////////////////////////////////////////////////// +// register assemble functions +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template<> +void ParticleBndCondDiffusion:: +register_all(bool bHang) +{ +// switch assemble functions + if(!bHang) + { + register_func > >(); + +// register_func >(); + } + else + { + UG_THROW("ParticleBndCondDiffusion: Hanging Nodes not implemented.") + } +} +#endif + +#ifdef UG_DIM_2 +template<> +void ParticleBndCondDiffusion:: +register_all(bool bHang) +{ +// switch assemble functions + if(!bHang) + { + register_func > >(); +/* + register_func >(); + register_func >(); + */ + } + else + { + UG_THROW("ParticleBndCondDiffusion: Hanging Nodes not implemented.") + } +} +#endif + +#ifdef UG_DIM_3 +template<> +void ParticleBndCondDiffusion:: +register_all(bool bHang) +{ +// switch assemble functions + if(!bHang) + { + register_func > >(); +/* + register_func >(); + register_func >(); + register_func >(); + register_func >(); + */ + } + else + { + UG_THROW("ParticleBndCondDiffusion: Hanging Nodes not implemented.") + } +} +#endif + +template +template +void +ParticleBndCondDiffusion:: +register_func() +{ + ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; + typedef ParticleBndCondDiffusion T; + + this->clear_add_fct(id); + this->set_prep_elem_loop_fct( id, &T::template prep_elem_loop); + this->set_prep_elem_fct( id, &T::template prep_elem); + this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); + this->set_add_jac_A_elem_fct( id, &T::template add_jac_A_elem); + this->set_add_jac_M_elem_fct( id, &T::template add_jac_M_elem); + this->set_add_def_A_elem_fct( id, &T::template add_def_A_elem); + this->set_add_def_M_elem_fct( id, &T::template add_def_M_elem); + this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); +} + + +//////////////////////////////////////////////////////////////////////////////// +// explicit template instantiations +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template class ParticleBndCondDiffusion; +#endif +#ifdef UG_DIM_2 +template class ParticleBndCondDiffusion; +#endif +#ifdef UG_DIM_3 +template class ParticleBndCondDiffusion; +#endif + + +} // end namespace MovingInterfaceDiffusion +} // end namespace ug + + +#endif /* DIFFUSION_BND_COND_IMPL_H_ */ diff --git a/fv1_cutElem/diffusion_interface/diffusion_interface Kopie.h b/fv1_cutElem/diffusion_interface/diffusion_interface Kopie.h new file mode 100644 index 0000000..14bf174 --- /dev/null +++ b/fv1_cutElem/diffusion_interface/diffusion_interface Kopie.h @@ -0,0 +1,235 @@ +/* + * diffusion_interface.h + * + * Created on: 24.08.2017 + * Author: suze + */ + +#ifndef DIFFUSION_INTERFACE_DIFFUSION_H_ +#define DIFFUSION_INTERFACE_DIFFUSION_H_ + + +#ifdef UG_PARALLEL + #include "lib_grid/parallelization/load_balancer_util.h" +#endif + +#include "../../../../ConvectionDiffusion/fv1/convection_diffusion_fv1.h" +#include "../../../../ConvectionDiffusion/convection_diffusion_base.h" +#include "interface_handler_diffusion.h" +#include "loc_to_glob_mapper_diffusion.h" +#include "../immersed_interface_base/immersed_interface_base.h" + +namespace ug{ +namespace MovingInterfaceDiffusion{ + + + +template < typename TDomain, typename TAlgebra> +class MovingInterfaceDiffusion + : public MovingInterfaceBase::IMovingInterface +{ + public: + /// world Dimension + static const int dim = TDomain::dim; + + /// Algebra type + typedef TAlgebra algebra_type; + + /// Type of algebra matrix + typedef typename algebra_type::matrix_type matrix_type; + + /// Type of algebra vector + typedef typename algebra_type::vector_type vector_type; + + typedef typename domain_traits::grid_base_object grid_base_object; + + MovingInterfaceDiffusion( + SmartPtr > ass, + SmartPtr > spMaster, + SmartPtr > interfaceProvider, + SmartPtr > cutElementHandler); + + void set_StdFV_assembling(bool bValue) { m_spInterfaceHandlerLocal->set_StdFV_assembling(bValue);} + bool StdFV_assembling() { return m_spInterfaceHandlerLocal->StdFV_assembling(); } + + + // destructor + ~MovingInterfaceDiffusion(){}; + + /// called via .lua: + void initialize_threshold(TDomain& domain, const int baseLevel, const int topLevel); + void set_threshold(size_t level, const number threshold) + { m_spCutElementHandler->set_threshold(level, threshold); } + + ////////////////////////////////////////////////////////////////////////////////// + /// Info - 'initialize_interface()': + /// + /// computes vertices on intersection of cut element edges and interface: + /// for 2d: instead of computing intersections: count number of cut elements! + /// -> #cutElements == #m_vertices + /// -> called during init() + ////////////////////////////////////////////////////////////////////////////////// + + const size_t initialize_interface(vector_type& u, ConstSmartPtr dd); + const size_t initialize_interface_Nitsche(vector_type& u, ConstSmartPtr dd); + + number MeanElementDiameter(TDomain& domain, int level); + + ////////////////////////////////////////////////////////////////////////////////// + // ---> .lua: update(u, deltaT, u:grid_level()): update global indices (transInd...) + // => A. copy_solution(topLev) + // B. update(baseLev-topLev) + // C. update_solution(topLev) + ////////////////////////////////////////////////////////////////////////////////// + // write solution to nodes outside fluid with particle velocities + // --> call method vie .lua BEFORE 'solTimeSeries:push_discard_oldest(oldestSol, time)': + // => in case that outside nodes are inside AFTER update_prtCoords: NO solution defined here! + + + /// call of the method via lua to set the real velocity values within the particle domain + void adjust_global_solution(vector_type& u, const int topLevel); + void fill_particle_solution(vector_type& u, const int topLevel, const number time); + void update(vector_type& u, SmartPtr > spApproxSpace, const int baseLevel, const int topLevel, const number time) + { + int topLev = spApproxSpace->num_levels()-1; + if ( topLev != topLevel ) + UG_THROW("update: parameter 'topLevel' = " << topLevel << " != " + << topLev << "current top leven! \n"); + + // fill particle nodes with their real solution + fill_particle_solution(u, topLevel, time); + + // update data: bool_marker + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + m_spCutElementHandler->template init(dd, baseLevel, topLevel); + + } + + void set_interface_values(vector_type& u, const int numDoFs, const int num_newDoFs) + { + double value = 20.0*0.4*0.4*0.4*0.4; + DoFIndex index; + + for (size_t i = 0; i < num_newDoFs; ++i) + { + index = DoFIndex(numDoFs + i,0); + // DoFRef(u, index) = value; + } + } + void set_analytic_solution(vector_type& u, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel); + void adjust_for_error(vector_type& u, vector_type& uCopy, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel); + + double compute_solution_value(const MathVector& vrtPos); + + number get_integral() + { return m_spInterfaceHandlerLocal->get_integral(); } + + void set_Nitsche(bool bNitsche) + { return m_spInterfaceHandlerLocal->set_Nitsche(bNitsche); } + + void init(vector_type& u, SmartPtr > spApproxSpace, const int baseLevel, const int topLevel, bool bScaleDoFs) + { + m_spApproxSpace = spApproxSpace; + + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + + m_spInterfaceMapper->set_numDoFs(u.size()); + + size_t numDoFs = u.size(); + UG_LOG("domain disc: numDoFs = " << numDoFs << "\n"); + size_t num_newDoFs = initialize_interface(u, dd); + UG_LOG("________________ num_newDoFs = " << initialize_interface(u, dd) << "\n"); + m_spInterfaceMapper->set_numNewDoFs(num_newDoFs); + + + if ( m_spInterfaceHandlerLocal->get_Nitsche() ) + { + const size_t buffer = initialize_interface_Nitsche(u, dd); + UG_LOG(" buffer = " << buffer << "\n"); + + const size_t num_NitscheDoFs = m_spInterfaceHandlerLocal->get_num_NitscheDoFs(); + UG_LOG(" num_NitscheDoFs = " << num_NitscheDoFs << "\n"); + + num_newDoFs = num_NitscheDoFs; + m_spInterfaceMapper->set_numNewDoFs(num_newDoFs); + + for ( size_t i = 0; i < num_NitscheDoFs; ++i ) + { + size_t global_index = m_spInterfaceHandlerLocal->get_global_index_Nitsche(i); + UG_LOG(" global_index = " << global_index << "\n"); + } + } + + // values for new DoFs are set to 0.0 by the 'resize()'-method (see vector.h): + if ( bScaleDoFs ) + u.resize(numDoFs + 2*num_newDoFs); + else + u.resize(numDoFs + num_newDoFs); + + UG_LOG("AGAIN: in init(): numDoFs = " << u.size() << "\n"); + + m_spInterfaceMapper->set_bScaleDoFs(bScaleDoFs); + m_spInterfaceHandlerLocal->set_bScaleDoFs(bScaleDoFs); + + m_spInterfaceHandlerLocal->init_integral(); + + // lieber in jedem Schritt über 'modify_GlobalSol()' (mapper!) setzten! + //set_interface_values(u, numDoFs, num_newDoFs); + + // not necessary anymore: only local evaluations within diffusion problem! + //m_spCutElementHandler->template init_marker(dd, baseLevel, topLevel); + } + + /// checks if grid data is updated and returns 'levIndex'-pair for 'gridLevel' in 'm_Map' + int get_Index(const GridLevel& gridLevel) + { + ConstSmartPtr dd = m_spApproxSpace->dof_distribution(gridLevel); + + const int levIndex = m_spCutElementHandler->get_Index(gridLevel, dd); + + return levIndex; + } + + //ToDo: method needed? + void update_interface( const int topLevel, number deltaT); + + bool is_time_dependent() { return m_spInterfaceHandlerLocal->is_time_dependent();} + + /// helper functions for compute_error_on_circle() + void interpolate_point(ConstSmartPtr dd, const vector_type& u, + const MathVector& evalPos, MathVector& interpolation); + void compute_error_on_circle(const vector_type& u, const int topLevel, number radius); + + void print_deltaP(const vector_type& u, const int topLevel); + void print_pressure(const vector_type& u, const int topLevel); + void print_pressure_nodal(const vector_type& u, const int topLevel); + + /// writing data to file; called via .lua + void print_velocity(const vector_type& u, const int topLevel, number time, const char* filename); + void print_velocity_many_particles(const vector_type& u, const int topLevel, number time, const char* filename); + + size_t get_numDoFs(const vector_type& u) {return u.size(); } + + private: + /// current ApproxSpace + SmartPtr > m_spApproxSpace; + + SmartPtr > m_spInterfaceProvider; + SmartPtr > m_spCutElementHandler; + SmartPtr > m_spInterfaceHandlerLocal; + + SmartPtr > m_spInterfaceMapper; + +}; + +} // end namespace MovingInterfaceDiffusion +} // end namespace ug + + +#include "diffusion_interface_impl.h" + +#endif /* DIFFUSION_INTERFACE_DIFFUSION_H_ */ + + + + diff --git a/fv1_cutElem/diffusion_interface/diffusion_interface.h b/fv1_cutElem/diffusion_interface/diffusion_interface.h new file mode 100644 index 0000000..30968c9 --- /dev/null +++ b/fv1_cutElem/diffusion_interface/diffusion_interface.h @@ -0,0 +1,242 @@ +/* + * diffusion_interface.h + * + * Created on: 24.08.2017 + * Author: suze + */ + +#ifndef DIFFUSION_INTERFACE_DIFFUSION_H_ +#define DIFFUSION_INTERFACE_DIFFUSION_H_ + + +#ifdef UG_PARALLEL + #include "lib_grid/parallelization/load_balancer_util.h" +#endif + +#include "../convection_diffusion_fv1_cutElem.h" +#include "../../convection_diffusion_base.h" +#include "lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion.h" +#include "loc_to_glob_mapper_diffusion.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + + + +template < typename TDomain, typename TAlgebra> +class MovingInterfaceDiffusion + : public IMovingInterface +{ + public: + /// world Dimension + static const int dim = TDomain::dim; + + /// Algebra type + typedef TAlgebra algebra_type; + + /// Type of algebra matrix + typedef typename algebra_type::matrix_type matrix_type; + + /// Type of algebra vector + typedef typename algebra_type::vector_type vector_type; + + typedef typename domain_traits::grid_base_object grid_base_object; + + MovingInterfaceDiffusion( + SmartPtr > ass, + SmartPtr > spMaster, + SmartPtr > interfaceProvider, + SmartPtr > cutElementHandler); + + void set_StdFV_assembling(bool bValue) { m_spInterfaceHandlerLocal->set_StdFV_assembling(bValue);} + bool StdFV_assembling() { return m_spInterfaceHandlerLocal->StdFV_assembling(); } + + + // destructor + ~MovingInterfaceDiffusion(){}; + + /// called via .lua: + void initialize_threshold(TDomain& domain, const int baseLevel, const int topLevel); + void set_threshold(size_t level, const number threshold) + { m_spCutElementHandler->set_threshold(level, threshold); } + + ////////////////////////////////////////////////////////////////////////////////// + /// Info - 'initialize_interface()': + /// + /// computes vertices on intersection of cut element edges and interface: + /// for 2d: instead of computing intersections: count number of cut elements! + /// -> #cutElements == #m_vertices + /// -> called during init() + ////////////////////////////////////////////////////////////////////////////////// + + const size_t initialize_interface(vector_type& u, ConstSmartPtr dd); + const size_t initialize_interface_Nitsche(vector_type& u, ConstSmartPtr dd); + + number MeanElementDiameter(TDomain& domain, int level); + + ////////////////////////////////////////////////////////////////////////////////// + // ---> .lua: update(u, deltaT, u:grid_level()): update global indices (transInd...) + // => A. copy_solution(topLev) + // B. update(baseLev-topLev) + // C. update_solution(topLev) + ////////////////////////////////////////////////////////////////////////////////// + // write solution to nodes outside fluid with particle velocities + // --> call method vie .lua BEFORE 'solTimeSeries:push_discard_oldest(oldestSol, time)': + // => in case that outside nodes are inside AFTER update_prtCoords: NO solution defined here! + + + /// call of the method via lua to set the real velocity values within the particle domain + void adjust_global_solution(vector_type& u, const int topLevel); + void fill_particle_solution(vector_type& u, const int topLevel, const number time); + void update(vector_type& u, SmartPtr > spApproxSpace, const int baseLevel, const int topLevel, const number time) + { + int topLev = spApproxSpace->num_levels()-1; + if ( topLev != topLevel ) + UG_THROW("update: parameter 'topLevel' = " << topLevel << " != " + << topLev << "current top leven! \n"); + + // fill particle nodes with their real solution + fill_particle_solution(u, topLevel, time); + + // update data: bool_marker + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + m_spCutElementHandler->template init(dd, baseLevel, topLevel); + + } + + void set_interface_values(vector_type& u, const int numDoFs, const int num_newDoFs) + { + double value = 20.0*0.4*0.4*0.4*0.4; + DoFIndex index; + + for (size_t i = 0; i < num_newDoFs; ++i) + { + index = DoFIndex(numDoFs + i,0); + // DoFRef(u, index) = value; + } + } + void set_analytic_solution(vector_type& u, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel); + void adjust_for_error(vector_type& u, vector_type& uCopy, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel); + + double compute_solution_value(const MathVector& vrtPos); + + number get_integral() + { return m_spInterfaceHandlerLocal->get_integral(); } + + void set_Nitsche(bool bNitsche) + { return m_spInterfaceHandlerLocal->set_Nitsche(bNitsche); } + + void init(vector_type& u, SmartPtr > spApproxSpace, const int baseLevel, const int topLevel, bool bScaleDoFs, bool bBndFct) + { + m_spApproxSpace = spApproxSpace; + + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + + m_spInterfaceMapper->set_numDoFs(u.size()); + + size_t numDoFs = u.size(); + UG_LOG("domain disc: numDoFs = " << numDoFs << "\n"); + size_t num_newDoFs = initialize_interface(u, dd); + UG_LOG("________________ num_newDoFs = " << initialize_interface(u, dd) << "\n"); + m_spInterfaceMapper->set_numNewDoFs(num_newDoFs); + + + if ( m_spInterfaceHandlerLocal->get_Nitsche() ) + { + const size_t buffer = initialize_interface_Nitsche(u, dd); + UG_LOG(" buffer = " << buffer << "\n"); + + const size_t num_NitscheDoFs = m_spInterfaceHandlerLocal->get_num_NitscheDoFs(); + UG_LOG(" num_NitscheDoFs = " << num_NitscheDoFs << "\n"); + + num_newDoFs = num_NitscheDoFs; + m_spInterfaceMapper->set_numNewDoFs(num_newDoFs); + + for ( size_t i = 0; i < num_NitscheDoFs; ++i ) + { + size_t global_index = m_spInterfaceHandlerLocal->get_global_index_Nitsche(i); + UG_LOG(" global_index = " << global_index << "\n"); + } + } + + // values for new DoFs are set to 0.0 by the 'resize()'-method (see vector.h): + if ( bScaleDoFs ) + u.resize(numDoFs + 2*num_newDoFs); + else + u.resize(numDoFs + num_newDoFs); + + UG_LOG("AGAIN: in init(): numDoFs = " << u.size() << "\n"); + + m_spInterfaceMapper->set_bScaleDoFs(bScaleDoFs); + m_spInterfaceHandlerLocal->set_bScaleDoFs(bScaleDoFs); + + m_spInterfaceHandlerLocal->check_interface_data(bBndFct); + + m_spInterfaceHandlerLocal->init_integral(); + + // lieber in jedem Schritt über 'modify_GlobalSol()' (mapper!) setzten! + //set_interface_values(u, numDoFs, num_newDoFs); + + // not necessary anymore: only local evaluations within diffusion problem! + //m_spCutElementHandler->template init_marker(dd, baseLevel, topLevel); + } + + void set_source_data(const number interfaceSourceVal) { m_spInterfaceHandlerLocal->set_source_lua(interfaceSourceVal); } + void set_jump_data(const number interfaceJumpVal) { m_spInterfaceHandlerLocal->set_jump_lua(interfaceJumpVal); } + void set_jump_grad_data(const MathVector<2>& interfaceJumpGradVal) { m_spInterfaceHandlerLocal->set_jump_grad_lua(interfaceJumpGradVal); } + void set_diffusion_data(const MathVector<2>& diffusionCoeffs) { m_spInterfaceHandlerLocal->set_diffusion_coeff_lua(diffusionCoeffs); } + + + /// checks if grid data is updated and returns 'levIndex'-pair for 'gridLevel' in 'm_Map' + int get_Index(const GridLevel& gridLevel) + { + ConstSmartPtr dd = m_spApproxSpace->dof_distribution(gridLevel); + + const int levIndex = m_spCutElementHandler->get_Index(gridLevel, dd); + + return levIndex; + } + + //ToDo: method needed? + void update_interface( const int topLevel, number deltaT); + + bool is_time_dependent() { return m_spInterfaceHandlerLocal->is_time_dependent();} + + /// helper functions for compute_error_on_circle() + void interpolate_point(ConstSmartPtr dd, const vector_type& u, + const MathVector& evalPos, MathVector& interpolation); + void compute_error_on_circle(const vector_type& u, const int topLevel, number radius); + + void print_deltaP(const vector_type& u, const int topLevel); + void print_pressure(const vector_type& u, const int topLevel); + void print_pressure_nodal(const vector_type& u, const int topLevel); + + /// writing data to file; called via .lua + void print_velocity(const vector_type& u, const int topLevel, number time, const char* filename); + void print_velocity_many_particles(const vector_type& u, const int topLevel, number time, const char* filename); + + size_t get_numDoFs(const vector_type& u) {return u.size(); } + + private: + /// current ApproxSpace + SmartPtr > m_spApproxSpace; + + SmartPtr > m_spInterfaceProvider; + SmartPtr > m_spCutElementHandler; + SmartPtr > m_spInterfaceHandlerLocal; + + SmartPtr > m_spInterfaceMapper; + +}; + +} // end namespace ConvectionDiffusionPlugin +} // end namespace ug + + +#include "diffusion_interface_impl.h" + +#endif /* DIFFUSION_INTERFACE_DIFFUSION_H_ */ + + + + diff --git a/fv1_cutElem/diffusion_interface/diffusion_interface_impl Kopie.h b/fv1_cutElem/diffusion_interface/diffusion_interface_impl Kopie.h new file mode 100644 index 0000000..7d300f3 --- /dev/null +++ b/fv1_cutElem/diffusion_interface/diffusion_interface_impl Kopie.h @@ -0,0 +1,371 @@ + +/* + * moving_interface_diffusion_impl.h + * + * Created on: 24.08.2017 + * Author: suze + */ + +#ifndef DIFFUSION_INTERFACE_IMPL_H_ +#define DIFFUSION_INTERFACE_IMPL_H_ + + +namespace ug { +namespace MovingInterfaceDiffusion { + +/////////////////////////////////////////////////////////// +// Implementation of the methods class +// 'MovingInterfaceDiffusion' +/////////////////////////////////////////////////////////// + + +template +MovingInterfaceDiffusion::MovingInterfaceDiffusion( + SmartPtr > ass, + SmartPtr > spMaster, + SmartPtr > interfaceProvider, + SmartPtr > cutElementHandler) : + m_spInterfaceHandlerLocal(new InterfaceHandlerLocalDiffusion(interfaceProvider, cutElementHandler)), + m_spInterfaceProvider(interfaceProvider), + m_spCutElementHandler(cutElementHandler), + m_spInterfaceMapper(new DiffusionInterfaceMapper (m_spInterfaceHandlerLocal)) +{ + if (interfaceProvider->num_particles() == 0) + UG_THROW("MovingParticle::Constructor(): no particles initializen in 'globalHandler\n"); + + // initialize singleton and set local handler + typedef DimFV1CutGeometry > TFVGeom; + TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); + geo.set_interface_handler(m_spInterfaceHandlerLocal); + + // initialize mapper within domainDisc: + SmartPtr > assAdapt = ass->ass_tuner(); + assAdapt->set_mapping(m_spInterfaceMapper.get()); + + assAdapt->enable_modify_solution(true); + // => assTuner->modify_LocSol() = mapper->modify_LocSol() + // see: ass_tuner.h: 114 + + +} + +template +double MovingInterfaceDiffusion:: +compute_solution_value(const MathVector& vrtPos) +{ + double kappa_1 = 1.0; + double kappa_2 = 10.0; + double sqR = 0.4*0.4; + double dist_x = vrtPos[0] - 0.1; + double dist_y = vrtPos[1] - 0.2; + double sqDist = dist_x*dist_x+dist_y*dist_y; + + double value = -4*kappa_1*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_1*kappa_2 - 1); + + double dist = sqrt(sqDist); + if ( dist > 0.4 ) + { + value = -2*kappa_2*sqDist*sqDist; + UG_LOG("value = " << value << "\n"); + } + return value; +} + +template +void MovingInterfaceDiffusion:: +set_analytic_solution(vector_type& u, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel) +{ + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + + typedef MathVector position_type; + typedef Attachment position_attachment_type; + typedef Grid::VertexAttachmentAccessor position_accessor_type; + + //SmartPtr m_spMG = mg.operator->(); + position_attachment_type m_aPos = GetDefaultPositionAttachment(); + position_accessor_type m_aaPos; + + if(!mg->has_attachment(m_aPos)) + mg->attach_to(m_aPos); + m_aaPos.access(*mg, m_aPos); + + typedef typename domain_traits::grid_base_object grid_base_object; + + typename DoFDistribution::traits::const_iterator iter, iterEnd; + iter = dd->template begin(); + iterEnd = dd->template end(); + + // loop elements in order to compute the volume and set rhs: + for( ; iter != iterEnd; iter++) + { + // get element + grid_base_object* elem = *iter; + std::vector > vCornerCoords; + CollectCornerCoordinates(vCornerCoords, *elem, m_aaPos); + + std::vector ind; + dd->dof_indices(elem, 0, ind); + + // loop vertices + for(size_t i = 0; i < elem->num_vertices(); ++i) + { + // get vertex + Vertex* vrt = elem->vertex(i); + double value = compute_solution_value(vCornerCoords[i]); + DoFRef(u, ind[i]) = value; + } + } + +} + +template +void MovingInterfaceDiffusion:: +adjust_for_error(vector_type& u, vector_type& uCopy, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel) +{ + + + size_t numDoFs = u.size(); + UG_LOG("domain disc: numDoFs = " << numDoFs << "\n"); + size_t numDoFsCopy = uCopy.size(); + UG_LOG("domain disc: numDoFsCopy = " << numDoFsCopy << "\n"); + + u.resize(numDoFsCopy); + + numDoFs = u.size(); + UG_LOG("**domain disc: numDoFs = " << numDoFs << "\n"); + + + + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + + typedef MathVector position_type; + typedef Attachment position_attachment_type; + typedef Grid::VertexAttachmentAccessor position_accessor_type; + + //SmartPtr m_spMG = mg.operator->(); + position_attachment_type m_aPos = GetDefaultPositionAttachment(); + position_accessor_type m_aaPos; + + if(!mg->has_attachment(m_aPos)) + mg->attach_to(m_aPos); + m_aaPos.access(*mg, m_aPos); + + typedef typename domain_traits::grid_base_object grid_base_object; + + typename DoFDistribution::traits::const_iterator iter, iterEnd; + iter = dd->template begin(); + iterEnd = dd->template end(); + + // loop elements in order to compute the volume and set rhs: + for( ; iter != iterEnd; iter++) + { + // get element + grid_base_object* elem = *iter; + + ElementModus elemModus = m_spInterfaceHandlerLocal->compute_element_modus(elem, 1); + bool do_adjust = false; + + switch(elemModus) + { + case INSIDE_DOM: break; + case OUTSIDE_DOM: break; + + case CUT_BY_INTERFACE: do_adjust = true; break; + default: + throw(UGError("Error in InterfaceHandlerLocalDiffusion::update(): switch(m_elemModus)!")); + } + + + std::vector > vCornerCoords; + CollectCornerCoordinates(vCornerCoords, *elem, m_aaPos); + + std::vector ind; + dd->dof_indices(elem, 0, ind); + + // loop vertices + for(size_t i = 0; i < elem->num_vertices(); ++i) + { + // get vertex + Vertex* vrt = elem->vertex(i); + + if (do_adjust) DoFRef(u, ind[i]) = 0.0; + } + + } + +} + +template +const size_t MovingInterfaceDiffusion:: +initialize_interface_Nitsche(vector_type& u, ConstSmartPtr dd) +{ + m_spInterfaceHandlerLocal->m_MapInserted_Nitsche.clear(); + + typedef typename domain_traits::grid_base_object grid_base_object; + + typename DoFDistribution::traits::const_iterator iter, iterEnd; + iter = dd->template begin(); + iterEnd = dd->template end(); + + size_t num_cutElements = 0; + + // loop elements in order to compute the volume and set rhs: + for( ; iter != iterEnd; iter++) + { + // get element + grid_base_object* elem = *iter; + + ElementModus elemModus = m_spCutElementHandler->compute_element_modus(elem, 1); + + if ( elemModus == CUT_BY_INTERFACE ) + { + num_cutElements += 1; + + // get global indices + LocalIndices ind; + dd->indices(elem, ind, false); + + // fill 'm_MapInserted_Nitsche' with global indices: + for(size_t i = 0; i < 3; ++i) + m_spInterfaceHandlerLocal->get_or_insert_indexPair_Nitsche(ind.index(0, i)); + + } + } + + return num_cutElements; + +} + +template +const size_t MovingInterfaceDiffusion:: +initialize_interface(vector_type& u, ConstSmartPtr dd) +{ + typedef typename domain_traits::grid_base_object grid_base_object; + + typename DoFDistribution::traits::const_iterator iter, iterEnd; + iter = dd->template begin(); + iterEnd = dd->template end(); + + size_t num_cutElements = 0; + + // loop elements in order to compute the volume and set rhs: + for( ; iter != iterEnd; iter++) + { + // get element + grid_base_object* elem = *iter; + + ElementModus elemModus = m_spCutElementHandler->compute_element_modus(elem, 1); + + if ( elemModus == CUT_BY_INTERFACE ) + num_cutElements += 1; + + } + + return num_cutElements; + +} + +template +number MovingInterfaceDiffusion:: +MeanElementDiameter(TDomain& domain, int level) +{ + typedef typename domain_traits::grid_base_object TElem; + typedef typename geometry_traits::iterator ListIter; + + ListIter iter = domain.grid()->template begin(level); + ListIter iterEnd = domain.grid()->template end(level); + + number mean = 0.0; + size_t numIter = 0; + for (; iter != iterEnd; ++iter) { + mean += ElementDiameterSq(*domain.grid(), domain.position_accessor(), + *iter); + numIter++; + } + + mean = mean / numIter; + +#ifdef UG_PARALLEL + // share value between all procs + pcl::ProcessCommunicator com; + // ToDO: PCL_RO_MIN oder MAX oder doch mean noch berechnen m.H.v. /numProcs??? + //UG_THROW("in MeanElementDiameter(): was macht 'allredue' im Parallelen???\n"); + mean = com.allreduce(mean, PCL_RO_MIN); +#endif + + UG_LOG("nach com.allreduce: mean = " << std::sqrt(mean) << "\n"); + return std::sqrt(mean); +} + +template +void MovingInterfaceDiffusion:: +initialize_threshold(TDomain& domain, const int baseLevel, const int topLevel) +{ + UG_LOG("----------------- START initialize_threshold() ---------------- \n"); + + if (baseLevel < 0) + UG_THROW( + "initialize_threshold(): no cast of baselevel from 'int' tp 'size_t' possible! \n"); + if (topLevel < 0) + UG_THROW( + "initialize_threshold(): no cast of toplevel from 'int' tp 'size_t' possible! \n"); + +// compute level-dependent value for threshold: + for (size_t lev = baseLevel; lev <= (size_t) topLevel; ++lev) { + const number maxLength = MaxElementDiameter(domain, lev); + const number meanLength = MeanElementDiameter(domain, lev); + UG_LOG("maxLength = " << maxLength << "\n"); + UG_LOG("meanLength = " << meanLength << "\n"); + UG_LOG("threshold_max = " << maxLength*maxLength << "\n"); + UG_LOG("threshold_mean = " << meanLength*meanLength << "\n"); + +// set_threshold(lev, meanLength * meanLength); + set_threshold(lev, 0.25 * meanLength*meanLength); + } + + UG_LOG("----------------- END initialize_threshold() ---------------- \n"); + +} + +template +void MovingInterfaceDiffusion:: +update_interface( const int topLevel, number deltaT) +{ + if ( deltaT == 0.0 ) + UG_THROW("InterfaceProvider:update_prtCoords: deltaT = " << deltaT << " => no update necessary!\n"); + +// get level index + const int levIndex = get_Index(GridLevel(topLevel, GridLevel::LEVEL)); + UG_LOG("update_prtCoords() for levIndex = " << levIndex << "\n"); + UG_LOG("update_prtCoords() for deltaT = " << deltaT << "\n"); + +// update center + for (size_t p = 0; p < m_spInterfaceProvider->num_particles(); ++p) + { +#ifdef UG_PARALLEL + std::vector ElemList = m_spCutElementHandler->m_vvvElemListCut[levIndex][p]; +// std::vector ElemList = m_vvvElemListCut[levIndex][p]; + UG_LOG("1_ update_prtCoords() ElemList.size(): " << ElemList.size() << "\n"); + if ( ElemList.size() == 0 ) { + UG_LOG("2_ update_prtCoords() ElemList.size(): " << ElemList.size() << " => skip assembling! \n"); + continue; + } +#endif + + // get data: + MathVector centerNew = m_spInterfaceProvider->get_center(p); + number soution = m_spInterfaceProvider->get_solution(p, 0); + UG_LOG(" solution = " << soution << "\n"); + UG_LOG("deltaT = " << deltaT << "\n"); + +// ToDo: Hier das interface irgendwie updaten?? + + + } // end particle loop + +} + +} // end namespace MovingParticle +} // end namespace ug + +#endif /* DIFFUSION_INTERFACE_IMPL_H_ */ diff --git a/fv1_cutElem/diffusion_interface/diffusion_interface_impl.h b/fv1_cutElem/diffusion_interface/diffusion_interface_impl.h new file mode 100644 index 0000000..8422631 --- /dev/null +++ b/fv1_cutElem/diffusion_interface/diffusion_interface_impl.h @@ -0,0 +1,372 @@ + +/* + * moving_interface_diffusion_impl.h + * + * Created on: 24.08.2017 + * Author: suze + */ + +#ifndef DIFFUSION_INTERFACE_IMPL_H_ +#define DIFFUSION_INTERFACE_IMPL_H_ + +#include "lib_disc/spatial_disc/disc_util/geom_provider.h" + +namespace ug { +namespace ConvectionDiffusionPlugin { + +/////////////////////////////////////////////////////////// +// Implementation of the methods class +// 'MovingInterfaceDiffusion' +/////////////////////////////////////////////////////////// + + +template +MovingInterfaceDiffusion::MovingInterfaceDiffusion( + SmartPtr > ass, + SmartPtr > spMaster, + SmartPtr > interfaceProvider, + SmartPtr > cutElementHandler) : + m_spInterfaceHandlerLocal(new InterfaceHandlerLocalDiffusion(interfaceProvider, cutElementHandler)), + m_spInterfaceProvider(interfaceProvider), + m_spCutElementHandler(cutElementHandler), + m_spInterfaceMapper(new DiffusionInterfaceMapper (m_spInterfaceHandlerLocal)) +{ + if (interfaceProvider->num_particles() == 0) + UG_THROW("MovingInterfaceDiffusion::Constructor(): no particles initializen in 'globalHandler\n"); + + // initialize singleton and set local handler + typedef DimFV1CutGeometry > TFVGeom; + TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); + geo.set_interface_handler(m_spInterfaceHandlerLocal); + + // initialize mapper within domainDisc: + SmartPtr > assAdapt = ass->ass_tuner(); + assAdapt->set_mapping(m_spInterfaceMapper.get()); + + assAdapt->enable_modify_solution(true); + // => assTuner->modify_LocSol() = mapper->modify_LocSol() + // see: ass_tuner.h: 114 + + +} + +template +double MovingInterfaceDiffusion:: +compute_solution_value(const MathVector& vrtPos) +{ + double kappa_1 = 1.0; + double kappa_2 = 10.0; + double sqR = 0.4*0.4; + double dist_x = vrtPos[0] - 0.1; + double dist_y = vrtPos[1] - 0.2; + double sqDist = dist_x*dist_x+dist_y*dist_y; + + double value = -4*kappa_1*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_1*kappa_2 - 1); + + double dist = sqrt(sqDist); + if ( dist > 0.4 ) + { + value = -2*kappa_2*sqDist*sqDist; + UG_LOG("value = " << value << "\n"); + } + return value; +} + +template +void MovingInterfaceDiffusion:: +set_analytic_solution(vector_type& u, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel) +{ + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + + typedef MathVector position_type; + typedef Attachment position_attachment_type; + typedef Grid::VertexAttachmentAccessor position_accessor_type; + + //SmartPtr m_spMG = mg.operator->(); + position_attachment_type m_aPos = GetDefaultPositionAttachment(); + position_accessor_type m_aaPos; + + if(!mg->has_attachment(m_aPos)) + mg->attach_to(m_aPos); + m_aaPos.access(*mg, m_aPos); + + typedef typename domain_traits::grid_base_object grid_base_object; + + typename DoFDistribution::traits::const_iterator iter, iterEnd; + iter = dd->template begin(); + iterEnd = dd->template end(); + + // loop elements in order to compute the volume and set rhs: + for( ; iter != iterEnd; iter++) + { + // get element + grid_base_object* elem = *iter; + std::vector > vCornerCoords; + CollectCornerCoordinates(vCornerCoords, *elem, m_aaPos); + + std::vector ind; + dd->dof_indices(elem, 0, ind); + + // loop vertices + for(size_t i = 0; i < elem->num_vertices(); ++i) + { + // get vertex + Vertex* vrt = elem->vertex(i); + double value = compute_solution_value(vCornerCoords[i]); + DoFRef(u, ind[i]) = value; + } + } + +} + +template +void MovingInterfaceDiffusion:: +adjust_for_error(vector_type& u, vector_type& uCopy, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel) +{ + + + size_t numDoFs = u.size(); + UG_LOG("domain disc: numDoFs = " << numDoFs << "\n"); + size_t numDoFsCopy = uCopy.size(); + UG_LOG("domain disc: numDoFsCopy = " << numDoFsCopy << "\n"); + + u.resize(numDoFsCopy); + + numDoFs = u.size(); + UG_LOG("**domain disc: numDoFs = " << numDoFs << "\n"); + + + + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + + typedef MathVector position_type; + typedef Attachment position_attachment_type; + typedef Grid::VertexAttachmentAccessor position_accessor_type; + + //SmartPtr m_spMG = mg.operator->(); + position_attachment_type m_aPos = GetDefaultPositionAttachment(); + position_accessor_type m_aaPos; + + if(!mg->has_attachment(m_aPos)) + mg->attach_to(m_aPos); + m_aaPos.access(*mg, m_aPos); + + typedef typename domain_traits::grid_base_object grid_base_object; + + typename DoFDistribution::traits::const_iterator iter, iterEnd; + iter = dd->template begin(); + iterEnd = dd->template end(); + + // loop elements in order to compute the volume and set rhs: + for( ; iter != iterEnd; iter++) + { + // get element + grid_base_object* elem = *iter; + + ElementModus elemModus = m_spInterfaceHandlerLocal->compute_element_modus(elem, 1); + bool do_adjust = false; + + switch(elemModus) + { + case INSIDE_DOM: break; + case OUTSIDE_DOM: break; + + case CUT_BY_INTERFACE: do_adjust = true; break; + default: + throw(UGError("Error in InterfaceHandlerLocalDiffusion::update(): switch(m_elemModus)!")); + } + + + std::vector > vCornerCoords; + CollectCornerCoordinates(vCornerCoords, *elem, m_aaPos); + + std::vector ind; + dd->dof_indices(elem, 0, ind); + + // loop vertices + for(size_t i = 0; i < elem->num_vertices(); ++i) + { + // get vertex + Vertex* vrt = elem->vertex(i); + + if (do_adjust) DoFRef(u, ind[i]) = 0.0; + } + + } + +} + +template +const size_t MovingInterfaceDiffusion:: +initialize_interface_Nitsche(vector_type& u, ConstSmartPtr dd) +{ + m_spInterfaceHandlerLocal->m_MapInserted_Nitsche.clear(); + + typedef typename domain_traits::grid_base_object grid_base_object; + + typename DoFDistribution::traits::const_iterator iter, iterEnd; + iter = dd->template begin(); + iterEnd = dd->template end(); + + size_t num_cutElements = 0; + + // loop elements in order to compute the volume and set rhs: + for( ; iter != iterEnd; iter++) + { + // get element + grid_base_object* elem = *iter; + + ElementModus elemModus = m_spCutElementHandler->compute_element_modus(elem, 1); + + if ( elemModus == CUT_BY_INTERFACE ) + { + num_cutElements += 1; + + // get global indices + LocalIndices ind; + dd->indices(elem, ind, false); + + // fill 'm_MapInserted_Nitsche' with global indices: + for(size_t i = 0; i < 3; ++i) + m_spInterfaceHandlerLocal->get_or_insert_indexPair_Nitsche(ind.index(0, i)); + + } + } + + return num_cutElements; + +} + +template +const size_t MovingInterfaceDiffusion:: +initialize_interface(vector_type& u, ConstSmartPtr dd) +{ + typedef typename domain_traits::grid_base_object grid_base_object; + + typename DoFDistribution::traits::const_iterator iter, iterEnd; + iter = dd->template begin(); + iterEnd = dd->template end(); + + size_t num_cutElements = 0; + + // loop elements in order to compute the volume and set rhs: + for( ; iter != iterEnd; iter++) + { + // get element + grid_base_object* elem = *iter; + + ElementModus elemModus = m_spCutElementHandler->compute_element_modus(elem, 1); + + if ( elemModus == CUT_BY_INTERFACE ) + num_cutElements += 1; + + } + + return num_cutElements; + +} + +template +number MovingInterfaceDiffusion:: +MeanElementDiameter(TDomain& domain, int level) +{ + typedef typename domain_traits::grid_base_object TElem; + typedef typename geometry_traits::iterator ListIter; + + ListIter iter = domain.grid()->template begin(level); + ListIter iterEnd = domain.grid()->template end(level); + + number mean = 0.0; + size_t numIter = 0; + for (; iter != iterEnd; ++iter) { + mean += ElementDiameterSq(*domain.grid(), domain.position_accessor(), + *iter); + numIter++; + } + + mean = mean / numIter; + +#ifdef UG_PARALLEL + // share value between all procs + pcl::ProcessCommunicator com; + // ToDO: PCL_RO_MIN oder MAX oder doch mean noch berechnen m.H.v. /numProcs??? + //UG_THROW("in MeanElementDiameter(): was macht 'allredue' im Parallelen???\n"); + mean = com.allreduce(mean, PCL_RO_MIN); +#endif + + UG_LOG("nach com.allreduce: mean = " << std::sqrt(mean) << "\n"); + return std::sqrt(mean); +} + +template +void MovingInterfaceDiffusion:: +initialize_threshold(TDomain& domain, const int baseLevel, const int topLevel) +{ + UG_LOG("----------------- START initialize_threshold() ---------------- \n"); + + if (baseLevel < 0) + UG_THROW( + "initialize_threshold(): no cast of baselevel from 'int' tp 'size_t' possible! \n"); + if (topLevel < 0) + UG_THROW( + "initialize_threshold(): no cast of toplevel from 'int' tp 'size_t' possible! \n"); + +// compute level-dependent value for threshold: + for (size_t lev = baseLevel; lev <= (size_t) topLevel; ++lev) { + const number maxLength = MaxElementDiameter(domain, lev); + const number meanLength = MeanElementDiameter(domain, lev); + UG_LOG("maxLength = " << maxLength << "\n"); + UG_LOG("meanLength = " << meanLength << "\n"); + UG_LOG("threshold_max = " << maxLength*maxLength << "\n"); + UG_LOG("threshold_mean = " << meanLength*meanLength << "\n"); + +// set_threshold(lev, meanLength * meanLength); + set_threshold(lev, 0.25 * meanLength*meanLength); + } + + UG_LOG("----------------- END initialize_threshold() ---------------- \n"); + +} + +template +void MovingInterfaceDiffusion:: +update_interface( const int topLevel, number deltaT) +{ + if ( deltaT == 0.0 ) + UG_THROW("InterfaceProvider:update_prtCoords: deltaT = " << deltaT << " => no update necessary!\n"); + +// get level index + const int levIndex = get_Index(GridLevel(topLevel, GridLevel::LEVEL)); + UG_LOG("update_prtCoords() for levIndex = " << levIndex << "\n"); + UG_LOG("update_prtCoords() for deltaT = " << deltaT << "\n"); + +// update center + for (size_t p = 0; p < m_spInterfaceProvider->num_particles(); ++p) + { +#ifdef UG_PARALLEL + std::vector ElemList = m_spCutElementHandler->m_vvvElemListCut[levIndex][p]; +// std::vector ElemList = m_vvvElemListCut[levIndex][p]; + UG_LOG("1_ update_prtCoords() ElemList.size(): " << ElemList.size() << "\n"); + if ( ElemList.size() == 0 ) { + UG_LOG("2_ update_prtCoords() ElemList.size(): " << ElemList.size() << " => skip assembling! \n"); + continue; + } +#endif + + // get data: + MathVector centerNew = m_spInterfaceProvider->get_center(p); + number soution = m_spInterfaceProvider->get_solution(p, 0); + UG_LOG(" solution = " << soution << "\n"); + UG_LOG("deltaT = " << deltaT << "\n"); + +// ToDo: Hier das interface irgendwie updaten?? + + + } // end particle loop + +} + +} // end namespace ConvectionDiffusionPlugin +} // end namespace ug + +#endif /* DIFFUSION_INTERFACE_IMPL_H_ */ diff --git a/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion.h b/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion.h new file mode 100644 index 0000000..8655399 --- /dev/null +++ b/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion.h @@ -0,0 +1,130 @@ +/* + * diffusion_interface_handler_local.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef DIFFUSION_INTERFACE_MAPPER_H_ +#define DIFFUSION_INTERFACE_MAPPER_H_ + +#include "lib_disc/spatial_disc/immersed_util/immersed_interface_base.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + + +template +class DiffusionInterfaceMapper : public IInterfaceMapper +{ + + public: + /// World dimension + static const int dim = TDomain::dim; + /// Algebra type + typedef TAlgebra algebra_type; + + /// Type of algebra matrix + typedef typename algebra_type::matrix_type matrix_type; + + /// Type of algebra vector + typedef typename algebra_type::vector_type vector_type; + + /// Type of geometric base object + typedef typename domain_traits::grid_base_object grid_base_object; + + DiffusionInterfaceMapper(){}; + + DiffusionInterfaceMapper(SmartPtr > localHandler) + : m_spInterfaceHandlerLocal(localHandler), + m_numDoFs(0), + m_resized(false), + m_resized_defect(false), + m_scaleDoFs(false) + {} + + virtual ~DiffusionInterfaceMapper() {} + + + /// send local entries to global rhs + void add_local_vec_to_global(vector_type& vec, const LocalVector& lvec, + ConstSmartPtr dd); + void add_local_vec_to_global_interface(vector_type& vec, const LocalVector& lvec, + ConstSmartPtr dd); + void add_local_vec_to_global_Nitsche(vector_type& vec, const LocalVector& lvec, + ConstSmartPtr dd); + + /// send local entries to global matrix + void add_local_mat_to_global(matrix_type& mat, const LocalMatrix& lmat, + ConstSmartPtr dd); + void add_local_mat_to_global_interface(matrix_type& mat, const LocalMatrix& lmat, + ConstSmartPtr dd); + void add_local_mat_to_global_Nitsche(matrix_type& mat, const LocalMatrix& lmat, + ConstSmartPtr dd); + + void adjust_mat_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd); + + /// modifies local solution vector for adapted defect computation + void modify_LocalData(LocalMatrix& locJ, LocalVector& locU, + ConstSmartPtr dd){}; + void modify_LocalData(LocalVectorTimeSeries& uT, LocalMatrix& locJ, LocalVector& locU, + ConstSmartPtr dd){}; + + void modify_LocalData(LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd){}; + void modify_LocalData(LocalVectorTimeSeries& uT, LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd, size_t t){}; + + /// modifies global solution vector for adapted defect computation + void modify_GlobalSol(vector_type& vecMod, const vector_type& vec, + ConstSmartPtr dd); + + void modify_GlobalSol(SmartPtr > vSolMod, + ConstSmartPtr > vSol, + ConstSmartPtr dd){}; + + /////////////////////////////////////////////////////////////// + /// new methods: + /////////////////////////////////////////////////////////////// + void set_identity_mat_constraint(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd); + + LocalMatrix& get_local_jacobian_tri() + { return m_spInterfaceHandlerLocal->get_local_jacobian_tri(); } + LocalMatrix& get_local_jacobian_quad() + { return m_spInterfaceHandlerLocal->get_local_jacobian_quad(); } + + LocalVector& get_local_defect_tri() + { return m_spInterfaceHandlerLocal->get_local_defect_tri(); } + LocalVector& get_local_defect_quad() + { return m_spInterfaceHandlerLocal->get_local_defect_quad(); } + + void write_solution(const std::vector verticesValues) + { m_spInterfaceHandlerLocal->write_solution(verticesValues); } + + // called during init() of diffusionInterface: + void set_numDoFs(const size_t numDoFs) + { m_numDoFs = numDoFs;} + void set_numNewDoFs(const size_t numNewDoFs) + { m_numNewDoFs = numNewDoFs;} + + void set_bScaleDoFs(bool bScaleDoF) { m_scaleDoFs = bScaleDoF; } + + private: + SmartPtr > m_spInterfaceHandlerLocal; + // number of DoFs in global matrix + size_t m_numDoFs; + size_t m_numNewDoFs; + bool m_resized; + bool m_resized_defect; + bool m_scaleDoFs; + + +}; + +}// namespace ConvectionDiffusionPlugin +} // end ug namespace + +#include "loc_to_glob_mapper_diffusion_impl.h" + + +#endif /* DIFFUSION_INTERFACE_MAPPER_H_ */ diff --git a/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion_impl.h b/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion_impl.h new file mode 100644 index 0000000..afe088a --- /dev/null +++ b/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion_impl.h @@ -0,0 +1,579 @@ +/* + * diffusion_interface_handler_local_impl.h + * + * Created on: 15.01.2015 + * Author: suze + */ + +#ifndef DIFFUSION_INTERFACE_MAPPER_IMPL_H_ +#define DIFFUSION_INTERFACE_MAPPER_IMPL_H_ + + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + + +template +void DiffusionInterfaceMapper:: +set_identity_mat_constraint(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) +{ + + const LocalIndices& rowInd = lmat.get_row_indices(); + + for (size_t fct1 = 0; fct1 < lmat.num_all_row_fct(); ++fct1) + for (size_t dof1 = 0; dof1 < lmat.num_all_row_dof(fct1); ++dof1) + { + const size_t rowIndex = rowInd.index(fct1, dof1); + const size_t rowComp = rowInd.comp(fct1, dof1); + + if ( fabs(lmat.value(fct1, dof1, fct1, dof1)) < 0.000001 && BlockRef(mat(rowIndex, rowIndex), rowComp, rowComp) == 0.0 ) + BlockRef(mat(rowIndex, rowIndex), rowComp, rowComp) = 1.0; + } + +} + + +template +void DiffusionInterfaceMapper:: +adjust_mat_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) +{ + DoFIndex index; + + for (size_t i = 0; i < m_numDoFs; ++i) + { + if ( BlockRef(mat(i, i), 0, 0) == 0.0 ) + BlockRef(mat(i, i), 0, 0) = 1.0; + } +} + + +template +void DiffusionInterfaceMapper:: +modify_GlobalSol(vector_type& vecMod, const vector_type& vec, ConstSmartPtr dd) +{ + size_t numDoFs = vecMod.size(); + const size_t numNewDoFs = numDoFs - m_numDoFs; + + UG_LOG("---------------modify_GlobalSol--------------\n"); + UG_LOG(" vecMod.size(): " << numDoFs << "\n"); + UG_LOG("m_numDoFs: " << m_numDoFs << "\n"); + UG_LOG(" computed numNewDoFs: " << numNewDoFs << "\n"); + UG_LOG(" m_numNewDoFs: " << m_numNewDoFs << "\n"); + + DoFIndex index; + std::vector verticesValue; + verticesValue.clear(); + + for (size_t i = 0; i < numNewDoFs; ++i) + { + index = DoFIndex(m_numDoFs + i,0); + // if vrt on interface == DoF: get value from vec + // if vrt on interface != DoF: written via 'compute_values()' + double value; + if ( 1 ) + { value = DoFRef(vec, index); } + else + { + value = 0.0; //m_spInterfaceHandlerLocal->compute_value(m_spInterfaceHandlerLocal->m_verticesPos[i]); + } + + verticesValue.push_back(value); + } + + // call InterfaceHandlerLocal-method: + // no not doing it! Done locally in add_def: locU_tri and locU_quad: + write_solution(verticesValue); + +} + +template +void DiffusionInterfaceMapper:: +add_local_mat_to_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) +{ + const LocalIndices& rowInd = lmat.get_row_indices(); + const LocalIndices& colInd = lmat.get_col_indices(); + + DoFIndex indexRow, indexCol; + + bool print = false; + +// resize global matrix dynamically: + const size_t numDoFs = mat.num_rows(); + + if ( print ) UG_LOG("*** vorher: vec.size(): " << numDoFs << "\n"); + + size_t numAllDoFs = m_numDoFs + m_numNewDoFs; + if ( m_scaleDoFs ) + numAllDoFs = m_numDoFs + 2*m_numNewDoFs; + + const int diffDoFs = numAllDoFs - numDoFs; + +// resize global defect ONCE: + if ( diffDoFs > 0 ) + { + mat.resize_and_keep_values(numAllDoFs, numAllDoFs); + if ( print ) + { + UG_LOG("*** m_numDoFs: " << m_numDoFs << "\n"); + UG_LOG("*** m_numNewDoFs: " << m_numNewDoFs << "\n"); + UG_LOG("*** numAllDoFs: " << numAllDoFs << "\n"); + UG_LOG("*** nachher: mat.num_rows(): " << mat.num_rows() << "\n"); + } + } + else if ( diffDoFs == 0 ) + { if ( print ) UG_LOG("no resizing!\n");} + else if ( diffDoFs < 0 ) + { + if ( print ) UG_LOG("diffDoFs = " << diffDoFs << "\n"); + UG_THROW("error in add_local_mat_to_global: diffDofs < 0\n"); + } + + + ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); + + switch(modus) + { + case OUTSIDE_DOM: + AddLocalMatrixToGlobal(mat, lmat); + break; + case INSIDE_DOM: + AddLocalMatrixToGlobal(mat, lmat); + //set_identity_mat_constraint(mat, lmat, dd); + break; + case CUT_BY_INTERFACE: + //AddLocalMatrixToGlobal(mat, lmat); + if ( m_spInterfaceHandlerLocal->get_Nitsche() ) + add_local_mat_to_global_Nitsche(mat, lmat, dd); + else + add_local_mat_to_global_interface(mat, lmat, dd); + break; + default: + throw(UGError("Error in IInterfaceMapper::add_local_mat_to_global()!")); + + } + +} + + +template +void DiffusionInterfaceMapper:: +add_local_vec_to_global(vector_type& vec, const LocalVector& lvec, ConstSmartPtr dd) +{ + bool print = false; + + const size_t numDoFs = vec.size(); + + if ( print ) UG_LOG("*** vorher: vec.size(): " << numDoFs << "\n"); + + size_t numAllDoFs = m_numDoFs + m_numNewDoFs; + if ( m_scaleDoFs ) + numAllDoFs = m_numDoFs + 2*m_numNewDoFs; + + const int diffDoFs = numAllDoFs - numDoFs; + +// resize global defect ONCE: + if ( diffDoFs > 0 ) + { + vec.resize(numAllDoFs, true); + vec.set(0.0); +/* + bool bJac = m_spInterfaceHandlerLocal->get_jac_bool(); + if ( !bJac ) + { + // vec.set(0.0); + m_spInterfaceHandlerLocal->set_jac_bool(true); + } +*/ + if ( print ) + { + UG_LOG("*** m_numDoFs: " << m_numDoFs << "\n"); + UG_LOG("*** m_numNewDoFs: " << m_numNewDoFs << "\n"); + UG_LOG("*** numAllDoFs: " << numAllDoFs << "\n"); + UG_LOG("*** nachher: vec.size(): " << vec.size() << "\n"); + } + } + else if ( diffDoFs == 0 ) + { if ( print ) UG_LOG("no resizing!\n");} + else if ( diffDoFs < 0 ) + { + if ( print ) UG_LOG("diffDoFs = " << diffDoFs << "\n"); + UG_THROW("error in add_local_vec_to_global: diffDofs < 0\n"); + } + + + ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); + + switch(modus) + { + case OUTSIDE_DOM: + AddLocalVector(vec, lvec); + break; + case INSIDE_DOM: + AddLocalVector(vec, lvec); + break; + case CUT_BY_INTERFACE: + // AddLocalVector(vec, lvec); + if ( m_spInterfaceHandlerLocal->get_Nitsche() ) + add_local_vec_to_global_Nitsche(vec, lvec, dd); + else + add_local_vec_to_global_interface(vec, lvec, dd); + break; + default: + throw(UGError("Error in IInterfaceMapper::add_local_vec_to_global()!")); + + } +} + +template +void DiffusionInterfaceMapper:: +add_local_mat_to_global_Nitsche(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) +{ + + UG_LOG("------------------------ START DiffusionInterfaceMapper - Nitsche ------------------------\n"); + + const LocalIndices& rowInd = lmat.get_row_indices(); + const LocalIndices& colInd = lmat.get_col_indices(); + + DoFIndex indexRow, indexCol; + + /////////////////////////////////////////////////////////////// + /// FIRST: add loc to glob for locJ_tri: + /////////////////////////////////////////////////////////////// + const LocalMatrix& locJ_tri = get_local_jacobian_tri(); + const bool shift_global_index_tri = m_spInterfaceHandlerLocal->get_index_shift_tri(); + + if ( lmat.num_all_row_dof(0) != locJ_tri.num_all_row_dof(0) ) + UG_THROW("in 'add_local_mat_to_global_Nitsche': non-consistent sizees!\n"); + + size_t numAllDoFs = m_numDoFs; + + if ( shift_global_index_tri ) + numAllDoFs = m_numDoFs + m_numNewDoFs; + + for (size_t dof1 = 0; dof1 < locJ_tri.num_all_row_dof(0); ++dof1) + { + size_t global_index1 = rowInd.index(0, dof1); + + // if global_index1 is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface(dof1) ) + global_index1 = numAllDoFs + m_spInterfaceHandlerLocal->get_index_for_global_index_Nitsche(global_index1); + + indexRow = DoFIndex(global_index1, rowInd.comp(0, dof1)); + + for (size_t dof2 = 0; dof2 < locJ_tri.num_all_col_dof(0); ++dof2) + { + size_t global_index2 = rowInd.index(0, dof2); + + // if global_index2 is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface(dof2) ) + global_index2 = numAllDoFs + m_spInterfaceHandlerLocal->get_index_for_global_index_Nitsche(global_index2); + + indexCol = DoFIndex(global_index2, colInd.comp(0, dof2)); + + // finally add loc to glob: + DoFRef(mat, indexRow, indexCol) += locJ_tri.value(0, dof1, 0, dof2); + + } + } + + indexRow = DoFIndex(3, 0); + indexCol = DoFIndex(0, 0); + number value = DoFRef(mat, indexRow, indexCol); + + if ( DoFRef(mat, indexRow, indexCol) > 0 ) + UG_LOG("waiting...\n"); + UG_LOG("value: " << value << "\n"); + + + /////////////////////////////////////////////////////////////// + /// SECOND: add loc to glob for locJ_tri: + /// -> same as FIRST, but: + /// (1) lmat instead of locJ_tri + /// (2) if ( !m_spInterfaceHandlerLocal->lies_onInterface(dof) ) + /// instead of + /// if ( m_spInterfaceHandlerLocal->lies_onInterface(dof) ) + /////////////////////////////////////////////////////////////// + + for (size_t dof1 = 0; dof1 < lmat.num_all_row_dof(0); ++dof1) + { + size_t global_index1 = rowInd.index(0, dof1); + + // if global_index1 is index of m_vertex: compute global index: + if ( !m_spInterfaceHandlerLocal->lies_onInterface(dof1) ) + global_index1 = numAllDoFs + m_spInterfaceHandlerLocal->get_index_for_global_index_Nitsche(global_index1); + + indexRow = DoFIndex(global_index1, rowInd.comp(0, dof1)); + + for (size_t dof2 = 0; dof2 < lmat.num_all_col_dof(0); ++dof2) + { + size_t global_index2 = rowInd.index(0, dof2); + + // if global_index2 is index of m_vertex: compute global index: + if ( !m_spInterfaceHandlerLocal->lies_onInterface(dof2) ) + global_index2 = numAllDoFs + m_spInterfaceHandlerLocal->get_index_for_global_index_Nitsche(global_index2); + + indexCol = DoFIndex(global_index2, colInd.comp(0, dof2)); + + // finally add loc to glob: + DoFRef(mat, indexRow, indexCol) += lmat.value(0, dof1, 0, dof2); + + } + } + + +} + +//get_real_index(dof): +// if dof NOT on interface: returns orig corner index +// if dof ON interface: returns index of m_vertex-array + +template +void DiffusionInterfaceMapper:: +add_local_mat_to_global_interface(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) +{ + // UG_LOG("------------------------ START DiffusionInterfaceMapper ------------------------\n"); + + const LocalIndices& rowInd = lmat.get_row_indices(); + const LocalIndices& colInd = lmat.get_col_indices(); + + DoFIndex indexRow, indexCol; + + /////////////////////////////////////////////////////////////// + /// FIRST: add loc to glob for locJ_tri: + /////////////////////////////////////////////////////////////// + const LocalMatrix& locJ_tri = get_local_jacobian_tri(); + const bool shift_global_index_tri = m_spInterfaceHandlerLocal->get_index_shift_tri(); + + size_t numAllDoFs = m_numDoFs; + + if ( shift_global_index_tri ) + numAllDoFs = m_numDoFs + m_numNewDoFs; + +// UG_LOG("in DiffusionInterfaceMapper::add_loc_mat(): locJ_tri = " << locJ_tri << "\n"); + + + for (size_t dof1 = 0; dof1 < locJ_tri.num_all_row_dof(0); ++dof1) + { + const size_t dof1_real = m_spInterfaceHandlerLocal->real_index_tri(dof1); + + // if dof1_real is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface_tri(dof1) ) + indexRow = DoFIndex(numAllDoFs + dof1_real, 0); + else + indexRow = DoFIndex(rowInd.index(0, dof1_real), rowInd.comp(0, dof1_real)); + + for (size_t dof2 = 0; dof2 < locJ_tri.num_all_col_dof(0); ++dof2) + { + const size_t dof2_real = m_spInterfaceHandlerLocal->real_index_tri(dof2); + + // if dof1_real is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface_tri(dof2) ) + indexCol = DoFIndex(numAllDoFs + dof2_real, 0); + else + indexCol = DoFIndex(colInd.index(0, dof2_real), colInd.comp(0, dof2_real)); + + // finally add loc to glob: + DoFRef(mat, indexRow, indexCol) += locJ_tri.value(0, dof1, 0, dof2); + + if ( indexRow[0] == 0 || indexRow[0] == 30 ){ + UG_LOG("------------------------ tri: += " << locJ_tri.value(0, dof1, 0, dof2) << "\n"); + UG_LOG("(indexRow, indexCol) = " << indexRow[0] << "," << indexCol[0] << "\n"); + } + } + } + + /////////////////////////////////////////////////////////////// + /// SECOND: add loc to glob for locJ_tri: + /////////////////////////////////////////////////////////////// + const LocalMatrix& locJ_quad = get_local_jacobian_quad(); + const bool shift_global_index_quad = m_spInterfaceHandlerLocal->get_index_shift_quad(); + + // reset numAllDoFs! + numAllDoFs = m_numDoFs; + + if ( shift_global_index_quad ) + numAllDoFs = m_numDoFs + m_numNewDoFs; + +// UG_LOG("in DiffusionInterfaceMapper::add_loc_mat(): locJ_quad = " << locJ_quad << "\n"); + + for (size_t dof1 = 0; dof1 < locJ_quad.num_all_row_dof(0); ++dof1) + { + size_t dof1_real = m_spInterfaceHandlerLocal->real_index_quad(dof1); + + // if dof1_real is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface_quad(dof1) && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof1, -1) ) + indexRow = DoFIndex(numAllDoFs + dof1_real, 0); + else + indexRow = DoFIndex(rowInd.index(0, dof1_real), rowInd.comp(0, dof1_real)); + + for (size_t dof2 = 0; dof2 < locJ_quad.num_all_col_dof(0); ++dof2) + { + size_t dof2_real = m_spInterfaceHandlerLocal->real_index_quad(dof2); + + // if dof1_real is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface_quad(dof2) && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof2, -1) ) + indexCol = DoFIndex(numAllDoFs + dof2_real, 0); + else + indexCol = DoFIndex(colInd.index(0, dof2_real), colInd.comp(0, dof2_real)); + + // finally add loc to glob: + DoFRef(mat, indexRow, indexCol) += locJ_quad.value(0, dof1, 0, dof2); + + if ( indexRow[0] == 0 || indexRow[0] == 30){ + UG_LOG("------------------------ quad: += " << locJ_quad.value(0, dof1, 0, dof2) << "\n"); + UG_LOG("(indexRow, indexCol) = " << indexRow[0] << "," << indexCol[0] << "\n"); + } + } + } + + //UG_LOG("------------------------ END DiffusionInterfaceMapper ------------------------\n"); + +} + + +template +void DiffusionInterfaceMapper:: +add_local_vec_to_global_Nitsche(vector_type& vec, const LocalVector& lvec, ConstSmartPtr dd) +{ + const LocalIndices& ind = lvec.get_indices(); + DoFIndex index; + + /////////////////////////////////////////////////////////////// + /// FIRST: add loc to glob for 'locD_tri': + /////////////////////////////////////////////////////////////// + const LocalVector& locD_tri = get_local_defect_tri(); + const bool shift_global_index_tri = m_spInterfaceHandlerLocal->get_index_shift_tri(); + + if ( lvec.num_all_dof(0) != locD_tri.num_all_dof(0) ) + UG_THROW("in 'add_local_vec_to_global_Nitsche': non-consistent sizees!\n"); + + size_t numAllDoFs = m_numDoFs; + + if ( shift_global_index_tri ) + { numAllDoFs = m_numDoFs + m_numNewDoFs; + } + + for (size_t dof = 0; dof < locD_tri.num_all_dof(0); ++dof) + { + size_t global_index = ind.index(0, dof); + + // if dof_real is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface(dof) ) + global_index = numAllDoFs + m_spInterfaceHandlerLocal->get_index_for_global_index_Nitsche(global_index); + + index = DoFIndex(global_index, ind.comp(0, dof)); + + // finally add loc to glob: + DoFRef(vec, index) += locD_tri.value(0, dof); + + } + + + /////////////////////////////////////////////////////////////// + /// SECOND: add loc to glob for 'lvec': + /// -> same as FIRST, but: + /// (1) lvec instead of locD_tri + /// (2) if ( !m_spInterfaceHandlerLocal->lies_onInterface(dof) ) + /// instead of + /// if ( m_spInterfaceHandlerLocal->lies_onInterface(dof) ) + /////////////////////////////////////////////////////////////// + + for (size_t dof = 0; dof < lvec.num_all_dof(0); ++dof) + { + size_t global_index = ind.index(0, dof); + + // if dof_real is index of m_vertex: compute global index: + if ( !m_spInterfaceHandlerLocal->lies_onInterface(dof) ) + global_index = numAllDoFs + m_spInterfaceHandlerLocal->get_index_for_global_index_Nitsche(global_index); + + index = DoFIndex(global_index, ind.comp(0, dof)); + + // finally add loc to glob: + DoFRef(vec, index) += lvec.value(0, dof); + + } + +} + +template +void DiffusionInterfaceMapper:: +add_local_vec_to_global_interface(vector_type& vec, const LocalVector& lvec, ConstSmartPtr dd) +{ + + bool print = false; + DoFIndex index_print; + + const LocalIndices& ind = lvec.get_indices(); + DoFIndex index; + + /////////////////////////////////////////////////////////////// + /// FIRST: add loc to glob for locD_tri: + /////////////////////////////////////////////////////////////// + const LocalVector& locD_tri = get_local_defect_tri(); + const bool shift_global_index_tri = m_spInterfaceHandlerLocal->get_index_shift_tri(); + + size_t numAllDoFs = m_numDoFs; + + if ( shift_global_index_tri ) + { numAllDoFs = m_numDoFs + m_numNewDoFs; + UG_LOG("it is shifted!\n"); + } +// UG_LOG("in DiffusionInterfaceMapper::add_loc_vec(): locD_tri = " << locD_tri << "\n"); + + for (size_t dof = 0; dof < locD_tri.num_all_dof(0); ++dof) + { + const size_t dof_real = m_spInterfaceHandlerLocal->real_index_tri(dof); + + if ( (numAllDoFs + dof_real) > 352 ) + { print = true;index_print = DoFIndex(numAllDoFs + dof_real,0);} + + // if dof_real is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface_tri(dof) && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof, 1) ) + index = DoFIndex(numAllDoFs + dof_real,0); + else + index = DoFIndex(ind.index(0, dof_real), ind.comp(0, dof_real)); + + // finally add loc to glob: + DoFRef(vec, index) += locD_tri.value(0, dof); + + } + + + /////////////////////////////////////////////////////////////// + /// SECOND: add loc to glob for locU_quad: + /////////////////////////////////////////////////////////////// + const LocalVector& locD_quad = get_local_defect_quad(); + const bool shift_global_index_quad = m_spInterfaceHandlerLocal->get_index_shift_quad(); + +// reset numAllDoFs! + numAllDoFs = m_numDoFs; + + if ( shift_global_index_quad ) + numAllDoFs = m_numDoFs + m_numNewDoFs; + +// UG_LOG("in DiffusionInterfaceMapper::add_loc_vec(): locD_quad = " << locD_quad << "\n"); + + for (size_t dof = 0; dof < locD_quad.num_all_dof(0); ++dof) + { + size_t dof_real = m_spInterfaceHandlerLocal->real_index_quad(dof); + + if ( (numAllDoFs + dof_real) > 352 ) + { print = true;index_print = DoFIndex(numAllDoFs + dof_real,0);} + + // if dof_real is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface_quad(dof) && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof, 1) ) + index = DoFIndex(numAllDoFs + dof_real,0); + else + index = DoFIndex(ind.index(0, dof_real), ind.comp(0, dof_real)); + + // finally add loc to glob: + DoFRef(vec, index) += locD_quad.value(0, dof); + } + + +} + +} // namespace ConvectionDiffusionPlugin +} // end ug namespace + +#endif /* DIFFUSION_INTERFACE_MAPPER_IMPL_H_ */ diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.cpp b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.cpp new file mode 100644 index 0000000..115d1d7 --- /dev/null +++ b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.cpp @@ -0,0 +1,2165 @@ +/* + * convection_diffusion_fv1.cpp + * + * Created on: 26.02.2010 + * Author: andreasvogel + */ + +#include "convection_diffusion_fv1.h" + +#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" + +#include "lib_disc/spatial_disc/disc_util/geom_provider.h" +//#include "lib_disc/spatial_disc/disc_util/fv1_geom.h" +//#include "lib_disc/spatial_disc/disc_util/hfv1_geom.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +//////////////////////////////////////////////////////////////////////////////// +// general +//////////////////////////////////////////////////////////////////////////////// + +template +ConvectionDiffusionFV1:: +ConvectionDiffusionFV1(const char* functions, const char* subsets) + : ConvectionDiffusionBase(functions,subsets), + m_spConvShape(new ConvectionShapesNoUpwind), + m_bNonRegularGrid(false) +{ + register_all_funcs(m_bNonRegularGrid); +} + + +template +void ConvectionDiffusionFV1:: +prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid) +{ +// check number + if(vLfeID.size() != 1) + UG_THROW("ConvectionDiffusion: Wrong number of functions given. " + "Need exactly "<<1); + + if(vLfeID[0].order() != 1 || vLfeID[0].type() != LFEID::LAGRANGE) + UG_THROW("ConvectionDiffusion FV Scheme only implemented for 1st order."); + +// remember + m_bNonRegularGrid = bNonRegularGrid; + + m_LFEID = vLfeID[0]; + +// update assemble functions + register_all_funcs(m_bNonRegularGrid); +} + +template +bool ConvectionDiffusionFV1:: +use_hanging() const +{ + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Assembling functions +//////////////////////////////////////////////////////////////////////////////// + +template +template +void ConvectionDiffusionFV1:: +prep_elem_loop(const ReferenceObjectID roid, const int si) +{ + // Only first order implementation + if(!(TFVGeom::order == 1)) + UG_THROW("Only first order implementation, but other Finite Volume" + " Geometry set."); + +// check, that upwind has been set + if(m_spConvShape.invalid()) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Upwind has not been set."); + +// set local positions + if(!TFVGeom::usesHangingNodes && TFVGeom::staticLocalData) + { + static const int refDim = TElem::dim; + TFVGeom& geo = GeomProvider::get(); +// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + const MathVector* vSCVFip = geo.scvf_local_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_local_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip, false); + m_imVelocity.template set_local_ips(vSCVFip,numSCVFip, false); + m_imFlux.template set_local_ips(vSCVFip,numSCVFip, false); + m_imSource.template set_local_ips(vSCVip,numSCVip, false); + m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip, false); + m_imReactionRate.template set_local_ips(vSCVip,numSCVip, false); + m_imReaction.template set_local_ips(vSCVip,numSCVip, false); + m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imReactionExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imSourceExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imMassScale.template set_local_ips(vSCVip,numSCVip, false); + m_imMass.template set_local_ips(vSCVip,numSCVip, false); + + // init upwind for element type + if(!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Cannot init upwind for element type."); + } +} + +template +template +void ConvectionDiffusionFV1:: +fsh_elem_loop() +{} + +template +template +void ConvectionDiffusionFV1:: +prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) +{ +// Update Geometry for this element + //static TFVGeom& geo = GeomProvider::get(); +// TFVGeom& geo = GeomProvider::get(m_LFEID,1); + TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); + +// TFVGeom& geo = GeomProvider::get(); +// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + + // fix: set orientation initially globally! + geo.set_orientation(-1); + + try{ + geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::prep_elem:" + " Cannot update Finite Volume Geometry."); +// set local positions + if(TFVGeom::usesHangingNodes || !TFVGeom::staticLocalData) + { + const int refDim = TElem::dim; + const MathVector* vSCVFip = geo.scvf_local_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_local_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip); + m_imVelocity.template set_local_ips(vSCVFip,numSCVFip); + m_imFlux.template set_local_ips(vSCVFip,numSCVFip); + m_imSource.template set_local_ips(vSCVip,numSCVip); + m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip); + m_imReactionRate.template set_local_ips(vSCVip,numSCVip); + m_imReaction.template set_local_ips(vSCVip,numSCVip); + m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip); + m_imReactionExpl.template set_local_ips(vSCVip,numSCVip); + m_imSourceExpl.template set_local_ips(vSCVip,numSCVip); + m_imMassScale.template set_local_ips(vSCVip,numSCVip); + m_imMass.template set_local_ips(vSCVip,numSCVip); +/* + if(m_spConvShape.valid()) + if(!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Cannot init upwind for element type."); + */ + } + + // set global positions + const MathVector* vSCVFip = geo.scvf_global_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_global_ips(); + const size_t numSCVip = geo.num_scv_ips(); + + m_imDiffusion. set_global_ips(vSCVFip, numSCVFip); + m_imVelocity. set_global_ips(vSCVFip, numSCVFip); + m_imFlux. set_global_ips(vSCVFip, numSCVFip); + m_imSource. set_global_ips(vSCVip, numSCVip); + m_imVectorSource. set_global_ips(vSCVFip, numSCVFip); + m_imReactionRate. set_global_ips(vSCVip, numSCVip); + m_imReactionRateExpl. set_global_ips(vSCVip, numSCVip); + m_imReactionExpl. set_global_ips(vSCVip, numSCVip); + m_imSourceExpl. set_global_ips(vSCVip, numSCVip); + m_imReaction. set_global_ips(vSCVip, numSCVip); + m_imMassScale. set_global_ips(vSCVip, numSCVip); + m_imMass. set_global_ips(vSCVip, numSCVip); + +} + + +template +static TVector CalculateCenter(GridObject* o, const TVector* coords) +{ + TVector v; + VecSet(v, 0); + + size_t numCoords = 0; + switch(o->base_object_id()){ + case VERTEX: numCoords = 1; break; + case EDGE: numCoords = static_cast(o)->num_vertices(); break; + case FACE: numCoords = static_cast(o)->num_vertices(); break; + case VOLUME: numCoords = static_cast(o)->num_vertices(); break; + default: UG_THROW("Unknown element type."); break; + } + + for(size_t i = 0; i < numCoords; ++i) + VecAdd(v, v, coords[i]); + + if(numCoords > 0) + VecScale(v, v, 1. / (number)numCoords); + + return v; +} + +void LU(MathMatrix<3, 3>& R, MathMatrix<3, 3>& L, MathMatrix<3, 3> A) +{ + // n-1 Iterationsschritte + for ( size_t i = 1; i < 2; ++i) + { + for ( size_t k = i+1; i < 3; ++i) + { + L[k][i] = R[k][i] / R[i][i]; + + for ( size_t j = i; i < 3; ++i) + R[k][j] = R[k][j] - L[k][i] * R[i][j]; + } + } + +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + + bool debug = false; + bool boundary = false; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + bool bElementIsCut = geo.get_element_modus(); + + // First call with orientation = 1: + int orientation = 1; + geo.set_orientation(orientation); + + if ( !bElementIsCut ) + { + this->template add_jac_A_elem_local (geo, J, u, elem, vCornerCoords, bElementIsCut); + return; + } + + this->template add_jac_A_elem_local (geo, J, u, elem, vCornerCoords, bElementIsCut); + +// get data: + geo.resize_local_data(u); + LocalMatrix& locJ_tri = geo.get_jacobian_tri(); + + LocalVector& locU_tri = geo.get_solution_tri(); + +// reset data: + locJ_tri = 0; + + orientation *= -1; + geo.set_orientation(orientation); + try{ + geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" + " Cannot update Finite Volume Geometry."); + + this->template add_jac_A_elem_local (geo, locJ_tri, u, elem, vCornerCoords, bElementIsCut); + +// locJ_tri = 0; + + geo.set_jacobian_tri(locJ_tri); + +} + + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsCut) +{ + ug::MathMatrix diffusion = m_imDiffusion[0]; + diffusion *= 1.0; + + number areaElem = 0.0; + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + areaElem += geo.scv(ip).volume(); + + number areaScale = 1.0; + + if ( bElementIsCut ) + { + areaScale = geo.Area()/areaElem; + + UG_LOG("check area: areaElem = " << areaElem << " geo.AreaOrig() = " << geo.AreaOrig() << "\n"); + + if ( fabs(areaScale - geo.AreaScale()) > 0.00001 ) + UG_THROW("error for area: areaScale = " << areaScale << " geo.AreaScale() = " << geo.AreaScale() << "\n"); + } + + //areaScale = 1.0; + + const number kappa_1 = areaScale; + const number alpha_1 = 1.0; + const number scaleFactor = alpha_1 * kappa_1; + +// Diff. Tensor times Gradient + MathVector Dgrad; + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// Diffusion and Velocity Term + if(m_imDiffusion.data_given() || m_imVelocity.data_given()) + { + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCV + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + //////////////////////////////////////////////////// + // Diffusive Term + //////////////////////////////////////////////////// + if(m_imDiffusion.data_given()) + { + number add = 0.0; + + // loop shape functions + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + // Compute Diffusion Tensor times Gradient + MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); + + // Compute flux at IP + const number D_diff_flux = VecDot(Dgrad, scvf.normal()); + + UG_LOG("sh = " << sh << " D_diff_flux = " << D_diff_flux << "\n"); + + J(_C_, scvf.from(), _C_, sh) -= areaScale * D_diff_flux; + J(_C_, scvf.to() , _C_, sh) += areaScale * D_diff_flux; + } + + } + + } // end ip-loop + + //////////////////////////////////////////////////// + // Boundary Terms + //////////////////////////////////////////////////// + + if ( bElementIsCut ) + { + // loop trial space + MathVector NormalToFace = geo.NormalToFace(); + + const typename TFVGeom::SCVF& scvf = geo.scvf(0); + for(size_t j = 0; j < geo.num_sh(); ++j) + { + // Diffusion + if(m_imDiffusion.data_given()) + MatVecMult(Dgrad, m_imDiffusion[0], scvf.global_grad(j)); + else + VecSet(Dgrad, 0.0); + + // loop test space + for(size_t i = 0; i < geo.num_sh(); ++i) + { + // multiply by integral along Gamma of shape fct \phi_i + number integrand = VecDot(Dgrad, NormalToFace) * geo.IntegralGamma(i); + UG_LOG("geo.IntegralGamma(i): " << geo.IntegralGamma(i) << "\n"); + + // SUBTRACT to local matrix + J(_C_, i, _C_, j) -= scaleFactor * integrand; // = (grad(U), phi_i) + J(_C_, j, _C_, i) -= scaleFactor * integrand; // = (U, grad(phi_j)) + + } // end i-loop + + } // end j-loop + + } + + } + +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + double diffusion = 10.0; + + if ( bElementIsOutside ) + diffusion = 1.0; + + std::vector& vBF = geo.get_boundary_faces(); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + +// loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + + // loop trial space + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + { + UG_LOG("bf.node_id(): " << bf.node_id() << "\n"); + UG_LOG("bf.global_grad(sh): " << bf.global_grad(sh) << "\n"); + UG_LOG("normal(): " << bf.normal() << "\n"); + + // add to local matrix + J(_C_, bf.node_id(), _C_, sh) += VecDot(bf.global_grad(sh), bf.normal()); + J(_C_, bf.node_id(), _C_, sh) *= diffusion; + } + } + +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + if(!m_imMassScale.data_given()) return; + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local matrix + J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip]; + } + +// m_imMass part does not explicitly depend on associated unknown function +} + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + bool debug = false; + bool boundary = false; + bool add = true; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + bool bElementIsCut = geo.get_element_modus(); + + // First call with orientation = 1: + int orientation = 1; + geo.set_orientation(orientation); + + if ( bElementIsCut ) + { + geo.print_Nitsche_Data(); + + for(size_t i = 0; i < 3; ++i) + { + UG_LOG("vAlpha(i,0): " << geo.vAlpha(i,0) << "\n"); + UG_LOG("vAlpha(i,1): " << geo.vAlpha(i,1) << "\n"); + UG_LOG("Integral(i): " << geo.IntegralGamma(i) << "\n"); + } + + UG_LOG("m_vIntersectionPnts(0): " << geo.vIntersectionPnts(0) << "\n"); + UG_LOG("m_vIntersectionPnts(1): " << geo.vIntersectionPnts(1) << "\n"); + UG_LOG("m_vShapeValues: " << geo.ShapeValues() << "\n"); + UG_LOG("m_NormalToFace: " << geo.NormalToFace() << "\n"); + UG_LOG("m_Gamma: " << geo.Gamma() << "\n"); + UG_LOG("m_Area: " << geo.Area() << "\n"); + } + + if ( !bElementIsCut ) + { + this->template add_def_A_elem_local (geo, d, u, elem, vCornerCoords, bElementIsCut); + return; + } + + this->template add_def_A_elem_local (geo, d, u, elem, vCornerCoords, bElementIsCut); + +// get data: + geo.resize_local_data(u); + LocalVector& locD_tri = geo.get_defect_tri(); + + LocalVector& locU_tri = geo.get_solution_tri(); + +// reset data: + locD_tri = 0; + + orientation*= -1; + geo.set_orientation(orientation); + try{ + geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" + " Cannot update Finite Volume Geometry."); + + this->template add_def_A_elem_local (geo, locD_tri, u, elem, vCornerCoords, bElementIsCut); + + geo.set_defect_tri(locD_tri); + +} + +template +number get_exact_sol_test(MathVector position) +{ + return sin(2*M_PI*position[0]) + sin(2*M_PI*position[1]); +} + +template +number get_exact_sol_Gangl(MathVector position) +{ + double kappa_2 = 10.0; + double dist_x = position[0] - 0.1; + double dist_y = position[1] - 0.2; + double sqR = 0.4*0.4; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = -4*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_2 - 1); + + if ( dist >= 0.4 ) + returnValue = -2*kappa_2*sqDist*sqDist; + + return returnValue; +} + +template +MathVector get_exact_grad_Gangl(MathVector position) +{ + double kappa_2 = 10.0; + double dist_x = position[0] - 0.1; + double dist_y = position[1] - 0.2; + double sqR = 0.4*0.4; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double factor = -8*kappa_2*kappa_2*sqR; + + if ( dist >= 0.4 ) + factor = -8*kappa_2*sqDist; + + MathVector returnVector; + returnVector[0] = factor*dist_x; + returnVector[1] = factor*dist_y; + + return returnVector; +} + +template +MathVector get_exact_grad_FedkiwEx5(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + double radius = 0.5; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double absValue = position[0]*position[0] + position[1]* position[1]; + + MathVector returnVector; + returnVector[0] = 0.0; + returnVector[1] = 0.0; + + double factor = 1.0/absValue; + if ( dist >= radius ) + { + returnVector[0] = factor*position[0]; + returnVector[1] = factor*position[1]; + } + + return returnVector; + +} + +template +number get_exact_sol_FedkiwEx6(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + double radius = 0.5; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = 0.0; + + if ( dist <= radius ) + returnValue = exp(position[0])*cos(position[1]); + + return returnValue; +} + +template +number get_exact_sol_FedkiwEx5(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + + double dist_x = position[0]-center_x; + double dist_y = position[1]-center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = 1.0; + + if ( dist > 0.5 ) + returnValue = 1.0 + log(2*dist); + + return returnValue; +} + +template +number get_exact_sol_FedkiwEx3(MathVector position) +{ + double center_x = 0.5; + double center_y = 0.5; + double radius = 0.25; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double absValue = position[0]*position[0] + position[1]* position[1]; + + double returnValue = 0.0; + + if ( dist <= radius ) + returnValue = exp(-absValue); + + return returnValue; +} + +template +MathVector get_exact_grad(MathVector position) +{ + +} + +////////////////////////////////////////////////////////////////////// +// code see ugbase/lib_disc/function_spaces/integrate.h: evaluate() for +// --> L2ErrorIntegrand (for value) +// --> H1ErrorIntegrand (for gradient): lines 1873-1910 +// +// called bei Integrate() via method 'integrand.values': +// integrand.values(&(vValue[0]), &(vGlobIP[0]), +// pElem, &vCorner[0], rQuadRule.points(), +// &(vJT[0]), +// numIP); +// +////////////////////////////////////////////////////////////////////// +template +template +number ConvectionDiffusionFV1:: +add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem) +{ + number integral = 0; + + std::vector > vCorner; + std::vector > vGlobIP; + std::vector > vLocIP; + std::vector > vJT; + std::vector vValue; + std::vector vValueGrad; + + QuadType type = GetQuadratureType("best"); + + const QuadratureRule& rQuadRule + = QuadratureRuleProvider::get(roid, 1, type); + +// get reference element mapping by reference object id + DimReferenceMapping& mapping + = ReferenceMappingProvider::get(roid); + +// number of integration points + const size_t numIP = rQuadRule.size(); + +// get all corner coordinates +// CollectCornerCoordinates(vCorner, *pElem, aaPos, true); + + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(roid); + + vCorner.clear(); +// remember global position of nodes + for(size_t i = 0; i < rRefElem.num(0); ++i) + vCorner.push_back(geo.get_corner(i)); + + for ( size_t i = 0; i < rRefElem.num(0); ++i) + UG_LOG("vCorner" << vCorner[i][0] << " and " << vCorner[i][1] << "\n" ); + UG_LOG("\n" ); + +// update the reference mapping for the corners + mapping.update(vCorner); + +// compute global integration points + vGlobIP.resize(numIP); + mapping.local_to_global(&(vGlobIP[0]), rQuadRule.points(), numIP); + + UG_LOG("vGlobIP" << vGlobIP[0][0] << " and " << vGlobIP[0][1] << "\n" ); + UG_LOG("\n" ); + +// compute local integration points + vLocIP.resize(numIP); + for(size_t ip = 0; ip < numIP; ++ip) + vLocIP[ip] = rQuadRule.points()[ip]; + + UG_LOG("vLocIP" << vLocIP[0][0] << " and " << vLocIP[0][1] << "\n" ); + UG_LOG("\n" ); + + +// compute transformation matrices + vJT.resize(numIP); + mapping.jacobian_transposed(&(vJT[0]), rQuadRule.points(), numIP); + + const size_t num_sh = geo.num_scvf(); + + if ( num_sh != rRefElem.num(0) ) + UG_THROW("wrong number of corners: sh = " << num_sh << ", but rRefElem.num(0) = " << rRefElem.num(0) << "\n"); + +// compute integrand values at integration points + vValue.resize(numIP); + vValueGrad.resize(numIP); + + try + { + // loop all integration points + for(size_t ip = 0; ip < numIP; ++ip) + { + // compute exact solution at integration point + number exactSolIP = get_exact_sol_Gangl(vGlobIP[ip]); + + // compute exact gradient at integration point + MathVector exactGradIP = get_exact_grad_FedkiwEx5(vGlobIP[ip]); + + // compute approximated solution at integration point + number approxSolIP = 0.0; + MathVector locTmp; VecSet(locTmp, 0.0); + + const typename TFVGeom::SCV& scv = geo.scv(ip); + + for(size_t sh = 0; sh < num_sh; ++sh) + { + // add shape fct at ip * value at shape + approxSolIP += u(_C_,sh) * geo.get_shape(sh, vLocIP[ip], roid); + + // add gradient at ip + VecScaleAppend(locTmp, u(_C_,sh), scv.local_grad(sh)); + } + + // get squared of difference + vValue[ip] = (exactSolIP - approxSolIP); + vValue[ip] *= vValue[ip]; + + // compute global gradient + MathVector approxGradIP; + MathMatrix JTInv; + Inverse(JTInv, vJT[ip]); + MatVecMult(approxGradIP, JTInv, locTmp); + + // get error of gradient + vValueGrad[ip] = VecDistanceSq(approxGradIP, exactGradIP); + + + } +/* integrand.values(&(vValue[0]), &(vGlobIP[0]), + pElem, &vCorner[0], rQuadRule.points(), + &(vJT[0]), + numIP); +*/ + } + UG_CATCH_THROW("Unable to compute values of integrand at integration point."); + +// reset contribution of this element + number intValElem = 0; + +// loop integration points + for(size_t ip = 0; ip < numIP; ++ip) + { + // get quadrature weight + const number weightIP = rQuadRule.weight(ip); + + // get determinate of mapping + const number det = SqrtGramDeterminant(vJT[ip]); + + // add contribution of integration point + intValElem += vValue[ip] * weightIP * det; +// intValElem += vValueGrad[ip] * weightIP * det; + + } + +// add to global sum + + UG_LOG("added: " << intValElem << "\n\n"); + + return intValElem; +} + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + double diffusion = 10.0; + + if ( bElementIsOutside ) + diffusion = 1.0; + + std::vector& vBF = geo.get_boundary_faces(); + MathVector Dgrad; + VecSet(Dgrad, 0.0); + + UG_LOG("---------- vBF.size(): " << vBF.size() << "\n"); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + +// set solution +/* for(size_t sh = 0; sh < geo.num_sh(); ++sh) + { + u(_C_, sh) = 1.0; + u(_C_, sh) -= corners[sh][0]*(2*corners[sh][0] - 1.0); + u(_C_, sh) -= corners[sh][1]*(2*corners[sh][1] - 1.0); + } +*/ +// u(_C_, sh) = 1 - 2*(corners[sh][0]*corners[sh][0] + corners[sh][1]*corners[sh][1]) - (corners[sh][0]+corners[sh][1]); +// u(_C_, sh) = corners[sh][1]*(2*corners[sh][1] - 1.0); +// u(_C_, sh) = (1.0 - corners[sh][0] - corners[sh][1]) * (1.0 - 2*corners[sh][0] - 2*corners[sh][1]); +// u(_C_, sh) = corners[sh][1]; +// for(size_t sh = 0; sh < geo.num_sh(); ++sh) +// u(_C_, sh) = corners[sh][0]*(2*corners[sh][0] - 1.0); //corners[sh][0]; + // u(_C_, sh) = corners[sh][0]*(2* corners[sh][0]-1); + +//////////////////////////////////////////////////////////////////////////////// +// NO loop integration points! +// /* for(size_t ip = 0; ip < vBF.size(); ++ip) */ +// Reason: the length of the normal is already the length of the total face (NOT the scvf!) +//////////////////////////////////////////////////////////////////////////////// + +// loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + VecSet(Dgrad, 0.0); + + // loop trial space + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + { + // Diffusion + UG_LOG("bf.num_sh(): " << bf.num_sh() << "\n"); + UG_LOG("Dgrad: " << Dgrad << "\n"); + UG_LOG("bf.normal(): " << bf.normal() << "\n"); + UG_LOG("bf.global_grad(ip, sh): " << bf.global_grad(sh) << "\n"); + + UG_LOG("u(_C_, sh): " << u(_C_, sh) << "\n"); + + VecScaleAppend(Dgrad, diffusion * u(_C_, sh), bf.global_grad(sh)); + } + + // add to local vector + d(_C_, bf.node_id()) += VecDot(Dgrad, bf.normal()); + + } + + UG_LOG("---------- end ----------- \n\n"); + +} + + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsCut) +{ + ug::MathMatrix diffusion = m_imDiffusion[0]; + diffusion *= 1.0; + + number areaElem = 0.0; + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + areaElem += geo.scv(ip).volume(); + + number areaScale = 1.0; + + if ( bElementIsCut ) + { + areaScale = geo.Area()/areaElem; + UG_LOG("check area: areaElem = " << areaElem << " geo.AreaOrig() = " << geo.AreaOrig() << "\n"); + + if ( fabs(areaScale - geo.AreaScale()) > 0.00001 ) + UG_LOG("error for area: areaScale = " << areaScale << " geo.AreaScale() = " << geo.AreaScale() << "\n"); + } + + const number kappa_1 = areaScale; + const number alpha_1 = 1.0; + const number scaleFactor = alpha_1 * kappa_1; + + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + ///////////////////////////////////////////////////// + // Diffusive Term + ///////////////////////////////////////////////////// + if(m_imDiffusion.data_given()) + { + // to compute D \nabla c + MathVector Dgrad_c, grad_c; + MathVector Dgrad_debug, grad_debug; + + // compute gradient and shape at ip + VecSet(grad_c, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + VecScaleAppend(grad_c, u(_C_,sh), scvf.global_grad(sh)); + UG_LOG("u(_C_,sh) " << u(_C_,sh) << "\n"); + } + // scale by diffusion tensor + MatVecMult(Dgrad_c, diffusion, grad_c); + + // Compute flux + const number diff_flux = VecDot(Dgrad_c, scvf.normal()); + + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + VecSet(grad_debug, 0.0); + VecScaleAppend(grad_debug, 1.0, scvf.global_grad(sh)); + MatVecMult(Dgrad_debug, diffusion, grad_debug); + const number diff_flux_debug = VecDot(Dgrad_debug, scvf.normal()); + + UG_LOG("sh: " << sh << "diff_flux_debug = " << diff_flux_debug << "\n"); + } + + // Add to local defect + d(_C_, scvf.from()) -= areaScale * diff_flux; + d(_C_, scvf.to() ) += areaScale * diff_flux; + + } + + } // end ip-loop + + //////////////////////////////////////////////////// + // Boundary Terms + //////////////////////////////////////////////////// + + if ( bElementIsCut ) + { + // loop trial space + MathVector NormalToFace = geo.NormalToFace(); + + MathVector Dgrad, grad; + VecSet(grad, 0.0); + + const typename TFVGeom::SCVF& scvf = geo.scvf(0); + //////////////////////////////////////////////////// + // FIRST TERM OF BOUNDARY + for(size_t j = 0; j < geo.num_sh(); ++j) + VecScaleAppend(grad, u(_C_,j), scvf.global_grad(j)); + + MatVecMult(Dgrad, diffusion, grad); + + number integrand1_1 = VecDot(Dgrad, NormalToFace); + + // loop test space + for(size_t i = 0; i < geo.num_sh(); ++i) + { + // multiply by integral along Gamma of shape fct \phi_i + number integrand2_1 = geo.IntegralGamma(i); + UG_LOG("geo.IntegralGamma(i): " << geo.IntegralGamma(i) << "\n"); + + // SUBTRACT to local defect + d(_C_, i) -= scaleFactor * integrand1_1 * integrand2_1; + + } // end i-loop + + + //////////////////////////////////////////////////// + // SECOND TERM OF BOUNDARY + + number integrand2_1 = 0.0; + for(size_t j = 0; j < geo.num_sh(); ++j) + integrand2_1 += u(_C_,j) * geo.IntegralGamma(j); + + // loop test space + for(size_t i = 0; i < geo.num_sh(); ++i) + { + VecSet(grad, 0.0); + VecSet(Dgrad, 0.0); + + MatVecMult(Dgrad, diffusion, scvf.global_grad(i)); + number integrand2_2 = VecDot(Dgrad, NormalToFace); + + // SUBTRACT to local defect + d(_C_, i) -= scaleFactor * integrand2_1 * integrand2_2; + // da jump [U] = 0! + } // end i-loop + } + + + ////////////////////////////////////////////////////////////// + // Source Term - NOT added during 'add_rhs_elm()': + // during elem_disc_assemble: rhs is NOT added anymore!! + ////////////////////////////////////////////////////////////// + + if ( m_imSource.data_given() ) + { + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) += areaScale * m_imSource[ip] * scv.volume(); + UG_LOG("scv.volume() = " << scv.volume() << "\n"); + } + } + +} + + +template +template +void ConvectionDiffusionFV1:: +add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + +// reaction rate + if(m_imReactionRateExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local defect + d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume(); + } + } + +// reaction + if(m_imReactionExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local defect + d(_C_, co) += m_imReactionExpl[ip] * scv.volume(); + } + } + + if(m_imSourceExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) -= m_imSourceExpl[ip] * scv.volume(); + } + } +} + +template +template +void ConvectionDiffusionFV1:: +add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + if(!m_imMassScale.data_given() && !m_imMass.data_given()) return; + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // mass value + number val = 0.0; + + // multiply by scaling + if(m_imMassScale.data_given()) + val += m_imMassScale[ip] * u(_C_, co); + + // add mass + if(m_imMass.data_given()) + val += m_imMass[ip]; + + // Add to local defect + d(_C_, co) += val * scv.volume(); + } +} + + +template +template +void ConvectionDiffusionFV1:: +add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) +{ + ///////////////////////////////////////////////////// + // add rhs ALLREADY(!) during 'add_def_A_elem_local()' method! + // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! + ///////////////////////////////////////////////////// + + return; + + // get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + // loop Sub Control Volumes (SCV) + if ( m_imSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) += m_imSource[ip] * scv.volume(); + } + } + + // loop Sub Control Volumes (SCVF) + if ( m_imVectorSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); + + // Add to local rhs + d(_C_, scvf.from()) -= VecDot(m_imVectorSource[ip], scvf.normal() ); + d(_C_, scvf.to() ) += VecDot(m_imVectorSource[ip], scvf.normal() ); + } + } +} + + +//////////////////////////////////// +/// error estimation (begin) /// + +// prepares the loop over all elements of one type for the computation of the error estimator +template +template +void ConvectionDiffusionFV1:: +prep_err_est_elem_loop(const ReferenceObjectID roid, const int si) +{ + // get the error estimator data object and check that it is of the right type + // we check this at this point in order to be able to dispense with this check later on + // (i.e. in prep_err_est_elem and compute_err_est_A_elem()) + if (this->m_spErrEstData.get() == NULL) + { + UG_THROW("No ErrEstData object has been given to this ElemDisc!"); + } + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (!err_est_data) + { + UG_THROW("Dynamic cast to SideAndElemErrEstData failed." + << std::endl << "Make sure you handed the correct type of ErrEstData to this discretization."); + } + + +// check that upwind has been set + if (m_spConvShape.invalid()) + UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " + "Upwind has not been set."); + +// set local positions + if (!TFVGeom::usesHangingNodes) + { + static const int refDim = TElem::dim; + + // get local IPs + size_t numSideIPs, numElemIPs; + const MathVector* sideIPs; + const MathVector* elemIPs; + try + { + numSideIPs = err_est_data->num_all_side_ips(roid); + numElemIPs = err_est_data->num_elem_ips(roid); + sideIPs = err_est_data->template side_local_ips(roid); + elemIPs = err_est_data->template elem_local_ips(roid); + + if (!sideIPs || !elemIPs) return; // are NULL if TElem is not of the same dim as TDomain + } + UG_CATCH_THROW("Integration points for error estimator cannot be set."); + + // set local IPs in imports + m_imDiffusion.template set_local_ips(sideIPs, numSideIPs, false); + m_imVelocity.template set_local_ips(sideIPs, numSideIPs, false); + m_imFlux.template set_local_ips(sideIPs, numSideIPs, false); + m_imSource.template set_local_ips(elemIPs, numElemIPs, false); + m_imVectorSource.template set_local_ips(sideIPs, numSideIPs, false); + m_imReactionRate.template set_local_ips(elemIPs, numElemIPs, false); + m_imReaction.template set_local_ips(elemIPs, numElemIPs, false); + m_imMassScale.template set_local_ips(elemIPs, numElemIPs, false); + m_imMass.template set_local_ips(elemIPs, numElemIPs, false); + + // init upwind for element type + TFVGeom& geo = GeomProvider::get(); + if (!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " + "Cannot init upwind for element type."); + + // store values of shape functions in local IPs + LagrangeP1::reference_element_type> trialSpace + = Provider::reference_element_type> >::get(); + + m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh()); + for (size_t ip = 0; ip < numElemIPs; ip++) + trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]); + for (size_t ip = 0; ip < numSideIPs; ip++) + trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]); + } +} + +template +template +void ConvectionDiffusionFV1:: +prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{} + +// computes the error estimator contribution (stiffness part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ + typedef typename reference_element_traits::reference_element_type ref_elem_type; + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + +// request geometry + static const TFVGeom& geo = GeomProvider::get(); + +//////////////// +// SIDE TERMS // +//////////////// + +// get the sides of the element + // We have to cast elem to a pointer of type SideAndElemErrEstData::elem_type + // for the SideAndElemErrEstData::operator() to work properly. + // This cannot generally be achieved by casting to TElem*, since this method is also registered for + // lower-dimensional types TElem, and must therefore be compilable, even if it is never EVER to be executed. + // The way we achieve this here, is by calling associated_elements_sorted() which has an implementation for + // all possible types. Whatever comes out of it is of course complete nonsense if (and only if) + // SideAndElemErrEstData::elem_type != TElem. To be on the safe side, we throw an error if the number of + // entries in the list is not as it should be. + + typename MultiGrid::traits::side_type>::secure_container side_list; + pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); + if (side_list.size() != (size_t) ref_elem_type::numSides) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// some help variables + MathVector fluxDensity, gradC, normal; + +// calculate grad u (take grad from first scvf ip (grad u is constant on the entire element)) + if (geo.num_scvf() < 1) {UG_THROW("Element has no SCVFs!");} + const typename TFVGeom::SCVF& scvf = geo.scvf(0); + + VecSet(gradC, 0.0); + for (size_t j=0; j(normal, side, vCornerCoords); + VecNormalize(normal, normal); + + try + { + for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) + { + size_t ip = passedIPs + sip; + + VecSet(fluxDensity, 0.0); + + ////// diffusion ////// + if (m_imDiffusion.data_given()) + MatVecScaleMultAppend(fluxDensity, -1.0, m_imDiffusion[0], gradC); + + ////// convection ////// + if (m_imVelocity.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtSideIP(sh,sip); + + VecScaleAppend(fluxDensity, val, m_imVelocity[ip]); + } + + ////// general flux ////// + if (m_imFlux.data_given()) + VecAppend(fluxDensity, m_imFlux[ip]); + + (*err_est_data)(side_list[side],sip) += scale * VecDot(fluxDensity, normal); + } + + passedIPs += err_est_data->num_side_ips(side_list[side]); + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); + } + +////////////////// +// VOLUME TERMS // +////////////////// + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + { + number total = 0.0; + + ////// diffusion ////// TODO ONLY FOR (PIECEWISE) CONSTANT DIFFUSION TENSOR SO FAR! + // div(D*grad(c)) = div(v)*u + v*grad(c) + // nothing to do, as u is piecewise linear and div(D*grad(c)) disappears + + ////// convection ////// TODO ONLY FOR CONSTANT VELOCITY FIELDS SO FAR! + // div(v*c) = div(v)*u + v*grad(c) -- gradC has been calculated above + if (m_imVelocity.data_given()) + total += VecDot(m_imVelocity[ip], gradC); + + ////// general flux ////// TODO ONLY FOR DIVERGENCE-FREE FLUX FIELD SO FAR! + // nothing to do + + ////// reaction ////// + if (m_imReactionRate.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < geo.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); + + total += m_imReactionRate[ip] * val; + } + + if (m_imReaction.data_given()) + { + total += m_imReaction[ip]; + } + + (*err_est_data)(elem_list[0],ip) += scale * total; + } + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// computes the error estimator contribution (mass part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ +// note: mass parts only enter volume term + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// request geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop integration points + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + { + number total = 0.0; + + ////// mass scale ////// + if (m_imMassScale.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < geo.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); + + total += m_imMassScale[ip] * val; + } + + ////// mass ////// + if (m_imMass.data_given()) + { + total += m_imMass[ip]; + } + + (*err_est_data)(elem_list[0],ip) += scale * total; + } + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// computes the error estimator contribution (rhs part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ + typedef typename reference_element_traits::reference_element_type ref_elem_type; + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + +//////////////// +// SIDE TERMS // +//////////////// +// get the sides of the element + typename MultiGrid::traits::side_type>::secure_container side_list; + pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); + if (side_list.size() != (size_t) ref_elem_type::numSides) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// loop sides + size_t passedIPs = 0; + for (size_t side = 0; side < (size_t) ref_elem_type::numSides; side++) + { + // normal on side + MathVector normal; + SideNormal(normal, side, vCornerCoords); + VecNormalize(normal, normal); + + try + { + for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) + { + size_t ip = passedIPs + sip; + + ////// vector source ////// + if (m_imVectorSource.data_given()) + (*err_est_data)(side_list[side],sip) += scale * VecDot(m_imVectorSource[ip], normal); + } + + passedIPs += err_est_data->num_side_ips(side_list[side]); + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); + } + +////////////////// +// VOLUME TERMS // +////////////////// + if (!m_imSource.data_given()) return; + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +////// source ////// + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + (*err_est_data)(elem_list[0],ip) += scale * m_imSource[ip]; + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// postprocesses the loop over all elements of one type in the computation of the error estimator +template +template +void ConvectionDiffusionFV1:: +fsh_err_est_elem_loop() +{ +// finish the element loop in the same way as the actual discretization + this->template fsh_elem_loop (); +}; + +/// error estimation (end) /// +//////////////////////////////////// + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +lin_def_velocity(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // sum up contributions of convection shapes + MathVector linDefect; + VecSet(linDefect, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(linDefect, u(_C_,sh), convShape.D_vel(ip, sh)); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] += linDefect; + vvvLinDef[ip][_C_][scvf.to()] -= linDefect; + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +lin_def_diffusion(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // compute gradient at ip + MathVector grad_u; VecSet(grad_u, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad_u, u(_C_,sh), scvf.global_grad(sh)); + + // compute the lin defect at this ip + MathMatrix linDefect; + + // part coming from -\nabla u * \vec{n} + for(size_t k=0; k < (size_t)dim; ++k) + for(size_t j = 0; j < (size_t)dim; ++j) + linDefect(j,k) = (scvf.normal())[j] * grad_u[k]; + + // add contribution from convection shapes + if(convShape.non_zero_deriv_diffusion()) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + MatAdd(linDefect, convShape.D_diffusion(ip, sh), u(_C_, sh)); + + // add contributions + vvvLinDef[ip][_C_][scvf.from()] -= linDefect; + vvvLinDef[ip][_C_][scvf.to() ] += linDefect; + } +} + +template +template +void ConvectionDiffusionFV1:: +lin_def_flux(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] += scvf.normal(); + vvvLinDef[ip][_C_][scvf.to()] -= scvf.normal(); + } +} +// computes the linearized defect w.r.t to the reaction rate +template +template +void ConvectionDiffusionFV1:: +lin_def_reaction_rate(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = u(_C_, co) * scv.volume(); + } +} + +// computes the linearized defect w.r.t to the reaction +template +template +void ConvectionDiffusionFV1:: +lin_def_reaction(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the source +template +template +void ConvectionDiffusionFV1:: +lin_def_source(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the vector source +// (in analogy to velocity) +template +template +void ConvectionDiffusionFV1:: +lin_def_vector_source(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ + // get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + + // loop Sub Control Volumes Faces (SCVF) + for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] -= scvf.normal(); + vvvLinDef[ip][_C_][scvf.to()] += scvf.normal(); + } +} + +// computes the linearized defect w.r.t to the mass scale +template +template +void ConvectionDiffusionFV1:: +lin_def_mass_scale(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t co = 0; co < geo.num_scv(); ++co) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(co); + + // Check associated node + UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); + + // set lin defect + vvvLinDef[co][_C_][co] = u(_C_, co) * scv.volume(); + } +} + +// computes the linearized defect w.r.t to the mass scale +template +template +void ConvectionDiffusionFV1:: +lin_def_mass(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t co = 0; co < geo.num_scv(); ++co) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(co); + + // Check associated node + UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); + + // set lin defect + vvvLinDef[co][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +ex_value(number vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > vvvDeriv[]) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reference element + typedef typename reference_element_traits::reference_element_type + ref_elem_type; + +// number of shape functions + static const size_t numSH = ref_elem_type::numCorners; + +// FV1 SCVF ip + if(vLocIP == geo.scvf_local_ips()) + { + // Loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // Get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // compute concentration at ip + vValue[ip] = 0.0; + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vValue[ip] += u(_C_, sh) * scvf.shape(sh); + + // compute derivative w.r.t. to unknowns iff needed + if(bDeriv) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vvvDeriv[ip][_C_][sh] = scvf.shape(sh); + } + } +// FV1 SCV ip + else if(vLocIP == geo.scv_local_ips()) + { + // solution at ip + for(size_t sh = 0; sh < numSH; ++sh) + vValue[sh] = u(_C_, sh); + + // set derivatives if needed + if(bDeriv) + for(size_t sh = 0; sh < numSH; ++sh) + for(size_t sh2 = 0; sh2 < numSH; ++sh2) + vvvDeriv[sh][_C_][sh2] = (sh==sh2) ? 1.0 : 0.0; + } +// general case + else + { + // get trial space + LagrangeP1& rTrialSpace = Provider >::get(); + + // storage for shape function at ip + number vShape[numSH]; + + // loop ips + for(size_t ip = 0; ip < nip; ++ip) + { + // evaluate at shapes at ip + rTrialSpace.shapes(vShape, vLocIP[ip]); + + // compute concentration at ip + vValue[ip] = 0.0; + for(size_t sh = 0; sh < numSH; ++sh) + vValue[ip] += u(_C_, sh) * vShape[sh]; + + // compute derivative w.r.t. to unknowns iff needed + // \todo: maybe store shapes directly in vvvDeriv + if(bDeriv) + for(size_t sh = 0; sh < numSH; ++sh) + vvvDeriv[ip][_C_][sh] = vShape[sh]; + } + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +ex_grad(MathVector vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > > vvvDeriv[]) +{ +// Get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reference element + typedef typename reference_element_traits::reference_element_type + ref_elem_type; + +// reference dimension + static const int refDim = ref_elem_type::dim; + +// number of shape functions + static const size_t numSH = ref_elem_type::numCorners; + +// FV1 SCVF ip + if(vLocIP == geo.scvf_local_ips()) + { + // Loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // Get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + VecSet(vValue[ip], 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(vValue[ip], u(_C_, sh), scvf.global_grad(sh)); + + if(bDeriv) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vvvDeriv[ip][_C_][sh] = scvf.global_grad(sh); + } + } +// general case + else + { + // get trial space + LagrangeP1& rTrialSpace = Provider >::get(); + + // storage for shape function at ip + MathVector vLocGrad[numSH]; + MathVector locGrad; + + // Reference Mapping + MathMatrix JTInv; + ReferenceMapping mapping(vCornerCoords); + + // loop ips + for(size_t ip = 0; ip < nip; ++ip) + { + // evaluate at shapes at ip + rTrialSpace.grads(vLocGrad, vLocIP[ip]); + + // compute grad at ip + VecSet(locGrad, 0.0); + for(size_t sh = 0; sh < numSH; ++sh) + VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]); + + // compute global grad + mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]); + MatVecMult(vValue[ip], JTInv, locGrad); + + // compute derivative w.r.t. to unknowns iff needed + if(bDeriv) + for(size_t sh = 0; sh < numSH; ++sh) + MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// upwind +//////////////////////////////////////////////////////////////////////////////// + +template +void ConvectionDiffusionFV1:: +set_upwind(SmartPtr > shapes) {m_spConvShape = shapes;} + +// computes the linearized defect w.r.t to the velocity +template +const typename ConvectionDiffusionFV1::conv_shape_type& +ConvectionDiffusionFV1:: +get_updated_conv_shapes(const FVGeometryBase& geo) +{ +// compute upwind shapes for transport equation +// \todo: we should move this computation into the preparation part of the +// disc, to only compute the shapes once, reusing them several times. + if(m_imVelocity.data_given()) + { + // get diffusion at ips + const MathMatrix* vDiffusion = NULL; + if(m_imDiffusion.data_given()) vDiffusion = m_imDiffusion.values(); + + // update convection shapes + if(!m_spConvShape->update(&geo, m_imVelocity.values(), vDiffusion, true)) + { + UG_LOG("ERROR in 'ConvectionDiffusionFV1::add_jac_A_elem': " + "Cannot compute convection shapes.\n"); + } + } + +// return a const (!!) reference to the upwind + return *const_cast*>(m_spConvShape.get()); +} + + +//////////////////////////////////////////////////////////////////////////////// +// register assemble functions +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + + /* +// switch assemble functions + if(!bHang) + { + register_func >(); + } + else + { + register_func >(); + } +*/ +} +#endif + +#ifdef UG_DIM_2 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + /* +// switch assemble functions + if(!bHang) + { + register_func >(); + register_func >(); + register_func >(); + } + else + { + register_func >(); + register_func >(); + register_func >(); + } + */ +} +#endif + +#ifdef UG_DIM_3 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + /* +// switch assemble functions + if(!bHang) + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + } + else + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + } + */ +} +#endif + +template +template +void ConvectionDiffusionFV1:: +register_func() +{ + ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; + typedef this_type T; + static const int refDim = reference_element_traits::dim; + + this->clear_add_fct(id); + this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); + this->set_prep_elem_fct( id, &T::template prep_elem); + this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); + this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem); + this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem); + this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem); + this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem); + this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem); + this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); + +// error estimator parts +/* this->set_prep_err_est_elem_loop(id, &T::template prep_err_est_elem_loop); + this->set_prep_err_est_elem(id, &T::template prep_err_est_elem); + this->set_compute_err_est_A_elem(id, &T::template compute_err_est_A_elem); + this->set_compute_err_est_M_elem(id, &T::template compute_err_est_M_elem); + this->set_compute_err_est_rhs_elem(id, &T::template compute_err_est_rhs_elem); + this->set_fsh_err_est_elem_loop(id, &T::template fsh_err_est_elem_loop); +*/ +// set computation of linearized defect w.r.t velocity + m_imDiffusion.set_fct(id, this, &T::template lin_def_diffusion); + m_imVelocity. set_fct(id, this, &T::template lin_def_velocity); + m_imFlux.set_fct(id, this, &T::template lin_def_flux); + m_imReactionRate. set_fct(id, this, &T::template lin_def_reaction_rate); + m_imReaction. set_fct(id, this, &T::template lin_def_reaction); + m_imSource. set_fct(id, this, &T::template lin_def_source); + m_imVectorSource.set_fct(id, this, &T::template lin_def_vector_source); + m_imMassScale.set_fct(id, this, &T::template lin_def_mass_scale); + m_imMass. set_fct(id, this, &T::template lin_def_mass); + +// exports + m_exValue-> template set_fct(id, this, &T::template ex_value); + m_exGrad->template set_fct(id, this, &T::template ex_grad); +} + +//////////////////////////////////////////////////////////////////////////////// +// explicit template instantiations +//////////////////////////////////////////////////////////////////////////////// +#ifdef UG_DIM_1 +template class ConvectionDiffusionFV1; +#endif +#ifdef UG_DIM_2 +template class ConvectionDiffusionFV1; +#endif +#ifdef UG_DIM_3 +template class ConvectionDiffusionFV1; +#endif + +} // end namespace ConvectionDiffusionPlugin +} // namespace ug + diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.h b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.h new file mode 100644 index 0000000..f457dee --- /dev/null +++ b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.h @@ -0,0 +1,326 @@ +/* + * convection_diffusion_fv1.h + * + * Created on: 26.02.2010 + * Author: andreasvogel + */ + +#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ +#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ + +// library intern headers +#include "../convection_diffusion_base.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +// \ingroup lib_disc_elem_disc +/// \addtogroup convection_diffusion +/// \{ + +/// Discretization for the Convection-Diffusion Equation +/** + * This class implements the IElemDisc interface to provide element local + * assemblings for the convection diffusion equation. + * The Equation has the form + * \f[ + * \partial_t (m1*c + m2) - \nabla \left( D \nabla c - \vec{v} c \right - \vec{F}) + + * r1 \cdot c + r2 = f + f2 + * \f] + * with + *
    + *
  • \f$ c \f$ is the unknown solution + *
  • \f$ m1 \equiv m(\vec{x},t) \f$ is the Mass Scaling Term + *
  • \f$ m2 \equiv m(\vec{x},t) \f$ is the Mass Term + *
  • \f$ D \equiv D(\vec{x},t) \f$ is the Diffusion Tensor + *
  • \f$ v \equiv \vec{v}(\vec{x},t) \f$ is the Velocity Field + *
  • \f$ F \equiv \vec{F}(\vec{x},t) \f$ is the Flux + *
  • \f$ r1 \equiv r(\vec{x},t) \f$ is the Reaction Rate + *
  • \f$ r2 \equiv r(\vec{x},t) \f$ is a Reaction Term + *
  • \f$ f \equiv f(\vec{x},t) \f$ is a Source Term + *
  • \f$ f2 \equiv f_2(\vec{x},t) \f$ is a Vector Source Term + *
+ * + * \tparam TDomain Domain + * \tparam TAlgebra Algebra + */ +template< typename TDomain> +class ConvectionDiffusionFV1 : public ConvectionDiffusionBase +{ + private: + /// Base class type + typedef ConvectionDiffusionBase base_type; + + /// Own type + typedef ConvectionDiffusionFV1 this_type; + + /// error estimator type + typedef SideAndElemErrEstData err_est_type; + + public: + /// World dimension + static const int dim = base_type::dim; + + public: + /// Constructor + ConvectionDiffusionFV1(const char* functions, const char* subsets); + + /// set the upwind method + /** + * This method sets the upwind method used to upwind the convection. + * + * \param shapes upwind method + */ + void set_upwind(SmartPtr > shapes); + + private: + /// prepares the loop over all elements + /** + * This method prepares the loop over all elements. It resizes the Position + * array for the corner coordinates and schedules the local ip positions + * at the data imports. + */ + template + void prep_elem_loop(const ReferenceObjectID roid, const int si); + + /// prepares the element for assembling + /** + * This methods prepares an element for the assembling. The Positions of + * the Element Corners are read and the Finite Volume Geometry is updated. + * The global ip positions are scheduled at the data imports. + */ + template + void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]); + + /// finishes the loop over all elements + template + void fsh_elem_loop(); + + /// assembles the local stiffness matrix using a finite volume scheme + template + void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsCut); + + template + void add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + + /// assembles the local mass matrix using a finite volume scheme + template + void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the stiffness part of the local defect + template + void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the stiffness part of the local defect + template + void add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsCut); + + template + void add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + + template + number add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem); + + /// assembles the stiffness part of the local defect explicit reaction, reaction_rate and source + template + void add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the mass part of the local defect + template + void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the local right hand side + template + void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_rhs_elem_local(TFVGeom& geo, LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); + + /// prepares the loop over all elements of one type for the computation of the error estimator + template + void prep_err_est_elem_loop(const ReferenceObjectID roid, const int si); + + /// prepares the element for assembling the error estimator + template + void prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// computes the error estimator contribution for one element + template + void compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// computes the error estimator contribution for one element + template + void compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// computes the error estimator contribution for one element + template + void compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// postprocesses the loop over all elements of one type in the computation of the error estimator + template + void fsh_err_est_elem_loop(); + + protected: + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_velocity(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_diffusion(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_flux(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the reaction + template + void lin_def_reaction(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the reaction + template + void lin_def_reaction_rate(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the source term + template + void lin_def_source(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the vector source term + template + void lin_def_vector_source(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the mass scale term + template + void lin_def_mass_scale(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the mass scale term + template + void lin_def_mass(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + private: + /// abbreviation for the local solution + static const size_t _C_ = 0; + + using base_type::m_imDiffusion; + using base_type::m_imVelocity; + using base_type::m_imFlux; + using base_type::m_imSource; + using base_type::m_imSourceExpl; + using base_type::m_imVectorSource; + using base_type::m_imReactionRate; + using base_type::m_imReactionRateExpl; + using base_type::m_imReaction; + using base_type::m_imReactionExpl; + using base_type::m_imMassScale; + using base_type::m_imMass; + + using base_type::m_exGrad; + using base_type::m_exValue; + + protected: + /// method to compute the upwind shapes + SmartPtr > m_spConvShape; + + /// returns the updated convection shapes + typedef IConvectionShapes conv_shape_type; + const IConvectionShapes& get_updated_conv_shapes(const FVGeometryBase& geo); + + /// computes the concentration + template + void ex_value(number vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > vvvDeriv[]); + + /// computes the gradient of the concentration + template + void ex_grad(MathVector vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > > vvvDeriv[]); + + public: + /// type of trial space for each function used + virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid); + + /// returns if hanging nodes are needed + virtual bool use_hanging() const; + + protected: + /// current regular grid flag + bool m_bNonRegularGrid; + + /// current shape function set (needed for GeomProvider::get()) + LFEID m_LFEID; + + /// register utils + /// \{ + void register_all_funcs(bool bHang); + template void register_func(); + /// \} + + private: + /// struct holding values of shape functions in IPs + struct ShapeValues + { + public: + void resize(std::size_t nEip, std::size_t nSip, std::size_t _nSh) + { + nSh = _nSh; + elemVals.resize(nEip); + sideVals.resize(nSip); + for (std::size_t i = 0; i < nEip; i++) elemVals[i].resize(nSh); + for (std::size_t i = 0; i < nSip; i++) sideVals[i].resize(nSh); + } + number& shapeAtElemIP(std::size_t sh, std::size_t ip) {return elemVals[ip][sh];} + number& shapeAtSideIP(std::size_t sh, std::size_t ip) {return sideVals[ip][sh];} + number* shapesAtElemIP(std::size_t ip) {return &elemVals[ip][0];} + number* shapesAtSideIP(std::size_t ip) {return &sideVals[ip][0];} + std::size_t num_sh() {return nSh;} + private: + std::size_t nSh; + std::vector > elemVals; + std::vector > sideVals; + } m_shapeValues; +}; + +// end group convection_diffusion +/// \} + +} // end ConvectionDiffusionPlugin +} // end namespace ug + + +#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__*/ diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.cpp b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.cpp new file mode 100644 index 0000000..b0f1331 --- /dev/null +++ b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.cpp @@ -0,0 +1,2377 @@ +/* + * convection_diffusion_fv1.cpp + * + * Created on: 26.02.2010 + * Author: andreasvogel + */ + +#include "convection_diffusion_fv1.h" + +#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" + +#include "lib_disc/spatial_disc/disc_util/geom_provider.h" +//#include "lib_disc/spatial_disc/disc_util/fv1_geom.h" +//#include "lib_disc/spatial_disc/disc_util/hfv1_geom.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +//////////////////////////////////////////////////////////////////////////////// +// general +//////////////////////////////////////////////////////////////////////////////// + +template +ConvectionDiffusionFV1:: +ConvectionDiffusionFV1(const char* functions, const char* subsets) + : ConvectionDiffusionBase(functions,subsets), + m_spConvShape(new ConvectionShapesNoUpwind), + m_bNonRegularGrid(false) +{ + register_all_funcs(m_bNonRegularGrid); +} + + +template +void ConvectionDiffusionFV1:: +prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid) +{ +// check number + if(vLfeID.size() != 1) + UG_THROW("ConvectionDiffusion: Wrong number of functions given. " + "Need exactly "<<1); + + if(vLfeID[0].order() != 1 || vLfeID[0].type() != LFEID::LAGRANGE) + UG_THROW("ConvectionDiffusion FV Scheme only implemented for 1st order."); + +// remember + m_bNonRegularGrid = bNonRegularGrid; + + m_LFEID = vLfeID[0]; + +// update assemble functions + register_all_funcs(m_bNonRegularGrid); +} + +template +bool ConvectionDiffusionFV1:: +use_hanging() const +{ + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Assembling functions +//////////////////////////////////////////////////////////////////////////////// + +template +template +void ConvectionDiffusionFV1:: +prep_elem_loop(const ReferenceObjectID roid, const int si) +{ + // Only first order implementation + if(!(TFVGeom::order == 1)) + UG_THROW("Only first order implementation, but other Finite Volume" + " Geometry set."); + +// check, that upwind has been set + if(m_spConvShape.invalid()) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Upwind has not been set."); + +// set local positions + if(!TFVGeom::usesHangingNodes && TFVGeom::staticLocalData) + { + static const int refDim = TElem::dim; + TFVGeom& geo = GeomProvider::get(); +// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + const MathVector* vSCVFip = geo.scvf_local_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_local_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip, false); + m_imVelocity.template set_local_ips(vSCVFip,numSCVFip, false); + m_imFlux.template set_local_ips(vSCVFip,numSCVFip, false); + m_imSource.template set_local_ips(vSCVip,numSCVip, false); + m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip, false); + m_imReactionRate.template set_local_ips(vSCVip,numSCVip, false); + m_imReaction.template set_local_ips(vSCVip,numSCVip, false); + m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imReactionExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imSourceExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imMassScale.template set_local_ips(vSCVip,numSCVip, false); + m_imMass.template set_local_ips(vSCVip,numSCVip, false); + + // init upwind for element type + if(!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Cannot init upwind for element type."); + } +} + +template +template +void ConvectionDiffusionFV1:: +fsh_elem_loop() +{} + +template +template +void ConvectionDiffusionFV1:: +prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) +{ +// Update Geometry for this element + //static TFVGeom& geo = GeomProvider::get(); +// TFVGeom& geo = GeomProvider::get(m_LFEID,1); + TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); + +// TFVGeom& geo = GeomProvider::get(); +// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + + // fix: set orientation initially globally! + geo.set_orientation(1); + + try{ + geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::prep_elem:" + " Cannot update Finite Volume Geometry."); + +// set local positions + if(TFVGeom::usesHangingNodes || !TFVGeom::staticLocalData) + { + const int refDim = TElem::dim; + const MathVector* vSCVFip = geo.scvf_local_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_local_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip); + m_imVelocity.template set_local_ips(vSCVFip,numSCVFip); + m_imFlux.template set_local_ips(vSCVFip,numSCVFip); + m_imSource.template set_local_ips(vSCVip,numSCVip); + m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip); + m_imReactionRate.template set_local_ips(vSCVip,numSCVip); + m_imReaction.template set_local_ips(vSCVip,numSCVip); + m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip); + m_imReactionExpl.template set_local_ips(vSCVip,numSCVip); + m_imSourceExpl.template set_local_ips(vSCVip,numSCVip); + m_imMassScale.template set_local_ips(vSCVip,numSCVip); + m_imMass.template set_local_ips(vSCVip,numSCVip); +/* + if(m_spConvShape.valid()) + if(!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Cannot init upwind for element type."); + */ + } + + // set global positions + const MathVector* vSCVFip = geo.scvf_global_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_global_ips(); + const size_t numSCVip = geo.num_scv_ips(); + + m_imDiffusion. set_global_ips(vSCVFip, numSCVFip); + m_imVelocity. set_global_ips(vSCVFip, numSCVFip); + m_imFlux. set_global_ips(vSCVFip, numSCVFip); + m_imSource. set_global_ips(vSCVip, numSCVip); + m_imVectorSource. set_global_ips(vSCVFip, numSCVFip); + m_imReactionRate. set_global_ips(vSCVip, numSCVip); + m_imReactionRateExpl. set_global_ips(vSCVip, numSCVip); + m_imReactionExpl. set_global_ips(vSCVip, numSCVip); + m_imSourceExpl. set_global_ips(vSCVip, numSCVip); + m_imReaction. set_global_ips(vSCVip, numSCVip); + m_imMassScale. set_global_ips(vSCVip, numSCVip); + m_imMass. set_global_ips(vSCVip, numSCVip); + +} + + +template +static TVector CalculateCenter(GridObject* o, const TVector* coords) +{ + TVector v; + VecSet(v, 0); + + size_t numCoords = 0; + switch(o->base_object_id()){ + case VERTEX: numCoords = 1; break; + case EDGE: numCoords = static_cast(o)->num_vertices(); break; + case FACE: numCoords = static_cast(o)->num_vertices(); break; + case VOLUME: numCoords = static_cast(o)->num_vertices(); break; + default: UG_THROW("Unknown element type."); break; + } + + for(size_t i = 0; i < numCoords; ++i) + VecAdd(v, v, coords[i]); + + if(numCoords > 0) + VecScale(v, v, 1. / (number)numCoords); + + return v; +} + +void LU(MathMatrix<3, 3>& R, MathMatrix<3, 3>& L, MathMatrix<3, 3> A) +{ + // n-1 Iterationsschritte + for ( size_t i = 1; i < 2; ++i) + { + for ( size_t k = i+1; i < 3; ++i) + { + L[k][i] = R[k][i] / R[i][i]; + + for ( size_t j = i; i < 3; ++i) + R[k][j] = R[k][j] - L[k][i] * R[i][j]; + } + } + +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + + bool debug = false; + bool boundary = false; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + const bool bElementIsCut = geo.get_element_modus(); + const bool bElementIsOutside = geo.get_boolian_for_diffusion(); + + // First call with orientation = 1: + int orientation = 1; + geo.set_orientation(orientation); + + geo.init_integral(); + + UG_LOG("------------------> jac = " << geo.get_integral() << "\n"); + +// normal assembling if not cut by interface: + if ( !bElementIsCut ) + { + LocalVector dummyU; + LocalIndices ind = u.get_indices(); + dummyU.resize(ind); + dummyU = 0; + + this->template add_jac_A_elem_local (geo, J, u, dummyU, elem, vCornerCoords, bElementIsOutside); + return; + } + +// get data: + geo.resize_local_data(u); + LocalMatrix& locJ_tri = geo.get_jacobian_tri(); + LocalMatrix& locJ_quad = geo.get_jacobian_quad(); + + LocalVector& locU_tri = geo.get_solution_tri(); + LocalVector& locU_quad = geo.get_solution_quad(); + +// reset data: + locJ_tri = 0; + locJ_quad = 0; + + LocalIndices ind = u.get_indices(); + + // call elem disc twice: + + if ( debug ) geo.print_InterfaceIDdata(); + + ReferenceObjectID roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + + this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, false); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_tri, 3); + this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords, false); + } + + geo.set_jacobian_tri(locJ_tri); + geo.set_DoF_tag_tri(false); + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + + this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, false); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_quad, 4); + this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords, false); + } + + geo.set_jacobian_quad(locJ_quad); + geo.set_DoF_tag_quad(false); + } + + +// Second call with orientation = 1: + bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! + + orientation *= -1; + geo.set_orientation(orientation); + try{ + geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" + " Cannot update Finite Volume Geometry."); + + if ( debug ) geo.print_InterfaceIDdata(); + + roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + + this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, true); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_tri, 3); + this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords, true); + } + + geo.set_jacobian_tri(locJ_tri); + geo.set_DoF_tag_tri(shiftTag); + + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + + this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, true); + + if ( boundary ) + { + geo.reset_jacobian_on_interface(locJ_quad, 4); + this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords, true); + } + + geo.set_jacobian_quad(locJ_quad); + geo.set_DoF_tag_quad(shiftTag); + } + + +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + ug::MathMatrix diffusion = m_imDiffusion[0]; + diffusion *= 1.0; + + if ( bElementIsOutside ) // = inside circle line!! + diffusion *= 1.0; + +// Diff. Tensor times Gradient + MathVector Dgrad; + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// Diffusion and Velocity Term + if(m_imDiffusion.data_given() || m_imVelocity.data_given()) + { + + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCV + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + //////////////////////////////////////////////////// + // Diffusive Term + //////////////////////////////////////////////////// + if(m_imDiffusion.data_given()) + { + // loop shape functions + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + // Compute Diffusion Tensor times Gradient + MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); + + // Compute flux at IP + const number D_diff_flux = VecDot(Dgrad, scvf.normal()); + + J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; + J(_C_, scvf.to() , _C_, sh) += D_diff_flux; + } + } + + ///////////////////////////////////////////////////////////////////////////// + // Additional diffusive Term due to jump in solution at the interface + // u^+ - u^- = jump + ///////////////////////////////////////////////////////////////////////////// + if ( 0 ) + { + // loop shape functions + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + // Compute Diffusion Tensor times Gradient + MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); + + // Compute flux at IP + const number D_diff_flux = jump(_C_,sh) * VecDot(Dgrad, scvf.normal()); + + J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; + J(_C_, scvf.to() , _C_, sh) += D_diff_flux; + } + + } + //////////////////////////////////////////////////// + // Convective Term + //////////////////////////////////////////////////// + if(m_imVelocity.data_given()) + { + // Add Flux contribution + for(size_t sh = 0; sh < convShape.num_sh(); ++sh) + { + const number D_conv_flux = convShape(ip, sh); + + // Add flux term to local matrix + J(_C_, scvf.from(), _C_, sh) += D_conv_flux; + J(_C_, scvf.to(), _C_, sh) -= D_conv_flux; + } + } + + // no explicit dependency on flux import + } + } + + +//////////////////////////////////////////////////// +// Reaction Term (using lumping) +//////////////////////////////////////////////////// + +// if no data for reaction rate given, return + if(!m_imReactionRate.data_given()) return; + +// loop Sub Control Volume (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local matrix + J(_C_, co, _C_, co) += m_imReactionRate[ip] * scv.volume(); + } + +// reaction term does not explicitly depend on the associated unknown function +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + double diffusion = 10.0; + + if ( bElementIsOutside ) + diffusion = 1.0; + + std::vector& vBF = geo.get_boundary_faces(); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + +// loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + + // loop trial space + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + { + UG_LOG("bf.node_id(): " << bf.node_id() << "\n"); + UG_LOG("bf.global_grad(sh): " << bf.global_grad(sh) << "\n"); + UG_LOG("normal(): " << bf.normal() << "\n"); + + // add to local matrix + J(_C_, bf.node_id(), _C_, sh) += VecDot(bf.global_grad(sh), bf.normal()); + J(_C_, bf.node_id(), _C_, sh) *= diffusion; + } + } + +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + if(!m_imMassScale.data_given()) return; + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local matrix + J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip]; + } + +// m_imMass part does not explicitly depend on associated unknown function +} + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + bool output = false; + bool output_integral = true; + + bool debug = false; + bool boundary = false; + bool add = true; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + const bool bElementIsCut = geo.get_element_modus(); + const bool bElementIsOutside = geo.get_boolian_for_diffusion(); + + // First call with orientation = 1: + int orientation = 1; + geo.set_orientation(orientation); + + // necessary for call of 'get_solution_tri' an 'get_solution_quad': + geo.resize_local_data(u); + std::vector imSource; + if ( m_imSource.data_given() ) { + for ( size_t i = 0; i < 3; ++i ) + imSource.push_back(m_imSource[i]); + } + + +// normal assembling if not cut by interface: + if ( !bElementIsCut ) + { + LocalVector dummyU; + LocalIndices ind = d.get_indices(); + dummyU.resize(ind); + dummyU = 0; + LocalVector source = geo.set_source(imSource, ind, 3, true); + + if ( output ) + { + for ( size_t i = 0; i < 3; ++i) + UG_LOG("*** corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); + UG_LOG("\n" ); + } + + this->template add_def_A_elem_local (geo, d, u, dummyU, dummyU, source, elem, vCornerCoords, bElementIsOutside); + + number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, d, u, elem); + geo.add_to_integral(intValElem); + if ( output_integral ) + UG_LOG("------------------> usual: integral = " << sqrt(geo.get_integral()) << "\n"); + + + + return; + } + +// get data: + LocalVector& locD_tri = geo.get_defect_tri(); + LocalVector& locD_quad = geo.get_defect_quad(); + + LocalVector& locU_tri = geo.get_solution_tri(); + LocalVector& locU_quad = geo.get_solution_quad(); + +// reset data: + locD_tri = 0; + locD_quad = 0; + + // call elem disc twice: + + if ( debug ) geo.print_InterfaceIDdata(); + + LocalIndices ind = d.get_indices(); + + ReferenceObjectID roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + + LocalVector jump_tri = geo.set_jump_values(ind, 3); + LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); + LocalVector source_tri = geo.set_source(imSource, ind, 3, false); + + if ( output ) UG_LOG(" tri 1: orientaten: " << orientation << "\n"); + + this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords, false); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_tri, 3); + this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords, false); + } + + if ( output ) + { + for ( size_t i = 0; i < 3; ++i) + UG_LOG("corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); + UG_LOG("\n" ); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output_integral ) UG_LOG("------------------> tri1: integral = " << sqrt(geo.get_integral()) << "\n"); + + geo.set_defect_tri(locD_tri); + geo.set_DoF_tag_tri(false); + + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + + LocalVector jump_quad = geo.set_jump_values(ind, 4); + LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); + LocalVector source_quad = geo.set_source(imSource, ind, 4, false); + + if ( output ) UG_LOG(" quad 1: orientaten: " << orientation << "\n"); + this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem, vCornerCoords, false); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_quad, 4); + this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords, false); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output_integral ) UG_LOG("------------------> quad1: integral = " << sqrt(geo.get_integral()) << "\n"); + + + geo.set_defect_quad(locD_quad); + geo.set_DoF_tag_quad(false); + + } + + +// Second call with orientation = -1: + bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! + + orientation *= -1; + if ( output ) UG_LOG(" ____2: orientaten: " << orientation << "\n"); + + geo.set_orientation(orientation); + try{ + geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" + " Cannot update Finite Volume Geometry."); + + if ( debug ) geo.print_InterfaceIDdata(); + + roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); + LocalVector source_tri = geo.set_source(imSource, ind, 3, false); + + if ( output ) UG_LOG(" tri 2: orientaten: " << orientation << "\n"); + + this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords, true); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_tri, 3); + this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords, true); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output ) UG_LOG("------------------> tri2: integral = " << sqrt(geo.get_integral()) << "\n"); + + + geo.set_defect_tri(locD_tri); + geo.set_DoF_tag_tri(shiftTag); + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); + LocalVector source_quad = geo.set_source(imSource, ind, 4, false); + + if ( output ) UG_LOG(" quad 2: orientaten: " << orientation << "\n"); + + this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem, vCornerCoords, true); + + if ( boundary ) + { + geo.reset_defect_on_interface(locD_quad, 4); + this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords, true); + } + + number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); + if ( add ) geo.add_to_integral(intValElem); + + if ( output_integral ) UG_LOG("------------------> quad2: integral = " << sqrt(geo.get_integral()) << "\n"); + + geo.set_defect_quad(locD_quad); + geo.set_DoF_tag_quad(shiftTag); + + } +} + +template +number get_exact_sol_test(MathVector position) +{ + return sin(2*M_PI*position[0]) + sin(2*M_PI*position[1]); +} + +template +number get_exact_sol_Gangl(MathVector position) +{ + double kappa_2 = 10.0; + double dist_x = position[0] - 0.1; + double dist_y = position[1] - 0.2; + double sqR = 0.4*0.4; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = -4*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_2 - 1); + + if ( dist >= 0.4 ) + returnValue = -2*kappa_2*sqDist*sqDist; + + return returnValue; +} + +template +MathVector get_exact_grad_Gangl(MathVector position) +{ + double kappa_2 = 10.0; + double dist_x = position[0] - 0.1; + double dist_y = position[1] - 0.2; + double sqR = 0.4*0.4; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double factor = -8*kappa_2*kappa_2*sqR; + + if ( dist >= 0.4 ) + factor = -8*kappa_2*sqDist; + + MathVector returnVector; + returnVector[0] = factor*dist_x; + returnVector[1] = factor*dist_y; + + return returnVector; +} + +template +MathVector get_exact_grad_FedkiwEx5(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + double radius = 0.5; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double absValue = position[0]*position[0] + position[1]* position[1]; + + MathVector returnVector; + returnVector[0] = 0.0; + returnVector[1] = 0.0; + + double factor = 1.0/absValue; + if ( dist >= radius ) + { + returnVector[0] = factor*position[0]; + returnVector[1] = factor*position[1]; + } + + return returnVector; + +} + +template +number get_exact_sol_FedkiwEx6(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + double radius = 0.5; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = 0.0; + + if ( dist <= radius ) + returnValue = exp(position[0])*cos(position[1]); + + return returnValue; +} + +template +number get_exact_sol_FedkiwEx5(MathVector position) +{ + double center_x = 0.0; + double center_y = 0.0; + + double dist_x = position[0]-center_x; + double dist_y = position[1]-center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double returnValue = 1.0; + + if ( dist > 0.5 ) + returnValue = 1.0 + log(2*dist); + + return returnValue; +} + +template +number get_exact_sol_FedkiwEx3(MathVector position) +{ + double center_x = 0.5; + double center_y = 0.5; + double radius = 0.25; + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + + double sqDist = dist_x*dist_x + dist_y*dist_y; + double dist = sqrt(sqDist); + + double absValue = position[0]*position[0] + position[1]* position[1]; + + double returnValue = 0.0; + + if ( dist <= radius ) + returnValue = exp(-absValue); + + return returnValue; +} + +template +MathVector get_exact_grad(MathVector position) +{ + +} + +////////////////////////////////////////////////////////////////////// +// code see ugbase/lib_disc/function_spaces/integrate.h: evaluate() for +// --> L2ErrorIntegrand (for value) +// --> H1ErrorIntegrand (for gradient): lines 1873-1910 +// +// called bei Integrate() via method 'integrand.values': +// integrand.values(&(vValue[0]), &(vGlobIP[0]), +// pElem, &vCorner[0], rQuadRule.points(), +// &(vJT[0]), +// numIP); +// +////////////////////////////////////////////////////////////////////// +template +template +number ConvectionDiffusionFV1:: +add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem) +{ + bool output = false; + + number integral = 0; + + std::vector > vCorner; + std::vector > vGlobIP; + std::vector > vLocIP; + std::vector > vJT; + std::vector vValue; + std::vector vValueGrad; + + QuadType type = GetQuadratureType("best"); + + const QuadratureRule& rQuadRule + = QuadratureRuleProvider::get(roid, 1, type); + +// get reference element mapping by reference object id + DimReferenceMapping& mapping + = ReferenceMappingProvider::get(roid); + +// number of integration points + const size_t numIP = rQuadRule.size(); + +// get all corner coordinates +// CollectCornerCoordinates(vCorner, *pElem, aaPos, true); + + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(roid); + + vCorner.clear(); +// remember global position of nodes + for(size_t i = 0; i < rRefElem.num(0); ++i) + vCorner.push_back(geo.get_corner(i)); + + if ( output ) + { + for ( size_t i = 0; i < rRefElem.num(0); ++i) + UG_LOG("vCorner" << vCorner[i][0] << " and " << vCorner[i][1] << "\n" ); + UG_LOG("\n" ); + } + +// update the reference mapping for the corners + mapping.update(vCorner); + +// compute global integration points + vGlobIP.resize(numIP); + mapping.local_to_global(&(vGlobIP[0]), rQuadRule.points(), numIP); + + if ( output ) UG_LOG("vGlobIP" << vGlobIP[0][0] << " and " << vGlobIP[0][1] << "\n" ); + if ( output ) UG_LOG("\n" ); + +// compute local integration points + vLocIP.resize(numIP); + for(size_t ip = 0; ip < numIP; ++ip) + vLocIP[ip] = rQuadRule.points()[ip]; + + if ( output ) UG_LOG("vLocIP" << vLocIP[0][0] << " and " << vLocIP[0][1] << "\n" ); + if ( output ) UG_LOG("\n" ); + + +// compute transformation matrices + vJT.resize(numIP); + mapping.jacobian_transposed(&(vJT[0]), rQuadRule.points(), numIP); + + const size_t num_sh = geo.num_scvf(); + + if ( num_sh != rRefElem.num(0) ) + UG_THROW("wrong number of corners: sh = " << num_sh << ", but rRefElem.num(0) = " << rRefElem.num(0) << "\n"); + +// compute integrand values at integration points + vValue.resize(numIP); + vValueGrad.resize(numIP); + + try + { + // loop all integration points + for(size_t ip = 0; ip < numIP; ++ip) + { + // compute exact solution at integration point + number exactSolIP = get_exact_sol_FedkiwEx5(vGlobIP[ip]); + + // compute exact gradient at integration point + MathVector exactGradIP = get_exact_grad_FedkiwEx5(vGlobIP[ip]); + + // compute approximated solution at integration point + number approxSolIP = 0.0; + MathVector locTmp; VecSet(locTmp, 0.0); + + const typename TFVGeom::SCV& scv = geo.scv(ip); + + for(size_t sh = 0; sh < num_sh; ++sh) + { + // add shape fct at ip * value at shape + approxSolIP += u(_C_,sh) * geo.get_shape(sh, vLocIP[ip], roid); + + // add gradient at ip + VecScaleAppend(locTmp, u(_C_,sh), scv.local_grad(sh)); + } + + // get squared of difference + vValue[ip] = (exactSolIP - approxSolIP); + vValue[ip] *= vValue[ip]; + + // compute global gradient + MathVector approxGradIP; + MathMatrix JTInv; + Inverse(JTInv, vJT[ip]); + MatVecMult(approxGradIP, JTInv, locTmp); + + // get error of gradient + vValueGrad[ip] = VecDistanceSq(approxGradIP, exactGradIP); + + + } +/* integrand.values(&(vValue[0]), &(vGlobIP[0]), + pElem, &vCorner[0], rQuadRule.points(), + &(vJT[0]), + numIP); +*/ + } + UG_CATCH_THROW("Unable to compute values of integrand at integration point."); + +// reset contribution of this element + number intValElem = 0; + +// loop integration points + for(size_t ip = 0; ip < numIP; ++ip) + { + // get quadrature weight + const number weightIP = rQuadRule.weight(ip); + + // get determinate of mapping + const number det = SqrtGramDeterminant(vJT[ip]); + + // add contribution of integration point + intValElem += vValue[ip] * weightIP * det; +// intValElem += vValueGrad[ip] * weightIP * det; + + } + +// add to global sum + + if ( output ) UG_LOG("added: " << intValElem << "\n\n"); + + return intValElem; +} + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + double diffusion = 10.0; + + if ( bElementIsOutside ) + diffusion = 1.0; + + std::vector& vBF = geo.get_boundary_faces(); + MathVector Dgrad; + VecSet(Dgrad, 0.0); + + UG_LOG("---------- vBF.size(): " << vBF.size() << "\n"); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + +// set solution +/* for(size_t sh = 0; sh < geo.num_sh(); ++sh) + { + u(_C_, sh) = 1.0; + u(_C_, sh) -= corners[sh][0]*(2*corners[sh][0] - 1.0); + u(_C_, sh) -= corners[sh][1]*(2*corners[sh][1] - 1.0); + } +*/ +// u(_C_, sh) = 1 - 2*(corners[sh][0]*corners[sh][0] + corners[sh][1]*corners[sh][1]) - (corners[sh][0]+corners[sh][1]); +// u(_C_, sh) = corners[sh][1]*(2*corners[sh][1] - 1.0); +// u(_C_, sh) = (1.0 - corners[sh][0] - corners[sh][1]) * (1.0 - 2*corners[sh][0] - 2*corners[sh][1]); +// u(_C_, sh) = corners[sh][1]; +// for(size_t sh = 0; sh < geo.num_sh(); ++sh) +// u(_C_, sh) = corners[sh][0]*(2*corners[sh][0] - 1.0); //corners[sh][0]; + // u(_C_, sh) = corners[sh][0]*(2* corners[sh][0]-1); + +//////////////////////////////////////////////////////////////////////////////// +// NO loop integration points! +// /* for(size_t ip = 0; ip < vBF.size(); ++ip) */ +// Reason: the length of the normal is already the length of the total face (NOT the scvf!) +//////////////////////////////////////////////////////////////////////////////// + +// loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + VecSet(Dgrad, 0.0); + + // loop trial space + for(size_t sh = 0; sh < bf.num_sh(); ++sh) + { + // Diffusion + UG_LOG("bf.num_sh(): " << bf.num_sh() << "\n"); + UG_LOG("Dgrad: " << Dgrad << "\n"); + UG_LOG("bf.normal(): " << bf.normal() << "\n"); + UG_LOG("bf.global_grad(ip, sh): " << bf.global_grad(sh) << "\n"); + + UG_LOG("u(_C_, sh): " << u(_C_, sh) << "\n"); + + VecScaleAppend(Dgrad, diffusion * u(_C_, sh), bf.global_grad(sh)); + } + + // add to local vector + d(_C_, bf.node_id()) += VecDot(Dgrad, bf.normal()); + + } + + UG_LOG("---------- end ----------- \n\n"); + +} + + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + ug::MathMatrix diffusion = m_imDiffusion[0]; + diffusion *= 1.0; + double diffCoeff = 1.0; + + if ( bElementIsOutside ) // = inside circle line!! + { diffusion *= 1.0; diffCoeff = 1.0;} + + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + ///////////////////////////////////////////////////// + // Diffusive Term + ///////////////////////////////////////////////////// + if(m_imDiffusion.data_given()) + { + // to compute D \nabla c + MathVector Dgrad_c, grad_c; + + // compute gradient and shape at ip + VecSet(grad_c, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad_c, u(_C_,sh), scvf.global_grad(sh)); + + // scale by diffusion tensor + MatVecMult(Dgrad_c, diffusion, grad_c); + + // Compute flux + const number diff_flux = VecDot(Dgrad_c, scvf.normal()); + + // Add to local defect + d(_C_, scvf.from()) -= diff_flux; + d(_C_, scvf.to() ) += diff_flux; + + } + + ///////////////////////////////////////////////////////////////////////////// + // Additional diffusive Term due to jump in solution at the interface + // u^+ - u^- = jump + ///////////////////////////////////////////////////////////////////////////// + if ( 1 ) + { + // scale diffusion by jump in solution: + // const double jump = 2.0; + // diffusion *= jump; + + // to compute D \nabla c=Id_interface + MathVector Dgrad, grad; + + // compute gradient and shape at ip + VecSet(grad, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad, jump(_C_,sh), scvf.global_grad(sh)); + + // scale by diffusion tensor + MatVecMult(Dgrad, diffusion, grad); + + // Compute flux + const number diff_flux = VecDot(Dgrad, scvf.normal()); + + // Add to local defect + d(_C_, scvf.from()) -= diff_flux; + d(_C_, scvf.to() ) += diff_flux; + + } + } + + ///////////////////////////////////////////////////// + // add rhs during same method! + // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! + ///////////////////////////////////////////////////// + + if ( 1 ) + { //m_imSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); + + // get associated node + int co = scv.node_id(); + d(_C_, co) -= source(_C_, co) * scv.volume(); + + // Add to local rhs +/* if ( co > 2 ) + { + d(_C_, co) -= m_imSource[2] * scv.volume(); + UG_LOG("m_imSource[2] * scv.volume(): " << m_imSource[2] << "\n"); + UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); + } + else + { + d(_C_, co) -= m_imSource[co] * scv.volume(); + UG_LOG("m_imSource[co] * scv.volume(): " << m_imSource[co] << "\n"); + UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); + } + + */ + } + } + ///////////////////////////////////////////////////////////////////////////// + // Additional source Term due to jump in gradient at the interface + // (\nabla u^+ - \nabla u^-)\cdot n = h(x) * |n| + ///////////////////////////////////////////////////////////////////////////// + if ( 1 ) + { + std::vector& vBF = geo.get_boundary_faces(); + MathVector Dgrad; + VecSet(Dgrad, 0.0); + + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + // loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) + { + typename TFVGeom::BF bf = vBF[ip]; + // Add to local rhs + d(_C_, bf.node_id()) += jump_grad(_C_,bf.node_id()) * bf.Vol; + } + } + +} + + +template +template +void ConvectionDiffusionFV1:: +add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + +// reaction rate + if(m_imReactionRateExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local defect + d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume(); + } + } + +// reaction + if(m_imReactionExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local defect + d(_C_, co) += m_imReactionExpl[ip] * scv.volume(); + } + } + + if(m_imSourceExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) -= m_imSourceExpl[ip] * scv.volume(); + } + } +} + +template +template +void ConvectionDiffusionFV1:: +add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + if(!m_imMassScale.data_given() && !m_imMass.data_given()) return; + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // mass value + number val = 0.0; + + // multiply by scaling + if(m_imMassScale.data_given()) + val += m_imMassScale[ip] * u(_C_, co); + + // add mass + if(m_imMass.data_given()) + val += m_imMass[ip]; + + // Add to local defect + d(_C_, co) += val * scv.volume(); + } +} + + +template +template +void ConvectionDiffusionFV1:: +add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) +{ + ///////////////////////////////////////////////////// + // add rhs ALLREADY(!) during 'add_def_A_elem_local()' method! + // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! + ///////////////////////////////////////////////////// + + return; + + // get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + // loop Sub Control Volumes (SCV) + if ( m_imSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) += m_imSource[ip] * scv.volume(); + } + } + + // loop Sub Control Volumes (SCVF) + if ( m_imVectorSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); + + // Add to local rhs + d(_C_, scvf.from()) -= VecDot(m_imVectorSource[ip], scvf.normal() ); + d(_C_, scvf.to() ) += VecDot(m_imVectorSource[ip], scvf.normal() ); + } + } +} + + +//////////////////////////////////// +/// error estimation (begin) /// + +// prepares the loop over all elements of one type for the computation of the error estimator +template +template +void ConvectionDiffusionFV1:: +prep_err_est_elem_loop(const ReferenceObjectID roid, const int si) +{ + // get the error estimator data object and check that it is of the right type + // we check this at this point in order to be able to dispense with this check later on + // (i.e. in prep_err_est_elem and compute_err_est_A_elem()) + if (this->m_spErrEstData.get() == NULL) + { + UG_THROW("No ErrEstData object has been given to this ElemDisc!"); + } + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (!err_est_data) + { + UG_THROW("Dynamic cast to SideAndElemErrEstData failed." + << std::endl << "Make sure you handed the correct type of ErrEstData to this discretization."); + } + + +// check that upwind has been set + if (m_spConvShape.invalid()) + UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " + "Upwind has not been set."); + +// set local positions + if (!TFVGeom::usesHangingNodes) + { + static const int refDim = TElem::dim; + + // get local IPs + size_t numSideIPs, numElemIPs; + const MathVector* sideIPs; + const MathVector* elemIPs; + try + { + numSideIPs = err_est_data->num_all_side_ips(roid); + numElemIPs = err_est_data->num_elem_ips(roid); + sideIPs = err_est_data->template side_local_ips(roid); + elemIPs = err_est_data->template elem_local_ips(roid); + + if (!sideIPs || !elemIPs) return; // are NULL if TElem is not of the same dim as TDomain + } + UG_CATCH_THROW("Integration points for error estimator cannot be set."); + + // set local IPs in imports + m_imDiffusion.template set_local_ips(sideIPs, numSideIPs, false); + m_imVelocity.template set_local_ips(sideIPs, numSideIPs, false); + m_imFlux.template set_local_ips(sideIPs, numSideIPs, false); + m_imSource.template set_local_ips(elemIPs, numElemIPs, false); + m_imVectorSource.template set_local_ips(sideIPs, numSideIPs, false); + m_imReactionRate.template set_local_ips(elemIPs, numElemIPs, false); + m_imReaction.template set_local_ips(elemIPs, numElemIPs, false); + m_imMassScale.template set_local_ips(elemIPs, numElemIPs, false); + m_imMass.template set_local_ips(elemIPs, numElemIPs, false); + + // init upwind for element type + TFVGeom& geo = GeomProvider::get(); + if (!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " + "Cannot init upwind for element type."); + + // store values of shape functions in local IPs + LagrangeP1::reference_element_type> trialSpace + = Provider::reference_element_type> >::get(); + + m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh()); + for (size_t ip = 0; ip < numElemIPs; ip++) + trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]); + for (size_t ip = 0; ip < numSideIPs; ip++) + trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]); + } +} + +template +template +void ConvectionDiffusionFV1:: +prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{} + +// computes the error estimator contribution (stiffness part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ + typedef typename reference_element_traits::reference_element_type ref_elem_type; + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + +// request geometry + static const TFVGeom& geo = GeomProvider::get(); + +//////////////// +// SIDE TERMS // +//////////////// + +// get the sides of the element + // We have to cast elem to a pointer of type SideAndElemErrEstData::elem_type + // for the SideAndElemErrEstData::operator() to work properly. + // This cannot generally be achieved by casting to TElem*, since this method is also registered for + // lower-dimensional types TElem, and must therefore be compilable, even if it is never EVER to be executed. + // The way we achieve this here, is by calling associated_elements_sorted() which has an implementation for + // all possible types. Whatever comes out of it is of course complete nonsense if (and only if) + // SideAndElemErrEstData::elem_type != TElem. To be on the safe side, we throw an error if the number of + // entries in the list is not as it should be. + + typename MultiGrid::traits::side_type>::secure_container side_list; + pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); + if (side_list.size() != (size_t) ref_elem_type::numSides) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// some help variables + MathVector fluxDensity, gradC, normal; + +// calculate grad u (take grad from first scvf ip (grad u is constant on the entire element)) + if (geo.num_scvf() < 1) {UG_THROW("Element has no SCVFs!");} + const typename TFVGeom::SCVF& scvf = geo.scvf(0); + + VecSet(gradC, 0.0); + for (size_t j=0; j(normal, side, vCornerCoords); + VecNormalize(normal, normal); + + try + { + for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) + { + size_t ip = passedIPs + sip; + + VecSet(fluxDensity, 0.0); + + ////// diffusion ////// + if (m_imDiffusion.data_given()) + MatVecScaleMultAppend(fluxDensity, -1.0, m_imDiffusion[0], gradC); + + ////// convection ////// + if (m_imVelocity.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtSideIP(sh,sip); + + VecScaleAppend(fluxDensity, val, m_imVelocity[ip]); + } + + ////// general flux ////// + if (m_imFlux.data_given()) + VecAppend(fluxDensity, m_imFlux[ip]); + + (*err_est_data)(side_list[side],sip) += scale * VecDot(fluxDensity, normal); + } + + passedIPs += err_est_data->num_side_ips(side_list[side]); + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); + } + +////////////////// +// VOLUME TERMS // +////////////////// + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + { + number total = 0.0; + + ////// diffusion ////// TODO ONLY FOR (PIECEWISE) CONSTANT DIFFUSION TENSOR SO FAR! + // div(D*grad(c)) = div(v)*u + v*grad(c) + // nothing to do, as u is piecewise linear and div(D*grad(c)) disappears + + ////// convection ////// TODO ONLY FOR CONSTANT VELOCITY FIELDS SO FAR! + // div(v*c) = div(v)*u + v*grad(c) -- gradC has been calculated above + if (m_imVelocity.data_given()) + total += VecDot(m_imVelocity[ip], gradC); + + ////// general flux ////// TODO ONLY FOR DIVERGENCE-FREE FLUX FIELD SO FAR! + // nothing to do + + ////// reaction ////// + if (m_imReactionRate.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < geo.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); + + total += m_imReactionRate[ip] * val; + } + + if (m_imReaction.data_given()) + { + total += m_imReaction[ip]; + } + + (*err_est_data)(elem_list[0],ip) += scale * total; + } + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// computes the error estimator contribution (mass part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ +// note: mass parts only enter volume term + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// request geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop integration points + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + { + number total = 0.0; + + ////// mass scale ////// + if (m_imMassScale.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < geo.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); + + total += m_imMassScale[ip] * val; + } + + ////// mass ////// + if (m_imMass.data_given()) + { + total += m_imMass[ip]; + } + + (*err_est_data)(elem_list[0],ip) += scale * total; + } + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// computes the error estimator contribution (rhs part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ + typedef typename reference_element_traits::reference_element_type ref_elem_type; + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + +//////////////// +// SIDE TERMS // +//////////////// +// get the sides of the element + typename MultiGrid::traits::side_type>::secure_container side_list; + pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); + if (side_list.size() != (size_t) ref_elem_type::numSides) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// loop sides + size_t passedIPs = 0; + for (size_t side = 0; side < (size_t) ref_elem_type::numSides; side++) + { + // normal on side + MathVector normal; + SideNormal(normal, side, vCornerCoords); + VecNormalize(normal, normal); + + try + { + for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) + { + size_t ip = passedIPs + sip; + + ////// vector source ////// + if (m_imVectorSource.data_given()) + (*err_est_data)(side_list[side],sip) += scale * VecDot(m_imVectorSource[ip], normal); + } + + passedIPs += err_est_data->num_side_ips(side_list[side]); + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); + } + +////////////////// +// VOLUME TERMS // +////////////////// + if (!m_imSource.data_given()) return; + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +////// source ////// + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + (*err_est_data)(elem_list[0],ip) += scale * m_imSource[ip]; + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// postprocesses the loop over all elements of one type in the computation of the error estimator +template +template +void ConvectionDiffusionFV1:: +fsh_err_est_elem_loop() +{ +// finish the element loop in the same way as the actual discretization + this->template fsh_elem_loop (); +}; + +/// error estimation (end) /// +//////////////////////////////////// + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +lin_def_velocity(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // sum up contributions of convection shapes + MathVector linDefect; + VecSet(linDefect, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(linDefect, u(_C_,sh), convShape.D_vel(ip, sh)); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] += linDefect; + vvvLinDef[ip][_C_][scvf.to()] -= linDefect; + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +lin_def_diffusion(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // compute gradient at ip + MathVector grad_u; VecSet(grad_u, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad_u, u(_C_,sh), scvf.global_grad(sh)); + + // compute the lin defect at this ip + MathMatrix linDefect; + + // part coming from -\nabla u * \vec{n} + for(size_t k=0; k < (size_t)dim; ++k) + for(size_t j = 0; j < (size_t)dim; ++j) + linDefect(j,k) = (scvf.normal())[j] * grad_u[k]; + + // add contribution from convection shapes + if(convShape.non_zero_deriv_diffusion()) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + MatAdd(linDefect, convShape.D_diffusion(ip, sh), u(_C_, sh)); + + // add contributions + vvvLinDef[ip][_C_][scvf.from()] -= linDefect; + vvvLinDef[ip][_C_][scvf.to() ] += linDefect; + } +} + +template +template +void ConvectionDiffusionFV1:: +lin_def_flux(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] += scvf.normal(); + vvvLinDef[ip][_C_][scvf.to()] -= scvf.normal(); + } +} +// computes the linearized defect w.r.t to the reaction rate +template +template +void ConvectionDiffusionFV1:: +lin_def_reaction_rate(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = u(_C_, co) * scv.volume(); + } +} + +// computes the linearized defect w.r.t to the reaction +template +template +void ConvectionDiffusionFV1:: +lin_def_reaction(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the source +template +template +void ConvectionDiffusionFV1:: +lin_def_source(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the vector source +// (in analogy to velocity) +template +template +void ConvectionDiffusionFV1:: +lin_def_vector_source(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ + // get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + + // loop Sub Control Volumes Faces (SCVF) + for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] -= scvf.normal(); + vvvLinDef[ip][_C_][scvf.to()] += scvf.normal(); + } +} + +// computes the linearized defect w.r.t to the mass scale +template +template +void ConvectionDiffusionFV1:: +lin_def_mass_scale(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t co = 0; co < geo.num_scv(); ++co) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(co); + + // Check associated node + UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); + + // set lin defect + vvvLinDef[co][_C_][co] = u(_C_, co) * scv.volume(); + } +} + +// computes the linearized defect w.r.t to the mass scale +template +template +void ConvectionDiffusionFV1:: +lin_def_mass(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t co = 0; co < geo.num_scv(); ++co) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(co); + + // Check associated node + UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); + + // set lin defect + vvvLinDef[co][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +ex_value(number vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > vvvDeriv[]) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reference element + typedef typename reference_element_traits::reference_element_type + ref_elem_type; + +// number of shape functions + static const size_t numSH = ref_elem_type::numCorners; + +// FV1 SCVF ip + if(vLocIP == geo.scvf_local_ips()) + { + // Loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // Get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // compute concentration at ip + vValue[ip] = 0.0; + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vValue[ip] += u(_C_, sh) * scvf.shape(sh); + + // compute derivative w.r.t. to unknowns iff needed + if(bDeriv) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vvvDeriv[ip][_C_][sh] = scvf.shape(sh); + } + } +// FV1 SCV ip + else if(vLocIP == geo.scv_local_ips()) + { + // solution at ip + for(size_t sh = 0; sh < numSH; ++sh) + vValue[sh] = u(_C_, sh); + + // set derivatives if needed + if(bDeriv) + for(size_t sh = 0; sh < numSH; ++sh) + for(size_t sh2 = 0; sh2 < numSH; ++sh2) + vvvDeriv[sh][_C_][sh2] = (sh==sh2) ? 1.0 : 0.0; + } +// general case + else + { + // get trial space + LagrangeP1& rTrialSpace = Provider >::get(); + + // storage for shape function at ip + number vShape[numSH]; + + // loop ips + for(size_t ip = 0; ip < nip; ++ip) + { + // evaluate at shapes at ip + rTrialSpace.shapes(vShape, vLocIP[ip]); + + // compute concentration at ip + vValue[ip] = 0.0; + for(size_t sh = 0; sh < numSH; ++sh) + vValue[ip] += u(_C_, sh) * vShape[sh]; + + // compute derivative w.r.t. to unknowns iff needed + // \todo: maybe store shapes directly in vvvDeriv + if(bDeriv) + for(size_t sh = 0; sh < numSH; ++sh) + vvvDeriv[ip][_C_][sh] = vShape[sh]; + } + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +ex_grad(MathVector vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > > vvvDeriv[]) +{ +// Get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reference element + typedef typename reference_element_traits::reference_element_type + ref_elem_type; + +// reference dimension + static const int refDim = ref_elem_type::dim; + +// number of shape functions + static const size_t numSH = ref_elem_type::numCorners; + +// FV1 SCVF ip + if(vLocIP == geo.scvf_local_ips()) + { + // Loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // Get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + VecSet(vValue[ip], 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(vValue[ip], u(_C_, sh), scvf.global_grad(sh)); + + if(bDeriv) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vvvDeriv[ip][_C_][sh] = scvf.global_grad(sh); + } + } +// general case + else + { + // get trial space + LagrangeP1& rTrialSpace = Provider >::get(); + + // storage for shape function at ip + MathVector vLocGrad[numSH]; + MathVector locGrad; + + // Reference Mapping + MathMatrix JTInv; + ReferenceMapping mapping(vCornerCoords); + + // loop ips + for(size_t ip = 0; ip < nip; ++ip) + { + // evaluate at shapes at ip + rTrialSpace.grads(vLocGrad, vLocIP[ip]); + + // compute grad at ip + VecSet(locGrad, 0.0); + for(size_t sh = 0; sh < numSH; ++sh) + VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]); + + // compute global grad + mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]); + MatVecMult(vValue[ip], JTInv, locGrad); + + // compute derivative w.r.t. to unknowns iff needed + if(bDeriv) + for(size_t sh = 0; sh < numSH; ++sh) + MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// upwind +//////////////////////////////////////////////////////////////////////////////// + +template +void ConvectionDiffusionFV1:: +set_upwind(SmartPtr > shapes) {m_spConvShape = shapes;} + +// computes the linearized defect w.r.t to the velocity +template +const typename ConvectionDiffusionFV1::conv_shape_type& +ConvectionDiffusionFV1:: +get_updated_conv_shapes(const FVGeometryBase& geo) +{ +// compute upwind shapes for transport equation +// \todo: we should move this computation into the preparation part of the +// disc, to only compute the shapes once, reusing them several times. + if(m_imVelocity.data_given()) + { + // get diffusion at ips + const MathMatrix* vDiffusion = NULL; + if(m_imDiffusion.data_given()) vDiffusion = m_imDiffusion.values(); + + // update convection shapes + if(!m_spConvShape->update(&geo, m_imVelocity.values(), vDiffusion, true)) + { + UG_LOG("ERROR in 'ConvectionDiffusionFV1::add_jac_A_elem': " + "Cannot compute convection shapes.\n"); + } + } + +// return a const (!!) reference to the upwind + return *const_cast*>(m_spConvShape.get()); +} + + +//////////////////////////////////////////////////////////////////////////////// +// register assemble functions +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + + /* +// switch assemble functions + if(!bHang) + { + register_func >(); + } + else + { + register_func >(); + } +*/ +} +#endif + +#ifdef UG_DIM_2 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + /* +// switch assemble functions + if(!bHang) + { + register_func >(); + register_func >(); + register_func >(); + } + else + { + register_func >(); + register_func >(); + register_func >(); + } + */ +} +#endif + +#ifdef UG_DIM_3 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + /* +// switch assemble functions + if(!bHang) + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + } + else + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + } + */ +} +#endif + +template +template +void ConvectionDiffusionFV1:: +register_func() +{ + ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; + typedef this_type T; + static const int refDim = reference_element_traits::dim; + + this->clear_add_fct(id); + this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); + this->set_prep_elem_fct( id, &T::template prep_elem); + this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); + this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem); + this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem); + this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem); + this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem); + this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem); + this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); + +// error estimator parts +/* this->set_prep_err_est_elem_loop(id, &T::template prep_err_est_elem_loop); + this->set_prep_err_est_elem(id, &T::template prep_err_est_elem); + this->set_compute_err_est_A_elem(id, &T::template compute_err_est_A_elem); + this->set_compute_err_est_M_elem(id, &T::template compute_err_est_M_elem); + this->set_compute_err_est_rhs_elem(id, &T::template compute_err_est_rhs_elem); + this->set_fsh_err_est_elem_loop(id, &T::template fsh_err_est_elem_loop); +*/ +// set computation of linearized defect w.r.t velocity + m_imDiffusion.set_fct(id, this, &T::template lin_def_diffusion); + m_imVelocity. set_fct(id, this, &T::template lin_def_velocity); + m_imFlux.set_fct(id, this, &T::template lin_def_flux); + m_imReactionRate. set_fct(id, this, &T::template lin_def_reaction_rate); + m_imReaction. set_fct(id, this, &T::template lin_def_reaction); + m_imSource. set_fct(id, this, &T::template lin_def_source); + m_imVectorSource.set_fct(id, this, &T::template lin_def_vector_source); + m_imMassScale.set_fct(id, this, &T::template lin_def_mass_scale); + m_imMass. set_fct(id, this, &T::template lin_def_mass); + +// exports + m_exValue-> template set_fct(id, this, &T::template ex_value); + m_exGrad->template set_fct(id, this, &T::template ex_grad); +} + +//////////////////////////////////////////////////////////////////////////////// +// explicit template instantiations +//////////////////////////////////////////////////////////////////////////////// +#ifdef UG_DIM_1 +template class ConvectionDiffusionFV1; +#endif +#ifdef UG_DIM_2 +template class ConvectionDiffusionFV1; +#endif +#ifdef UG_DIM_3 +template class ConvectionDiffusionFV1; +#endif + +} // end namespace ConvectionDiffusionPlugin +} // namespace ug + diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.h b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.h new file mode 100644 index 0000000..6afb1eb --- /dev/null +++ b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.h @@ -0,0 +1,325 @@ +/* + * convection_diffusion_fv1.h + * + * Created on: 26.02.2010 + * Author: andreasvogel + */ + +#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ +#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ + +// library intern headers +#include "../convection_diffusion_base.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +// \ingroup lib_disc_elem_disc +/// \addtogroup convection_diffusion +/// \{ + +/// Discretization for the Convection-Diffusion Equation +/** + * This class implements the IElemDisc interface to provide element local + * assemblings for the convection diffusion equation. + * The Equation has the form + * \f[ + * \partial_t (m1*c + m2) - \nabla \left( D \nabla c - \vec{v} c \right - \vec{F}) + + * r1 \cdot c + r2 = f + f2 + * \f] + * with + *
    + *
  • \f$ c \f$ is the unknown solution + *
  • \f$ m1 \equiv m(\vec{x},t) \f$ is the Mass Scaling Term + *
  • \f$ m2 \equiv m(\vec{x},t) \f$ is the Mass Term + *
  • \f$ D \equiv D(\vec{x},t) \f$ is the Diffusion Tensor + *
  • \f$ v \equiv \vec{v}(\vec{x},t) \f$ is the Velocity Field + *
  • \f$ F \equiv \vec{F}(\vec{x},t) \f$ is the Flux + *
  • \f$ r1 \equiv r(\vec{x},t) \f$ is the Reaction Rate + *
  • \f$ r2 \equiv r(\vec{x},t) \f$ is a Reaction Term + *
  • \f$ f \equiv f(\vec{x},t) \f$ is a Source Term + *
  • \f$ f2 \equiv f_2(\vec{x},t) \f$ is a Vector Source Term + *
+ * + * \tparam TDomain Domain + * \tparam TAlgebra Algebra + */ +template< typename TDomain> +class ConvectionDiffusionFV1 : public ConvectionDiffusionBase +{ + private: + /// Base class type + typedef ConvectionDiffusionBase base_type; + + /// Own type + typedef ConvectionDiffusionFV1 this_type; + + /// error estimator type + typedef SideAndElemErrEstData err_est_type; + + public: + /// World dimension + static const int dim = base_type::dim; + + public: + /// Constructor + ConvectionDiffusionFV1(const char* functions, const char* subsets); + + /// set the upwind method + /** + * This method sets the upwind method used to upwind the convection. + * + * \param shapes upwind method + */ + void set_upwind(SmartPtr > shapes); + + private: + /// prepares the loop over all elements + /** + * This method prepares the loop over all elements. It resizes the Position + * array for the corner coordinates and schedules the local ip positions + * at the data imports. + */ + template + void prep_elem_loop(const ReferenceObjectID roid, const int si); + + /// prepares the element for assembling + /** + * This methods prepares an element for the assembling. The Positions of + * the Element Corners are read and the Finite Volume Geometry is updated. + * The global ip positions are scheduled at the data imports. + */ + template + void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]); + + /// finishes the loop over all elements + template + void fsh_elem_loop(); + + /// assembles the local stiffness matrix using a finite volume scheme + template + void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + + template + void add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + + /// assembles the local mass matrix using a finite volume scheme + template + void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the stiffness part of the local defect + template + void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + /// assembles the stiffness part of the local defect + template + void add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + + template + void add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + + template + number add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem); + + /// assembles the stiffness part of the local defect explicit reaction, reaction_rate and source + template + void add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the mass part of the local defect + template + void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the local right hand side + template + void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_rhs_elem_local(TFVGeom& geo, LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); + + /// prepares the loop over all elements of one type for the computation of the error estimator + template + void prep_err_est_elem_loop(const ReferenceObjectID roid, const int si); + + /// prepares the element for assembling the error estimator + template + void prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// computes the error estimator contribution for one element + template + void compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// computes the error estimator contribution for one element + template + void compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// computes the error estimator contribution for one element + template + void compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// postprocesses the loop over all elements of one type in the computation of the error estimator + template + void fsh_err_est_elem_loop(); + + protected: + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_velocity(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_diffusion(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_flux(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the reaction + template + void lin_def_reaction(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the reaction + template + void lin_def_reaction_rate(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the source term + template + void lin_def_source(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the vector source term + template + void lin_def_vector_source(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the mass scale term + template + void lin_def_mass_scale(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the mass scale term + template + void lin_def_mass(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + private: + /// abbreviation for the local solution + static const size_t _C_ = 0; + + using base_type::m_imDiffusion; + using base_type::m_imVelocity; + using base_type::m_imFlux; + using base_type::m_imSource; + using base_type::m_imSourceExpl; + using base_type::m_imVectorSource; + using base_type::m_imReactionRate; + using base_type::m_imReactionRateExpl; + using base_type::m_imReaction; + using base_type::m_imReactionExpl; + using base_type::m_imMassScale; + using base_type::m_imMass; + + using base_type::m_exGrad; + using base_type::m_exValue; + + protected: + /// method to compute the upwind shapes + SmartPtr > m_spConvShape; + + /// returns the updated convection shapes + typedef IConvectionShapes conv_shape_type; + const IConvectionShapes& get_updated_conv_shapes(const FVGeometryBase& geo); + + /// computes the concentration + template + void ex_value(number vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > vvvDeriv[]); + + /// computes the gradient of the concentration + template + void ex_grad(MathVector vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > > vvvDeriv[]); + + public: + /// type of trial space for each function used + virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid); + + /// returns if hanging nodes are needed + virtual bool use_hanging() const; + + protected: + /// current regular grid flag + bool m_bNonRegularGrid; + + /// current shape function set (needed for GeomProvider::get()) + LFEID m_LFEID; + + /// register utils + /// \{ + void register_all_funcs(bool bHang); + template void register_func(); + /// \} + + private: + /// struct holding values of shape functions in IPs + struct ShapeValues + { + public: + void resize(std::size_t nEip, std::size_t nSip, std::size_t _nSh) + { + nSh = _nSh; + elemVals.resize(nEip); + sideVals.resize(nSip); + for (std::size_t i = 0; i < nEip; i++) elemVals[i].resize(nSh); + for (std::size_t i = 0; i < nSip; i++) sideVals[i].resize(nSh); + } + number& shapeAtElemIP(std::size_t sh, std::size_t ip) {return elemVals[ip][sh];} + number& shapeAtSideIP(std::size_t sh, std::size_t ip) {return sideVals[ip][sh];} + number* shapesAtElemIP(std::size_t ip) {return &elemVals[ip][0];} + number* shapesAtSideIP(std::size_t ip) {return &sideVals[ip][0];} + std::size_t num_sh() {return nSh;} + private: + std::size_t nSh; + std::vector > elemVals; + std::vector > sideVals; + } m_shapeValues; +}; + +// end group convection_diffusion +/// \} + +} // end ConvectionDiffusionPlugin +} // end namespace ug + + +#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__*/ diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.cpp b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.cpp new file mode 100644 index 0000000..cb5858c --- /dev/null +++ b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.cpp @@ -0,0 +1,1828 @@ +/* + * convection_diffusion_fv1.cpp + * + * Created on: 26.02.2010 + * Author: andreasvogel + */ + +#include "convection_diffusion_fv1.h" + +#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" + +#include "lib_disc/spatial_disc/disc_util/geom_provider.h" +//#include "lib_disc/spatial_disc/disc_util/fv1_geom.h" +//#include "lib_disc/spatial_disc/disc_util/hfv1_geom.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +//////////////////////////////////////////////////////////////////////////////// +// general +//////////////////////////////////////////////////////////////////////////////// + +template +ConvectionDiffusionFV1:: +ConvectionDiffusionFV1(const char* functions, const char* subsets) + : ConvectionDiffusionBase(functions,subsets), + m_spConvShape(new ConvectionShapesNoUpwind), + m_bNonRegularGrid(false) +{ + register_all_funcs(m_bNonRegularGrid); +} + + +template +void ConvectionDiffusionFV1:: +prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid) +{ +// check number + if(vLfeID.size() != 1) + UG_THROW("ConvectionDiffusion: Wrong number of functions given. " + "Need exactly "<<1); + + if(vLfeID[0].order() != 1 || vLfeID[0].type() != LFEID::LAGRANGE) + UG_THROW("ConvectionDiffusion FV Scheme only implemented for 1st order."); + +// remember + m_bNonRegularGrid = bNonRegularGrid; + + m_LFEID = vLfeID[0]; + +// update assemble functions + register_all_funcs(m_bNonRegularGrid); +} + +template +bool ConvectionDiffusionFV1:: +use_hanging() const +{ + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Assembling functions +//////////////////////////////////////////////////////////////////////////////// + +template +template +void ConvectionDiffusionFV1:: +prep_elem_loop(const ReferenceObjectID roid, const int si) +{ + // Only first order implementation + if(!(TFVGeom::order == 1)) + UG_THROW("Only first order implementation, but other Finite Volume" + " Geometry set."); + +// check, that upwind has been set + if(m_spConvShape.invalid()) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Upwind has not been set."); + +// set local positions + if(!TFVGeom::usesHangingNodes && TFVGeom::staticLocalData) + { + static const int refDim = TElem::dim; + TFVGeom& geo = GeomProvider::get(); +// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + const MathVector* vSCVFip = geo.scvf_local_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_local_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip, false); + m_imVelocity.template set_local_ips(vSCVFip,numSCVFip, false); + m_imFlux.template set_local_ips(vSCVFip,numSCVFip, false); + m_imSource.template set_local_ips(vSCVip,numSCVip, false); + m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip, false); + m_imReactionRate.template set_local_ips(vSCVip,numSCVip, false); + m_imReaction.template set_local_ips(vSCVip,numSCVip, false); + m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imReactionExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imSourceExpl.template set_local_ips(vSCVip,numSCVip, false); + m_imMassScale.template set_local_ips(vSCVip,numSCVip, false); + m_imMass.template set_local_ips(vSCVip,numSCVip, false); + + // init upwind for element type + if(!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Cannot init upwind for element type."); + } +} + +template +template +void ConvectionDiffusionFV1:: +fsh_elem_loop() +{} + +template +template +void ConvectionDiffusionFV1:: +prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) +{ +// Update Geometry for this element + //static TFVGeom& geo = GeomProvider::get(); +// TFVGeom& geo = GeomProvider::get(m_LFEID,1); + TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); + +// TFVGeom& geo = GeomProvider::get(); +// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + + // fix: set orientation initially globally! + geo.set_orientation(1); + + try{ + geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::prep_elem:" + " Cannot update Finite Volume Geometry."); + +// set local positions + if(TFVGeom::usesHangingNodes || !TFVGeom::staticLocalData) + { + const int refDim = TElem::dim; + const MathVector* vSCVFip = geo.scvf_local_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_local_ips(); + const size_t numSCVip = geo.num_scv_ips(); + m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip); + m_imVelocity.template set_local_ips(vSCVFip,numSCVFip); + m_imFlux.template set_local_ips(vSCVFip,numSCVFip); + m_imSource.template set_local_ips(vSCVip,numSCVip); + m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip); + m_imReactionRate.template set_local_ips(vSCVip,numSCVip); + m_imReaction.template set_local_ips(vSCVip,numSCVip); + m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip); + m_imReactionExpl.template set_local_ips(vSCVip,numSCVip); + m_imSourceExpl.template set_local_ips(vSCVip,numSCVip); + m_imMassScale.template set_local_ips(vSCVip,numSCVip); + m_imMass.template set_local_ips(vSCVip,numSCVip); +/* + if(m_spConvShape.valid()) + if(!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" + " Cannot init upwind for element type."); + */ + } + + // set global positions + const MathVector* vSCVFip = geo.scvf_global_ips(); + const size_t numSCVFip = geo.num_scvf_ips(); + const MathVector* vSCVip = geo.scv_global_ips(); + const size_t numSCVip = geo.num_scv_ips(); + + m_imDiffusion. set_global_ips(vSCVFip, numSCVFip); + m_imVelocity. set_global_ips(vSCVFip, numSCVFip); + m_imFlux. set_global_ips(vSCVFip, numSCVFip); + m_imSource. set_global_ips(vSCVip, numSCVip); + m_imVectorSource. set_global_ips(vSCVFip, numSCVFip); + m_imReactionRate. set_global_ips(vSCVip, numSCVip); + m_imReactionRateExpl. set_global_ips(vSCVip, numSCVip); + m_imReactionExpl. set_global_ips(vSCVip, numSCVip); + m_imSourceExpl. set_global_ips(vSCVip, numSCVip); + m_imReaction. set_global_ips(vSCVip, numSCVip); + m_imMassScale. set_global_ips(vSCVip, numSCVip); + m_imMass. set_global_ips(vSCVip, numSCVip); + +} + + +template +static TVector CalculateCenter(GridObject* o, const TVector* coords) +{ + TVector v; + VecSet(v, 0); + + size_t numCoords = 0; + switch(o->base_object_id()){ + case VERTEX: numCoords = 1; break; + case EDGE: numCoords = static_cast(o)->num_vertices(); break; + case FACE: numCoords = static_cast(o)->num_vertices(); break; + case VOLUME: numCoords = static_cast(o)->num_vertices(); break; + default: UG_THROW("Unknown element type."); break; + } + + for(size_t i = 0; i < numCoords; ++i) + VecAdd(v, v, coords[i]); + + if(numCoords > 0) + VecScale(v, v, 1. / (number)numCoords); + + return v; +} + +void LU(MathMatrix<3, 3>& R, MathMatrix<3, 3>& L, MathMatrix<3, 3> A) +{ + // n-1 Iterationsschritte + for ( size_t i = 1; i < 2; ++i) + { + for ( size_t k = i+1; i < 3; ++i) + { + L[k][i] = R[k][i] / R[i][i]; + + for ( size_t j = i; i < 3; ++i) + R[k][j] = R[k][j] - L[k][i] * R[i][j]; + } + } + +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + + bool debug = false; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + const bool bElementIsCut = geo.get_element_modus(); + const bool bElementIsOutside = geo.get_boolian_for_diffusion(); + + // First call with orientation = 1: + size_t orientation = 1; + geo.set_orientation(orientation); + + +// normal assembling if not cut by interface: + if ( !bElementIsCut ) + { + LocalVector dummyU; + LocalIndices ind = u.get_indices(); + dummyU.resize(ind); + dummyU = 0; + + this->template add_jac_A_elem_local (geo, J, u, dummyU, elem, vCornerCoords, bElementIsOutside); + return; + } + +// get data: + geo.resize_local_data(u); + LocalMatrix& locJ_tri = geo.get_jacobian_tri(); + LocalMatrix& locJ_quad = geo.get_jacobian_quad(); + + LocalVector& locU_tri = geo.get_solution_tri(); + LocalVector& locU_quad = geo.get_solution_quad(); + +// reset data: + locJ_tri = 0; + locJ_quad = 0; + + LocalIndices ind = u.get_indices(); + + // call elem disc twice: + + if ( debug ) geo.print_InterfaceIDdata(); + + ReferenceObjectID roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + + this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, true); + + geo.set_jacobian_tri(locJ_tri); + geo.set_DoF_tag_tri(false); + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + + this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, true); + geo.set_jacobian_quad(locJ_quad); + geo.set_DoF_tag_quad(false); + } + + +// Second call with orientation = 1: + bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! + + orientation *= -1; + geo.set_orientation(orientation); + try{ + geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" + " Cannot update Finite Volume Geometry."); + + if ( debug ) geo.print_InterfaceIDdata(); + + roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + + this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, false); + geo.set_jacobian_tri(locJ_tri); + geo.set_DoF_tag_tri(shiftTag); + + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + + this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, false); + + geo.set_jacobian_quad(locJ_quad); + geo.set_DoF_tag_quad(shiftTag); + } + + +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + ug::MathMatrix diffusion = m_imDiffusion[0]; + if ( bElementIsOutside ) + diffusion *= 1.0; + +// Diff. Tensor times Gradient + MathVector Dgrad; + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// Diffusion and Velocity Term + if(m_imDiffusion.data_given() || m_imVelocity.data_given()) + { + + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + //////////////////////////////////////////////////// + // Diffusive Term + //////////////////////////////////////////////////// + if(m_imDiffusion.data_given()) + { + // loop shape functions + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + // Compute Diffusion Tensor times Gradient + MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); + + // Compute flux at IP + const number D_diff_flux = VecDot(Dgrad, scvf.normal()); + + // Add flux term to local matrix // HIER MATRIXINDIZES!!! + /* UG_ASSERT((scvf.from() < J.num_row_dof(_C_)) && (scvf.to() < J.num_col_dof(_C_)), + "Bad local dof-index on element with object-id " << elem->base_object_id() + << " with center: " << CalculateCenter(elem, vCornerCoords)); +*/ + J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; + J(_C_, scvf.to() , _C_, sh) += D_diff_flux; + } + } + + ///////////////////////////////////////////////////////////////////////////// + // Additional diffusive Term due to jump in solution at the interface + // u^+ - u^- = jump + ///////////////////////////////////////////////////////////////////////////// + if ( 1 ) + { + // loop shape functions + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { + // Compute Diffusion Tensor times Gradient + MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); + + // Compute flux at IP + const number D_diff_flux = jump(_C_,sh)*VecDot(Dgrad, scvf.normal()); + + J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; + J(_C_, scvf.to() , _C_, sh) += D_diff_flux; + } + + } + //////////////////////////////////////////////////// + // Convective Term + //////////////////////////////////////////////////// + if(m_imVelocity.data_given()) + { + // Add Flux contribution + for(size_t sh = 0; sh < convShape.num_sh(); ++sh) + { + const number D_conv_flux = convShape(ip, sh); + + // Add flux term to local matrix + J(_C_, scvf.from(), _C_, sh) += D_conv_flux; + J(_C_, scvf.to(), _C_, sh) -= D_conv_flux; + } + } + + // no explicit dependency on flux import + } + } + + +//////////////////////////////////////////////////// +// Reaction Term (using lumping) +//////////////////////////////////////////////////// + +// if no data for reaction rate given, return + if(!m_imReactionRate.data_given()) return; + +// loop Sub Control Volume (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local matrix + J(_C_, co, _C_, co) += m_imReactionRate[ip] * scv.volume(); + } + +// reaction term does not explicitly depend on the associated unknown function +} + +template +template +void ConvectionDiffusionFV1:: +add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + if(!m_imMassScale.data_given()) return; + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local matrix + J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip]; + } + +// m_imMass part does not explicitly depend on associated unknown function +} + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + bool debug = true; + + // get finite volume geometry + // static const TFVGeom& geo = GeomProvider::get(); + TFVGeom& geo = GeomProvider::get(m_LFEID,1); + const bool bElementIsCut = geo.get_element_modus(); + const bool bElementIsOutside = geo.get_boolian_for_diffusion(); + + // First call with orientation = 1: + size_t orientation = 1; + geo.set_orientation(orientation); + + // necessary for call of 'get_solution_tri' an 'get_solution_quad': + geo.resize_local_data(u); + std::vector imSource; + if ( m_imSource.data_given() ) { + for ( size_t i = 0; i < 3; ++i ) + imSource.push_back(m_imSource[i]); + } + +// normal assembling if not cut by interface: + if ( !bElementIsCut ) + { + LocalVector dummyU; + LocalIndices ind = d.get_indices(); + dummyU.resize(ind); + dummyU = 0; + LocalVector source = geo.set_source(imSource, ind, 3); + + this->template add_def_A_elem_local (geo, d, u, dummyU, dummyU, source, elem, vCornerCoords, bElementIsOutside); + + return; + } + +// get data: + LocalVector& locD_tri = geo.get_defect_tri(); + LocalVector& locD_quad = geo.get_defect_quad(); + + LocalVector& locU_tri = geo.get_solution_tri(); + LocalVector& locU_quad = geo.get_solution_quad(); + +// reset data: + locD_tri = 0; + locD_quad = 0; + + // call elem disc twice: + + if ( debug ) geo.print_InterfaceIDdata(); + + LocalIndices ind = d.get_indices(); + + ReferenceObjectID roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + + LocalVector jump_tri = geo.set_jump_values(ind, 3); + LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); + LocalVector source_tri = geo.set_source(imSource, ind, 3); + + this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords, true); + + geo.set_defect_tri(locD_tri); + geo.set_DoF_tag_tri(false); + + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + + LocalVector jump_quad = geo.set_jump_values(ind, 4); + LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); + LocalVector source_quad = geo.set_source(imSource, ind, 4); + + this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem, vCornerCoords, true); + geo.set_defect_quad(locD_quad); + geo.set_DoF_tag_quad(false); + + } + + +// Second call with orientation = -1: + bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! + + orientation *= -1; + geo.set_orientation(orientation); + try{ + geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" + " Cannot update Finite Volume Geometry."); + + if ( debug ) geo.print_InterfaceIDdata(); + + roidCheck = geo.get_roid(); + if ( roidCheck == ROID_TRIANGLE ) + { + geo.set_local_sol(locU_tri, 3, u, orientation); + LocalVector jump_tri = geo.set_jump_values(ind, 3); + LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); + LocalVector source_tri = geo.set_source(imSource, ind, 3); + + this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords, false); + geo.set_defect_tri(locD_tri); + geo.set_DoF_tag_tri(shiftTag); + } + if ( roidCheck == ROID_QUADRILATERAL ) + { + geo.set_local_sol(locU_quad, 4, u, orientation); + LocalVector jump_quad = geo.set_jump_values(ind, 4); + LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); + LocalVector source_quad = geo.set_source(imSource, ind, 4); + + this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem, vCornerCoords, false); + geo.set_defect_quad(locD_quad); + geo.set_DoF_tag_quad(shiftTag); + + } +} + +template +template +void ConvectionDiffusionFV1:: +add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) +{ + ug::MathMatrix diffusion = m_imDiffusion[0]; + if ( bElementIsOutside ) + diffusion *= 1.0; + + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + ///////////////////////////////////////////////////// + // Diffusive Term + ///////////////////////////////////////////////////// + if(m_imDiffusion.data_given()) + { + // to compute D \nabla c + MathVector Dgrad_c, grad_c; + + // compute gradient and shape at ip + VecSet(grad_c, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad_c, u(_C_,sh), scvf.global_grad(sh)); + + // scale by diffusion tensor + MatVecMult(Dgrad_c, diffusion, grad_c); + + // Compute flux + const number diff_flux = VecDot(Dgrad_c, scvf.normal()); + + // Add to local defect + d(_C_, scvf.from()) -= diff_flux; + d(_C_, scvf.to() ) += diff_flux; + + } + + ///////////////////////////////////////////////////////////////////////////// + // Additional diffusive Term due to jump in solution at the interface + // u^+ - u^- = jump + ///////////////////////////////////////////////////////////////////////////// + if ( 1 ) + { + // scale diffusion by jump in solution: + // const double jump = 2.0; + // diffusion *= jump; + + // to compute D \nabla c=Id_interface + MathVector Dgrad, grad; + + // compute gradient and shape at ip + VecSet(grad, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + { VecScaleAppend(grad, jump(_C_,sh), scvf.global_grad(sh)); + UG_LOG("jump(_C_,sh): " << jump(_C_,sh) << "\n"); + } + // scale by diffusion tensor + MatVecMult(Dgrad, diffusion, grad); + + // Compute flux + const number diff_flux = VecDot(Dgrad, scvf.normal()); + + // Add to local defect + d(_C_, scvf.from()) -= diff_flux; + d(_C_, scvf.to() ) += diff_flux; + + } + } + + ///////////////////////////////////////////////////// + // add rhs during same method! + // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! + ///////////////////////////////////////////////////// + + if ( 1 ) { //m_imSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { + + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); + + // get associated node + int co = scv.node_id(); + + // Add to local rhs +/* if ( co > 2 ) + d(_C_, co) -= m_imSource[2] * scv.volume(); + else + d(_C_, co) -= m_imSource[co] * scv.volume(); +*/ + d(_C_, co) -= source(_C_, co) * scv.volume(); + UG_LOG("source: " << source(_C_, co) << "\n"); + UG_LOG("d(_C_, co): " << d(_C_, co) << "\n"); + + //if ( fabs(scv.volume()-0.00260416) > 0.00001 ) + } + } + ///////////////////////////////////////////////////////////////////////////// + // Additional source Term due to jump in gradient at the interface + // (\nabla u^+ - \nabla u^-)\cdot n = h(x) * |n| + ///////////////////////////////////////////////////////////////////////////// + if ( 1 ) + { + // Add to local rhs + for ( size_t sh = 0; sh < geo.num_scv(); ++sh ) + d(_C_, sh) -= jump_grad(_C_,sh); + } + +} + +template +template +void ConvectionDiffusionFV1:: +add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + +// reaction rate + if(m_imReactionRateExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local defect + d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume(); + } + } + +// reaction + if(m_imReactionExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local defect + d(_C_, co) += m_imReactionExpl[ip] * scv.volume(); + } + } + + if(m_imSourceExpl.data_given()) + { + // loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) -= m_imSourceExpl[ip] * scv.volume(); + } + } +} + +template +template +void ConvectionDiffusionFV1:: +add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ +// get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + if(!m_imMassScale.data_given() && !m_imMass.data_given()) return; + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // mass value + number val = 0.0; + + // multiply by scaling + if(m_imMassScale.data_given()) + val += m_imMassScale[ip] * u(_C_, co); + + // add mass + if(m_imMass.data_given()) + val += m_imMass[ip]; + + // Add to local defect + d(_C_, co) += val * scv.volume(); + } +} + + +template +template +void ConvectionDiffusionFV1:: +add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) +{ + ///////////////////////////////////////////////////// + // add rhs ALLREADY(!) during 'add_def_A_elem_local()' method! + // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! + ///////////////////////////////////////////////////// + + return; + + // get finite volume geometry +// static const TFVGeom& geo = GeomProvider::get(); + static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); + + // loop Sub Control Volumes (SCV) + if ( m_imSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); + + // get associated node + const int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) += m_imSource[ip] * scv.volume(); + } + } + + // loop Sub Control Volumes (SCVF) + if ( m_imVectorSource.data_given() ) { + for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); + + // Add to local rhs + d(_C_, scvf.from()) -= VecDot(m_imVectorSource[ip], scvf.normal() ); + d(_C_, scvf.to() ) += VecDot(m_imVectorSource[ip], scvf.normal() ); + } + } +} + + +//////////////////////////////////// +/// error estimation (begin) /// + +// prepares the loop over all elements of one type for the computation of the error estimator +template +template +void ConvectionDiffusionFV1:: +prep_err_est_elem_loop(const ReferenceObjectID roid, const int si) +{ + // get the error estimator data object and check that it is of the right type + // we check this at this point in order to be able to dispense with this check later on + // (i.e. in prep_err_est_elem and compute_err_est_A_elem()) + if (this->m_spErrEstData.get() == NULL) + { + UG_THROW("No ErrEstData object has been given to this ElemDisc!"); + } + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (!err_est_data) + { + UG_THROW("Dynamic cast to SideAndElemErrEstData failed." + << std::endl << "Make sure you handed the correct type of ErrEstData to this discretization."); + } + + +// check that upwind has been set + if (m_spConvShape.invalid()) + UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " + "Upwind has not been set."); + +// set local positions + if (!TFVGeom::usesHangingNodes) + { + static const int refDim = TElem::dim; + + // get local IPs + size_t numSideIPs, numElemIPs; + const MathVector* sideIPs; + const MathVector* elemIPs; + try + { + numSideIPs = err_est_data->num_all_side_ips(roid); + numElemIPs = err_est_data->num_elem_ips(roid); + sideIPs = err_est_data->template side_local_ips(roid); + elemIPs = err_est_data->template elem_local_ips(roid); + + if (!sideIPs || !elemIPs) return; // are NULL if TElem is not of the same dim as TDomain + } + UG_CATCH_THROW("Integration points for error estimator cannot be set."); + + // set local IPs in imports + m_imDiffusion.template set_local_ips(sideIPs, numSideIPs, false); + m_imVelocity.template set_local_ips(sideIPs, numSideIPs, false); + m_imFlux.template set_local_ips(sideIPs, numSideIPs, false); + m_imSource.template set_local_ips(elemIPs, numElemIPs, false); + m_imVectorSource.template set_local_ips(sideIPs, numSideIPs, false); + m_imReactionRate.template set_local_ips(elemIPs, numElemIPs, false); + m_imReaction.template set_local_ips(elemIPs, numElemIPs, false); + m_imMassScale.template set_local_ips(elemIPs, numElemIPs, false); + m_imMass.template set_local_ips(elemIPs, numElemIPs, false); + + // init upwind for element type + TFVGeom& geo = GeomProvider::get(); + if (!m_spConvShape->template set_geometry_type(geo)) + UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " + "Cannot init upwind for element type."); + + // store values of shape functions in local IPs + LagrangeP1::reference_element_type> trialSpace + = Provider::reference_element_type> >::get(); + + m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh()); + for (size_t ip = 0; ip < numElemIPs; ip++) + trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]); + for (size_t ip = 0; ip < numSideIPs; ip++) + trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]); + } +} + +template +template +void ConvectionDiffusionFV1:: +prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{} + +// computes the error estimator contribution (stiffness part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ + typedef typename reference_element_traits::reference_element_type ref_elem_type; + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + +// request geometry + static const TFVGeom& geo = GeomProvider::get(); + +//////////////// +// SIDE TERMS // +//////////////// + +// get the sides of the element + // We have to cast elem to a pointer of type SideAndElemErrEstData::elem_type + // for the SideAndElemErrEstData::operator() to work properly. + // This cannot generally be achieved by casting to TElem*, since this method is also registered for + // lower-dimensional types TElem, and must therefore be compilable, even if it is never EVER to be executed. + // The way we achieve this here, is by calling associated_elements_sorted() which has an implementation for + // all possible types. Whatever comes out of it is of course complete nonsense if (and only if) + // SideAndElemErrEstData::elem_type != TElem. To be on the safe side, we throw an error if the number of + // entries in the list is not as it should be. + + typename MultiGrid::traits::side_type>::secure_container side_list; + pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); + if (side_list.size() != (size_t) ref_elem_type::numSides) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// some help variables + MathVector fluxDensity, gradC, normal; + +// calculate grad u (take grad from first scvf ip (grad u is constant on the entire element)) + if (geo.num_scvf() < 1) {UG_THROW("Element has no SCVFs!");} + const typename TFVGeom::SCVF& scvf = geo.scvf(0); + + VecSet(gradC, 0.0); + for (size_t j=0; j(normal, side, vCornerCoords); + VecNormalize(normal, normal); + + try + { + for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) + { + size_t ip = passedIPs + sip; + + VecSet(fluxDensity, 0.0); + + ////// diffusion ////// + if (m_imDiffusion.data_given()) + MatVecScaleMultAppend(fluxDensity, -1.0, m_imDiffusion[0], gradC); + + ////// convection ////// + if (m_imVelocity.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtSideIP(sh,sip); + + VecScaleAppend(fluxDensity, val, m_imVelocity[ip]); + } + + ////// general flux ////// + if (m_imFlux.data_given()) + VecAppend(fluxDensity, m_imFlux[ip]); + + (*err_est_data)(side_list[side],sip) += scale * VecDot(fluxDensity, normal); + } + + passedIPs += err_est_data->num_side_ips(side_list[side]); + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); + } + +////////////////// +// VOLUME TERMS // +////////////////// + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + { + number total = 0.0; + + ////// diffusion ////// TODO ONLY FOR (PIECEWISE) CONSTANT DIFFUSION TENSOR SO FAR! + // div(D*grad(c)) = div(v)*u + v*grad(c) + // nothing to do, as u is piecewise linear and div(D*grad(c)) disappears + + ////// convection ////// TODO ONLY FOR CONSTANT VELOCITY FIELDS SO FAR! + // div(v*c) = div(v)*u + v*grad(c) -- gradC has been calculated above + if (m_imVelocity.data_given()) + total += VecDot(m_imVelocity[ip], gradC); + + ////// general flux ////// TODO ONLY FOR DIVERGENCE-FREE FLUX FIELD SO FAR! + // nothing to do + + ////// reaction ////// + if (m_imReactionRate.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < geo.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); + + total += m_imReactionRate[ip] * val; + } + + if (m_imReaction.data_given()) + { + total += m_imReaction[ip]; + } + + (*err_est_data)(elem_list[0],ip) += scale * total; + } + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// computes the error estimator contribution (mass part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ +// note: mass parts only enter volume term + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// request geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop integration points + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + { + number total = 0.0; + + ////// mass scale ////// + if (m_imMassScale.data_given()) + { + number val = 0.0; + for (size_t sh = 0; sh < geo.num_sh(); sh++) + val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); + + total += m_imMassScale[ip] * val; + } + + ////// mass ////// + if (m_imMass.data_given()) + { + total += m_imMass[ip]; + } + + (*err_est_data)(elem_list[0],ip) += scale * total; + } + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// computes the error estimator contribution (rhs part) for one element +template +template +void ConvectionDiffusionFV1:: +compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale) +{ + typedef typename reference_element_traits::reference_element_type ref_elem_type; + + err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + + if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} + MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); + +//////////////// +// SIDE TERMS // +//////////////// +// get the sides of the element + typename MultiGrid::traits::side_type>::secure_container side_list; + pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); + if (side_list.size() != (size_t) ref_elem_type::numSides) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +// loop sides + size_t passedIPs = 0; + for (size_t side = 0; side < (size_t) ref_elem_type::numSides; side++) + { + // normal on side + MathVector normal; + SideNormal(normal, side, vCornerCoords); + VecNormalize(normal, normal); + + try + { + for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) + { + size_t ip = passedIPs + sip; + + ////// vector source ////// + if (m_imVectorSource.data_given()) + (*err_est_data)(side_list[side],sip) += scale * VecDot(m_imVectorSource[ip], normal); + } + + passedIPs += err_est_data->num_side_ips(side_list[side]); + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); + } + +////////////////// +// VOLUME TERMS // +////////////////// + if (!m_imSource.data_given()) return; + + typename MultiGrid::traits::elem_type>::secure_container elem_list; + pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); + if (elem_list.size() != 1) + UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); + +////// source ////// + try + { + for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) + (*err_est_data)(elem_list[0],ip) += scale * m_imSource[ip]; + } + UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl + << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); +} + +// postprocesses the loop over all elements of one type in the computation of the error estimator +template +template +void ConvectionDiffusionFV1:: +fsh_err_est_elem_loop() +{ +// finish the element loop in the same way as the actual discretization + this->template fsh_elem_loop (); +}; + +/// error estimation (end) /// +//////////////////////////////////// + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +lin_def_velocity(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // sum up contributions of convection shapes + MathVector linDefect; + VecSet(linDefect, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(linDefect, u(_C_,sh), convShape.D_vel(ip, sh)); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] += linDefect; + vvvLinDef[ip][_C_][scvf.to()] -= linDefect; + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +lin_def_diffusion(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes(geo); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // compute gradient at ip + MathVector grad_u; VecSet(grad_u, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad_u, u(_C_,sh), scvf.global_grad(sh)); + + // compute the lin defect at this ip + MathMatrix linDefect; + + // part coming from -\nabla u * \vec{n} + for(size_t k=0; k < (size_t)dim; ++k) + for(size_t j = 0; j < (size_t)dim; ++j) + linDefect(j,k) = (scvf.normal())[j] * grad_u[k]; + + // add contribution from convection shapes + if(convShape.non_zero_deriv_diffusion()) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + MatAdd(linDefect, convShape.D_diffusion(ip, sh), u(_C_, sh)); + + // add contributions + vvvLinDef[ip][_C_][scvf.from()] -= linDefect; + vvvLinDef[ip][_C_][scvf.to() ] += linDefect; + } +} + +template +template +void ConvectionDiffusionFV1:: +lin_def_flux(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] += scvf.normal(); + vvvLinDef[ip][_C_][scvf.to()] -= scvf.normal(); + } +} +// computes the linearized defect w.r.t to the reaction rate +template +template +void ConvectionDiffusionFV1:: +lin_def_reaction_rate(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = u(_C_, co) * scv.volume(); + } +} + +// computes the linearized defect w.r.t to the reaction +template +template +void ConvectionDiffusionFV1:: +lin_def_reaction(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the source +template +template +void ConvectionDiffusionFV1:: +lin_def_source(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t ip = 0; ip < geo.num_scv(); ++ip) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(ip); + + // get associated node + const int co = scv.node_id(); + + // set lin defect + vvvLinDef[ip][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the vector source +// (in analogy to velocity) +template +template +void ConvectionDiffusionFV1:: +lin_def_vector_source(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip) +{ + // get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + + // loop Sub Control Volumes Faces (SCVF) + for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { + // get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][scvf.from()] -= scvf.normal(); + vvvLinDef[ip][_C_][scvf.to()] += scvf.normal(); + } +} + +// computes the linearized defect w.r.t to the mass scale +template +template +void ConvectionDiffusionFV1:: +lin_def_mass_scale(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t co = 0; co < geo.num_scv(); ++co) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(co); + + // Check associated node + UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); + + // set lin defect + vvvLinDef[co][_C_][co] = u(_C_, co) * scv.volume(); + } +} + +// computes the linearized defect w.r.t to the mass scale +template +template +void ConvectionDiffusionFV1:: +lin_def_mass(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// loop Sub Control Volumes (SCV) + for(size_t co = 0; co < geo.num_scv(); ++co) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv(co); + + // Check associated node + UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); + + // set lin defect + vvvLinDef[co][_C_][co] = scv.volume(); + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +ex_value(number vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > vvvDeriv[]) +{ +// get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reference element + typedef typename reference_element_traits::reference_element_type + ref_elem_type; + +// number of shape functions + static const size_t numSH = ref_elem_type::numCorners; + +// FV1 SCVF ip + if(vLocIP == geo.scvf_local_ips()) + { + // Loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // Get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + // compute concentration at ip + vValue[ip] = 0.0; + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vValue[ip] += u(_C_, sh) * scvf.shape(sh); + + // compute derivative w.r.t. to unknowns iff needed + if(bDeriv) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vvvDeriv[ip][_C_][sh] = scvf.shape(sh); + } + } +// FV1 SCV ip + else if(vLocIP == geo.scv_local_ips()) + { + // solution at ip + for(size_t sh = 0; sh < numSH; ++sh) + vValue[sh] = u(_C_, sh); + + // set derivatives if needed + if(bDeriv) + for(size_t sh = 0; sh < numSH; ++sh) + for(size_t sh2 = 0; sh2 < numSH; ++sh2) + vvvDeriv[sh][_C_][sh2] = (sh==sh2) ? 1.0 : 0.0; + } +// general case + else + { + // get trial space + LagrangeP1& rTrialSpace = Provider >::get(); + + // storage for shape function at ip + number vShape[numSH]; + + // loop ips + for(size_t ip = 0; ip < nip; ++ip) + { + // evaluate at shapes at ip + rTrialSpace.shapes(vShape, vLocIP[ip]); + + // compute concentration at ip + vValue[ip] = 0.0; + for(size_t sh = 0; sh < numSH; ++sh) + vValue[ip] += u(_C_, sh) * vShape[sh]; + + // compute derivative w.r.t. to unknowns iff needed + // \todo: maybe store shapes directly in vvvDeriv + if(bDeriv) + for(size_t sh = 0; sh < numSH; ++sh) + vvvDeriv[ip][_C_][sh] = vShape[sh]; + } + } +} + +// computes the linearized defect w.r.t to the velocity +template +template +void ConvectionDiffusionFV1:: +ex_grad(MathVector vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > > vvvDeriv[]) +{ +// Get finite volume geometry + static const TFVGeom& geo = GeomProvider::get(); + +// reference element + typedef typename reference_element_traits::reference_element_type + ref_elem_type; + +// reference dimension + static const int refDim = ref_elem_type::dim; + +// number of shape functions + static const size_t numSH = ref_elem_type::numCorners; + +// FV1 SCVF ip + if(vLocIP == geo.scvf_local_ips()) + { + // Loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < geo.num_scvf(); ++ip) + { + // Get current SCVF + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + + VecSet(vValue[ip], 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(vValue[ip], u(_C_, sh), scvf.global_grad(sh)); + + if(bDeriv) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + vvvDeriv[ip][_C_][sh] = scvf.global_grad(sh); + } + } +// general case + else + { + // get trial space + LagrangeP1& rTrialSpace = Provider >::get(); + + // storage for shape function at ip + MathVector vLocGrad[numSH]; + MathVector locGrad; + + // Reference Mapping + MathMatrix JTInv; + ReferenceMapping mapping(vCornerCoords); + + // loop ips + for(size_t ip = 0; ip < nip; ++ip) + { + // evaluate at shapes at ip + rTrialSpace.grads(vLocGrad, vLocIP[ip]); + + // compute grad at ip + VecSet(locGrad, 0.0); + for(size_t sh = 0; sh < numSH; ++sh) + VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]); + + // compute global grad + mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]); + MatVecMult(vValue[ip], JTInv, locGrad); + + // compute derivative w.r.t. to unknowns iff needed + if(bDeriv) + for(size_t sh = 0; sh < numSH; ++sh) + MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// upwind +//////////////////////////////////////////////////////////////////////////////// + +template +void ConvectionDiffusionFV1:: +set_upwind(SmartPtr > shapes) {m_spConvShape = shapes;} + +// computes the linearized defect w.r.t to the velocity +template +const typename ConvectionDiffusionFV1::conv_shape_type& +ConvectionDiffusionFV1:: +get_updated_conv_shapes(const FVGeometryBase& geo) +{ +// compute upwind shapes for transport equation +// \todo: we should move this computation into the preparation part of the +// disc, to only compute the shapes once, reusing them several times. + if(m_imVelocity.data_given()) + { + // get diffusion at ips + const MathMatrix* vDiffusion = NULL; + if(m_imDiffusion.data_given()) vDiffusion = m_imDiffusion.values(); + + // update convection shapes + if(!m_spConvShape->update(&geo, m_imVelocity.values(), vDiffusion, true)) + { + UG_LOG("ERROR in 'ConvectionDiffusionFV1::add_jac_A_elem': " + "Cannot compute convection shapes.\n"); + } + } + +// return a const (!!) reference to the upwind + return *const_cast*>(m_spConvShape.get()); +} + + +//////////////////////////////////////////////////////////////////////////////// +// register assemble functions +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + + /* +// switch assemble functions + if(!bHang) + { + register_func >(); + } + else + { + register_func >(); + } +*/ +} +#endif + +#ifdef UG_DIM_2 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + /* +// switch assemble functions + if(!bHang) + { + register_func >(); + register_func >(); + register_func >(); + } + else + { + register_func >(); + register_func >(); + register_func >(); + } + */ +} +#endif + +#ifdef UG_DIM_3 +template<> +void ConvectionDiffusionFV1:: +register_all_funcs(bool bHang) +{ + register_func > >(); + + /* +// switch assemble functions + if(!bHang) + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + } + else + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + } + */ +} +#endif + +template +template +void ConvectionDiffusionFV1:: +register_func() +{ + ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; + typedef this_type T; + static const int refDim = reference_element_traits::dim; + + this->clear_add_fct(id); + this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); + this->set_prep_elem_fct( id, &T::template prep_elem); + this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); + this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem); + this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem); + this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem); + this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem); + this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem); + this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); + +// error estimator parts +/* this->set_prep_err_est_elem_loop(id, &T::template prep_err_est_elem_loop); + this->set_prep_err_est_elem(id, &T::template prep_err_est_elem); + this->set_compute_err_est_A_elem(id, &T::template compute_err_est_A_elem); + this->set_compute_err_est_M_elem(id, &T::template compute_err_est_M_elem); + this->set_compute_err_est_rhs_elem(id, &T::template compute_err_est_rhs_elem); + this->set_fsh_err_est_elem_loop(id, &T::template fsh_err_est_elem_loop); +*/ +// set computation of linearized defect w.r.t velocity + m_imDiffusion.set_fct(id, this, &T::template lin_def_diffusion); + m_imVelocity. set_fct(id, this, &T::template lin_def_velocity); + m_imFlux.set_fct(id, this, &T::template lin_def_flux); + m_imReactionRate. set_fct(id, this, &T::template lin_def_reaction_rate); + m_imReaction. set_fct(id, this, &T::template lin_def_reaction); + m_imSource. set_fct(id, this, &T::template lin_def_source); + m_imVectorSource.set_fct(id, this, &T::template lin_def_vector_source); + m_imMassScale.set_fct(id, this, &T::template lin_def_mass_scale); + m_imMass. set_fct(id, this, &T::template lin_def_mass); + +// exports + m_exValue-> template set_fct(id, this, &T::template ex_value); + m_exGrad->template set_fct(id, this, &T::template ex_grad); +} + +//////////////////////////////////////////////////////////////////////////////// +// explicit template instantiations +//////////////////////////////////////////////////////////////////////////////// +#ifdef UG_DIM_1 +template class ConvectionDiffusionFV1; +#endif +#ifdef UG_DIM_2 +template class ConvectionDiffusionFV1; +#endif +#ifdef UG_DIM_3 +template class ConvectionDiffusionFV1; +#endif + +} // end namespace ConvectionDiffusionPlugin +} // namespace ug + diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.h b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.h new file mode 100644 index 0000000..8b3dea8 --- /dev/null +++ b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.h @@ -0,0 +1,316 @@ +/* + * convection_diffusion_fv1.h + * + * Created on: 26.02.2010 + * Author: andreasvogel + */ + +#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ +#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ + +// library intern headers +#include "../convection_diffusion_base.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +// \ingroup lib_disc_elem_disc +/// \addtogroup convection_diffusion +/// \{ + +/// Discretization for the Convection-Diffusion Equation +/** + * This class implements the IElemDisc interface to provide element local + * assemblings for the convection diffusion equation. + * The Equation has the form + * \f[ + * \partial_t (m1*c + m2) - \nabla \left( D \nabla c - \vec{v} c \right - \vec{F}) + + * r1 \cdot c + r2 = f + f2 + * \f] + * with + *
    + *
  • \f$ c \f$ is the unknown solution + *
  • \f$ m1 \equiv m(\vec{x},t) \f$ is the Mass Scaling Term + *
  • \f$ m2 \equiv m(\vec{x},t) \f$ is the Mass Term + *
  • \f$ D \equiv D(\vec{x},t) \f$ is the Diffusion Tensor + *
  • \f$ v \equiv \vec{v}(\vec{x},t) \f$ is the Velocity Field + *
  • \f$ F \equiv \vec{F}(\vec{x},t) \f$ is the Flux + *
  • \f$ r1 \equiv r(\vec{x},t) \f$ is the Reaction Rate + *
  • \f$ r2 \equiv r(\vec{x},t) \f$ is a Reaction Term + *
  • \f$ f \equiv f(\vec{x},t) \f$ is a Source Term + *
  • \f$ f2 \equiv f_2(\vec{x},t) \f$ is a Vector Source Term + *
+ * + * \tparam TDomain Domain + * \tparam TAlgebra Algebra + */ +template< typename TDomain> +class ConvectionDiffusionFV1 : public ConvectionDiffusionBase +{ + private: + /// Base class type + typedef ConvectionDiffusionBase base_type; + + /// Own type + typedef ConvectionDiffusionFV1 this_type; + + /// error estimator type + typedef SideAndElemErrEstData err_est_type; + + public: + /// World dimension + static const int dim = base_type::dim; + + public: + /// Constructor + ConvectionDiffusionFV1(const char* functions, const char* subsets); + + /// set the upwind method + /** + * This method sets the upwind method used to upwind the convection. + * + * \param shapes upwind method + */ + void set_upwind(SmartPtr > shapes); + + private: + /// prepares the loop over all elements + /** + * This method prepares the loop over all elements. It resizes the Position + * array for the corner coordinates and schedules the local ip positions + * at the data imports. + */ + template + void prep_elem_loop(const ReferenceObjectID roid, const int si); + + /// prepares the element for assembling + /** + * This methods prepares an element for the assembling. The Positions of + * the Element Corners are read and the Finite Volume Geometry is updated. + * The global ip positions are scheduled at the data imports. + */ + template + void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]); + + /// finishes the loop over all elements + template + void fsh_elem_loop(); + + /// assembles the local stiffness matrix using a finite volume scheme + template + void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + + /// assembles the local mass matrix using a finite volume scheme + template + void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the stiffness part of the local defect + template + void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + /// assembles the stiffness part of the local defect + template + void add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); + + /// assembles the stiffness part of the local defect explicit reaction, reaction_rate and source + template + void add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the mass part of the local defect + template + void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the local right hand side + template + void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); + template + void add_rhs_elem_local(TFVGeom& geo, LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); + + /// prepares the loop over all elements of one type for the computation of the error estimator + template + void prep_err_est_elem_loop(const ReferenceObjectID roid, const int si); + + /// prepares the element for assembling the error estimator + template + void prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// computes the error estimator contribution for one element + template + void compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// computes the error estimator contribution for one element + template + void compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// computes the error estimator contribution for one element + template + void compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale); + + /// postprocesses the loop over all elements of one type in the computation of the error estimator + template + void fsh_err_est_elem_loop(); + + protected: + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_velocity(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_diffusion(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the velocity + template + void lin_def_flux(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the reaction + template + void lin_def_reaction(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the reaction + template + void lin_def_reaction_rate(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the source term + template + void lin_def_source(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the vector source term + template + void lin_def_vector_source(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the mass scale term + template + void lin_def_mass_scale(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the mass scale term + template + void lin_def_mass(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + private: + /// abbreviation for the local solution + static const size_t _C_ = 0; + + using base_type::m_imDiffusion; + using base_type::m_imVelocity; + using base_type::m_imFlux; + using base_type::m_imSource; + using base_type::m_imSourceExpl; + using base_type::m_imVectorSource; + using base_type::m_imReactionRate; + using base_type::m_imReactionRateExpl; + using base_type::m_imReaction; + using base_type::m_imReactionExpl; + using base_type::m_imMassScale; + using base_type::m_imMass; + + using base_type::m_exGrad; + using base_type::m_exValue; + + protected: + /// method to compute the upwind shapes + SmartPtr > m_spConvShape; + + /// returns the updated convection shapes + typedef IConvectionShapes conv_shape_type; + const IConvectionShapes& get_updated_conv_shapes(const FVGeometryBase& geo); + + /// computes the concentration + template + void ex_value(number vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > vvvDeriv[]); + + /// computes the gradient of the concentration + template + void ex_grad(MathVector vValue[], + const MathVector vGlobIP[], + number time, int si, + const LocalVector& u, + GridObject* elem, + const MathVector vCornerCoords[], + const MathVector vLocIP[], + const size_t nip, + bool bDeriv, + std::vector > > vvvDeriv[]); + + public: + /// type of trial space for each function used + virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid); + + /// returns if hanging nodes are needed + virtual bool use_hanging() const; + + protected: + /// current regular grid flag + bool m_bNonRegularGrid; + + /// current shape function set (needed for GeomProvider::get()) + LFEID m_LFEID; + + /// register utils + /// \{ + void register_all_funcs(bool bHang); + template void register_func(); + /// \} + + private: + /// struct holding values of shape functions in IPs + struct ShapeValues + { + public: + void resize(std::size_t nEip, std::size_t nSip, std::size_t _nSh) + { + nSh = _nSh; + elemVals.resize(nEip); + sideVals.resize(nSip); + for (std::size_t i = 0; i < nEip; i++) elemVals[i].resize(nSh); + for (std::size_t i = 0; i < nSip; i++) sideVals[i].resize(nSh); + } + number& shapeAtElemIP(std::size_t sh, std::size_t ip) {return elemVals[ip][sh];} + number& shapeAtSideIP(std::size_t sh, std::size_t ip) {return sideVals[ip][sh];} + number* shapesAtElemIP(std::size_t ip) {return &elemVals[ip][0];} + number* shapesAtSideIP(std::size_t ip) {return &sideVals[ip][0];} + std::size_t num_sh() {return nSh;} + private: + std::size_t nSh; + std::vector > elemVals; + std::vector > sideVals; + } m_shapeValues; +}; + +// end group convection_diffusion +/// \} + +} // end ConvectionDiffusionPlugin +} // end namespace ug + + +#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__*/ From 794ade62d57f7d874c888eb3871bafb217bc1c88 Mon Sep 17 00:00:00 2001 From: Susanne Date: Mon, 23 Sep 2019 21:05:43 +0200 Subject: [PATCH 2/3] final cleaningConvectionDiffusin plugin --- CMakeLists.txt | 4 +- convection_diffusion_plugin.cpp | 165 +- convection_diffusion_plugin_Kopie.cpp | 271 -- convection_diffusion_sss.h | 196 ++ fe/convection_diffusion_fe.cpp | 42 +- fe/convection_diffusion_stab_fe.cpp | 444 +++ fe/convection_diffusion_stab_fe.h | 212 ++ fractfv1/convection_diffusion_fractfv1.cpp | 1462 +++++++++ fractfv1/convection_diffusion_fractfv1.h | 441 +++ fv1_cutElem/Info File 1 | 31 + fv1_cutElem/Info File 2 | 39 + .../convection_diffusion_fv1 Kopie.cpp | 2617 ----------------- fv1_cutElem/convection_diffusion_fv1 Kopie.h | 363 --- .../convection_diffusion_fv1_cutElem.cpp | 843 ++---- .../convection_diffusion_fv1_cutElem.h | 57 +- .../___immersed_bnd_cond_diffusion_impl.h | 952 ------ .../diffusion_interface Kopie.h | 235 -- .../diffusion_interface/diffusion_interface.h | 275 +- .../diffusion_interface_impl Kopie.h | 371 --- .../diffusion_interface_impl.h | 263 +- .../loc_to_glob_mapper_diffusion.h | 126 +- .../loc_to_glob_mapper_diffusion_impl.h | 294 +- 22 files changed, 3759 insertions(+), 5944 deletions(-) delete mode 100644 convection_diffusion_plugin_Kopie.cpp create mode 100644 convection_diffusion_sss.h create mode 100644 fe/convection_diffusion_stab_fe.cpp create mode 100644 fe/convection_diffusion_stab_fe.h create mode 100644 fractfv1/convection_diffusion_fractfv1.cpp create mode 100644 fractfv1/convection_diffusion_fractfv1.h create mode 100644 fv1_cutElem/Info File 1 create mode 100644 fv1_cutElem/Info File 2 delete mode 100644 fv1_cutElem/convection_diffusion_fv1 Kopie.cpp delete mode 100644 fv1_cutElem/convection_diffusion_fv1 Kopie.h delete mode 100644 fv1_cutElem/diffusion_interface/___immersed_bnd_cond_diffusion_impl.h delete mode 100644 fv1_cutElem/diffusion_interface/diffusion_interface Kopie.h delete mode 100644 fv1_cutElem/diffusion_interface/diffusion_interface_impl Kopie.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6359a24..00fa761 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,10 +38,12 @@ set(pluginName ConvectionDiffusion) set(SOURCES convection_diffusion_base.cpp fv1/convection_diffusion_fv1.cpp - fv1_cutElem/convection_diffusion_fv1_cutElem.cpp + fv1_cutElem/convection_diffusion_fv1_cutElem.cpp fe/convection_diffusion_fe.cpp + fe/convection_diffusion_stab_fe.cpp fvcr/convection_diffusion_fvcr.cpp fv/convection_diffusion_fv.cpp + fractfv1/convection_diffusion_fractfv1.cpp convection_diffusion_plugin.cpp) diff --git a/convection_diffusion_plugin.cpp b/convection_diffusion_plugin.cpp index c5169fc..df98912 100644 --- a/convection_diffusion_plugin.cpp +++ b/convection_diffusion_plugin.cpp @@ -38,17 +38,18 @@ #include "bridge/util_domain_dependent.h" #include "bridge/util_domain_algebra_dependent.h" #include "convection_diffusion_base.h" +#include "convection_diffusion_sss.h" #include "fv1/convection_diffusion_fv1.h" #include "fv1_cutElem/convection_diffusion_fv1_cutElem.h" #include "fe/convection_diffusion_fe.h" +#include "fe/convection_diffusion_stab_fe.h" #include "fvcr/convection_diffusion_fvcr.h" #include "fv/convection_diffusion_fv.h" - #include "fv1_cutElem/diffusion_interface/diffusion_interface.h" //#include "lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion.h" -#include "lib_disc/spatial_disc/elem_disc/sss.h" +#include "fractfv1/convection_diffusion_fractfv1.h" using namespace std; using namespace ug::bridge; @@ -173,7 +174,12 @@ static void Domain(Registry& reg, string grp) #endif .add_method("value", &T::value) - .add_method("gradient", &T::gradient); + .add_method("gradient", &T::gradient); + /* + .add_method("set_partial_velocity", &T::set_partial_velocity) + .add_method("set_partial_flux", &T::set_partial_flux) + .add_method("set_partial_mass", &T::set_partial_mass); + */ reg.add_class_to_group(name, "ConvectionDiffusionBase", tag); } @@ -185,12 +191,13 @@ static void Domain(Registry& reg, string grp) reg.add_class_(name, grp) .template add_constructor("Function(s)#Subset(s)") .add_method("set_upwind", &T::set_upwind) - .add_method("set_singular_sources_and_sinks", &T::set_sss, "", "Singular Sources and Sinks") + .add_method("set_singular_sources_and_sinks", &T::set_sss_manager, "", "Sets the singular sources and sinks manager") + .add_method("singular_sources_and_sinks", &T::sss_manager, "", "Returns the singular sources and sinks manager") .set_construct_as_smart_pointer(true); reg.add_class_to_group(name, "ConvectionDiffusionFV1", tag); } -// Convection Diffusion FV1 non-conforming Boundary +// Convection Diffusion FV1 immersed Boundary { typedef ConvectionDiffusionFV1_cutElem T; typedef ConvectionDiffusionBase TBase; @@ -198,7 +205,7 @@ static void Domain(Registry& reg, string grp) reg.add_class_(name, grp) .template add_constructor("Function(s)#Subset(s)") .add_method("set_upwind", &T::set_upwind) - .add_method("set_singular_sources_and_sinks", &T::set_sss, "", "Singular Sources and Sinks") + .add_method("set_testCase", &T::set_testCase) .set_construct_as_smart_pointer(true); reg.add_class_to_group(name, "ConvectionDiffusionFV1_cutElem", tag); } @@ -215,6 +222,21 @@ static void Domain(Registry& reg, string grp) reg.add_class_to_group(name, "ConvectionDiffusionFE", tag); } +// Convection Diffusion (FE) stabilization + { + typedef ConvectionDiffusionStabFE T; + typedef IElemDisc TBase; + string name = string("ConvectionDiffusionStabFE").append(suffix); + reg.add_class_(name, grp) + .template add_constructor("Function(s)#Subset(s)") + .template add_constructor("Function(s)#Subset(s)#stabilization") + .template add_constructor("Function(s)#Subset(s)#stabilization") + .add_method("set_quad_order", &T::set_quad_order) + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "ConvectionDiffusionStabFE", tag); + } + + // Convection Diffusion FVCR { typedef ConvectionDiffusionFVCR T; @@ -259,31 +281,33 @@ static void Domain(Registry& reg, string grp) typedef GridFunction function_type; - // MovingInterfaceDiffusion + // ImmersedInterfaceDiffusion { - typedef MovingInterfaceDiffusion T; - typedef IMovingInterface TBase; - string name = string("MovingInterfaceDiffusion").append(suffix); + typedef ImmersedInterfaceDiffusion T; + typedef IImmersedInterface TBase; + string name = string("ImmersedInterfaceDiffusion").append(suffix); reg.add_class_(name, grp) .template add_constructor > ass, SmartPtr > spMaster, SmartPtr > interfaceProvider, - SmartPtr > cutElementHandler)>("domain disc, global handler") + SmartPtr > cutElementHandler)>("domain disc, global handler") .add_method("init", &T::init) - .add_method("set_source_data", &T::set_source_data) - .add_method("set_jump_data", &T::set_jump_data) - .add_method("set_jump_grad_data", &T::set_jump_grad_data) - .add_method("set_diffusion_data", &T::set_diffusion_data) - .add_method("get_integral", &T::get_integral) + .add_method("set_source_data_lua", &T::set_source_data_lua) + .add_method("set_jump_data_lua", &T::set_jump_data_lua) + .add_method("set_diffusion_data_lua", &T::set_diffusion_data_lua) + .add_method("set_jump_grad_data_lua", &T::set_jump_grad_data_lua) + .add_method("get_L2Error", &T::get_L2Error) .add_method("get_numDoFs", &T::get_numDoFs) .add_method("set_Nitsche", &T::set_Nitsche) + .add_method("set_print_cutElemData", &T::set_print_cutElemData) + .add_method("get_numCutElements", &T::get_numCutElements) .add_method("adjust_for_error", &T::adjust_for_error) .add_method("initialize_threshold", &T::initialize_threshold) - .add_method("set_threshold", &T::set_threshold, "", "Set Threshold") - .add_method("set_analytic_solution", &T::set_analytic_solution, "", "Set Threshold") + .add_method("set_threshold", &T::set_threshold) + .add_method("set_analytic_solution", &T::set_analytic_solution) .set_construct_as_smart_pointer(true); - reg.add_class_to_group(name, "MovingInterfaceDiffusion", tag); + reg.add_class_to_group(name, "ImmersedInterfaceDiffusion", tag); } } @@ -296,46 +320,119 @@ static void Dimension(Registry& reg, string grp) // singular sources and sinks { - typedef SingularSourcesAndSinks T; - string name = string("CdSingularSourcesAndSinks").append(dimSuffix); + typedef CDSingularSourcesAndSinks T; + typedef typename T::point_sss_type TPointSSS; + typedef typename T::line_sss_type TLineSSS; + + string point_name = string("CDPointSourcesSink").append(dimSuffix); + reg.add_class_(point_name, grp) + .template add_constructor&)> () + .add_method ("set", static_cast (&TPointSSS::set)) + .add_method ("set", static_cast (&TPointSSS::set)) + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(point_name, "CDPointSourcesSink", dimTag); + + string line_name = string("CDLineSourcesSink").append(dimSuffix); + reg.add_class_(line_name, grp) + .template add_constructor&, const std::vector&)> () + .add_method ("set", static_cast (&TLineSSS::set)) + .add_method ("set", static_cast (&TLineSSS::set)) + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(line_name, "CDLineSourcesSink", dimTag); + + string name = string("CDSingularSourcesAndSinks").append(dimSuffix); reg.add_class_(name, grp) .add_constructor() - .add_method("addps", static_cast&, const std::vector&)>(&T::addps)) - .add_method("addls", static_cast&, const std::vector&, const std::vector&)>(&T::addls)) + .add_method ("add_point", static_cast)> (&T::add_point)) + .add_method ("add_line", static_cast)> (&T::add_line)) + .set_construct_as_smart_pointer(true); + reg.add_class_to_group(name, "CDSingularSourcesAndSinks", dimTag); + } +} + +}; // end Functionality + +/** + * Class exporting the functionality of the plugin restricted to 2 and 3 spatial + * dimensions. All functionality that is to be used in scripts or visualization + * only in 2d and 3d must be registered here. + */ +struct Functionality2d3d +{ + +/** + * Function called for the registration of Domain dependent parts + * of the plugin. All Functions and Classes depending on the Domain + * are to be placed here when registering. The method is called for all + * available Domain types, based on the current build options. + * + * @param reg registry + * @param parentGroup group for sorting of functionality + */ +template +static void Domain(Registry& reg, string grp) +{ + static const int dim = TDomain::dim; + string suffix = GetDomainSuffix(); + string tag = GetDomainTag(); + +// Convection Diffusion FV1 for the low-dimensional fractures + { + typedef ConvectionDiffusionFractFV1 T; + typedef ConvectionDiffusionBase TBase; + string name = string("ConvectionDiffusionFractFV1").append(suffix); + reg.add_class_(name, grp) + .template add_constructor("Function(s)#Subset(s)") + .add_method("set_fract_manager", static_cast >)>(&T::set_fract_manager), "Sets the fracture manager", "Deg. fracture manager") + .add_method("set_upwind", &T::set_upwind) + .add_method("set_aperture", static_cast >)>(&T::set_aperture), "", "Fract. aperture") + .add_method("set_aperture", static_cast(&T::set_aperture), "", "Fract. aperture") +#ifdef UG_FOR_LUA + .add_method("set_aperture", static_cast(&T::set_aperture), "", "Fract. aperture") + .add_method("set_aperture", static_cast(&T::set_aperture), "", "Fract. aperture") +#endif + .add_method("set_ortho_velocity", static_cast >)>(&T::set_ortho_velocity), "", "Orthogonal Velocity Field") + .add_method("set_ortho_velocity", static_cast(&T::set_ortho_velocity), "", "Orthogonal Velocity Field") #ifdef UG_FOR_LUA - .add_method("addps", static_cast&, LuaFunctionHandle)>(&T::addps)) - .add_method("addls", static_cast&, const std::vector&, LuaFunctionHandle)>(&T::addls)) + .add_method("set_ortho_velocity", static_cast(&T::set_ortho_velocity), "", "Orthogonal Velocity Field") + .add_method("set_ortho_velocity", static_cast(&T::set_ortho_velocity), "", "Orthogonal Velocity Field") +#endif + .add_method("set_ortho_diffusion", static_cast >)>(&T::set_ortho_diffusion), "", "Orthogonal Diffusion") + .add_method("set_ortho_diffusion", static_cast(&T::set_ortho_diffusion), "", "Orthogonal Diffusion") +#ifdef UG_FOR_LUA + .add_method("set_ortho_diffusion", static_cast(&T::set_ortho_diffusion), "", "Orthogonal Diffusion") + .add_method("set_ortho_diffusion", static_cast(&T::set_ortho_diffusion), "", "Orthogonal Diffusion") #endif .set_construct_as_smart_pointer(true); - reg.add_class_to_group(name, "CdSingularSourcesAndSinks", dimTag); + reg.add_class_to_group(name, "ConvectionDiffusionFractFV1", tag); } - // CutElementHandlerImmersed + // CutElementHandler_TwoSided { - typedef CutElementHandlerImmersed T; - string name = string("CutElementHandlerImmersed").append(dimSuffix); + typedef CutElementHandler_TwoSided T; + string name = string("CutElementHandler_TwoSided").append(suffix); reg.add_class_(name, grp) .template add_constructor mg, const char*, SmartPtr >)>("multigrid, fct names") .set_construct_as_smart_pointer(true); - reg.add_class_to_group(name, "CutElementHandlerImmersed", dimTag); + reg.add_class_to_group(name, "CutElementHandler_TwoSided", tag); } // DiffusionInterfaceProvider { typedef DiffusionInterfaceProvider T; - string name = string("DiffusionInterfaceProvider").append(dimSuffix); + string name = string("DiffusionInterfaceProvider").append(suffix); reg.add_class_(name, grp) .template add_constructor("") .add_method("print", &T::print) .add_method("add", &T::add) .set_construct_as_smart_pointer(true); - reg.add_class_to_group(name, "DiffusionInterfaceProvider", dimTag); + reg.add_class_to_group(name, "DiffusionInterfaceProvider", tag); } } -}; // end Functionality +}; // end Functionality2d3d // end group convection_diffusion /// \} @@ -351,12 +448,14 @@ InitUGPlugin_ConvectionDiffusion(Registry* reg, string grp) { grp.append("/SpatialDisc/ElemDisc"); typedef ConvectionDiffusionPlugin::Functionality Functionality; + typedef ConvectionDiffusionPlugin::Functionality2d3d Functionality2d3d; try{ RegisterDimensionDependent(*reg,grp); RegisterDomainDependent(*reg,grp); RegisterDomainAlgebraDependent(*reg,grp); + RegisterDomain2d3dDependent(*reg,grp); } UG_REGISTRY_CATCH_THROW(grp); } diff --git a/convection_diffusion_plugin_Kopie.cpp b/convection_diffusion_plugin_Kopie.cpp deleted file mode 100644 index eaf61c9..0000000 --- a/convection_diffusion_plugin_Kopie.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (c) 2012-2015: G-CSC, Goethe University Frankfurt - * Author: Andreas Vogel - * - * This file is part of UG4. - * - * UG4 is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License version 3 (as published by the - * Free Software Foundation) with the following additional attribution - * requirements (according to LGPL/GPL v3 §7): - * - * (1) The following notice must be displayed in the Appropriate Legal Notices - * of covered and combined works: "Based on UG4 (www.ug4.org/license)". - * - * (2) The following notice must be displayed at a prominent place in the - * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". - * - * (3) The following bibliography is recommended for citation and must be - * preserved in all covered files: - * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively - * parallel geometric multigrid solver on hierarchically distributed grids. - * Computing and visualization in science 16, 4 (2013), 151-164" - * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel - * flexible software system for simulating pde based models on high performance - * computers. Computing and visualization in science 16, 4 (2013), 165-179" - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - */ - -/** - * File for registration of ConvectionDiffusion routines. - */ - -#include "bridge/util.h" -#include "bridge/util_domain_dependent.h" -#include "convection_diffusion_base.h" -#include "fv1/convection_diffusion_fv1.h" -#include "fe/convection_diffusion_fe.h" -#include "fvcr/convection_diffusion_fvcr.h" -#include "fv/convection_diffusion_fv.h" - -#include "lib_disc/spatial_disc/elem_disc/sss.h" - -using namespace std; -using namespace ug::bridge; - -namespace ug{ -namespace ConvectionDiffusionPlugin{ - -/** - * \defgroup convection_diffusion Convection Diffusion - * \ingroup plugins - * This plugin provides the discretization of convection and diffusion problems. - * \{ - */ - -/** - * Class exporting the functionality of the plugin. All functionality that is to - * be used in scripts or visualization must be registered here. - */ -struct Functionality -{ - -/** - * Function called for the registration of Domain dependent parts - * of the plugin. All Functions and Classes depending on the Domain - * are to be placed here when registering. The method is called for all - * available Domain types, based on the current build options. - * - * @param reg registry - * @param parentGroup group for sorting of functionality - */ -template -static void Domain(Registry& reg, string grp) -{ - static const int dim = TDomain::dim; - string suffix = GetDomainSuffix(); - string tag = GetDomainTag(); - -// Convection Diffusion Base - { - typedef ConvectionDiffusionBase T; - typedef IElemDisc TBase; - string name = string("ConvectionDiffusionBase").append(suffix); - reg.add_class_(name, grp) - .add_method("set_diffusion", static_cast, dim> >)>(&T::set_diffusion), "", "Diffusion") - .add_method("set_diffusion", static_cast(&T::set_diffusion), "", "Diagonal Diffusion") -#ifdef UG_FOR_LUA - .add_method("set_diffusion", static_cast(&T::set_diffusion), "", "Diffusion") - .add_method("set_diffusion", static_cast(&T::set_diffusion), "", "Diffusion") -#endif - - .add_method("set_velocity", static_cast, dim> >)>(&T::set_velocity), "", "Velocity Field") - .add_method("set_velocity", static_cast&)>(&T::set_velocity), "", "Velocity Field") -#ifdef UG_FOR_LUA - .add_method("set_velocity", static_cast(&T::set_velocity), "", "Velocity Field") - .add_method("set_velocity", static_cast(&T::set_velocity), "", "Velocity Field") -#endif - - .add_method("set_flux", static_cast, dim> >)>(&T::set_flux), "", "Flux") - .add_method("set_flux", static_cast&)>(&T::set_flux), "", "Flux") -#ifdef UG_FOR_LUA - .add_method("set_flux", static_cast(&T::set_flux), "", "Flux") - .add_method("set_flux", static_cast(&T::set_flux), "", "Flux") -#endif - - .add_method("set_reaction_rate", static_cast >)>(&T::set_reaction_rate), "", "Reaction Rate") - .add_method("set_reaction_rate", static_cast(&T::set_reaction_rate), "", "Reaction Rate") -#ifdef UG_FOR_LUA - .add_method("set_reaction_rate", static_cast(&T::set_reaction_rate), "", "Reaction Rate") - .add_method("set_reaction_rate", static_cast(&T::set_reaction_rate), "", "Reaction Rate") -#endif - - .add_method("set_reaction", static_cast >)>(&T::set_reaction), "", "Reaction") - .add_method("set_reaction", static_cast(&T::set_reaction), "", "Reaction") -#ifdef UG_FOR_LUA - .add_method("set_reaction", static_cast(&T::set_reaction), "", "Reaction") - .add_method("set_reaction", static_cast(&T::set_reaction), "", "Reaction") -#endif - - .add_method("set_reaction_rate_explicit", static_cast >)>(&T::set_reaction_rate_explicit), "", "Reaction Rate Explicit") - .add_method("set_reaction_rate_explicit", static_cast(&T::set_reaction_rate_explicit), "", "Reaction Rate Explicit") -#ifdef UG_FOR_LUA - .add_method("set_reaction_rate_explicit", static_cast(&T::set_reaction_rate_explicit), "", "Reaction Rate Explicit") -#endif - - .add_method("set_reaction_explicit", static_cast >)>(&T::set_reaction_explicit), "", "Reaction Explicit") - .add_method("set_reaction_explicit", static_cast(&T::set_reaction_explicit), "", "Reaction Explicit") -#ifdef UG_FOR_LUA - .add_method("set_reaction_explicit", static_cast(&T::set_reaction_explicit), "", "Reaction Explicit") -#endif - - .add_method("set_source_explicit", static_cast >)>(&T::set_source_explicit), "", "Source Explicit") - .add_method("set_source_explicit", static_cast(&T::set_source_explicit), "", "Source Explicit") - #ifdef UG_FOR_LUA - .add_method("set_source_explicit", static_cast(&T::set_source_explicit), "", "Source Explicit") - #endif - - .add_method("set_source", static_cast >)>(&T::set_source), "", "Source") - .add_method("set_source", static_cast(&T::set_source), "", "Source") -#ifdef UG_FOR_LUA - .add_method("set_source", static_cast(&T::set_source), "", "Source") - .add_method("set_source", static_cast(&T::set_source), "", "Source") -#endif - - .add_method("set_vector_source", static_cast, dim> >)>(&T::set_vector_source), "", "Vector Source") -#ifdef UG_FOR_LUA - .add_method("set_vector_source", static_cast(&T::set_vector_source), "", "Vector Source") - .add_method("set_vector_source", static_cast(&T::set_vector_source), "", "Vector Source") -#endif - - .add_method("set_mass_scale", static_cast >)>(&T::set_mass_scale), "", "Mass Scale") - .add_method("set_mass_scale", static_cast(&T::set_mass_scale), "", "Mass Scale") -#ifdef UG_FOR_LUA - .add_method("set_mass_scale", static_cast(&T::set_mass_scale), "", "Mass Scale") - .add_method("set_mass_scale", static_cast(&T::set_mass_scale), "", "Mass Scale") -#endif - - .add_method("set_mass", static_cast >)>(&T::set_mass), "", "Mass") - .add_method("set_mass", static_cast(&T::set_mass), "", "Mass") -#ifdef UG_FOR_LUA - .add_method("set_mass", static_cast(&T::set_mass), "", "Mass") - .add_method("set_mass", static_cast(&T::set_mass), "", "Mass") -#endif - - .add_method("value", &T::value) - .add_method("gradient", &T::gradient); - reg.add_class_to_group(name, "ConvectionDiffusionBase", tag); - } - -// Convection Diffusion FV1 - { - typedef ConvectionDiffusionFV1 T; - typedef ConvectionDiffusionBase TBase; - string name = string("ConvectionDiffusionFV1").append(suffix); - reg.add_class_(name, grp) - .template add_constructor("Function(s)#Subset(s)") - .add_method("set_upwind", &T::set_upwind) - .add_method("set_singular_sources_and_sinks", &T::set_sss, "", "Singular Sources and Sinks") - .set_construct_as_smart_pointer(true); - reg.add_class_to_group(name, "ConvectionDiffusionFV1", tag); - } - -// Convection Diffusion FE - { - typedef ConvectionDiffusionFE T; - typedef ConvectionDiffusionBase TBase; - string name = string("ConvectionDiffusionFE").append(suffix); - reg.add_class_(name, grp) - .template add_constructor("Function(s)#Subset(s)") - .add_method("set_quad_order", &T::set_quad_order) - .set_construct_as_smart_pointer(true); - reg.add_class_to_group(name, "ConvectionDiffusionFE", tag); - } - -// Convection Diffusion FVCR - { - typedef ConvectionDiffusionFVCR T; - typedef ConvectionDiffusionBase TBase; - string name = string("ConvectionDiffusionFVCR").append(suffix); - reg.add_class_(name, grp) - .template add_constructor("Function(s)#Subset(s)") - .add_method("set_upwind", &T::set_upwind) - .set_construct_as_smart_pointer(true); - reg.add_class_to_group(name, "ConvectionDiffusionFVCR", tag); - } - -// Convection Diffusion FV - { - typedef ConvectionDiffusionFV T; - typedef ConvectionDiffusionBase TBase; - string name = string("ConvectionDiffusionFV").append(suffix); - reg.add_class_(name, grp) - .template add_constructor("Function(s)#Subset(s)") - .add_method("set_quad_order", &T::set_quad_order) - .set_construct_as_smart_pointer(true); - reg.add_class_to_group(name, "ConvectionDiffusionFV", tag); - } -} - -template -static void Dimension(Registry& reg, string grp) -{ - string dimSuffix = GetDimensionSuffix(); - string dimTag = GetDimensionTag(); - - // singular sources and sinks - { - typedef SingularSourcesAndSinks T; - string name = string("CdSingularSourcesAndSinks").append(dimSuffix); - reg.add_class_(name, grp) - .add_constructor() - .add_method("addps", static_cast&, const std::vector&)>(&T::addps)) - .add_method("addls", static_cast&, const std::vector&, const std::vector&)>(&T::addls)) -#ifdef UG_FOR_LUA - .add_method("addps", static_cast&, LuaFunctionHandle)>(&T::addps)) - .add_method("addls", static_cast&, const std::vector&, LuaFunctionHandle)>(&T::addls)) -#endif - .set_construct_as_smart_pointer(true); - reg.add_class_to_group(name, "CdSingularSourcesAndSinks", dimTag); - } -} - -}; // end Functionality - -// end group convection_diffusion -/// \} - -} // end namespace ConvectionDiffusionPlugin - - -/** - * This function is called when the plugin is loaded. - */ -extern "C" void -InitUGPlugin_ConvectionDiffusion(Registry* reg, string grp) -{ - grp.append("/SpatialDisc/ElemDisc"); - typedef ConvectionDiffusionPlugin::Functionality Functionality; - - try{ - RegisterDimensionDependent(*reg,grp); - RegisterDomainDependent(*reg,grp); - } - UG_REGISTRY_CATCH_THROW(grp); -} - -}// namespace ug diff --git a/convection_diffusion_sss.h b/convection_diffusion_sss.h new file mode 100644 index 0000000..638222c --- /dev/null +++ b/convection_diffusion_sss.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2019: G-CSC, Goethe University Frankfurt + * Author: Dmitry Logashenko / Michael Lampe + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +/* + * Singular (point and line) sources and sinks in ConvectionDiffusion. + */ +#ifndef __H__UG__PLUGINS__CD__SINGULAR_SOURCES_AND_SINKS__ +#define __H__UG__PLUGINS__CD__SINGULAR_SOURCES_AND_SINKS__ + +#include + +// ug4 headers +#include "lib_disc/spatial_disc/disc_util/fv1_sss.h" +#include "lib_disc/spatial_disc/user_data/user_data.h" + +#ifdef UG_FOR_LUA +#include "bindings/lua/lua_user_data.h" +#endif + +namespace ug { +namespace ConvectionDiffusionPlugin { + +/// class for data for all the CD plugin sources and sinks +template +class cd_sss_data +{ + /** the data for the source/sink: + * [0]: total contaminant flux through the point + */ + MathVector<1> m_values; + + SmartPtr, dim> > m_spData; ///< an alternative method to specify the data + +public: + +/// class construction (there must exist a 'dummy' constructor!) + cd_sss_data () {m_values [0] = 0;} + +/// returns the flux + number flux () {return m_values [0];} + +/// computes the data from the user data object + void compute + ( + const MathVector& x, ///< point where to evaluate + number time, ///< time argument for the evaluation + int si ///< subset where to evaluate + ) + { + if (m_spData.valid ()) + (* m_spData) (m_values, x, time, si); + } + +/// sets the data + void set (number flux) + { + m_values[0] = flux; + m_spData = SPNULL; + } + +/// sets the data by an object + void set (SmartPtr, dim> > spData) + { + m_spData = spData; + } + +/// set as a LUA function + void set (LuaFunctionHandle func) + { + m_spData = make_sp (new LuaUserData, dim> (func)); + } +}; + +/** Class for markers of the point sources and sinks + * + * Note that there the point sinks are only used for full-dimensional subdomains. + */ +class point_sss_marker +{ + GridObject * m_elem; ///< grid element for the source/sink (not to take it into account twice) + size_t m_co; ///< corner of the element (not to take it into account twice inside of the element) + +public: + +/// class constructor + point_sss_marker () : m_elem (NULL), m_co (0) {}; + +/// resets the mark + void init () {m_elem = NULL; m_co = 0;} + +/// check and set the element mark + bool marked_for (GridObject * elem, size_t co) + { + if (m_elem == NULL) + { + m_elem = elem; m_co = co; + return true; + } + return m_elem == elem && m_co == co; + } +}; + +/** Class for markers of the line sources and sinks + * + * Note that for fractures, line sources/sinks are point sources/sinks. + * For full-dimensional subdomains, there is up to now no special markers. + */ +class line_sss_marker +{ +// All the members are used in the fractures only! + +/// a special structure to identify the element and its corner in a fracture + struct t_fract_elem + { + IVertexGroup * fract_face; + size_t fract_co; + + t_fract_elem (IVertexGroup * face, size_t co) : fract_face (face), fract_co (co) {}; + }; + +/// array keeping the elements from different(!) fractures + std::vector m_intersections; + +public: + +/// class constructor + line_sss_marker () {}; + +/// reset the mark + void init () {m_intersections.clear ();} + +/// check and set the element mark (use it only for fractures!) + bool marked_for (IVertexGroup * elem, size_t co) + { + // is the fracture already processed? + for (size_t i = 0; i < m_intersections.size (); i++) + { + // check if we have already registered this mark + t_fract_elem& intersection = m_intersections[i]; + if (intersection.fract_face == elem) + return intersection.fract_co == co; + + // check if a different corner is meant (i.e. this is the same fracture) + Vertex * vrt = elem->vertex (co); + for (size_t j = 0; j < intersection.fract_face->num_vertices (); j++) + if (vrt == intersection.fract_face->vertex (j)) + return false; // in this fracture, we use a different corner + } + // no, register this fracture, too + m_intersections.push_back (t_fract_elem (elem, co)); + return true; + } +}; + +template class cd_point_sss_data : public cd_sss_data, public point_sss_marker {}; +template class cd_line_sss_data : public cd_sss_data, public line_sss_marker {}; +template +class CDSingularSourcesAndSinks + : public FVSingularSourcesAndSinks, cd_line_sss_data > +{}; + +} // namespace ConvectionDiffusionPlugin +} // end namespace ug + +#endif // __H__UG__PLUGINS__CD__SINGULAR_SOURCES_AND_SINKS__ + +/* End of File */ diff --git a/fe/convection_diffusion_fe.cpp b/fe/convection_diffusion_fe.cpp index 6d2b1df..0acf665 100644 --- a/fe/convection_diffusion_fe.cpp +++ b/fe/convection_diffusion_fe.cpp @@ -97,21 +97,20 @@ template void ConvectionDiffusionFE:: prep_elem_loop(const ReferenceObjectID roid, const int si) { - if( m_imSourceExpl.data_given() || - m_imReactionExpl.data_given() || - m_imReactionRateExpl.data_given()) - UG_THROW("ConvectionDiffusionFE: Explicit terms not implemented."); + // Check for explicit terms. + UG_COND_THROW(m_imSourceExpl.data_given() || m_imReactionExpl.data_given() || m_imReactionRateExpl.data_given(), + "ConvectionDiffusionFE: Explicit terms not implemented."); -// request geometry + // Request geometry. TFEGeom& geo = GeomProvider::get(m_lfeID, m_quadOrder); -// prepare geometry for type and order + // Prepare geometry for type and order. try{ geo.update_local(roid, m_lfeID, m_quadOrder); - }UG_CATCH_THROW("ConvectionDiffusion::prep_elem_loop:" + } UG_CATCH_THROW("ConvectionDiffusion::prep_elem_loop:" << " Cannot update Finite Element Geometry."); -// set local positions + // Set local positions. static const int refDim = TElem::dim; m_imDiffusion.template set_local_ips(geo.local_ips(), geo.num_ip(), false); m_imVelocity.template set_local_ips(geo.local_ips(), geo.num_ip(), false); @@ -389,18 +388,14 @@ prep_err_est_elem_loop(const ReferenceObjectID roid, const int si) // get the error estimator data object and check that it is of the right type // we check this at this point in order to be able to dispense with this check later on // (i.e. in prep_err_est_elem and compute_err_est_A_elem()) - if (this->m_spErrEstData.get() == NULL) - { - UG_THROW("No ErrEstData object has been given to this ElemDisc!"); - } + UG_COND_THROW(this->m_spErrEstData.get() == NULL, + "No ErrEstData object has been given to this ElemDisc!"); err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - if (!err_est_data) - { - UG_THROW("Dynamic cast to SideAndElemErrEstData failed." - << std::endl << "Make sure you handed the correct type of ErrEstData to this discretization."); - } + UG_COND_THROW(!err_est_data, "Dynamic cast to SideAndElemErrEstData failed." << std::endl + << "Make sure you handed the correct type of ErrEstData to this discretization."); + // set local positions static const int refDim = TElem::dim; @@ -496,11 +491,11 @@ compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector< typedef typename reference_element_traits::reference_element_type ref_elem_type; err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); + UG_COND_THROW(err_est_data->surface_view().get() == NULL, "Error estimator has NULL surface view."); - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); -// request geometry + // Request geometry. static const TFEGeom& geo = GeomProvider::get(); @@ -521,7 +516,7 @@ compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector< if (side_list.size() != (size_t) ref_elem_type::numSides) UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFE::compute_err_est_elem'"); -// some help variables + // Some auxiliary variables. MathVector fluxDensity, gradC, normal; // FIXME: The computation of the gradient has to be reworked. @@ -529,7 +524,7 @@ compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector< // the gradient is not constant (but bilinear) on the element - and along the sides. // We cannot use the FVGeom here. Instead, we need to calculate the gradient in each IP! - // calculate grad u as average (over scvf) + // Calculate grad(u) as average (over scvf). VecSet(gradC, 0.0); for(size_t ii = 0; ii < geo.num_ip(); ++ii) { @@ -538,7 +533,7 @@ compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector< } VecScale(gradC, gradC, (1.0/geo.num_ip())); -// calculate flux through the sides + // Calculate flux through the sides. size_t passedIPs = 0; for (size_t side=0; side < (size_t) ref_elem_type::numSides; side++) { @@ -585,8 +580,7 @@ compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector< typename MultiGrid::traits::elem_type>::secure_container elem_list; pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFE::compute_err_est_elem'"); + UG_COND_THROW (elem_list.size() != 1, "Mismatch of numbers of sides in 'ConvectionDiffusionFE::compute_err_est_elem'"); try { diff --git a/fe/convection_diffusion_stab_fe.cpp b/fe/convection_diffusion_stab_fe.cpp new file mode 100644 index 0000000..44a4069 --- /dev/null +++ b/fe/convection_diffusion_stab_fe.cpp @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2018-: G-CSC, Goethe University Frankfurt + * Author: Arne Naegel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#include "convection_diffusion_stab_fe.h" + + +#include "lib_disc/spatial_disc/disc_util/fe_geom.h" +#include "lib_disc/spatial_disc/disc_util/geom_provider.h" +#include "lib_disc/local_finite_element/lagrange/lagrange.h" +#include "lib_disc/local_finite_element/lagrange/lagrangep1.h" +#include "lib_disc/quadrature/gauss/gauss_quad.h" + +#include "lib_grid/algorithms/volume_calculation.h" // For computing bounding box + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +//////////////////////////////////////////////////////////////////////////////// +// general +//////////////////////////////////////////////////////////////////////////////// + +template +ConvectionDiffusionStabFE:: +ConvectionDiffusionStabFE(const char* functions, const char* subsets) + : base_type(functions,subsets), + m_bQuadOrderUserDef(false), m_stabParamM(0.0), m_stabParamA(0.0) +{ + this->clear_add_fct(); +} + + +template +ConvectionDiffusionStabFE:: +ConvectionDiffusionStabFE(const char* functions, const char* subsets, double stabM) + : base_type(functions,subsets), + m_bQuadOrderUserDef(false), m_stabParamM(stabM), m_stabParamA(0.0) +{ + this->clear_add_fct(); +} + +template +ConvectionDiffusionStabFE:: +ConvectionDiffusionStabFE(const char* functions, const char* subsets, double stabM, double stabA) + : base_type(functions,subsets), + m_bQuadOrderUserDef(false), m_stabParamM(stabM), m_stabParamA(stabA) +{ + this->clear_add_fct(); +} + + +template +void ConvectionDiffusionStabFE:: +set_quad_order(size_t order) +{ + m_quadOrder = order; + m_bQuadOrderUserDef = true; +} + +template +void ConvectionDiffusionStabFE:: +prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid) +{ + // check number of fcts + if(vLfeID.size() != 1) + UG_THROW("ConvectionDiffusionStab: Wrong number of functions given. " + "Need exactly "<<1); + + // check that not ADAPTIVE + if(vLfeID[0].order() < 1) + UG_THROW("ConvectionDiffusionStab: Adaptive order not implemented."); + + // set order + m_lfeID = vLfeID[0]; + if(!m_bQuadOrderUserDef) m_quadOrder = 2*m_lfeID.order()+1; + + register_all_funcs(m_lfeID, m_quadOrder); +} + +template +bool ConvectionDiffusionStabFE:: +use_hanging() const +{ + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// Assembling functions +//////////////////////////////////////////////////////////////////////////////// + +template +template +void ConvectionDiffusionStabFE:: +prep_elem_loop(const ReferenceObjectID roid, const int si) +{ + +// request geometry + TFEGeom& geo = GeomProvider::get(m_lfeID, m_quadOrder); + +// prepare geometry for type and order + try{ + geo.update_local(roid, m_lfeID, m_quadOrder); + }UG_CATCH_THROW("ConvectionDiffusion::prep_elem_loop:" + " Cannot update Finite Element Geometry."); + +// set local positions +// static const int refDim = TElem::dim; +// m_imDiffusion.template set_local_ips(geo.local_ips(), geo.num_ip(), false); + +} + +template +template +void ConvectionDiffusionStabFE:: +fsh_elem_loop() +{} + +template +template +void ConvectionDiffusionStabFE:: +prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) +{ +// request geometry + TFEGeom& geo = GeomProvider::get(m_lfeID, m_quadOrder); + + try{ + geo.update(elem, vCornerCoords); + } + UG_CATCH_THROW("ConvectionDiffusion::prep_elem:" + " Cannot update Finite Element Geometry."); + +// set global positions for rhs + // m_imDiffusion. set_global_ips(geo.global_ips(), geo.num_ip()); + +} + + +/*! + * Assemble contribution: \sigma \int_{tau} \sum h_i^2 \partial_i u^k \partial_i v + */ +template +template +void ConvectionDiffusionStabFE:: +add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + const TFEGeom& geo = // Geometry + GeomProvider::get(m_lfeID, m_quadOrder); + /* const number scale = // Scaling factor + ElementDiameterSq(*elem, *this->domain()); */ + + MathVector vBoundingBox[2]; // Element bounding box + CalculateBoundingBox(NumVertices((TElem*)elem), vCornerCoords, vBoundingBox[0], vBoundingBox[1]); + + MathVector gradU; // Temporary + + // Loop integration points. + for (size_t ip = 0; ip < geo.num_ip(); ++ip) + { + // Loop trial space + VecSet(gradU, 0.0); + for (size_t psh = 0; psh < geo.num_sh(); ++psh) + VecScaleAppend(gradU, u(_C_, psh), geo.global_grad(ip, psh)); // * scale + + // Scale gradient + for(size_t i = 0; i < dim; ++i) + { + double hi = vBoundingBox[1][i] - vBoundingBox[0][i]; + gradU[i] *= (hi*hi); + } + + for (size_t psh = 0; psh < geo.num_sh(); ++psh) + { + d(_C_, psh) += + m_stabParamM * VecDot(geo.global_grad(ip, psh), gradU) * geo.weight(ip); + } + } + +} + + + +template +template +void ConvectionDiffusionStabFE:: +add_jac_X_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], double m_stabParam) +{ + const TFEGeom& geo = // request geometry + GeomProvider::get(m_lfeID, m_quadOrder); + /* const number scale = // Scaling factor + ElementDiameterSq(*elem, *this->domain());*/ + + MathVector vBoundingBox[2]; + CalculateBoundingBox(NumVertices((TElem*)elem), vCornerCoords, vBoundingBox[0], vBoundingBox[1]); + + // rescale using bounding box + for (size_t ip = 0; ip < geo.num_ip(); ++ip){ + for (size_t psh = 0; psh < geo.num_sh(); ++psh){ + + // Rescaled gradient (using bounding box) + MathVector grad = geo.global_grad(ip, psh); // *scale + for(size_t i = 0; i < dim; ++i) + { + double hi = vBoundingBox[1][i] - vBoundingBox[0][i]; + grad[i] *= (hi*hi); + } + + for (size_t psh2 = 0; psh2 < geo.num_sh(); ++psh2) + { + J(_C_, psh, _C_, psh2) += //* scale + m_stabParam* VecDot(grad, geo.global_grad(ip, psh2)) * geo.weight(ip); + } + } + } + +} + +template +template +void ConvectionDiffusionStabFE:: +add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + if (m_stabParamM != 0.0) add_jac_X_elem(J, u, elem,vCornerCoords, m_stabParamM); +} + +template +template +void ConvectionDiffusionStabFE:: +add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + if (m_stabParamA != 0.0) add_jac_X_elem(J, u, elem,vCornerCoords, m_stabParamA); +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +// register assemble functions +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template<> +void ConvectionDiffusionStabFE:: +register_all_funcs(const LFEID& lfeid, const int quadOrder) +{ +// RegularEdge + register_func >(); +} +#endif + +#ifdef UG_DIM_2 +template<> +void ConvectionDiffusionStabFE:: +register_all_funcs(const LFEID& lfeid, const int quadOrder) +{ + register_func >(); + + const int order = lfeid.order(); + if(quadOrder != 2*order+1 || lfeid.type() != LFEID::LAGRANGE) + { + register_func >(); + register_func >(); + return; + } + +// special compiled cases + +// Triangle + switch(order) + { + case 1: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + case 2: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + case 3: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + default: register_func >(); break; + } + +// Quadrilateral + switch(order) { + case 1: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + case 2: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + case 3: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + default: register_func >(); break; + } +} +#endif + +#ifdef UG_DIM_3 +template<> +void ConvectionDiffusionStabFE:: +register_all_funcs(const LFEID& lfeid, const int quadOrder) +{ + register_func >(); + register_func >(); + register_func >(); + + const int order = lfeid.order(); + if(quadOrder != 2*order+1 || lfeid.type() != LFEID::LAGRANGE) + { + register_func >(); + register_func >(); + register_func >(); + register_func >(); + register_func >(); + return; + } + +// special compiled cases + +// Tetrahedron + switch(order) + { + case 1: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + case 2: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + case 3: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + default: register_func >(); break; + } + +// Prism + switch(order) { + default: register_func >(); break; + } + +// Pyramid + switch(order) + { + default: register_func >(); break; + } + +// Octahedron + switch(order) + { + default: register_func >(); break; + } + +// Hexahedron + switch(order) + { + case 1: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + case 2: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + case 3: {typedef FEGeometry, GaussQuadrature > FEGeom; + register_func(); break;} + default: register_func >(); break; + } +} +#endif + +template +template +void ConvectionDiffusionStabFE::register_func() +{ + ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; + typedef this_type T; +// static const int refDim = reference_element_traits::dim; + + this->clear_add_fct(id); + this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); + this->set_prep_elem_fct( id, &T::template prep_elem); + this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); + this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem); + this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem); + this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem); + this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem); + this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); + +// error estimator parts + this->set_prep_err_est_elem_loop(id, &T::template prep_err_est_elem_loop); + this->set_prep_err_est_elem(id, &T::template prep_err_est_elem); + this->set_compute_err_est_A_elem(id, &T::template compute_err_est_A_elem); + this->set_compute_err_est_M_elem(id, &T::template compute_err_est_M_elem); + this->set_compute_err_est_rhs_elem(id, &T::template compute_err_est_rhs_elem); + this->set_fsh_err_est_elem_loop(id, &T::template fsh_err_est_elem_loop); + +// set computation of linearized defect w.r.t velocity +/* m_imDiffusion. set_fct(id, this, &T::template lin_def_diffusion); + m_imVelocity. set_fct(id, this, &T::template lin_def_velocity); + m_imFlux. set_fct(id, this, &T::template lin_def_flux); + m_imReactionRate. set_fct(id, this, &T::template lin_def_reaction_rate); + m_imReaction. set_fct(id, this, &T::template lin_def_reaction); + m_imSource. set_fct(id, this, &T::template lin_def_source); + m_imVectorSource. set_fct(id, this, &T::template lin_def_vector_source); + m_imMassScale. set_fct(id, this, &T::template lin_def_mass_scale); + m_imMass. set_fct(id, this, &T::template lin_def_mass); + +// exports + m_exValue-> template set_fct(id, this, &T::template ex_value); + m_exGrad-> template set_fct(id, this, &T::template ex_grad);*/ +} + +//////////////////////////////////////////////////////////////////////////////// +// explicit template instantiations +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_1 +template class ConvectionDiffusionStabFE; +#endif +#ifdef UG_DIM_2 +template class ConvectionDiffusionStabFE; +#endif +#ifdef UG_DIM_3 +template class ConvectionDiffusionStabFE; +#endif + +} // end namespace ConvectionDiffusionPlugin +} // namespace ug + diff --git a/fe/convection_diffusion_stab_fe.h b/fe/convection_diffusion_stab_fe.h new file mode 100644 index 0000000..79a9b16 --- /dev/null +++ b/fe/convection_diffusion_stab_fe.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2018: G-CSC, Goethe University Frankfurt + * Author: Arne Naegel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_STAB_FE__ +#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_STAB_FE__ + +// library intern headers +#include "../convection_diffusion_base.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +// \ingroup lib_disc_elem_disc +/// \addtogroup convection_diffusion +/// \{ + +/// Discretization for the Convection-Diffusion Equation +/** + * This class implements the IElemDisc interface to provide element local + * assemblings for the convection diffusion equation. + * \tparam TDomain Domain + * \tparam TAlgebra Algebra + */ +template< typename TDomain> +class ConvectionDiffusionStabFE : public IElemDisc +{ + private: + /// Base class type + typedef IElemDisc base_type; + + /// Own type + typedef ConvectionDiffusionStabFE this_type; + + public: + /// World dimension + static const int dim = base_type::dim; + + public: + /// Constructor + ConvectionDiffusionStabFE(const char* functions, const char* subsets); + ConvectionDiffusionStabFE(const char* functions, const char* subsets, number stabM); + ConvectionDiffusionStabFE(const char* functions, const char* subsets, number stabM, number stabA); + + /// Destructor + virtual ~ConvectionDiffusionStabFE() {}; + + /// sets the quad order + void set_quad_order(size_t order); + + private: + /// prepares the loop over all elements + /** + * This method prepares the loop over all elements. It resizes the Position + * array for the corner coordinates and schedules the local ip positions + * at the data imports. + */ + template + void prep_elem_loop(const ReferenceObjectID roid, const int si); + + /// prepares the element for assembling + /** + * This methods prepares an element for the assembling. The Positions of + * the Element Corners are read and the Finite Volume Geometry is updated. + * The global ip positions are scheduled at the data imports. + */ + template + void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]); + + /// finishes the loop over all elements + template + void fsh_elem_loop(); + + template + void add_jac_X_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], double stab); + + /// assembles the local stiffness matrix using a finite volume scheme + template + void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the stiffness part of the local defect + template + void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]){}; + + /// assembles the local mass matrix using a finite volume scheme + template + void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the mass part of the local defect + template + void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the local right hand side + template + void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) {} + + /// prepares the loop over all elements of one type for the computation of the error estimator + template + void prep_err_est_elem_loop(const ReferenceObjectID roid, const int si) {} + + /// prepares the element for assembling the error estimator + template + void prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) {} + + /// computes the error estimator contribution for one element + template + void compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) {} + + /// computes the error estimator contribution for one element + template + void compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) {} + + /// computes the error estimator contribution for one element + template + void compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale) {} + + /// postprocesses the loop over all elements of one type in the computation of the error estimator + template + void fsh_err_est_elem_loop() {} + + private: + /// abbreviation for the local solution + static const size_t _C_ = 0; + + + + public: + /// type of trial space for each function used + virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid); + + /// returns if hanging nodes are needed + virtual bool use_hanging() const; + + protected: + /// current integration order + bool m_bQuadOrderUserDef; + int m_quadOrder; + + /// current shape function set + LFEID m_lfeID; + + /// register utils + /// \{ + void register_all_funcs(const LFEID& lfeid, const int quadOrder); + template void register_func(); + /// \} + + private: + /// struct holding values of shape functions in IPs + /* struct ShapeValues + { + public: + void resize(std::size_t nEip, std::size_t nSip, std::size_t _nSh) + { + nSh = _nSh; + elemVals.resize(nEip); + sideVals.resize(nSip); + for (std::size_t i = 0; i < nEip; i++) elemVals[i].resize(nSh); + for (std::size_t i = 0; i < nSip; i++) sideVals[i].resize(nSh); + } + number& shapeAtElemIP(std::size_t sh, std::size_t ip) {return elemVals[ip][sh];} + number& shapeAtSideIP(std::size_t sh, std::size_t ip) {return sideVals[ip][sh];} + number* shapesAtElemIP(std::size_t ip) {return &elemVals[ip][0];} + number* shapesAtSideIP(std::size_t ip) {return &sideVals[ip][0];} + std::size_t num_sh() {return nSh;} + private: + std::size_t nSh; + std::vector > elemVals; + std::vector > sideVals; + } m_shapeValues;*/ + + double m_stabParamM; + double m_stabParamA; +}; + +// end group convection_diffusion +/// \} + +} // end ConvectionDiffusionPlugin +} // end namespace ug + + +#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FE__*/ diff --git a/fractfv1/convection_diffusion_fractfv1.cpp b/fractfv1/convection_diffusion_fractfv1.cpp new file mode 100644 index 0000000..d766506 --- /dev/null +++ b/fractfv1/convection_diffusion_fractfv1.cpp @@ -0,0 +1,1462 @@ +/* + * Copyright (c) 2013-2018: G-CSC, Goethe University Frankfurt + * Author: Dmitry Logashenko + * Based on the modules by Andreas Vogel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#include "convection_diffusion_fractfv1.h" + +#include "lib_disc/spatial_disc/disc_util/geom_provider.h" +#include "lib_disc/spatial_disc/disc_util/fv1_geom.h" +#include "lib_disc/spatial_disc/disc_util/hfv1_geom.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +//////////////////////////////////////////////////////////////////////////////// +// general +//////////////////////////////////////////////////////////////////////////////// + +template +ConvectionDiffusionFractFV1:: +ConvectionDiffusionFractFV1 (const char* functions, const char* subsets) +: ConvectionDiffusionBase (functions, subsets), + m_spConvShape (new ConvectionShapesNoUpwind) +{ +// initialize the fracture-specific input-export parameters that are not in the base + m_imAperture.set_comp_lin_defect (false); + +// register the fracture-specific input-export parameters that are not in the base + this->register_import (m_imAperture); + this->register_import (m_imOrthoDiffusion); + this->register_import (m_imOrthoVelocity); + this->register_import (m_imOrthoFlux); + this->register_import (m_imOrthoVectorSource); + +// register the element assembling functions + register_all_funcs (); +} + +//////////////////////////////////////////////////////////////////////////////// +// Local discretization interface +//////////////////////////////////////////////////////////////////////////////// + +/// checks the grid and the shape functions +template +void ConvectionDiffusionFractFV1::prepare_setting +( + const std::vector & vLfeID, + bool bNonRegular +) +{ +// check the grid + if (bNonRegular) + UG_THROW ("ERROR in ConvectionDiffusionFractFV1::prepare_setting:" + " This discretization does not support hanging nodes.\n"); + +// check number of the components + if (vLfeID.size () != 1) + UG_THROW ("ConvectionDiffusionFractFV1::prepare_setting: Wrong number of functions given. Need exactly 1."); + +// check whether these are the LagrangeP1 elements + if (vLfeID[0] != LFEID(LFEID::LAGRANGE, dim, 1)) + UG_THROW ("ConvectionDiffusionFractFV1::prepare_setting: ConvectionDiffusion FV Scheme only implemented for 1st order."); +} + +//////////////////////////////////////////////////////////////////////////////// +// Assembling functions +//////////////////////////////////////////////////////////////////////////////// + +/// computes and returns the upwind shapes for the given velocity +template +const typename ConvectionDiffusionFractFV1::conv_shape_type& +ConvectionDiffusionFractFV1::get_updated_conv_shapes +( + bool computeDeriv ///< whether to compute the derivatives of the shapes +) +{ + if(m_imVelocity.data_given()) + { + // get diffusion at ips + const MathMatrix* vDiffusion = NULL; + if (m_imDiffusion.data_given ()) vDiffusion = m_imDiffusion.values (); + + // update convection shapes + if (!m_spConvShape->update (m_pFractGeo, m_imVelocity.values (), vDiffusion, computeDeriv)) + { + UG_LOG("ERROR in 'ConvectionDiffusionFractFV1::get_updated_conv_shapes': " + "Cannot compute convection shapes.\n"); + } + } + +// return a const (!!) reference to the upwind + return *const_cast*>(m_spConvShape.get()); +} + +/// prepares the loop over the elements: checks whether the parameters are set, ... +template +template +void ConvectionDiffusionFractFV1::prep_elem_loop +( + ReferenceObjectID roid, ///< only elements with this roid are looped over + int si ///< and only in this subdomain +) +{ + typedef typename reference_element_traits::reference_element_type ref_elem_type; + +// check the imports + if (!m_imAperture.data_given()) + UG_THROW ("ConvectionDiffusionFractFV1::prep_elem_loop: Missing Import 'fracture width (aperture)'."); + +// check whether we are in a degenerated fracture + if (! m_spFractManager.valid()) + UG_THROW ("ConvectionDiffusionFractFV1::prep_elem_loop: No fracture manager specified."); + if (! m_spFractManager->is_closed ()) + UG_THROW ("ConvectionDiffusionFractFV1::prep_elem_loop: Fracture manager not closed."); + if (! m_spFractManager->contains (si)) + UG_THROW ("ConvectionDiffusionFractFV1::prep_elem_loop:" + " The fract. discretization is used for subset " << si << " which is not a degenerated fracture."); + +// check, that upwind has been set + if(m_spConvShape.invalid()) + UG_THROW("ConvectionDiffusionFractFV1::prep_elem_loop: Upwind has not been set."); + +// initialize the pointer to the FV geometry for fracture elements + m_pFractGeo = &GeomProvider::get (LFEID (LFEID::LAGRANGE, low_dim, 1), 1); + +// set up local ip coordinates for corner import parameters +// REMARK: Note that for the fracture elements, values of the corner import +// parameters are indexed not by scv (as for the normal elements) but by +// the corner indices in the reference element +} + +template +template +void ConvectionDiffusionFractFV1::fsh_elem_loop () +{} + +template +template +void ConvectionDiffusionFractFV1::prep_elem +( + const LocalVector & u, ///< local solution at the dofs associated with elem + GridObject * elem, ///< element to prepare + ReferenceObjectID roid, // id of reference element used for assembling + const position_type vCornerCoords [] ///< coordinates of the corners of the element +) +{ + typedef typename reference_element_traits::reference_element_type ref_elem_type; + + static const int refDim = TElem::dim; // dimensionality of the element, not the side! + TElem * pElem = static_cast (elem); + ref_elem_type& rRefElem = Provider::get (); + +// get the non-degenerated sides of the fracture element + try + { + m_spFractManager->get_layer_sides + (pElem, + m_numFractCo, m_innerFractSide, m_innerFractSideIdx, m_innerSideCo, + m_outerFractSide, m_outerFractSideIdx, m_outerSideCo, + m_assCo); + } + UG_CATCH_THROW("ConvectionDiffusionFractFV1::prep_elem: Cannot find orientation of a fracture element."); + +// compute the FV geometry of the inner side + position_type vSideCornerCoords [maxFractSideCorners]; // global side corner coords + try + { + for (size_t co = 0; co < m_numFractCo; co++) + vSideCornerCoords [co] = vCornerCoords [m_innerSideCo [co]]; + m_pFractGeo->update (m_innerFractSide, vSideCornerCoords, &(this->subset_handler())); + } + UG_CATCH_THROW("ConvectionDiffusionFractFV1::prep_elem: Cannot update the Finite Volume Geometry for a fracture element."); + size_t numSCVFip = m_pFractGeo->num_scvf_ips (); + size_t numSCVip = m_pFractGeo->num_scv_ips (); + +// convert local coordinates of the side into the local coordinates of the element (for the input parameters) + position_type vSideLocCornerCoords [maxFractSideCorners]; // local side corner coords + position_type vSideLocSCVFipCoords [TFractFVGeom::maxNumSCVF]; // local scvf ip's in a fracture element + position_type vSideLocSCVipCoords [TFractFVGeom::maxNumSCV]; // local scv ip's in a fracture element + position_type elemLocCOE; // local coordinates of the mass center of a fracture element + try + { + DimReferenceMapping& rMapping + = ReferenceMappingProvider::get (m_innerFractSide->reference_object_id ()); + for (size_t co = 0; co < m_numFractCo; co++) + vSideLocCornerCoords [co] = rRefElem.corner (m_innerSideCo [co]); + rMapping.update (vSideLocCornerCoords); + + rMapping.local_to_global (elemLocCOE, *(m_pFractGeo->coe_local ())); + rMapping.local_to_global (vSideLocSCVFipCoords, m_pFractGeo->scvf_local_ips (), numSCVFip); + rMapping.local_to_global (vSideLocSCVipCoords, m_pFractGeo->scv_local_ips (), numSCVip); + } + UG_CATCH_THROW("ConvectionDiffusionFractFV1::prep_elem: Cannot transform local side coordinates to local element coordinates in a fracture element."); + + +// set local positions + + m_imDiffusion.template set_local_ips (vSideLocSCVFipCoords, numSCVFip); + m_imVelocity.template set_local_ips (vSideLocSCVFipCoords, numSCVFip); + m_imFlux.template set_local_ips (vSideLocSCVFipCoords, numSCVFip); + m_imVectorSource.template set_local_ips (vSideLocSCVFipCoords, numSCVFip); + + m_imSource.template set_local_ips (vSideLocSCVipCoords, numSCVip); + m_imReactionRate.template set_local_ips (vSideLocSCVipCoords, numSCVip); + m_imReaction.template set_local_ips (vSideLocSCVipCoords, numSCVip); + m_imReactionRateExpl.template set_local_ips (vSideLocSCVipCoords, numSCVip); + m_imReactionExpl.template set_local_ips (vSideLocSCVipCoords, numSCVip); + m_imSourceExpl.template set_local_ips (vSideLocSCVipCoords, numSCVip); + m_imMassScale.template set_local_ips (vSideLocSCVipCoords, numSCVip); + m_imMass.template set_local_ips (vSideLocSCVipCoords, numSCVip); + + m_imOrthoDiffusion.template set_local_ips (vSideLocSCVipCoords, numSCVip); + m_imOrthoVelocity.template set_local_ips (vSideLocSCVipCoords, numSCVip); + m_imOrthoFlux.template set_local_ips (vSideLocSCVipCoords, numSCVip); + m_imOrthoVectorSource.template set_local_ips (vSideLocSCVipCoords, numSCVip); + + m_imAperture.template set_local_ips (&elemLocCOE, 1); + +// set global positions + + const position_type* vSCVFip = m_pFractGeo->scvf_global_ips (); + m_imDiffusion. set_global_ips (vSCVFip, numSCVFip); + m_imVelocity. set_global_ips (vSCVFip, numSCVFip); + m_imFlux. set_global_ips (vSCVFip, numSCVFip); + m_imVectorSource. set_global_ips (vSCVFip, numSCVFip); + + const position_type* vSCVip = m_pFractGeo->scv_global_ips (); + m_imSource. set_global_ips (vSCVip, numSCVip); + m_imReactionRate. set_global_ips (vSCVip, numSCVip); + m_imReactionRateExpl. set_global_ips (vSCVip, numSCVip); + m_imReactionExpl. set_global_ips (vSCVip, numSCVip); + m_imSourceExpl. set_global_ips (vSCVip, numSCVip); + m_imReaction. set_global_ips (vSCVip, numSCVip); + m_imMassScale. set_global_ips (vSCVip, numSCVip); + m_imMass. set_global_ips (vSCVip, numSCVip); + + const position_type* coe_global = m_pFractGeo->coe_global (); + m_imAperture.set_global_ips (coe_global, 1); + +// init upwind for element type + if(m_spConvShape.valid()) + if(!m_spConvShape->template set_geometry_type (*m_pFractGeo)) + UG_THROW("ConvectionDiffusionFractFV1::prep_elem:" + " Cannot init upwind for element type."); +} + +/// computes the local stiffness matrix +template +template +void ConvectionDiffusionFractFV1::add_jac_A_elem +( + LocalMatrix & J, ///< the local matrix to update + const LocalVector & u, ///< current approximation of the solution + GridObject * elem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + TElem * pElem = static_cast (elem); + + this->template fract_add_jac_A_elem (J, u, pElem, vCornerCoords); + this->template fract_bulk_add_jac_A_elem (J, u, pElem, vCornerCoords); +} + +/// assembles a singular source or sink in the jacobian +template +template +void ConvectionDiffusionFractFV1::add_sss_jac_elem +( + LocalMatrix& J, ///< the matrix to update + const LocalVector& u, ///< current solution + TElem* pElem, ///< the element + size_t co, ///< corner for the source/sink + number flux ///< flux through the source/sink (premultiplied by the length for lines) +) +{ + if (flux < 0.0) + // sink + J(_C_, co, _C_, co) -= flux; +} + +/// computes the local stiffness matrix on a fracture element +template +template +void ConvectionDiffusionFractFV1::fract_add_jac_A_elem +( + LocalMatrix & J, ///< the local matrix to update + const LocalVector & u, ///< current approximation of the solution + TElem * pElem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + number half_fr_width = m_imAperture[0] / 2; + + const size_t numSh = m_pFractGeo->num_sh (); + const size_t numScvf = m_pFractGeo->num_scvf (); + +// Diffusion and Velocity Term + if (m_imDiffusion.data_given () || m_imVelocity.data_given ()) + { + // get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes (false); + + // loop Sub Control Volume Faces (SCVF) + for (size_t ip = 0; ip < numScvf; ++ip) + { + // get current SCVF + const typename TFractFVGeom::SCVF& scvf = m_pFractGeo->scvf (ip); + + //////////////////////////////////////////////////// + // Diffusive Term + //////////////////////////////////////////////////// + if (m_imDiffusion.data_given ()) + { + // Diff. Tensor times Gradient + MathVector Dgrad; + + // loop shape functions + for (size_t sh = 0; sh < numSh; ++sh) + { + // Compute Diffusion Tensor times Gradient + MatVecMult (Dgrad, m_imDiffusion[ip], scvf.global_grad (sh)); + + // Compute flux at IP + const number D_diff_flux = VecDot (Dgrad, scvf.normal ()) * half_fr_width; + + J(_C_, m_innerSideCo[scvf.from()], _C_, m_innerSideCo[sh]) -= D_diff_flux; + J(_C_, m_innerSideCo[scvf.to() ], _C_, m_innerSideCo[sh]) += D_diff_flux; + } + } + + //////////////////////////////////////////////////// + // Convective Term + //////////////////////////////////////////////////// + if (m_imVelocity.data_given ()) + { + // Add Flux contribution + for (size_t sh = 0; sh < numSh; ++sh) + { + const number D_conv_flux = convShape (ip, sh) * half_fr_width; + + // Add flux term to local matrix + J(_C_, m_innerSideCo[scvf.from()], _C_, m_innerSideCo[sh]) += D_conv_flux; + J(_C_, m_innerSideCo[scvf.to() ], _C_, m_innerSideCo[sh]) -= D_conv_flux; + } + } + + // no explicit dependency on flux import + } + } + +// Reaction rate + if(m_imReactionRate.data_given()) + { + // loop Sub Control Volume (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // Add to local matrix + J(_C_, co, _C_, co) += m_imReactionRate[ip] * scv.volume () * half_fr_width; + } + } + +// Reaction term does not explicitly depend on the associated unknown function + +// Assemble the singular sources and sinks + if (m_sss_mngr.valid () && m_sss_mngr->num_lines () != 0) + { + typedef typename domain_type::position_accessor_type t_pos_accessor; + typedef typename CDSingularSourcesAndSinks::template + line_iterator t_lin_sss_iter; + + t_pos_accessor& aaPos = this->domain()->position_accessor (); + Grid& grid = (Grid&) *this->domain()->grid (); + + for(size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get the corner of the face + size_t side_co = m_pFractGeo->scv(ip).node_id (); + // Get associated node of the element (not side!) + size_t co = m_innerSideCo [m_pFractGeo->scv(ip).node_id ()]; + + // line sources (that correspond to the point sources) + for (t_lin_sss_iter line (m_sss_mngr.get (), m_innerFractSide, grid, aaPos, *m_pFractGeo, side_co); + ! line.is_over (); ++line) + { + FVLineSourceOrSink > * line_sss = *line; + if (! line_sss->marked_for (m_innerFractSide, side_co)) + continue; + line_sss->compute (line.seg_start (), this->time (), -1); //TODO: set the subset id instead of -1 + add_sss_jac_elem (J, u, pElem, co, line_sss->flux () / 2); + /* Remark: "/ 2" because the source is taken into account twice. */ + } + } + } +} + +/// computes the local stiffness matrix of the fracture-bulk interaction terms on a fracture element +template +template +void ConvectionDiffusionFractFV1::fract_bulk_add_jac_A_elem +( + LocalMatrix & J, ///< the local matrix to update + const LocalVector & u, ///< current approximation of the solution + TElem * pElem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + number half_fr_width = m_imAperture[0] / 2; + +// loop over the corners of the inner side + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip); + number s = scv.volume (); + + // Get associated node of the element (not side!) + const int co = m_innerSideCo [scv.node_id()]; + + // Assemble Diffusion and Convection + number D_flux = 0, D_flux_fr = 0; + + if (m_imOrthoDiffusion.data_given ()) + { + D_flux = m_imOrthoDiffusion[ip] / half_fr_width; + D_flux_fr = - D_flux; + } + + if (m_imOrthoVelocity.data_given ()) + { + /* We use the full upwind here: */ + if (m_imOrthoVelocity[ip] >= 0) + D_flux_fr -= m_imOrthoVelocity[ip]; + else + D_flux -= m_imOrthoVelocity[ip]; + } + + J(_C_, m_assCo [co], _C_, m_assCo [co]) += D_flux * s; + J(_C_, m_assCo [co], _C_, co ) += D_flux_fr * s; + + J(_C_, co, _C_, m_assCo [co]) -= D_flux * s; + J(_C_, co, _C_, co ) -= D_flux_fr * s; + } +} + + +/// computes the mass matrix of a time-dependent problem +template +template +void ConvectionDiffusionFractFV1::add_jac_M_elem +( + LocalMatrix & J, ///< the local matrix to update + const LocalVector & u, ///< current approximation of the solution + GridObject * elem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + if (!m_imMassScale.data_given ()) return; + + number half_fr_width = m_imAperture[0] / 2; + +// loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // Add to local matrix + J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip] * half_fr_width; + } + +// m_imMass part does not explicitly depend on associated unknown function +} + +/// computes the stiffness part of the local defect +template +template +void ConvectionDiffusionFractFV1::add_def_A_elem +( + LocalVector & d, ///< the local defect to update + const LocalVector & u, ///< current approximation of the solution + GridObject * elem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + TElem * pElem = static_cast (elem); + + this->template fract_add_def_A_elem (d, u, pElem, vCornerCoords); + this->template fract_bulk_add_def_A_elem (d, u, pElem, vCornerCoords); +} + +/// assembles a singular source or sink in the defect +template +template +void ConvectionDiffusionFractFV1::add_sss_def_elem +( + LocalVector& d, ///< the defect to update + const LocalVector& u, ///< current solution + TElem * pElem, ///< the element + size_t co, ///< corner for the source/sink + number flux ///< flux through the source/sink (premultiplied by the length for lines) +) +{ + if (flux > 0.0) + // source + d(_C_, co) -= flux; + else + // sink + d(_C_, co) -= flux * u(_C_, co); +} + +/// computes the stiffness part of the local defect on a fracture element +template +template +void ConvectionDiffusionFractFV1::fract_add_def_A_elem +( + LocalVector & d, ///< the local defect to update + const LocalVector & u, ///< current approximation of the solution + TElem * pElem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + number half_fr_width = m_imAperture[0] / 2; + +// Diff. Tensor times Gradient + MathVector Dgrad; + + const size_t numSh = m_pFractGeo->num_sh (); + const size_t numScvf = m_pFractGeo->num_scvf (); + +// Diffusion and Velocity Term + if (m_imDiffusion.data_given () || m_imVelocity.data_given () || m_imFlux.data_given ()) + { + // get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes (false); + + // loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < numScvf; ++ip) + { + // get current SCVF + const typename TFractFVGeom::SCVF& scvf = m_pFractGeo->scvf (ip); + + //////////////////////////////////////////////////// + // Diffusive Term + //////////////////////////////////////////////////// + if(m_imDiffusion.data_given ()) + { + // to compute D \nabla c + MathVector Dgrad_c, grad_c; + + // compute gradient and shape at ip + VecSet (grad_c, 0.0); + for(size_t sh = 0; sh < numSh; ++sh) + VecScaleAppend (grad_c, + u (_C_, m_innerSideCo[sh]), scvf.global_grad (sh)); + + // scale by diffusion tensor + MatVecMult (Dgrad_c, m_imDiffusion[ip], grad_c); + + // Compute flux + const number diff_flux = VecDot (Dgrad_c, scvf.normal ()) * half_fr_width; + + // Add to local defect + d(_C_, m_innerSideCo [scvf.from()]) -= diff_flux; + d(_C_, m_innerSideCo [scvf.to() ]) += diff_flux; + } + + //////////////////////////////////////////////////// + // Convective Term + //////////////////////////////////////////////////// + if(m_imVelocity.data_given()) + { + // sum up convective flux using convection shapes + number conv_flux = 0.0; + for(size_t sh = 0; sh < numSh; ++sh) + conv_flux += u (_C_, m_innerSideCo[sh]) * convShape (ip, sh); + conv_flux *= half_fr_width; + + // add to local defect + d(_C_, m_innerSideCo [scvf.from()]) += conv_flux; + d(_C_, m_innerSideCo [scvf.to() ]) -= conv_flux; + } + + ///////////////////////////////////////////////////// + // Flux Term + ///////////////////////////////////////////////////// + if(m_imFlux.data_given()) + { + // sum up flux + const number flux = VecDot (m_imFlux[ip], scvf.normal ()) * half_fr_width; + + // add to local defect + d(_C_, m_innerSideCo [scvf.from()]) += flux; + d(_C_, m_innerSideCo [scvf.to() ]) -= flux; + } + } + } + +// Reaction rate + if (m_imReactionRate.data_given ()) + { + // loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // Add to local defect + d(_C_, co) += u(_C_, co) * m_imReactionRate[ip] * scv.volume () * half_fr_width; + } + } + +// Reaction term + if (m_imReaction.data_given ()) + { + // loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // Add to local defect + d(_C_, co) += m_imReaction[ip] * scv.volume () * half_fr_width; + } + } + +// Assemble the singular sources and sinks + if (m_sss_mngr.valid () && m_sss_mngr->num_lines () != 0) + { + typedef typename domain_type::position_accessor_type t_pos_accessor; + typedef typename CDSingularSourcesAndSinks::template + line_iterator t_lin_sss_iter; + + t_pos_accessor& aaPos = this->domain()->position_accessor (); + Grid& grid = (Grid&) *this->domain()->grid (); + + for(size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get the corner of the face + size_t side_co = m_pFractGeo->scv(ip).node_id (); + // Get associated node of the element (not side!) + size_t co = m_innerSideCo [m_pFractGeo->scv(ip).node_id ()]; + + // line sources (that correspond to the point sources) + for (t_lin_sss_iter line (m_sss_mngr.get (), m_innerFractSide, grid, aaPos, *m_pFractGeo, side_co); + ! line.is_over (); ++line) + { + FVLineSourceOrSink > * line_sss = *line; + if (! line_sss->marked_for (m_innerFractSide, side_co)) + continue; + line_sss->compute (line.seg_start (), this->time (), -1); //TODO: set the subset id instead of -1 + add_sss_def_elem (d, u, pElem, co, line_sss->flux () / 2); + /* Remark: "/ 2" because the source is taken into account twice. */ + } + } + } +} + +/// computes the stiffness fracture-bulk interaction terms of the local defect on a fracture element +template +template +void ConvectionDiffusionFractFV1::fract_bulk_add_def_A_elem +( + LocalVector & d, ///< the local defect to update + const LocalVector & u, ///< current approximation of the solution + TElem * pElem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + number orthC_f, orthC_m; + + number half_fr_width = m_imAperture[0] / 2; + +// loop over the corners of the inner side + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip); + + // Get associated node of the element (not side!) + const int co = m_innerSideCo [scv.node_id()]; + + // Get the corner values + orthC_f = u(_C_, co); + orthC_m = u(_C_, m_assCo[co]); + + // Assemble Diffusion, Convection and the Flux + number flux = 0; + + if (m_imOrthoDiffusion.data_given ()) + flux = m_imOrthoDiffusion[ip] * (orthC_m - orthC_f) / half_fr_width; + + if (m_imOrthoVelocity.data_given ()) + { + number orthVelocity = m_imOrthoVelocity[ip]; + /* We use the full upwind here: */ + flux -= orthVelocity * ((orthVelocity >= 0)? orthC_f : orthC_m); + } + + if (m_imOrthoFlux.data_given ()) + flux -= m_imOrthoFlux[ip]; + + flux *= scv.volume (); + d(_C_, m_assCo[co]) += flux; + d(_C_, co) -= flux; + } +} + +/// computes the stiffness part of the local defect +template +template +void ConvectionDiffusionFractFV1::add_def_A_expl_elem +( + LocalVector & d, ///< the local defect to update + const LocalVector & u, ///< current approximation of the solution + GridObject * elem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + TElem * pElem = static_cast (elem); + + this->template fract_add_def_A_expl_elem (d, u, pElem, vCornerCoords); + this->template fract_bulk_add_def_A_expl_elem (d, u, pElem, vCornerCoords); +} + +/// computes the stiffness part of the local defect on a fracture element +template +template +void ConvectionDiffusionFractFV1::fract_add_def_A_expl_elem +( + LocalVector & d, ///< the local defect to update + const LocalVector & u, ///< current approximation of the solution + TElem * pElem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + number half_fr_width = m_imAperture[0] / 2; + +// Reaction rate + if (m_imReactionRateExpl.data_given ()) + { + // loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // Add to local defect + d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume () * half_fr_width; + } + } + +// reaction + if (m_imReactionExpl.data_given ()) + { + // loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // Add to local defect + d(_C_, co) += m_imReactionExpl[ip] * scv.volume () * half_fr_width; + } + } + +// source + if (m_imSourceExpl.data_given ()) + { + // loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // Add to local rhs + d(_C_, co) -= m_imSourceExpl[ip] * scv.volume () * half_fr_width; + } + } +} + +/// computes the stiffness fracture-bulk interaction terms of the local defect on a fracture element +template +template +void ConvectionDiffusionFractFV1::fract_bulk_add_def_A_expl_elem +( + LocalVector & d, ///< the local defect to update + const LocalVector & u, ///< current approximation of the solution + TElem * pElem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ +} + +/// computes the mass part of the defect of a time-dependent problem +template +template +void ConvectionDiffusionFractFV1::add_def_M_elem +( + LocalVector & d, ///< the local defect to update + const LocalVector & u, ///< current approximation of the solution + GridObject * elem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + if (!m_imMassScale.data_given () && !m_imMass.data_given ()) return; + + number half_fr_width = m_imAperture[0] / 2; + +// loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // mass value + number val = 0; + + // multiply by scaling + if (m_imMassScale.data_given ()) + val += m_imMassScale[ip] * u(_C_, co); + + // add mass + if (m_imMass.data_given ()) + val += m_imMass[ip]; + + // Add to local defect + d(_C_, co) += val * scv.volume () * half_fr_width; + } +} + +/// computes the right-hand side due to the sources +template +template +void ConvectionDiffusionFractFV1::add_rhs_elem +( + LocalVector & d, ///< the right-hand side to update + GridObject * elem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + TElem * pElem = static_cast (elem); + + this->template fract_add_rhs_elem (d, pElem, vCornerCoords); + this->template fract_bulk_add_rhs_elem (d, pElem, vCornerCoords); +} + +/// computes the right-hand side due to the sources on a fracture element +template +template +void ConvectionDiffusionFractFV1::fract_add_rhs_elem +( + LocalVector & d, ///< the local defect to update + TElem * pElem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + number half_fr_width = m_imAperture[0] / 2; + + if (m_imSource.data_given ()) + // loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // Add to local rhs + d(_C_, co) += m_imSource[ip] * scv.volume () * half_fr_width; + } + + if (m_imVectorSource.data_given ()) + // loop Sub Control Volume Fraces (SCVF) + for(size_t ip = 0; ip < m_pFractGeo->num_scvf (); ++ip) + { + // get current SCVF + const typename TFractFVGeom::SCVF& scvf = m_pFractGeo->scvf (ip); + + // compute the flux + number flux = VecDot (m_imVectorSource[ip], scvf.normal ()) * half_fr_width; + + // Add to local rhs + d(_C_, m_innerSideCo [scvf.from()]) -= flux; + d(_C_, m_innerSideCo [scvf.to() ]) += flux; + } +} + +/// computes the fracture-bulk interaction terms of the local rhs on a fracture element +template +template +void ConvectionDiffusionFractFV1::fract_bulk_add_rhs_elem +( + LocalVector & d, ///< the local defect to update + TElem * pElem, ///< grid element + const position_type vCornerCoords [] ///< corner coordinates of the grid element +) +{ + if (m_imOrthoVectorSource.data_given ()) + // loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip); + + // Get associated node of the element (not side!) + const int co = m_innerSideCo [scv.node_id()]; + + number flux = m_imOrthoVectorSource[ip] * scv.volume (); + d(_C_, m_assCo[co]) += flux; + d(_C_, co) -= flux; + } +} + +/// computes the linearized defect w.r.t to the fracture velocity +template +template +void ConvectionDiffusionFractFV1::lin_def_velocity +( + const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes (true); + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < m_pFractGeo->num_scvf (); ++ip) + { + // get current SCVF + const typename TFractFVGeom::SCVF& scvf = m_pFractGeo->scvf (ip); + + // sum up contributions of convection shapes + MathVector linDefect; + VecSet(linDefect, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend (linDefect, u (_C_, m_innerSideCo[sh]), convShape.D_vel (ip, sh)); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][m_innerSideCo [scvf.from()]] += linDefect; + vvvLinDef[ip][_C_][m_innerSideCo [scvf.to()] ] -= linDefect; + } +} + +/// computes the linearized defect w.r.t to the orthogonal velocity +template +template +void ConvectionDiffusionFractFV1::lin_def_ortho_velocity +( + const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip); + + // Get associated node of the element (not side!) + const int co = m_innerSideCo [scv.node_id()]; + + // Get the corner values + number orthC_f = u(_C_, co); + number orthC_m = u(_C_, m_assCo[co]); + + // Compute the derivative of the flux + number D_flux_vel = - ((m_imOrthoVelocity[ip] >= 0)? orthC_f : orthC_m) * scv.volume (); + + // add parts for both sides of the fracture + vvvLinDef[ip][_C_][m_assCo[co]] += D_flux_vel; + vvvLinDef[ip][_C_][co ] -= D_flux_vel; + } +} + +/// computes the linearized defect w.r.t to the fracture diffusion +template +template +void ConvectionDiffusionFractFV1::lin_def_diffusion +( + const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// get conv shapes + const IConvectionShapes& convShape = get_updated_conv_shapes (true); + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < m_pFractGeo->num_scvf (); ++ip) + { + // get current SCVF + const typename TFractFVGeom::SCVF& scvf = m_pFractGeo->scvf (ip); + + // compute gradient at ip + MathVector grad_c; + VecSet (grad_c, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend (grad_c, u (_C_, m_innerSideCo[sh]), scvf.global_grad (sh)); + + // compute the lin defect at this ip + MathMatrix linDefect; + + // part coming from $-\nabla u * \vec{n} + for(size_t k=0; k < (size_t) dim; ++k) + for(size_t j = 0; j < (size_t)dim; ++j) + linDefect(j,k) = (scvf.normal())[j] * grad_c[k]; + + // add contribution from convection shapes + if(convShape.non_zero_deriv_diffusion ()) + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + MatAdd (linDefect, + convShape.D_diffusion (ip, sh), u (_C_, m_innerSideCo[sh])); + + // add contributions + vvvLinDef[ip][_C_][m_innerSideCo[scvf.from()]] -= linDefect; + vvvLinDef[ip][_C_][m_innerSideCo[scvf.to()] ] += linDefect; + } +} + +/// computes the linearized defect w.r.t to the orthogonal diffusion +template +template +void ConvectionDiffusionFractFV1::lin_def_ortho_diffusion +( + const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + + number orthC_f, orthC_m; + + number half_fr_width = m_imAperture[0] / 2; + +// loop over the corners of the inner side + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip); + + // Get associated node of the element (not side!) + const int co = m_innerSideCo [scv.node_id()]; + + // Get the corner values + orthC_f = u(_C_, co); + orthC_m = u(_C_, m_assCo[co]); + + number linDefect = (orthC_m - orthC_f) * scv.volume () / half_fr_width; + + // add contributions + vvvLinDef[ip][_C_][m_assCo[co]] += linDefect; + vvvLinDef[ip][_C_][co ] -= linDefect; + } +} + +/// computes the linearized defect w.r.t to the fracture flux +template +template +void ConvectionDiffusionFractFV1::lin_def_flux +( + const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < m_pFractGeo->num_scvf(); ++ip) + { + // get current SCVF + const typename TFractFVGeom::SCVF& scvf = m_pFractGeo->scvf (ip); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][m_innerSideCo [scvf.from()]] += scvf.normal(); + vvvLinDef[ip][_C_][m_innerSideCo [scvf.to() ]] -= scvf.normal(); + } +} + +/// computes the linearized defect w.r.t to the orthogonal flux +template +template +void ConvectionDiffusionFractFV1::lin_def_ortho_flux +( + const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop over the corners of the inner side + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip); + + // Get associated node of the element (not side!) + const int co = m_innerSideCo [scv.node_id()]; + + // add parts for both sides of the fracture + vvvLinDef[ip][_C_][m_assCo[co]] += scv.volume (); + vvvLinDef[ip][_C_][co ] -= scv.volume (); + } +} + +/// computes the linearized defect w.r.t to the reaction source +template +template +void ConvectionDiffusionFractFV1::lin_def_reaction +( + const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + + number half_fr_width = m_imAperture[0] / 2; + +// loop over the corners of the inner side + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip); + + // Get associated node of the element (not side!) + const int co = m_innerSideCo [scv.node_id()]; + + // add parts for both sides of the fracture + vvvLinDef[ip][_C_][co] = scv.volume () * half_fr_width; + } +} + +/// computes the linearized defect w.r.t to the reaction rate +template +template +void ConvectionDiffusionFractFV1::lin_def_reaction_rate +( + const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + + number half_fr_width = m_imAperture[0] / 2; + +// loop over the corners of the inner side + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip); + + // Get associated node of the element (not side!) + const int co = m_innerSideCo [scv.node_id()]; + + // add parts for both sides of the fracture + vvvLinDef[ip][_C_][co] = u(_C_, co) * scv.volume () * half_fr_width; + } +} + +/// computes the linearized defect w.r.t to the source +template +template +void ConvectionDiffusionFractFV1::lin_def_source +( + const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + + number half_fr_width = m_imAperture[0] / 2; + +// loop over the corners of the inner side + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip); + + // Get associated node of the element (not side!) + const int co = m_innerSideCo [scv.node_id()]; + + // add parts for both sides of the fracture + vvvLinDef[ip][_C_][co] = scv.volume () * half_fr_width; + } +} + +/// computes the linearized defect w.r.t to the fracture flux +template +template +void ConvectionDiffusionFractFV1::lin_def_vector_source +( + const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop Sub Control Volume Faces (SCVF) + for(size_t ip = 0; ip < m_pFractGeo->num_scvf(); ++ip) + { + // get current SCVF + const typename TFractFVGeom::SCVF& scvf = m_pFractGeo->scvf (ip); + + // add parts for both sides of scvf + vvvLinDef[ip][_C_][m_innerSideCo [scvf.from()]] -= scvf.normal(); + vvvLinDef[ip][_C_][m_innerSideCo [scvf.to() ]] += scvf.normal(); + } +} + +/// computes the linearized defect w.r.t to the orthogonal flux +template +template +void ConvectionDiffusionFractFV1::lin_def_ortho_vector_source +( + const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip +) +{ +// reset the values for the linearized defect + for(size_t ip = 0; ip < nip; ++ip) + for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) + for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) + vvvLinDef[ip][c][sh] = 0.0; + +// loop over the corners of the inner side + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++) + { + // Get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip); + + // Get associated node of the element (not side!) + const int co = m_innerSideCo [scv.node_id()]; + + // add parts for both sides of the fracture + vvvLinDef[ip][_C_][m_assCo[co]] -= scv.volume (); + vvvLinDef[ip][_C_][co ] += scv.volume (); + } +} + +// computes the linearized defect w.r.t to the mass scale +template +template +void ConvectionDiffusionFractFV1::lin_def_mass_scale +( + const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip +) +{ + number half_fr_width = m_imAperture[0] / 2; + +// loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // set lin defect + vvvLinDef[co][_C_][co] = u(_C_, co) * scv.volume () * half_fr_width; + } +} + +// computes the linearized defect w.r.t to the mass scale +template +template +void ConvectionDiffusionFractFV1::lin_def_mass +( + const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip +) +{ + number half_fr_width = m_imAperture[0] / 2; + +// loop Sub Control Volumes (SCV) + for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ++ip) + { + // get current SCV + const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv (ip); + + // get associated node + const int co = m_innerSideCo [scv.node_id ()]; + + // set lin defect + vvvLinDef[co][_C_][co] = scv.volume () * half_fr_width; + } +} + +/// registers the local assembler functions for a given element +template +template +void ConvectionDiffusionFractFV1::register_func () +{ + ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; + typedef this_type T; + + this->clear_add_fct(id); + + this->set_prep_elem_loop_fct (id, &T::template prep_elem_loop); + this->set_prep_elem_fct ( id, &T::template prep_elem); + this->set_fsh_elem_loop_fct ( id, &T::template fsh_elem_loop); + this->set_add_jac_A_elem_fct (id, &T::template add_jac_A_elem); + this->set_add_jac_M_elem_fct (id, &T::template add_jac_M_elem); + this->set_add_def_A_elem_fct (id, &T::template add_def_A_elem); + this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem); + this->set_add_def_M_elem_fct (id, &T::template add_def_M_elem); + this->set_add_rhs_elem_fct ( id, &T::template add_rhs_elem); + +// set computation of linearized defect w.r.t velocity, diffusion etc. + m_imDiffusion.set_fct (id, this, &T::template lin_def_diffusion); + m_imOrthoDiffusion.set_fct (id, this, &T::template lin_def_ortho_diffusion); + m_imVelocity.set_fct (id, this, &T::template lin_def_velocity); + m_imOrthoVelocity.set_fct (id, this, &T::template lin_def_ortho_velocity); + m_imFlux.set_fct (id, this, &T::template lin_def_flux); + m_imOrthoFlux.set_fct (id, this, &T::template lin_def_ortho_flux); + m_imReactionRate.set_fct (id, this, &T::template lin_def_reaction_rate); + m_imReaction.set_fct (id, this, &T::template lin_def_reaction); + m_imSource.set_fct (id, this, &T::template lin_def_source); + m_imVectorSource.set_fct (id, this, &T::template lin_def_vector_source); + m_imOrthoVectorSource.set_fct (id, this, &T::template lin_def_ortho_vector_source); + m_imMassScale.set_fct (id, this, &T::template lin_def_mass_scale); + m_imMass.set_fct (id, this, &T::template lin_def_mass); +} + +/// registers the interface functions for all types of the elements +template +void ConvectionDiffusionFractFV1::register_all_funcs () +{ + typedef typename domain_traits::DimElemList AssembleElemList; + + boost::mpl::for_each (RegisterLocalDiscr (this)); +} + +//////////////////////////////////////////////////////////////////////////////// +// explicit template instantiations +//////////////////////////////////////////////////////////////////////////////// + +#ifdef UG_DIM_2 +template class ConvectionDiffusionFractFV1; +#endif +#ifdef UG_DIM_3 +template class ConvectionDiffusionFractFV1; +#endif + +} // end namespace ConvectionDiffusionPlugin +} // namespace ug + +/* End of File */ diff --git a/fractfv1/convection_diffusion_fractfv1.h b/fractfv1/convection_diffusion_fractfv1.h new file mode 100644 index 0000000..46e14f5 --- /dev/null +++ b/fractfv1/convection_diffusion_fractfv1.h @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2013-2018: G-CSC, Goethe University Frankfurt + * Author: Dmitry Logashenko + * Based on the modules by Andreas Vogel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FRACT_FV1__ +#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FRACT_FV1__ + +// ug4 headers +#include "lib_grid/algorithms/deg_layer_mngr.h" +#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" + +// plugin's internal headers +#include "../convection_diffusion_base.h" +#include "../convection_diffusion_sss.h" + +namespace ug{ +namespace ConvectionDiffusionPlugin{ + +/// Discretization for the Convection-Diffusion Equation in fractures +/** + * This class implements the IElemDisc interface to provide element local + * assemblings for the convection diffusion equation in the fractures. This + * module is complementary to convection_diffusion_fv1. + * The PDE has the form + * \f[ + * \partial_t (m1*c + m2) - \nabla \left( D \nabla c - \vec{v} c - \vec{F} \right ) + * + r1 \cdot c + r2 = f + f2 + * \f] + * along the fracture. We assume the corresponding fluxes also in the orthogonal + * direction. Here: + *
    + *
  • \f$ c \f$ is the unknown solution + *
  • \f$ m1 \equiv m(\vec{x},t) \f$ is the Mass Scaling Term + *
  • \f$ m2 \equiv m(\vec{x},t) \f$ is the Mass Term + *
  • \f$ D \equiv D(\vec{x},t) \f$ is the Diffusion Tensor + *
  • \f$ v \equiv \vec{v}(\vec{x},t) \f$ is the Velocity Field + *
  • \f$ F \equiv \vec{F}(\vec{x},t) \f$ is the Flux + *
  • \f$ r1 \equiv r(\vec{x},t) \f$ is the Reaction Rate + *
  • \f$ r2 \equiv r(\vec{x},t) \f$ is a Reaction Term + *
  • \f$ f \equiv f(\vec{x},t) \f$ is a Source Term + *
  • \f$ f2 \equiv f_2(\vec{x},t) \f$ is a Vector Source Term + *
+ * + * \tparam TDomain Domain + */ +template +class ConvectionDiffusionFractFV1 : public ConvectionDiffusionBase +{ + /// Own type + typedef ConvectionDiffusionFractFV1 this_type; + + public: + + /// Base class type + typedef ConvectionDiffusionBase base_type; + + /// domain type + typedef typename base_type::domain_type domain_type; + + /// position type + typedef typename base_type::position_type position_type; + + /// World ('full') dimension + static const int dim = base_type::dim; + + /// Manifold ('low') dimension + static const int low_dim = dim - 1; + + /// fracture manager type + typedef DegeneratedLayerManager fract_manager_type; + + private: + + /// FV geometry for the fractures + typedef DimFV1Geometry TFractFVGeom; + + /// type of the sides of elements (als low-dimensional fracture elements) + typedef typename fract_manager_type::side_type side_type; + + /// max. number of corners of non-degenerated sides + static const size_t maxFractSideCorners = fract_manager_type::maxLayerSideCorners; + + /// abbreviation for local function: brine mass fraction + static const size_t _C_ = 0; + + /// convection shapes type (for the upwind) + typedef IConvectionShapes conv_shape_type; + + public: + /// Constructor + ConvectionDiffusionFractFV1(const char* functions, const char* subsets); + + /// sets the fracture manager + /** + * This function sets the fracture manager object to recognize the fractures. + */ + void set_fract_manager (SmartPtr fract_manager) {m_spFractManager = fract_manager;} + + /// set the upwind method along the fracture + /** + * This method sets the upwind method used to upwind the convection + * along the fracture. + * + * \param shapes upwind method + */ + void set_upwind (SmartPtr shapes) {m_spConvShape = shapes;} + + // set Specific parameters for low-dimensional subdomains (fractures): + + void set_aperture(SmartPtr > user) + { + m_imAperture.set_data(user); + } + void set_aperture(number val) + { + set_aperture(make_sp(new ConstUserNumber(val))); + } + #ifdef UG_FOR_LUA + void set_aperture(const char* fctName) + { + set_aperture(LuaUserDataFactory::create(fctName)); + } + void set_aperture(LuaFunctionHandle fct) + { + set_aperture(make_sp(new LuaUserData(fct))); + } + #endif + + void set_ortho_velocity(SmartPtr > user) + { + m_imOrthoVelocity.set_data(user); + } + void set_ortho_velocity(number val) + { + set_ortho_velocity(make_sp(new ConstUserNumber(val))); + } + #ifdef UG_FOR_LUA + void set_ortho_velocity(const char* fctName) + { + set_ortho_velocity(LuaUserDataFactory::create(fctName)); + } + void set_ortho_velocity(LuaFunctionHandle fct) + { + set_ortho_velocity(make_sp(new LuaUserData(fct))); + } + #endif + + void set_ortho_diffusion(SmartPtr > user) + { + m_imOrthoDiffusion.set_data(user); + } + void set_ortho_diffusion(number val) + { + set_ortho_diffusion(make_sp(new ConstUserNumber(val))); + } + #ifdef UG_FOR_LUA + void set_ortho_diffusion(const char* fctName) + { + set_ortho_diffusion(LuaUserDataFactory::create(fctName)); + } + void set_ortho_diffusion(LuaFunctionHandle fct) + { + set_ortho_diffusion(make_sp(new LuaUserData(fct))); + } + #endif + + /// set singular sources and sinks + void set_sss_manager(SmartPtr > sss_mngr) {m_sss_mngr = sss_mngr;} + + /// get singular sources and sinks + SmartPtr > sss_manager() {return m_sss_mngr;} + + /// hanging nodes are not allowed in this discretization + virtual bool use_hanging() const {return false;} + + private: + + /// registers the interface function + void register_all_funcs (); + + /// auxiliary class for registering functions + struct RegisterLocalDiscr + { + this_type * m_pThis; + + RegisterLocalDiscr(this_type * pThis) : m_pThis(pThis) {} + + template void operator () (TElem &) {m_pThis->register_func ();} + }; + + /// registers the interface function for one element type + template void register_func (); + + private: + +//---- General interface assembling functions: ---- + + /// check the grid and the type of trial space for each function used + virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid); + + /// prepares the loop over all elements + /** + * This method prepares the loop over all elements. It resizes the Position + * array for the corner coordinates and schedules the local ip positions + * at the data imports. + */ + template + void prep_elem_loop(const ReferenceObjectID roid, const int si); + + /// finishes the loop over all elements + template + void fsh_elem_loop (); + + /// prepares the element for assembling + template + void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const position_type vCornerCoords[]); + + /// assembles the local stiffness matrix using a finite volume scheme + template + void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const position_type vCornerCoords[]); + + /// assembles the local mass matrix using a finite volume scheme + template + void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const position_type vCornerCoords[]); + + /// assembles the stiffness part of the local defect + template + void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const position_type vCornerCoords[]); + + /// assembles the stiffness part of the local defect explicit reaction, reaction_rate and source + template + void add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const position_type vCornerCoords[]); + + /// assembles the mass part of the local defect + template + void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const position_type vCornerCoords[]); + + /// assembles the local right hand side + template + void add_rhs_elem(LocalVector& d, GridObject* elem, const position_type vCornerCoords[]); + + /// computes the linearized defect w.r.t. to the fracture velocity + template + void lin_def_velocity(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t. to the orthogonal velocity + template + void lin_def_ortho_velocity(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t. to the fracture diffusion + template + void lin_def_diffusion(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t. to the orthogonal diffusion + template + void lin_def_ortho_diffusion(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t. to the fracture flux + template + void lin_def_flux(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t. to the orthogonal flux + template + void lin_def_ortho_flux(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t. to the reaction + template + void lin_def_reaction(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t. to the reaction + template + void lin_def_reaction_rate(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the source term + template + void lin_def_source(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the vector source term + template + void lin_def_vector_source(const LocalVector& u, + std::vector > > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the vector source term + template + void lin_def_ortho_vector_source(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the mass scale term + template + void lin_def_mass_scale(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + + /// computes the linearized defect w.r.t to the mass scale term + template + void lin_def_mass(const LocalVector& u, + std::vector > vvvLinDef[], + const size_t nip); + +//---- Assembling functions for fractures: ---- + + template + inline void fract_add_jac_A_elem(LocalMatrix& J, const LocalVector& u, TElem* elem, const position_type vCornerCoords[]); + + template + inline void fract_bulk_add_jac_A_elem(LocalMatrix& J, const LocalVector& u, TElem* elem, const position_type vCornerCoords[]); + + template + inline void fract_add_def_A_elem(LocalVector& d, const LocalVector& u, TElem* elem, const position_type vCornerCoords[]); + + template + inline void fract_bulk_add_def_A_elem(LocalVector& d, const LocalVector& u, TElem* elem, const position_type vCornerCoords[]); + + template + inline void fract_add_def_A_expl_elem(LocalVector& d, const LocalVector& u, TElem* elem, const position_type vCornerCoords[]); + + template + inline void fract_bulk_add_def_A_expl_elem(LocalVector& d, const LocalVector& u, TElem* elem, const position_type vCornerCoords[]); + + template + inline void fract_add_rhs_elem(LocalVector& b, TElem* elem, const position_type vCornerCoords[]); + + template + inline void fract_bulk_add_rhs_elem(LocalVector& b, TElem* elem, const position_type vCornerCoords[]); + + template + inline void add_sss_def_elem(LocalVector& d, const LocalVector& u, TElem* pElem, size_t co, number flux); + + template + inline void add_sss_jac_elem(LocalMatrix& J, const LocalVector& u, TElem* pElem, size_t co, number flux); + + private: + /// returns the updated convection shapes + const conv_shape_type& get_updated_conv_shapes (bool computeDeriv); + + protected: + +// Standard parameters of the convection-diffusion plugin + using base_type::m_imDiffusion; + using base_type::m_imVelocity; + using base_type::m_imFlux; + using base_type::m_imSource; + using base_type::m_imSourceExpl; + using base_type::m_imVectorSource; + using base_type::m_imReactionRate; + using base_type::m_imReactionRateExpl; + using base_type::m_imReaction; + using base_type::m_imReactionExpl; + using base_type::m_imMassScale; + using base_type::m_imMass; + + using base_type::m_exGrad; + using base_type::m_exValue; + +// Specific parameters for low-dimensional subdomains (fractures): + DataImport m_imAperture; ///< the fracture width (constant per element) + DataImport m_imOrthoDiffusion; ///< diffusion through the fracture-bulk interface + DataImport m_imOrthoVelocity; ///< convection velocity through the fracture-bulk interface + DataImport m_imOrthoFlux; ///< flux through the fracture-bulk interface + DataImport m_imOrthoVectorSource; ///< vector through the fracture-bulk interface + + private: + +// singular sources and sinks manager + SmartPtr > m_sss_mngr; + + protected: + +// Parameters of the discretization: + SmartPtr m_spFractManager; ///< degenerated fracture manager (may be SPNULL) + SmartPtr m_spConvShape; ///< method to compute the upwind shapes + + private: + +// Temporary data used in the assembling + TFractFVGeom * m_pFractGeo; ///< FV geometry object of fracture elements + size_t m_numFractCo; ///< number of corners of the fracture side + side_type * m_innerFractSide; ///< inner side of the fracture element + side_type * m_outerFractSide; ///< outer side of the fracture element + size_t m_innerFractSideIdx; ///< index of the inner side in the ref. elem. + size_t m_outerFractSideIdx; ///< index of the outer side in the ref. elem. + size_t m_innerSideCo[maxFractSideCorners]; ///< inner side corner idx -> elem. corner idx + size_t m_outerSideCo[maxFractSideCorners]; ///< outer side corner idx -> elem. corner idx + size_t m_assCo [2 * maxFractSideCorners]; ///< correspondence of the corners of the sides +}; + +} // end ConvectionDiffusionPlugin +} // end namespace ug + +#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FRACT_FV1__*/ + +/* End of File */ diff --git a/fv1_cutElem/Info File 1 b/fv1_cutElem/Info File 1 new file mode 100644 index 0000000..702eb21 --- /dev/null +++ b/fv1_cutElem/Info File 1 @@ -0,0 +1,31 @@ +/* Info File for 'ImmersedInterfaceDiffusion' class: */ + + +The 'ImmersedInterfaceDiffusion' class enables the computation of elliptic problems with discontinuous coefficients, whose line along the jump forms the immersed interface. A detailed description of the mathematical theory and numerical tests can be found in [1]. + +The 'ImmersedInterfaceDiffusion' class is a derivation of the 'ImmersedInterface' class. It therefore contains all the components of an 'ImmersedInterface' class implemented according to the necessities for an immersed interface with jumping coefficients. Those are explained in more detail in the according class types. + + +The special requirements for the elliptic immersed interface implementation are the following: + +(1) The domain on BOTH sides of the interface is relevant for the physics of the problem. Therefore, the cut element computations performed by the according classes ( CutElementHandler, LocalInterfaceHandler) will be called TWICE for each original element. Accordingly, all the 'ElemDisc' methods for the computation of the local stiffnes matrix and defect contain two calls of the same methods, but get as additional parameter the inversed orientation of the interface (see convection_diffusion_fv1_cutElem.cpp). + +(2) Due to (1) two local stiffness matrices and defects will be computed during the element-local assembling process. These can NOT be stored in the usual data structure. Therefore, according local data structures are contained in the 'InterfaceHandlerLocal'. + +(3) The ansatz space used for this application is an interface adapted space. It falls into case 2 of a local-to-global mapping type (for detailed explanation, see the description in 'Info File 2' within this folder, and also 'Info File 1 ' and 'Info File 2' in the ugbase/lib_disc/spatial_disc/immersed_util folder. ). + +(4) Due to (3) additional DoFs need to be provided by the algebra for the increased, interface adapted mesh. This will be done by increasing the matrix and vector data during the initialisation pahse. + + + + +The two central methods called during the initialisation via the 'init()' method are: + +---> update_interface_data(): called by the init() of the associated CutElementHandler; computes all cut elements; +---> call of 'u.resize()'; this yields the increase of DoFs; + + + +[1] Hoellbacher S., Wittum G.: + "A sharp interface method using enriched finite elements for elliptic interface problems." + submitted to Numerische Mathematik diff --git a/fv1_cutElem/Info File 2 b/fv1_cutElem/Info File 2 new file mode 100644 index 0000000..f53b275 --- /dev/null +++ b/fv1_cutElem/Info File 2 @@ -0,0 +1,39 @@ +/* Info File for 'DiffusionInterfaceMapper' class: */ + + +Influence of the local-to-global mapping on the mathematical ansatz space: + + +On a cut element, local couplings will be computed for all the intersection points of the interface with the edges of the cut element. The mapping of these couplings to its associated global indices finally defines the property of the underlying finite element space: + +Case 1: If each coupling entry is mapped to a distinguished global index, i.e. DoF, the resulting space will be the usual finite element space on that interface adaped grid containing additional nodes along the interface and consisting (virtually) of cut elements and original elements. + +Case 2: If the coupling entry of an intersection point is mapped onto the global index of the original node, which lies accross the interface, but on the corner of the element, the finite element space will be potentially smaller, since two intersection points can share the same node accross the interface. The resulting space is a so called "flat top" space, since it results in piecewise constant solutions along the connecting line between these intersection points. + + +The 'ParticleMapper' class is of type case 2: +It maps all couplings of intersection points to the same translational (and in analogy to the rotational) global index of a particle. Therefore, the 'ParticleMapper' is a flat-top mapper. + +In contrast, the 'DiffusionInterfaceMapper' is of type case 1: +The resulting space is an interface adapted space. + + +In particular, the 'DiffusionInterfaceMapper' is a 'TWO-SIDES' mapper: As described in the 'Info File 1' within this folder, the local couplings of BOTH parts of the cut element will be mapped onto the global matrix and vectors. As a consequence, the mapping will be performed TWICE. + + +The important methods are: + +---> 'add_local_mat_to_global_interface()', which performs the local-to-global mapping first for a triangle and second for a quadrilateral, as the two parts of a 2d cut element. + +---> 'add_local_vec_to_global_interface()', which performs the local-to-global mapping first for a triangle and second for a quadrilateral, as the two parts of a 2d cut element. + + +---> modify_GlobalSol(): writes the solution within the additional interface nodes into data structures of the 'InterfaceHandlerLocal' 'in order provide global access + + + +Remark: +The 'modify_LocalData()' will NOT be used. It enables the resizing of the local data (LocalMatrix or LocalVecor) BEFORE starting the assembling on (potentially more nodes containing) cut the element. + + + diff --git a/fv1_cutElem/convection_diffusion_fv1 Kopie.cpp b/fv1_cutElem/convection_diffusion_fv1 Kopie.cpp deleted file mode 100644 index ef04ceb..0000000 --- a/fv1_cutElem/convection_diffusion_fv1 Kopie.cpp +++ /dev/null @@ -1,2617 +0,0 @@ -/* - * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt - * Author: Andreas Vogel - * - * This file is part of UG4. - * - * UG4 is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License version 3 (as published by the - * Free Software Foundation) with the following additional attribution - * requirements (according to LGPL/GPL v3 §7): - * - * (1) The following notice must be displayed in the Appropriate Legal Notices - * of covered and combined works: "Based on UG4 (www.ug4.org/license)". - * - * (2) The following notice must be displayed at a prominent place in the - * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". - * - * (3) The following bibliography is recommended for citation and must be - * preserved in all covered files: - * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively - * parallel geometric multigrid solver on hierarchically distributed grids. - * Computing and visualization in science 16, 4 (2013), 151-164" - * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel - * flexible software system for simulating pde based models on high performance - * computers. Computing and visualization in science 16, 4 (2013), 165-179" - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - */ - - -#include "convection_diffusion_fv1.h" - -#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" -#include "lib_disc/spatial_disc/disc_util/geom_provider.h" - -//#include "lib_disc/spatial_disc/disc_util/fv1_geom.h" -//#include "lib_disc/spatial_disc/disc_util/hfv1_geom.h" -#include "lib_disc/spatial_disc/disc_util/conv_shape.h" -#include "../../NavierStokes/incompressible/fv1/diffusion_interface/interface_handler_diffusion.h" - -namespace ug{ -namespace ConvectionDiffusionPlugin{ - -DebugID DID_CONV_DIFF_FV1("CONV_DIFF_FV1"); - -//////////////////////////////////////////////////////////////////////////////// -// general -//////////////////////////////////////////////////////////////////////////////// - -template -ConvectionDiffusionFV1:: -ConvectionDiffusionFV1(const char* functions, const char* subsets) - : ConvectionDiffusionBase(functions,subsets), - m_spConvShape(new ConvectionShapesNoUpwind), - m_bNonRegularGrid(false) -{ - register_all_funcs(m_bNonRegularGrid); -} - -template -void ConvectionDiffusionFV1:: -prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid) -{ -// check number - if(vLfeID.size() != 1) - UG_THROW("ConvectionDiffusion: Wrong number of functions given. " - "Need exactly "<<1); - - if(vLfeID[0].order() != 1 || vLfeID[0].type() != LFEID::LAGRANGE) - UG_THROW("ConvectionDiffusion FV Scheme only implemented for 1st order."); - - m_LFEID = vLfeID[0]; - -// remember - m_bNonRegularGrid = bNonRegularGrid; - -// update assemble functions - register_all_funcs(m_bNonRegularGrid); -} - -template -bool ConvectionDiffusionFV1:: -use_hanging() const -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// Assembling functions -//////////////////////////////////////////////////////////////////////////////// - -template -void ConvectionDiffusionFV1:: -prep_assemble_loop() -{ - if (m_sss.valid()) - m_sss->clear_markers(); -} - -template -template -void ConvectionDiffusionFV1:: -prep_elem_loop(const ReferenceObjectID roid, const int si) -{ - -// check, that upwind has been set - if(m_spConvShape.invalid()) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Upwind has not been set."); - -// set local positions -// if(!TFVGeom::usesHangingNodes) - if(!TFVGeom::usesHangingNodes && TFVGeom::staticLocalData) - { - static const int refDim = TElem::dim; -// TFVGeom& geo = GeomProvider::get(); - TFVGeom& geo = GeomProvider::get(m_LFEID, 1); - const MathVector* vSCVFip = geo.scvf_local_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_local_ips(); - const size_t numSCVip = geo.num_scv_ips(); - m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip, false); - m_imVelocity.template set_local_ips(vSCVFip,numSCVFip, false); - m_imFlux.template set_local_ips(vSCVFip,numSCVFip, false); - m_imSource.template set_local_ips(vSCVip,numSCVip, false); - m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip, false); - m_imReactionRate.template set_local_ips(vSCVip,numSCVip, false); - m_imReaction.template set_local_ips(vSCVip,numSCVip, false); - m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imReactionExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imSourceExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imMassScale.template set_local_ips(vSCVip,numSCVip, false); - m_imMass.template set_local_ips(vSCVip,numSCVip, false); - - // init upwind for element type - if(!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Cannot init upwind for element type."); - } -} - -template -template -void ConvectionDiffusionFV1:: -fsh_elem_loop() -{} - -template -template -void ConvectionDiffusionFV1:: -prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) -{ -// Update Geometry for this element - //static TFVGeom& geo = GeomProvider::get(); - TFVGeom& geo = GeomProvider::get(m_LFEID,1); - //TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); - -// fix: set orientation initially globally! - geo.set_orientation(1); - - - try{ - UG_DLOG(DID_CONV_DIFF_FV1, 2, ">>OCT_DISC_DEBUG: " << "convection_diffusion_fv1.cpp: " << "prep_elem(): update(): "<< roid << std::endl); -// geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); - geo.update(elem, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::prep_elem:" - " Cannot update Finite Volume Geometry."); - -// set local positions -// if(TFVGeom::usesHangingNodes) - if(TFVGeom::usesHangingNodes || !TFVGeom::staticLocalData) - { - const int refDim = TElem::dim; - const MathVector* vSCVFip = geo.scvf_local_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_local_ips(); - const size_t numSCVip = geo.num_scv_ips(); - m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip); - m_imVelocity.template set_local_ips(vSCVFip,numSCVFip); - m_imFlux.template set_local_ips(vSCVFip,numSCVFip); - m_imSource.template set_local_ips(vSCVip,numSCVip); - m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip); - m_imReactionRate.template set_local_ips(vSCVip,numSCVip); - m_imReaction.template set_local_ips(vSCVip,numSCVip); - m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip); - m_imReactionExpl.template set_local_ips(vSCVip,numSCVip); - m_imSourceExpl.template set_local_ips(vSCVip,numSCVip); - m_imMassScale.template set_local_ips(vSCVip,numSCVip); - m_imMass.template set_local_ips(vSCVip,numSCVip); -/* - if(m_spConvShape.valid()) - if(!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Cannot init upwind for element type."); - */ - } - - // set global positions - const MathVector* vSCVFip = geo.scvf_global_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_global_ips(); - const size_t numSCVip = geo.num_scv_ips(); - m_imDiffusion. set_global_ips(vSCVFip, numSCVFip); - m_imVelocity. set_global_ips(vSCVFip, numSCVFip); - m_imFlux. set_global_ips(vSCVFip, numSCVFip); - m_imSource. set_global_ips(vSCVip, numSCVip); - m_imVectorSource. set_global_ips(vSCVFip, numSCVFip); - m_imReactionRate. set_global_ips(vSCVip, numSCVip); - m_imReactionRateExpl. set_global_ips(vSCVip, numSCVip); - m_imReactionExpl. set_global_ips(vSCVip, numSCVip); - m_imSourceExpl. set_global_ips(vSCVip, numSCVip); - m_imReaction. set_global_ips(vSCVip, numSCVip); - m_imMassScale. set_global_ips(vSCVip, numSCVip); - m_imMass. set_global_ips(vSCVip, numSCVip); -} - -template -static TVector CalculateCenter(GridObject* o, const TVector* coords) -{ - TVector v; - VecSet(v, 0); - - size_t numCoords = 0; - switch(o->base_object_id()){ - case VERTEX: numCoords = 1; break; - case EDGE: numCoords = static_cast(o)->num_vertices(); break; - case FACE: numCoords = static_cast(o)->num_vertices(); break; - case VOLUME: numCoords = static_cast(o)->num_vertices(); break; - default: UG_THROW("Unknown element type."); break; - } - - for(size_t i = 0; i < numCoords; ++i) - VecAdd(v, v, coords[i]); - - if(numCoords > 0) - VecScale(v, v, 1. / (number)numCoords); - - return v; -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - - bool debug = false; - bool boundary = false; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); - TFVGeom& geo = GeomProvider::get(m_LFEID,1); - const bool bElementIsCut = geo.get_element_modus(); - const bool bElementIsOutside = geo.get_boolian_for_diffusion(); - - // First call with orientation = 1: - int orientation = 1; - geo.set_orientation(orientation); - - geo.init_integral(); - - // normal assembling if not cut by interface: - if ( !bElementIsCut ) - { - LocalVector dummyU; - LocalIndices ind = u.get_indices(); - dummyU.resize(ind); - dummyU = 0; - - this->template add_jac_A_elem_local (geo, J, u, dummyU, elem, vCornerCoords, bElementIsOutside); - return; - } - - // get data: - geo.resize_local_data(u); - LocalMatrix& locJ_tri = geo.get_jacobian_tri(); - LocalMatrix& locJ_quad = geo.get_jacobian_quad(); - - LocalVector& locU_tri = geo.get_solution_tri(); - LocalVector& locU_quad = geo.get_solution_quad(); - - // reset data: - locJ_tri = 0; - locJ_quad = 0; - - LocalIndices ind = u.get_indices(); - - // call elem disc twice: - - if ( debug ) geo.print_InterfaceIDdata(); - - ReferenceObjectID roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - - this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, false); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_tri, 3); - this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords, false); - } - - geo.set_jacobian_tri(locJ_tri); - geo.set_DoF_tag_tri(false); - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - - this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, false); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_quad, 4); - this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords, false); - } - - geo.set_jacobian_quad(locJ_quad); - geo.set_DoF_tag_quad(false); - } - - - // Second call with orientation = 1: - bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! - - orientation *= -1; - geo.set_orientation(orientation); - try{ - geo.update(elem, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" - " Cannot update Finite Volume Geometry."); - - if ( debug ) geo.print_InterfaceIDdata(); - - roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - - this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, true); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_tri, 3); - this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords, true); - } - - geo.set_jacobian_tri(locJ_tri); - geo.set_DoF_tag_tri(shiftTag); - - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - - this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, true); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_quad, 4); - this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords, true); - } - - geo.set_jacobian_quad(locJ_quad); - geo.set_DoF_tag_quad(shiftTag); - } - - -} - - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - ug::MathMatrix diffusion = m_imDiffusion[0]; - diffusion *= 10.0; - - if ( bElementIsOutside ) // = inside circle line!! - diffusion *= 0.1; - -// Diff. Tensor times Gradient - MathVector Dgrad; - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// Diffusion and Velocity Term - if(m_imDiffusion.data_given() || m_imVelocity.data_given()) - { - // loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - //////////////////////////////////////////////////// - // Diffusive Term - //////////////////////////////////////////////////// - if(m_imDiffusion.data_given()) - { - // DID_CONV_DIFF_FV1 - number D_diff_flux_sum = 0.0; - - // loop shape functions - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - { - // Compute Diffusion Tensor times Gradient - MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); - - // Compute flux at IP - const number D_diff_flux = VecDot(Dgrad, scvf.normal()); - UG_DLOG(DID_CONV_DIFF_FV1, 2, ">>OCT_DISC_DEBUG: " << "convection_diffusion_fv1.cpp: " << "add_jac_A_elem(): " << "sh # " << sh << " ; normalSize scvf # " << ip << ": " << VecLength(scvf.normal()) << "; \t from "<< scvf.from() << "; to " << scvf.to() << "; D_diff_flux: " << D_diff_flux << "; scvf.global_grad(sh): " << scvf.global_grad(sh) << std::endl); - - // Add flux term to local matrix // HIER MATRIXINDIZES!!! - UG_ASSERT((scvf.from() < J.num_row_dof(_C_)) && (scvf.to() < J.num_col_dof(_C_)), - "Bad local dof-index on element with object-id " << elem->base_object_id() - << " with center: " << CalculateCenter(elem, vCornerCoords)); - - J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; - J(_C_, scvf.to() , _C_, sh) += D_diff_flux; - - // DID_CONV_DIFF_FV1 - D_diff_flux_sum += D_diff_flux; - } - - UG_DLOG(DID_CONV_DIFF_FV1, 2, "D_diff_flux_sum = " << D_diff_flux_sum << std::endl << std::endl); - } - - - ///////////////////////////////////////////////////////////////////////////// - // Additional diffusive Term due to jump in solution at the interface - // u^+ - u^- = jump - ///////////////////////////////////////////////////////////////////////////// - if ( 0 ) - { - // loop shape functions - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - { - // Compute Diffusion Tensor times Gradient - MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); - - // Compute flux at IP - const number D_diff_flux = jump(_C_,sh) * VecDot(Dgrad, scvf.normal()); - - J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; - J(_C_, scvf.to() , _C_, sh) += D_diff_flux; - } - - } - - //////////////////////////////////////////////////// - // Convective Term - //////////////////////////////////////////////////// - if(m_imVelocity.data_given()) - { - // Add Flux contribution - for(size_t sh = 0; sh < convShape.num_sh(); ++sh) - { - const number D_conv_flux = convShape(ip, sh); - - // Add flux term to local matrix - J(_C_, scvf.from(), _C_, sh) += D_conv_flux; - J(_C_, scvf.to(), _C_, sh) -= D_conv_flux; - } - } - - // no explicit dependency on flux import - } - } - - //UG_LOG("Local Matrix is: \n"<domain()->position_accessor(); - const typename TDomain::grid_type& grid = *this->domain()->grid(); - const number time = this->time(); - MathVector<1> out; - for(size_t i = 0; i < geo.num_scv(); i++) { - const typename TFVGeom::SCV& scv = geo.scv(i); - const int co = scv.node_id(); - const number len = m_sss->get_contrib_of_scv((TElem*)elem, (Grid&)grid, aaPos, geo, co, time, out); - if (len == 0.0) continue; - out[0] *= len; - if (out[0] < 0.0) - // sink - J(_C_, co, _C_, co) -= out[0]; - } - } -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - double diffusion = 10.0; - - if ( bElementIsOutside ) - diffusion = 1.0; - - std::vector& vBF = geo.get_boundary_faces(); - - if ( vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - - // loop integration points - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - typename TFVGeom::BF bf = vBF[ip]; - - // loop trial space - for(size_t sh = 0; sh < bf.num_sh(); ++sh) - { - UG_LOG("bf.node_id(): " << bf.node_id() << "\n"); - UG_LOG("bf.global_grad(sh): " << bf.global_grad(sh) << "\n"); - UG_LOG("normal(): " << bf.normal() << "\n"); - - // add to local matrix - J(_C_, bf.node_id(), _C_, sh) += VecDot(bf.global_grad(sh), bf.normal()); - J(_C_, bf.node_id(), _C_, sh) *= diffusion; - } - } - -} - - -template -template -void ConvectionDiffusionFV1:: -add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - if(!m_imMassScale.data_given()) return; - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local matrix - J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip]; - } - -// m_imMass part does not explicitly depend on associated unknown function -} - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - bool output = false; - bool output_integral = false; - - bool debug = false; - bool boundary = false; - bool add = true; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); - TFVGeom& geo = GeomProvider::get(m_LFEID,1); - const bool bElementIsCut = geo.get_element_modus(); - const bool bElementIsOutside = geo.get_boolian_for_diffusion(); - - // First call with orientation = 1: - int orientation = 1; - geo.set_orientation(orientation); - - // necessary for call of 'get_solution_tri' an 'get_solution_quad': - geo.resize_local_data(u); - std::vector imSource; - if ( m_imSource.data_given() ) { - for ( size_t i = 0; i < 3; ++i ) - imSource.push_back(m_imSource[i]); - } - - // normal assembling if not cut by interface: - if ( !bElementIsCut ) - { - LocalVector dummyU; - LocalIndices ind = d.get_indices(); - dummyU.resize(ind); - dummyU = 0; - LocalVector source = geo.set_source(imSource, ind, 3, false); - - if ( output ) - { - for ( size_t i = 0; i < 3; ++i) - UG_LOG("*** corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); - UG_LOG("\n" ); - } - - this->template add_def_A_elem_local (geo, d, u, dummyU, dummyU, source, elem, vCornerCoords, bElementIsOutside); - - number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, d, u, elem); - geo.add_to_integral(intValElem); - if ( output_integral ) - UG_LOG("------------------> usual: integral = " << sqrt(geo.get_integral()) << "\n"); - - return; - } - - // get data: - LocalVector& locD_tri = geo.get_defect_tri(); - LocalVector& locD_quad = geo.get_defect_quad(); - - LocalVector& locU_tri = geo.get_solution_tri(); - LocalVector& locU_quad = geo.get_solution_quad(); - - // reset data: - locD_tri = 0; - locD_quad = 0; - - // call elem disc twice: - - if ( debug ) geo.print_InterfaceIDdata(); - - LocalIndices ind = d.get_indices(); - - ReferenceObjectID roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - - LocalVector jump_tri = geo.set_jump_values(ind, 3); - LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); - LocalVector source_tri = geo.set_source(imSource, ind, 3, true); - - if ( output ) UG_LOG(" tri 1: orientaten: " << orientation << "\n"); - - this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords, false); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_tri, 3); - this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords, false); - } - - if ( output ) - { - for ( size_t i = 0; i < 3; ++i) - UG_LOG("corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); - UG_LOG("\n" ); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output_integral ) UG_LOG("------------------> tri1: integral = " << sqrt(geo.get_integral()) << "\n"); - - geo.set_defect_tri(locD_tri); - geo.set_DoF_tag_tri(false); - - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - - LocalVector jump_quad = geo.set_jump_values(ind, 4); - LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); - LocalVector source_quad = geo.set_source(imSource, ind, 4, true); - - if ( output ) UG_LOG(" quad 1: orientaten: " << orientation << "\n"); - this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem, vCornerCoords, false); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_quad, 4); - this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords, false); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output_integral ) UG_LOG("------------------> quad1: integral = " << sqrt(geo.get_integral()) << "\n"); - - - geo.set_defect_quad(locD_quad); - geo.set_DoF_tag_quad(false); - - } - - - // Second call with orientation = -1: - bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! - - orientation *= -1; - if ( output ) UG_LOG(" ____2: orientaten: " << orientation << "\n"); - - geo.set_orientation(orientation); - try{ - geo.update(elem, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" - " Cannot update Finite Volume Geometry."); - - if ( debug ) geo.print_InterfaceIDdata(); - - roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); - LocalVector source_tri = geo.set_source(imSource, ind, 3, true); - - if ( output ) UG_LOG(" tri 2: orientaten: " << orientation << "\n"); - - this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords,true); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_tri, 3); - this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords, true); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output ) UG_LOG("------------------> tri2: integral = " << sqrt(geo.get_integral()) << "\n"); - - - geo.set_defect_tri(locD_tri); - geo.set_DoF_tag_tri(shiftTag); - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); - LocalVector source_quad = geo.set_source(imSource, ind, 4, true); - - if ( output ) UG_LOG(" quad 2: orientaten: " << orientation << "\n"); - - this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem,vCornerCoords, true); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_quad, 4); - this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords, true); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output_integral ) UG_LOG("------------------> quad2: integral = " << sqrt(geo.get_integral()) << "\n"); - - geo.set_defect_quad(locD_quad); - geo.set_DoF_tag_quad(shiftTag); - - } -} - - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - ug::MathMatrix diffusion = m_imDiffusion[0]; - diffusion *= 10.0; - double diffCoeff = 10.0; - - if ( bElementIsOutside ) // = inside circle line!! - { diffusion *= 0.1; diffCoeff = 0.1;} - - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - - if(m_imDiffusion.data_given() || m_imVelocity.data_given() || m_imFlux.data_given()) - { - // loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - ///////////////////////////////////////////////////// - // Diffusive Term - ///////////////////////////////////////////////////// - if(m_imDiffusion.data_given()) - { - // to compute D \nabla c - MathVector Dgrad_c, grad_c; - - // compute gradient and shape at ip - VecSet(grad_c, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(grad_c, u(_C_,sh), scvf.global_grad(sh)); - - // scale by diffusion tensor - MatVecMult(Dgrad_c, diffusion, grad_c); - - // Compute flux - const number diff_flux = VecDot(Dgrad_c, scvf.normal()); - - // Add to local defect - d(_C_, scvf.from()) -= diff_flux; - d(_C_, scvf.to() ) += diff_flux; - } - - ///////////////////////////////////////////////////////////////////////////// - // Additional diffusive Term due to jump in solution at the interface - // u^+ - u^- = jump - ///////////////////////////////////////////////////////////////////////////// - if ( 1 ) - { - // scale diffusion by jump in solution: - // const double jump = 2.0; - // diffusion *= jump; - - // to compute D \nabla c=Id_interface - MathVector Dgrad, grad; - - // compute gradient and shape at ip - VecSet(grad, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(grad, jump(_C_,sh), scvf.global_grad(sh)); - - // scale by diffusion tensor - MatVecMult(Dgrad, diffusion, grad); - - // Compute flux - const number diff_flux = VecDot(Dgrad, scvf.normal()); - - // Add to local defect - d(_C_, scvf.from()) -= diff_flux; - d(_C_, scvf.to() ) += diff_flux; - - } - } - - } - - ///////////////////////////////////////////////////// - // add rhs during same method! - // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! - ///////////////////////////////////////////////////// - - if ( 1 ) - { //m_imSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv( ip ); - - // get associated node - int co = scv.node_id(); - d(_C_, co) -= source(_C_, co) * scv.volume(); - - // Add to local rhs - /* if ( co > 2 ) - { - d(_C_, co) -= m_imSource[2] * scv.volume(); - UG_LOG("m_imSource[2] * scv.volume(): " << m_imSource[2] << "\n"); - UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); - } - else - { - d(_C_, co) -= m_imSource[co] * scv.volume(); - UG_LOG("m_imSource[co] * scv.volume(): " << m_imSource[co] << "\n"); - UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); - } - - */ - } - } - - ///////////////////////////////////////////////////////////////////////////// - // Additional source Term due to jump in gradient at the interface - // (\nabla u^+ - \nabla u^-)\cdot n = h(x) * |n| - ///////////////////////////////////////////////////////////////////////////// - if ( 1 ) - { - std::vector& vBF = geo.get_boundary_faces(); - MathVector Dgrad; - VecSet(Dgrad, 0.0); - - if ( vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - // loop integration points - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - typename TFVGeom::BF bf = vBF[ip]; - // Add to local rhs - d(_C_, bf.node_id()) += jump_grad(_C_,bf.node_id()) * bf.Vol; - } - } - -//////////////////////////////// -// Singular sources and sinks -//////////////////////////////// - - if (m_sss.valid()) { - const typename TDomain::position_accessor_type& aaPos = this->domain()->position_accessor(); - const typename TDomain::grid_type& grid = *this->domain()->grid(); - const number time = this->time(); - MathVector<1> out; - for(size_t i = 0; i < geo.num_scv(); i++) { - const typename TFVGeom::SCV& scv = geo.scv(i); - const int co = scv.node_id(); - const number len = m_sss->get_contrib_of_scv((TElem*)elem, (Grid&)grid, aaPos, geo, co, time, out); - if (len == 0.0) continue; - out[0] *= len; - if (out[0] > 0.0) - // source - d(_C_, co) -= out[0]; - else - // sink - d(_C_, co) -= out[0] * u(_C_, co); - } - } -} - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - double diffusion = 10.0; - - if ( bElementIsOutside ) - diffusion = 1.0; - - std::vector& vBF = geo.get_boundary_faces(); - MathVector Dgrad; - VecSet(Dgrad, 0.0); - - UG_LOG("---------- vBF.size(): " << vBF.size() << "\n"); - - if ( vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - - // set solution - /* for(size_t sh = 0; sh < geo.num_sh(); ++sh) - { - u(_C_, sh) = 1.0; - u(_C_, sh) -= corners[sh][0]*(2*corners[sh][0] - 1.0); - u(_C_, sh) -= corners[sh][1]*(2*corners[sh][1] - 1.0); - } - */ - // u(_C_, sh) = 1 - 2*(corners[sh][0]*corners[sh][0] + corners[sh][1]*corners[sh][1]) - (corners[sh][0]+corners[sh][1]); - // u(_C_, sh) = corners[sh][1]*(2*corners[sh][1] - 1.0); - // u(_C_, sh) = (1.0 - corners[sh][0] - corners[sh][1]) * (1.0 - 2*corners[sh][0] - 2*corners[sh][1]); - // u(_C_, sh) = corners[sh][1]; - // for(size_t sh = 0; sh < geo.num_sh(); ++sh) - // u(_C_, sh) = corners[sh][0]*(2*corners[sh][0] - 1.0); //corners[sh][0]; - // u(_C_, sh) = corners[sh][0]*(2* corners[sh][0]-1); - - //////////////////////////////////////////////////////////////////////////////// - // NO loop integration points! - // /* for(size_t ip = 0; ip < vBF.size(); ++ip) */ - // Reason: the length of the normal is already the length of the total face (NOT the scvf!) - //////////////////////////////////////////////////////////////////////////////// - - // loop integration points - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - typename TFVGeom::BF bf = vBF[ip]; - VecSet(Dgrad, 0.0); - - // loop trial space - for(size_t sh = 0; sh < bf.num_sh(); ++sh) - { - // Diffusion - UG_LOG("bf.num_sh(): " << bf.num_sh() << "\n"); - UG_LOG("Dgrad: " << Dgrad << "\n"); - UG_LOG("bf.normal(): " << bf.normal() << "\n"); - UG_LOG("bf.global_grad(ip, sh): " << bf.global_grad(sh) << "\n"); - - UG_LOG("u(_C_, sh): " << u(_C_, sh) << "\n"); - - VecScaleAppend(Dgrad, diffusion * u(_C_, sh), bf.global_grad(sh)); - } - - // add to local vector - d(_C_, bf.node_id()) += VecDot(Dgrad, bf.normal()); - - } - - UG_LOG("---------- end ----------- \n\n"); - -} - - -//////////////////////////////////////////////////////////////////////////////// -/// -/// methods for cut element error computation via 'add_l2error_A_elem()' -/// -//////////////////////////////////////////////////////////////////////////////// - -template -number get_exact_sol_test(MathVector position) -{ - return sin(2*M_PI*position[0]) + sin(2*M_PI*position[1]); -} - -template -number get_exact_sol_Gangl(MathVector position) -{ - double kappa_2 = 10.0; - double dist_x = position[0] - 0.0; - double dist_y = position[1] - 0.0; - double sqR = 0.4*0.4; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double returnValue = -4*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_2 - 1); - - if ( dist >= 0.4 ) - returnValue = -2*kappa_2*sqDist*sqDist; - - return returnValue; -} - -template -MathVector get_exact_grad_Gangl(MathVector position) -{ - double kappa_2 = 10.0; - double dist_x = position[0] - 0.0; - double dist_y = position[1] - 0.0; - double sqR = 0.4*0.4; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double factor = -8*kappa_2*kappa_2*sqR; - - if ( dist >= 0.4 ) - factor = -8*kappa_2*sqDist; - - MathVector returnVector; - returnVector[0] = factor*dist_x; - returnVector[1] = factor*dist_y; - - return returnVector; -} - -template -MathVector get_exact_grad_FedkiwEx5(MathVector position) -{ - double center_x = 0.0; - double center_y = 0.0; - double radius = 0.5; - - double dist_x = position[0] - center_x; - double dist_y = position[1] - center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double absValue = position[0]*position[0] + position[1]* position[1]; - - MathVector returnVector; - returnVector[0] = 0.0; - returnVector[1] = 0.0; - - double factor = 1.0/absValue; - if ( dist >= radius ) - { - returnVector[0] = factor*position[0]; - returnVector[1] = factor*position[1]; - } - - return returnVector; - -} - -template -number get_exact_sol_FedkiwEx6(MathVector position) -{ - double center_x = 0.0; - double center_y = 0.0; - double radius = 0.5; - - double dist_x = position[0] - center_x; - double dist_y = position[1] - center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double returnValue = 0.0; - - if ( dist <= radius ) - returnValue = exp(position[0])*cos(position[1]); - - return returnValue; -} - -template -number get_exact_sol_FedkiwEx5(MathVector position) -{ - double center_x = 0.0; - double center_y = 0.0; - - double dist_x = position[0]-center_x; - double dist_y = position[1]-center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double returnValue = 1.0; - - if ( dist > 0.5 ) - returnValue = 1.0 + log(2*dist); - - return returnValue; -} - -template -number get_exact_sol_FedkiwEx3(MathVector position) -{ - double center_x = 0.5; - double center_y = 0.5; - double radius = 0.25; - - double dist_x = position[0] - center_x; - double dist_y = position[1] - center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double absValue = position[0]*position[0] + position[1]* position[1]; - - double returnValue = 0.0; - - if ( dist <= radius ) - returnValue = exp(-absValue); - - return returnValue; -} - -template -MathVector get_exact_grad(MathVector position) -{ - -} - -////////////////////////////////////////////////////////////////////// -// code see ugbase/lib_disc/function_spaces/integrate.h: evaluate() for -// --> L2ErrorIntegrand (for value) -// --> H1ErrorIntegrand (for gradient): lines 1873-1910 -// -// called bei Integrate() via method 'integrand.values': -// integrand.values(&(vValue[0]), &(vGlobIP[0]), -// pElem, &vCorner[0], rQuadRule.points(), -// &(vJT[0]), -// numIP); -// -////////////////////////////////////////////////////////////////////// -template -template -number ConvectionDiffusionFV1:: -add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem) -{ - bool output = false; - - // number integral = 0; - - std::vector > vCorner; - std::vector > vGlobIP; - std::vector > vLocIP; - std::vector > vJT; - std::vector vValue; - std::vector vValueGrad; - - QuadType type = GetQuadratureType("best"); - - const QuadratureRule& rQuadRule - = QuadratureRuleProvider::get(roid, 1, type); - - // get reference element mapping by reference object id - DimReferenceMapping& mapping - = ReferenceMappingProvider::get(roid); - - // number of integration points - const size_t numIP = rQuadRule.size(); - - // get all corner coordinates - // CollectCornerCoordinates(vCorner, *pElem, aaPos, true); - - const DimReferenceElement& rRefElem - = ReferenceElementProvider::get(roid); - - vCorner.clear(); - // remember global position of nodes - for(size_t i = 0; i < rRefElem.num(0); ++i) - vCorner.push_back(geo.get_corner(i)); - - if ( output ) - { - for ( size_t i = 0; i < rRefElem.num(0); ++i) - UG_LOG("vCorner" << vCorner[i][0] << " and " << vCorner[i][1] << "\n" ); - UG_LOG("\n" ); - } - - // update the reference mapping for the corners - mapping.update(vCorner); - - // compute global integration points - vGlobIP.resize(numIP); - mapping.local_to_global(&(vGlobIP[0]), rQuadRule.points(), numIP); - - if ( output ) UG_LOG("vGlobIP" << vGlobIP[0][0] << " and " << vGlobIP[0][1] << "\n" ); - if ( output ) UG_LOG("\n" ); - - // compute local integration points - vLocIP.resize(numIP); - for(size_t ip = 0; ip < numIP; ++ip) - vLocIP[ip] = rQuadRule.points()[ip]; - - if ( output ) UG_LOG("vLocIP" << vLocIP[0][0] << " and " << vLocIP[0][1] << "\n" ); - if ( output ) UG_LOG("\n" ); - - - // compute transformation matrices - vJT.resize(numIP); - mapping.jacobian_transposed(&(vJT[0]), rQuadRule.points(), numIP); - - const size_t num_sh = geo.num_scvf(); - - if ( num_sh != rRefElem.num(0) ) - UG_THROW("wrong number of corners: sh = " << num_sh << ", but rRefElem.num(0) = " << rRefElem.num(0) << "\n"); - - // compute integrand values at integration points - vValue.resize(numIP); - vValueGrad.resize(numIP); - - try - { - // loop all integration points - for(size_t ip = 0; ip < numIP; ++ip) - { - // compute exact solution at integration point -// number exactSolIP = get_exact_sol_FedkiwEx5(vGlobIP[ip]); - number exactSolIP = get_exact_sol_Gangl(vGlobIP[ip]); - - // compute exact gradient at integration point - MathVector exactGradIP = get_exact_grad_FedkiwEx5(vGlobIP[ip]); - - // compute approximated solution at integration point - number approxSolIP = 0.0; - MathVector locTmp; VecSet(locTmp, 0.0); - - const typename TFVGeom::SCV& scv = geo.scv(ip); - - for(size_t sh = 0; sh < num_sh; ++sh) - { - // add shape fct at ip * value at shape - approxSolIP += u(_C_,sh) * geo.get_shape(sh, vLocIP[ip], roid); - - // add gradient at ip - VecScaleAppend(locTmp, u(_C_,sh), scv.local_grad(sh)); - } - - // get squared of difference - vValue[ip] = (exactSolIP - approxSolIP); - vValue[ip] *= vValue[ip]; - - // compute global gradient - MathVector approxGradIP; - MathMatrix JTInv; - Inverse(JTInv, vJT[ip]); - MatVecMult(approxGradIP, JTInv, locTmp); - - // get error of gradient - vValueGrad[ip] = VecDistanceSq(approxGradIP, exactGradIP); - - - } - /* integrand.values(&(vValue[0]), &(vGlobIP[0]), - pElem, &vCorner[0], rQuadRule.points(), - &(vJT[0]), - numIP); - */ - } - UG_CATCH_THROW("Unable to compute values of integrand at integration point."); - - // reset contribution of this element - number intValElem = 0; - - // loop integration points - for(size_t ip = 0; ip < numIP; ++ip) - { - // get quadrature weight - const number weightIP = rQuadRule.weight(ip); - - // get determinate of mapping - const number det = SqrtGramDeterminant(vJT[ip]); - - // add contribution of integration point - intValElem += vValue[ip] * weightIP * det; - // intValElem += vValueGrad[ip] * weightIP * det; - - } - - // add to global sum - - if ( output ) UG_LOG("added: " << intValElem << "\n\n"); - - return intValElem; -} - - -template -template -void ConvectionDiffusionFV1:: -add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - -// reaction rate - if(m_imReactionRateExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local defect - d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume(); - } - } - -// reaction - if(m_imReactionExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local defect - d(_C_, co) += m_imReactionExpl[ip] * scv.volume(); - } - } - - if(m_imSourceExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local rhs - d(_C_, co) -= m_imSourceExpl[ip] * scv.volume(); - } - } -} - -template -template -void ConvectionDiffusionFV1:: -add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - if(!m_imMassScale.data_given() && !m_imMass.data_given()) return; - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // mass value - number val = 0.0; - - // multiply by scaling - if(m_imMassScale.data_given()) - val += m_imMassScale[ip] * u(_C_, co); - - // add mass - if(m_imMass.data_given()) - val += m_imMass[ip]; - - // Add to local defect - d(_C_, co) += val * scv.volume(); - } -} - - -template -template -void ConvectionDiffusionFV1:: -add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) -{ - ///////////////////////////////////////////////////// - // add rhs ALLREADY(!) during 'add_def_A_elem_local()' method! - // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! - ///////////////////////////////////////////////////// - - return; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - // loop Sub Control Volumes (SCV) - if ( m_imSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv( ip ); - - // get associated node - const int co = scv.node_id(); - - // Add to local rhs - d(_C_, co) += m_imSource[ip] * scv.volume(); - //UG_LOG("d(_C_, co) = " << d(_C_, co) << "; \t ip " << ip << "; \t co " << co << "; \t scv_vol " << scv.volume() << "; \t m_imSource[ip] " << m_imSource[ip] << std::endl); - } - } - - // loop Sub Control Volumes (SCVF) - if ( m_imVectorSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); - - // Add to local rhs - d(_C_, scvf.from()) -= VecDot(m_imVectorSource[ip], scvf.normal() ); - d(_C_, scvf.to() ) += VecDot(m_imVectorSource[ip], scvf.normal() ); - } - } -} - - -// //////////////////////////////// -// error estimation (begin) /// - -// prepares the loop over all elements of one type for the computation of the error estimator -template -template -void ConvectionDiffusionFV1:: -prep_err_est_elem_loop(const ReferenceObjectID roid, const int si) -{ - // get the error estimator data object and check that it is of the right type - // we check this at this point in order to be able to dispense with this check later on - // (i.e. in prep_err_est_elem and compute_err_est_A_elem()) - if (this->m_spErrEstData.get() == NULL) - { - UG_THROW("No ErrEstData object has been given to this ElemDisc!"); - } - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (!err_est_data) - { - UG_THROW("Dynamic cast to SideAndElemErrEstData failed." - << std::endl << "Make sure you handed the correct type of ErrEstData to this discretization."); - } - - -// check that upwind has been set - if (m_spConvShape.invalid()) - UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " - "Upwind has not been set."); - -// set local positions - if (!TFVGeom::usesHangingNodes) - { - static const int refDim = TElem::dim; - - // get local IPs - size_t numSideIPs, numElemIPs; - const MathVector* sideIPs; - const MathVector* elemIPs; - try - { - numSideIPs = err_est_data->num_all_side_ips(roid); - numElemIPs = err_est_data->num_elem_ips(roid); - sideIPs = err_est_data->template side_local_ips(roid); - elemIPs = err_est_data->template elem_local_ips(roid); - - if (!sideIPs || !elemIPs) return; // are NULL if TElem is not of the same dim as TDomain - } - UG_CATCH_THROW("Integration points for error estimator cannot be set."); - - // set local IPs in imports - m_imDiffusion.template set_local_ips(sideIPs, numSideIPs, false); - m_imVelocity.template set_local_ips(sideIPs, numSideIPs, false); - m_imFlux.template set_local_ips(sideIPs, numSideIPs, false); - m_imSource.template set_local_ips(elemIPs, numElemIPs, false); - m_imVectorSource.template set_local_ips(sideIPs, numSideIPs, false); - m_imReactionRate.template set_local_ips(elemIPs, numElemIPs, false); - m_imReaction.template set_local_ips(elemIPs, numElemIPs, false); - m_imMassScale.template set_local_ips(elemIPs, numElemIPs, false); - m_imMass.template set_local_ips(elemIPs, numElemIPs, false); - - // init upwind for element type - TFVGeom& geo = GeomProvider::get(); - if (!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " - "Cannot init upwind for element type."); - - // store values of shape functions in local IPs - LagrangeP1::reference_element_type> trialSpace - = Provider::reference_element_type> >::get(); - - m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh()); - for (size_t ip = 0; ip < numElemIPs; ip++) - trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]); - for (size_t ip = 0; ip < numSideIPs; ip++) - trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]); - } -} - -template -template -void ConvectionDiffusionFV1:: -prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - -// update geometry for this element - static TFVGeom& geo = GeomProvider::get(); - try - { - geo.update(elem, vCornerCoords, &(this->subset_handler())); - } - UG_CATCH_THROW("ConvectionDiffusionFV1::prep_err_est_elem: Cannot update Finite Volume Geometry."); - -// roid - ReferenceObjectID roid = elem->reference_object_id(); - -// set local positions - if (TFVGeom::usesHangingNodes) - { - static const int refDim = TElem::dim; - - size_t numSideIPs, numElemIPs; - const MathVector* sideIPs; - const MathVector* elemIPs; - try - { - numSideIPs = err_est_data->num_all_side_ips(roid); - numElemIPs = err_est_data->num_elem_ips(roid); - sideIPs = err_est_data->template side_local_ips(roid); - elemIPs = err_est_data->template elem_local_ips(roid); - - if (!sideIPs || !elemIPs) return; // are NULL if TElem is not of the same dim as TDomain - } - UG_CATCH_THROW("Integration points for error estimator cannot be set."); - - m_imDiffusion.template set_local_ips(sideIPs, numSideIPs); - m_imVelocity.template set_local_ips(sideIPs, numSideIPs); - m_imFlux.template set_local_ips(sideIPs, numSideIPs); - m_imSource.template set_local_ips(elemIPs, numElemIPs); - m_imVectorSource.template set_local_ips(sideIPs, numSideIPs); - m_imReactionRate.template set_local_ips(elemIPs, numElemIPs); - m_imReaction.template set_local_ips(elemIPs, numElemIPs); - m_imMassScale.template set_local_ips(elemIPs, numElemIPs); - m_imMass.template set_local_ips(elemIPs, numElemIPs); - - // init upwind for element type - TFVGeom& geo = GeomProvider::get(); - if (!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " - "Cannot init upwind for element type."); - - // store values of shape functions in local IPs - LagrangeP1::reference_element_type> trialSpace - = Provider::reference_element_type> >::get(); - - m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh()); - for (size_t ip = 0; ip < numElemIPs; ip++) - trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]); - for (size_t ip = 0; ip < numSideIPs; ip++) - trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]); - } - -// set global positions - size_t numSideIPs, numElemIPs; - const MathVector* sideIPs; - const MathVector* elemIPs; - - try - { - numSideIPs = err_est_data->num_all_side_ips(roid); - numElemIPs = err_est_data->num_elem_ips(roid); - - sideIPs = err_est_data->all_side_global_ips(elem, vCornerCoords); - elemIPs = err_est_data->elem_global_ips(elem, vCornerCoords); - } - UG_CATCH_THROW("Global integration points for error estimator cannot be set."); - - m_imDiffusion. set_global_ips(&sideIPs[0], numSideIPs); - m_imVelocity. set_global_ips(&sideIPs[0], numSideIPs); - m_imFlux. set_global_ips(&sideIPs[0], numSideIPs); - m_imSource. set_global_ips(&elemIPs[0], numElemIPs); - m_imVectorSource. set_global_ips(&sideIPs[0], numSideIPs); - m_imReactionRate. set_global_ips(&elemIPs[0], numElemIPs); - m_imReaction. set_global_ips(&elemIPs[0], numElemIPs); - m_imMassScale. set_global_ips(&elemIPs[0], numElemIPs); - m_imMass. set_global_ips(&elemIPs[0], numElemIPs); -} - -// computes the error estimator contribution (stiffness part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ - typedef typename reference_element_traits::reference_element_type ref_elem_type; - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - -// request geometry - static const TFVGeom& geo = GeomProvider::get(); - - -// SIDE TERMS // - -// get the sides of the element - // We have to cast elem to a pointer of type SideAndElemErrEstData::elem_type - // for the SideAndElemErrEstData::operator() to work properly. - // This cannot generally be achieved by casting to TElem*, since this method is also registered for - // lower-dimensional types TElem, and must therefore be compilable, even if it is never EVER to be executed. - // The way we achieve this here, is by calling associated_elements_sorted() which has an implementation for - // all possible types. Whatever comes out of it is of course complete nonsense if (and only if) - // SideAndElemErrEstData::elem_type != TElem. To be on the safe side, we throw an error if the number of - // entries in the list is not as it should be. - - typename MultiGrid::traits::side_type>::secure_container side_list; - pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); - if (side_list.size() != (size_t) ref_elem_type::numSides) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// some help variables - MathVector fluxDensity, gradC, normal; - - // FIXME: The computation of the gradient has to be reworked. - // In the case of P1 shape functions, it is valid. For Q1 shape functions, however, - // the gradient is not constant (but bilinear) on the element - and along the sides. - // We cannot use the FVGeom here. Instead, we need to calculate the gradient in each IP! - - // calculate grad u (take grad from first scvf ip (grad u is constant on the entire element)) -/* if (geo.num_scvf() < 1) {UG_THROW("Element has no SCVFs!");} - const typename TFVGeom::SCVF& scvf = geo.scvf(0); - - VecSet(gradC, 0.0); - for (size_t j=0; j(normal, side, vCornerCoords); - VecNormalize(normal, normal); - - try - { - for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) - { - size_t ip = passedIPs + sip; - - VecSet(fluxDensity, 0.0); - - // diffusion // - if (m_imDiffusion.data_given()) - MatVecScaleMultAppend(fluxDensity, -1.0, m_imDiffusion[ip], gradC); - - // convection // - if (m_imVelocity.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtSideIP(sh,sip); - - VecScaleAppend(fluxDensity, val, m_imVelocity[ip]); - } - - // general flux // - if (m_imFlux.data_given()) - VecAppend(fluxDensity, m_imFlux[ip]); - - (*err_est_data)(side_list[side],sip) += scale * VecDot(fluxDensity, normal); - } - - passedIPs += err_est_data->num_side_ips(side_list[side]); - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); - } - -// VOLUME TERMS // - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - { - number total = 0.0; - - // diffusion // TODO ONLY FOR (PIECEWISE) CONSTANT DIFFUSION TENSOR SO FAR! - // div(D*grad(c)) - // nothing to do, as c is piecewise linear and div(D*grad(c)) disappears - // if D is diagonal and c bilinear, this should also vanish (confirm this!) - - // convection // TODO ONLY FOR (PIECEWISE) CONSTANT OR DIVERGENCE-FREE - // VELOCITY FIELDS SO FAR! - // div(v*c) = div(v)*c + v*grad(c) -- gradC has been calculated above - if (m_imVelocity.data_given()) - total += VecDot(m_imVelocity[ip], gradC); - - // general flux // TODO ONLY FOR DIVERGENCE-FREE FLUX FIELD SO FAR! - // nothing to do - - // reaction // - if (m_imReactionRate.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < geo.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); - - total += m_imReactionRate[ip] * val; - } - - if (m_imReaction.data_given()) - { - total += m_imReaction[ip]; - } - - (*err_est_data)(elem_list[0],ip) += scale * total; - } - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// computes the error estimator contribution (mass part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ -// note: mass parts only enter volume term - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// request geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop integration points - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - { - number total = 0.0; - - // mass scale // - if (m_imMassScale.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < geo.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); - - total += m_imMassScale[ip] * val; - } - - // mass // - if (m_imMass.data_given()) - { - total += m_imMass[ip]; - } - - (*err_est_data)(elem_list[0],ip) += scale * total; - } - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// computes the error estimator contribution (rhs part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ - typedef typename reference_element_traits::reference_element_type ref_elem_type; - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - -// SIDE TERMS // - -// get the sides of the element - typename MultiGrid::traits::side_type>::secure_container side_list; - pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); - if (side_list.size() != (size_t) ref_elem_type::numSides) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// loop sides - size_t passedIPs = 0; - for (size_t side = 0; side < (size_t) ref_elem_type::numSides; side++) - { - // normal on side - MathVector normal; - SideNormal(normal, side, vCornerCoords); - VecNormalize(normal, normal); - - try - { - for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) - { - size_t ip = passedIPs + sip; - - // vector source // - if (m_imVectorSource.data_given()) - (*err_est_data)(side_list[side],sip) += scale * VecDot(m_imVectorSource[ip], normal); - } - - passedIPs += err_est_data->num_side_ips(side_list[side]); - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); - } - -// VOLUME TERMS // - - if (!m_imSource.data_given()) return; - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// source // - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - (*err_est_data)(elem_list[0],ip) += scale * m_imSource[ip]; - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// postprocesses the loop over all elements of one type in the computation of the error estimator -template -template -void ConvectionDiffusionFV1:: -fsh_err_est_elem_loop() -{ -// finish the element loop in the same way as the actual discretization - this->template fsh_elem_loop (); -}; - -// error estimation (end) /// -// ///////////////////////////////// - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -lin_def_velocity(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // sum up contributions of convection shapes - MathVector linDefect; - VecSet(linDefect, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(linDefect, u(_C_,sh), convShape.D_vel(ip, sh)); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] += linDefect; - vvvLinDef[ip][_C_][scvf.to()] -= linDefect; - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -lin_def_diffusion(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // compute gradient at ip - MathVector grad_u; VecSet(grad_u, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(grad_u, u(_C_,sh), scvf.global_grad(sh)); - - // compute the lin defect at this ip - MathMatrix linDefect; - - // part coming from -\nabla u * \vec{n} - for(size_t k=0; k < (size_t)dim; ++k) - for(size_t j = 0; j < (size_t)dim; ++j) - linDefect(j,k) = (scvf.normal())[j] * grad_u[k]; - - // add contribution from convection shapes - if(convShape.non_zero_deriv_diffusion()) - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - MatAdd(linDefect, convShape.D_diffusion(ip, sh), u(_C_, sh)); - - // add contributions - vvvLinDef[ip][_C_][scvf.from()] -= linDefect; - vvvLinDef[ip][_C_][scvf.to() ] += linDefect; - } -} - -template -template -void ConvectionDiffusionFV1:: -lin_def_flux(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] += scvf.normal(); - vvvLinDef[ip][_C_][scvf.to()] -= scvf.normal(); - } -} -// computes the linearized defect w.r.t to the reaction rate -template -template -void ConvectionDiffusionFV1:: -lin_def_reaction_rate(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = u(_C_, co) * scv.volume(); - } -} - -// computes the linearized defect w.r.t to the reaction -template -template -void ConvectionDiffusionFV1:: -lin_def_reaction(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the source -template -template -void ConvectionDiffusionFV1:: -lin_def_source(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the vector source -// (in analogy to velocity) -template -template -void ConvectionDiffusionFV1:: -lin_def_vector_source(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ - // get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - - // loop Sub Control Volumes Faces (SCVF) - for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] -= scvf.normal(); - vvvLinDef[ip][_C_][scvf.to()] += scvf.normal(); - } -} - -// computes the linearized defect w.r.t to the mass scale -template -template -void ConvectionDiffusionFV1:: -lin_def_mass_scale(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t co = 0; co < geo.num_scv(); ++co) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(co); - - // Check associated node - UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); - - // set lin defect - vvvLinDef[co][_C_][co] = u(_C_, co) * scv.volume(); - } -} - -// computes the linearized defect w.r.t to the mass scale -template -template -void ConvectionDiffusionFV1:: -lin_def_mass(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t co = 0; co < geo.num_scv(); ++co) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(co); - - // Check associated node - UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); - - // set lin defect - vvvLinDef[co][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -ex_value(number vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > vvvDeriv[]) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reference element - typedef typename reference_element_traits::reference_element_type - ref_elem_type; - -// number of shape functions - static const size_t numSH = ref_elem_type::numCorners; - - -// FV1 SCVF ip - if(vLocIP == geo.scvf_local_ips()) - { - // Loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // Get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // compute concentration at ip - vValue[ip] = 0.0; - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vValue[ip] += u(_C_, sh) * scvf.shape(sh); - - // compute derivative w.r.t. to unknowns iff needed - if(bDeriv) - { - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vvvDeriv[ip][_C_][sh] = scvf.shape(sh); - - // do not forget that number of DoFs (== vvvDeriv[ip][_C_]) - // might be > scvf.num_sh() in case of hanging nodes! - size_t ndof = vvvDeriv[ip][_C_].size(); - for (size_t sh = scvf.num_sh(); sh < ndof; ++sh) - vvvDeriv[ip][_C_][sh] = 0.0; - } - } - } -// FV1 SCV ip - else if(vLocIP == geo.scv_local_ips()) - { - // Loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // Get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get corner of SCV - const size_t co = scv.node_id(); - - // solution at ip - vValue[ip] = u(_C_, co); - - // set derivatives if needed - if(bDeriv) - { - size_t ndof = vvvDeriv[ip][_C_].size(); - for(size_t sh = 0; sh < ndof; ++sh) - vvvDeriv[ip][_C_][sh] = (sh==co) ? 1.0 : 0.0; - } - } - } -// general case - else - { - // get trial space - LagrangeP1& rTrialSpace = Provider >::get(); - - // storage for shape function at ip - number vShape[numSH]; - - // loop ips - for(size_t ip = 0; ip < nip; ++ip) - { - // evaluate at shapes at ip - rTrialSpace.shapes(vShape, vLocIP[ip]); - - // compute concentration at ip - vValue[ip] = 0.0; - for(size_t sh = 0; sh < numSH; ++sh) - vValue[ip] += u(_C_, sh) * vShape[sh]; - - // compute derivative w.r.t. to unknowns iff needed - // \todo: maybe store shapes directly in vvvDeriv - if(bDeriv) - { - for(size_t sh = 0; sh < numSH; ++sh) - vvvDeriv[ip][_C_][sh] = vShape[sh]; - - // beware of hanging nodes! - size_t ndof = vvvDeriv[ip][_C_].size(); - for (size_t sh = numSH; sh < ndof; ++sh) - vvvDeriv[ip][_C_][sh] = 0.0; - } - } - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -ex_grad(MathVector vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > > vvvDeriv[]) -{ -// Get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reference element - typedef typename reference_element_traits::reference_element_type - ref_elem_type; - -// reference dimension - static const int refDim = ref_elem_type::dim; - -// number of shape functions - static const size_t numSH = ref_elem_type::numCorners; - - -// FV1 SCVF ip - if(vLocIP == geo.scvf_local_ips()) - { - // Loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // Get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - VecSet(vValue[ip], 0.0); - - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(vValue[ip], u(_C_, sh), scvf.global_grad(sh)); - - if(bDeriv) - { - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vvvDeriv[ip][_C_][sh] = scvf.global_grad(sh); - - // beware of hanging nodes! - size_t ndof = vvvDeriv[ip][_C_].size(); - for (size_t sh = scvf.num_sh(); sh < ndof; ++sh) - vvvDeriv[ip][_C_][sh] = 0.0; - } - } - } -// general case - else - { - // get trial space - LagrangeP1& rTrialSpace = Provider >::get(); - - // storage for shape function at ip - MathVector vLocGrad[numSH]; - MathVector locGrad; - - // Reference Mapping - MathMatrix JTInv; - ReferenceMapping mapping(vCornerCoords); - - // loop ips - for(size_t ip = 0; ip < nip; ++ip) - { - // evaluate at shapes at ip - rTrialSpace.grads(vLocGrad, vLocIP[ip]); - - // compute grad at ip - VecSet(locGrad, 0.0); - for(size_t sh = 0; sh < numSH; ++sh) - VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]); - - // compute global grad - mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]); - MatVecMult(vValue[ip], JTInv, locGrad); - - // compute derivative w.r.t. to unknowns iff needed - if(bDeriv) - { - for(size_t sh = 0; sh < numSH; ++sh) - MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); - - // beware of hanging nodes! - size_t ndof = vvvDeriv[ip][_C_].size(); - for (size_t sh = numSH; sh < ndof; ++sh) - vvvDeriv[ip][_C_][sh] = 0.0; - } - } - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// upwind -//////////////////////////////////////////////////////////////////////////////// - -template -void ConvectionDiffusionFV1:: -set_upwind(SmartPtr > shapes) {m_spConvShape = shapes;} - -// computes the linearized defect w.r.t to the velocity -template -const typename ConvectionDiffusionFV1::conv_shape_type& -ConvectionDiffusionFV1:: -get_updated_conv_shapes(const FVGeometryBase& geo) -{ -// compute upwind shapes for transport equation -// \todo: we should move this computation into the preparation part of the -// disc, to only compute the shapes once, reusing them several times. - if(m_imVelocity.data_given()) - { - // get diffusion at ips - const MathMatrix* vDiffusion = NULL; - if(m_imDiffusion.data_given()) vDiffusion = m_imDiffusion.values(); - - // update convection shapes - if(!m_spConvShape->update(&geo, m_imVelocity.values(), vDiffusion, true)) - { - UG_LOG("ERROR in 'ConvectionDiffusionFV1::get_updated_conv_shapes': " - "Cannot compute convection shapes.\n"); - } - } - -// return a const (!!) reference to the upwind - return *const_cast*>(m_spConvShape.get()); -} - -//////////////////////////////////////////////////////////////////////////////// -// register assemble functions -//////////////////////////////////////////////////////////////////////////////// - -#ifdef UG_DIM_1 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - -/* -// switch assemble functions - if(!bHang) - { - register_func >(); - } - else - { - register_func >(); - } - */ -} -#endif - -#ifdef UG_DIM_2 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - -/* -// switch assemble functions - if(!bHang) - { - register_func >(); - register_func >(); - register_func >(); - } - else - { - register_func >(); - register_func >(); - register_func >(); - } - */ -} -#endif - -#ifdef UG_DIM_3 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - - /* - -// switch assemble functions - if(!bHang) - { - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - } - else - { - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - } -*/ -} -#endif - -template -template -void ConvectionDiffusionFV1:: -register_func() -{ - ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; - typedef this_type T; - static const int refDim = reference_element_traits::dim; - - this->clear_add_fct(id); - this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); - this->set_prep_elem_fct( id, &T::template prep_elem); - this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); - this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem); - this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem); - this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem); - this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem); - this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem); - this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); - -// error estimator parts - this->set_prep_err_est_elem_loop(id, &T::template prep_err_est_elem_loop); - this->set_prep_err_est_elem(id, &T::template prep_err_est_elem); - this->set_compute_err_est_A_elem(id, &T::template compute_err_est_A_elem); - this->set_compute_err_est_M_elem(id, &T::template compute_err_est_M_elem); - this->set_compute_err_est_rhs_elem(id, &T::template compute_err_est_rhs_elem); - this->set_fsh_err_est_elem_loop(id, &T::template fsh_err_est_elem_loop); - -// set computation of linearized defect w.r.t velocity - m_imDiffusion.set_fct(id, this, &T::template lin_def_diffusion); - m_imVelocity. set_fct(id, this, &T::template lin_def_velocity); - m_imFlux.set_fct(id, this, &T::template lin_def_flux); - m_imReactionRate. set_fct(id, this, &T::template lin_def_reaction_rate); - m_imReaction. set_fct(id, this, &T::template lin_def_reaction); - m_imSource. set_fct(id, this, &T::template lin_def_source); - m_imVectorSource.set_fct(id, this, &T::template lin_def_vector_source); - m_imMassScale.set_fct(id, this, &T::template lin_def_mass_scale); - m_imMass. set_fct(id, this, &T::template lin_def_mass); - -// exports - m_exValue-> template set_fct(id, this, &T::template ex_value); - m_exGrad->template set_fct(id, this, &T::template ex_grad); -} - -//////////////////////////////////////////////////////////////////////////////// -// explicit template instantiations -//////////////////////////////////////////////////////////////////////////////// - -#ifdef UG_DIM_1 -template class ConvectionDiffusionFV1; -#endif -#ifdef UG_DIM_2 -template class ConvectionDiffusionFV1; -#endif -#ifdef UG_DIM_3 -template class ConvectionDiffusionFV1; -#endif - -} // end namespace ConvectionDiffusionPlugin -} // namespace ug - diff --git a/fv1_cutElem/convection_diffusion_fv1 Kopie.h b/fv1_cutElem/convection_diffusion_fv1 Kopie.h deleted file mode 100644 index 71d988b..0000000 --- a/fv1_cutElem/convection_diffusion_fv1 Kopie.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (c) 2013-2015: G-CSC, Goethe University Frankfurt - * Author: Andreas Vogel - * - * This file is part of UG4. - * - * UG4 is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License version 3 (as published by the - * Free Software Foundation) with the following additional attribution - * requirements (according to LGPL/GPL v3 §7): - * - * (1) The following notice must be displayed in the Appropriate Legal Notices - * of covered and combined works: "Based on UG4 (www.ug4.org/license)". - * - * (2) The following notice must be displayed at a prominent place in the - * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". - * - * (3) The following bibliography is recommended for citation and must be - * preserved in all covered files: - * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively - * parallel geometric multigrid solver on hierarchically distributed grids. - * Computing and visualization in science 16, 4 (2013), 151-164" - * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel - * flexible software system for simulating pde based models on high performance - * computers. Computing and visualization in science 16, 4 (2013), 165-179" - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - */ - -#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ -#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ - - -// ug4 headers -#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" -#include "lib_disc/spatial_disc/elem_disc/sss.h" - -// plugin's internal headers -#include "../convection_diffusion_base.h" - -namespace ug{ -namespace ConvectionDiffusionPlugin{ - -// \ingroup lib_disc_elem_disc -/// \addtogroup convection_diffusion -/// \{ - -/// Discretization for the Convection-Diffusion Equation -/** - * This class implements the IElemDisc interface to provide element local - * assemblings for the convection diffusion equation. - * The Equation has the form - * \f[ - * \partial_t (m1*c + m2) - \nabla \left( D \nabla c - \vec{v} c - \vec{F} \right ) - * + r1 \cdot c + r2 = f + f2 - * \f] - * with - *
    - *
  • \f$ c \f$ is the unknown solution - *
  • \f$ m1 \equiv m(\vec{x},t) \f$ is the Mass Scaling Term - *
  • \f$ m2 \equiv m(\vec{x},t) \f$ is the Mass Term - *
  • \f$ D \equiv D(\vec{x},t) \f$ is the Diffusion Tensor - *
  • \f$ v \equiv \vec{v}(\vec{x},t) \f$ is the Velocity Field - *
  • \f$ F \equiv \vec{F}(\vec{x},t) \f$ is the Flux - *
  • \f$ r1 \equiv r(\vec{x},t) \f$ is the Reaction Rate - *
  • \f$ r2 \equiv r(\vec{x},t) \f$ is a Reaction Term - *
  • \f$ f \equiv f(\vec{x},t) \f$ is a Source Term - *
  • \f$ f2 \equiv f_2(\vec{x},t) \f$ is a Vector Source Term - *
- * - * \tparam TDomain Domain - */ -template< typename TDomain> -class ConvectionDiffusionFV1 : public ConvectionDiffusionBase -{ - private: - /// Base class type - typedef ConvectionDiffusionBase base_type; - - /// Own type - typedef ConvectionDiffusionFV1 this_type; - - /// error estimator type - typedef SideAndElemErrEstData err_est_type; - - public: - /// World dimension - static const int dim = base_type::dim; - - public: - /// Constructor - ConvectionDiffusionFV1(const char* functions, const char* subsets); - - /// set the upwind method - /** - * This method sets the upwind method used to upwind the convection. - * - * \param shapes upwind method - */ - void set_upwind(SmartPtr > shapes); - - /// set singular sources and sinks - void set_sss(SmartPtr > sss) { m_sss = sss; } - - private: - /// prepares assembling - virtual void prep_assemble_loop(); - - /// prepares the loop over all elements - /** - * This method prepares the loop over all elements. It resizes the Position - * array for the corner coordinates and schedules the local ip positions - * at the data imports. - */ - template - void prep_elem_loop(const ReferenceObjectID roid, const int si); - - /// prepares the element for assembling - /** - * This methods prepares an element for the assembling. The Positions of - * the Element Corners are read and the Finite Volume Geometry is updated. - * The global ip positions are scheduled at the data imports. - */ - template - void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]); - - /// finishes the loop over all elements - template - void fsh_elem_loop(); - - /// assembles the local stiffness matrix using a finite volume scheme - template - void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - template - void add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - template - void add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - - - /// assembles the local mass matrix using a finite volume scheme - template - void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - - /// assembles the stiffness part of the local defect - template - void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - /// assembles the stiffness part of the local defect - template - void add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - template - void add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - template - number add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem); - - - /// assembles the stiffness part of the local defect explicit reaction, reaction_rate and source - template - void add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the mass part of the local defect - template - void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the local right hand side - template - void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); - template - void add_rhs_elem_local(TFVGeom& geo, LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); - - - /// prepares the loop over all elements of one type for the computation of the error estimator - template - void prep_err_est_elem_loop(const ReferenceObjectID roid, const int si); - - /// prepares the element for assembling the error estimator - template - void prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// computes the error estimator contribution for one element - template - void compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// computes the error estimator contribution for one element - template - void compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// computes the error estimator contribution for one element - template - void compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// postprocesses the loop over all elements of one type in the computation of the error estimator - template - void fsh_err_est_elem_loop(); - - protected: - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_velocity(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_diffusion(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_flux(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the reaction - template - void lin_def_reaction(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the reaction - template - void lin_def_reaction_rate(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the source term - template - void lin_def_source(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the vector source term - template - void lin_def_vector_source(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the mass scale term - template - void lin_def_mass_scale(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the mass scale term - template - void lin_def_mass(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - private: - /// abbreviation for the local solution - static const size_t _C_ = 0; - - /// singular sources and sinks - SmartPtr > m_sss; - - using base_type::m_imDiffusion; - using base_type::m_imVelocity; - using base_type::m_imFlux; - using base_type::m_imSource; - using base_type::m_imSourceExpl; - using base_type::m_imVectorSource; - using base_type::m_imReactionRate; - using base_type::m_imReactionRateExpl; - using base_type::m_imReaction; - using base_type::m_imReactionExpl; - using base_type::m_imMassScale; - using base_type::m_imMass; - - using base_type::m_exGrad; - using base_type::m_exValue; - - protected: - /// method to compute the upwind shapes - SmartPtr > m_spConvShape; - - /// returns the updated convection shapes - typedef IConvectionShapes conv_shape_type; - const IConvectionShapes& get_updated_conv_shapes(const FVGeometryBase& geo); - - /// computes the concentration - template - void ex_value(number vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > vvvDeriv[]); - - /// computes the gradient of the concentration - template - void ex_grad(MathVector vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > > vvvDeriv[]); - - public: - /// type of trial space for each function used - virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid); - - /// returns if hanging nodes are needed - virtual bool use_hanging() const; - - protected: - /// current regular grid flag - bool m_bNonRegularGrid; - - /// current shape function set (needed for GeomProvider::get()) - LFEID m_LFEID; - - /// register utils - /// \{ - void register_all_funcs(bool bHang); - template void register_func(); - /// \} - - private: - /// struct holding values of shape functions in IPs - struct ShapeValues - { - public: - void resize(std::size_t nEip, std::size_t nSip, std::size_t _nSh) - { - nSh = _nSh; - elemVals.resize(nEip); - sideVals.resize(nSip); - for (std::size_t i = 0; i < nEip; i++) elemVals[i].resize(nSh); - for (std::size_t i = 0; i < nSip; i++) sideVals[i].resize(nSh); - } - number& shapeAtElemIP(std::size_t sh, std::size_t ip) {return elemVals[ip][sh];} - number& shapeAtSideIP(std::size_t sh, std::size_t ip) {return sideVals[ip][sh];} - number* shapesAtElemIP(std::size_t ip) {return &elemVals[ip][0];} - number* shapesAtSideIP(std::size_t ip) {return &sideVals[ip][0];} - std::size_t num_sh() {return nSh;} - private: - std::size_t nSh; - std::vector > elemVals; - std::vector > sideVals; - } m_shapeValues; -}; - -// end group convection_diffusion -/// \} - -} // end ConvectionDiffusionPlugin -} // end namespace ug - - -#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__*/ diff --git a/fv1_cutElem/convection_diffusion_fv1_cutElem.cpp b/fv1_cutElem/convection_diffusion_fv1_cutElem.cpp index aa54da0..5836799 100644 --- a/fv1_cutElem/convection_diffusion_fv1_cutElem.cpp +++ b/fv1_cutElem/convection_diffusion_fv1_cutElem.cpp @@ -30,6 +30,9 @@ * GNU Lesser General Public License for more details. */ +#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1_CUTELEM_IMPL +#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1_CUTELEM_IMPL + #include "convection_diffusion_fv1_cutElem.h" @@ -42,6 +45,13 @@ namespace ConvectionDiffusionPlugin{ DebugID DID_CONV_DIFF_FV1_CUTELEM("CONV_DIFF_FV1_CUTELEM"); +enum testCase +{ + GANGL_CENTER = 0, + GANGL_OFF_CENTER, + FEDKIW_EX5, +}; + //////////////////////////////////////////////////////////////////////////////// // helper function //////////////////////////////////////////////////////////////////////////////// @@ -50,13 +60,10 @@ DebugID DID_CONV_DIFF_FV1_CUTELEM("CONV_DIFF_FV1_CUTELEM"); template template void ConvectionDiffusionFV1_cutElem:: -get_local_data(TFVGeom& geo, const LocalVector& u, LocalVector& locUOut, MathMatrix diffusionOut, LocalVector& jumpOut, LocalVector& jump_gradOut, LocalVector& sourceOut) +get_local_data(TFVGeom& geo, const LocalVector& u, const LocalIndices& ind, LocalVector& locUOut, MathMatrix& diffusionOut, LocalVector& jumpOut, LocalVector& jump_gradOut, LocalVector& sourceOut) { const bool bElementIsCut = geo.get_element_modus(); - LocalIndices ind = u.get_indices(); - jumpOut.resize(ind); jump_gradOut.resize(ind); sourceOut.resize(ind); - const int orientation = geo.get_orientation(); std::vector imSource; @@ -72,11 +79,10 @@ get_local_data(TFVGeom& geo, const LocalVector& u, LocalVector& locUOut, MathMat diffusionOut *= geo.get_diffusion(geo.get_boolian_for_diffusion()); // set boundary condition values source, jump, jump_grad + jumpOut.resize(ind); jump_gradOut.resize(ind); jumpOut = 0.0; jump_gradOut = 0.0; - sourceOut = geo.set_source(imSource, ind, 3, false); - LocalVector source = geo.set_source(imSource, ind, 3, false); + geo.set_source(imSource, sourceOut, ind, 3, false); - int s = 0; } // B. set data for cut element else @@ -88,16 +94,19 @@ get_local_data(TFVGeom& geo, const LocalVector& u, LocalVector& locUOut, MathMat int indexSize = 3; if ( geo.get_roid() == ROID_QUADRILATERAL ) indexSize = 4; - + + // data for cut elements is stored in the InterfaceHandlerLocal and + // accessable by ElemDisc via the TFVGeom geometry class geo.set_local_sol(locUOut, indexSize, u, orientation); - - jumpOut = geo.set_jump_values(ind, indexSize); - jump_gradOut = geo.set_jump_grad_values(ind, indexSize); - sourceOut = geo.set_source(imSource, ind, indexSize, true); + geo.set_jump_values(jumpOut, ind, indexSize); + geo.set_jump_grad_values(jump_gradOut, ind, indexSize); + geo.set_source(imSource, sourceOut, ind, indexSize, true); } + + return; } - + //////////////////////////////////////////////////////////////////////////////// // general //////////////////////////////////////////////////////////////////////////////// @@ -107,7 +116,8 @@ ConvectionDiffusionFV1_cutElem:: ConvectionDiffusionFV1_cutElem(const char* functions, const char* subsets) : ConvectionDiffusionBase(functions,subsets), m_spConvShape(new ConvectionShapesNoUpwind), - m_bNonRegularGrid(false) + m_bNonRegularGrid(false), + m_testCase(0) { register_all_funcs(m_bNonRegularGrid); } @@ -148,8 +158,7 @@ template void ConvectionDiffusionFV1_cutElem:: prep_assemble_loop() { - if (m_sss.valid()) - m_sss->clear_markers(); + } template @@ -206,9 +215,8 @@ void ConvectionDiffusionFV1_cutElem:: prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) { // Update Geometry for this element - //static TFVGeom& geo = GeomProvider::get(); +//static TFVGeom& geo = GeomProvider::get(); TFVGeom& geo = GeomProvider::get(m_LFEID,1); - //TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); // fix: set orientation initially globally! geo.set_orientation(1); @@ -216,7 +224,6 @@ prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, try{ UG_DLOG(DID_CONV_DIFF_FV1_CUTELEM, 2, ">>OCT_DISC_DEBUG: " << "convection_diffusion_fv1.cpp: " << "prep_elem(): update(): "<< roid << std::endl); -// geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); geo.update(elem, vCornerCoords, &(this->subset_handler())); }UG_CATCH_THROW("ConvectionDiffusionFV1_cutElem::prep_elem:" " Cannot update Finite Volume Geometry."); @@ -298,149 +305,115 @@ template void ConvectionDiffusionFV1_cutElem:: add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) { - - bool debug = false; - bool boundary = false; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); +// get finite volume geometry TFVGeom& geo = GeomProvider::get(m_LFEID,1); - const bool bElementIsCut = geo.get_element_modus(); - - // First call with orientation = 1: - int orientation = 1; - geo.set_orientation(orientation); - geo.init_integral(); +// get the modus of the current element + const bool bElementIsCut = geo.get_element_modus(); - // normal assembling if not cut by interface: +//////////////////////////////////////////////////////////////////////////// +// (A) usual assembling for non-cut element: if ( !bElementIsCut ) { - LocalVector dummyU; - LocalIndices ind = u.get_indices(); - dummyU.resize(ind); - dummyU = 0; - + LocalVector dummyU = u; this->template add_jac_A_elem_local (geo, u, J, dummyU, elem, vCornerCoords); return; } - - // get data: - geo.resize_local_data(u); - LocalMatrix& locJ_tri = geo.get_jacobian_tri(); - LocalMatrix& locJ_quad = geo.get_jacobian_quad(); - - LocalVector& locU_tri = geo.get_solution_tri(); - LocalVector& locU_quad = geo.get_solution_quad(); - - // reset data: - locJ_tri = 0; - locJ_quad = 0; + +//////////////////////////////////////////////////////////////////////////// +// (B) call 'add_jac_A_elem_local_cut()', which handles the adaptions +// necessary for the cut element - LocalIndices ind = u.get_indices(); +// initialize cut element data: + geo.L2Error_init(); + geo.resize_local_data(u); - // call elem disc twice: + +//////////////////////////////////////////////////////////////////////////// +// (B1) First: call of 'add_jac_A_elem_local_cut()' with orientation = 1: + int orientation = 1; + geo.set_orientation(orientation); - if ( debug ) geo.print_InterfaceIDdata(); - - ReferenceObjectID roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - - this->template add_jac_A_elem_local (geo, u, locJ_tri, locU_tri, elem, vCornerCoords); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_tri, 3); - this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords); - } - - geo.set_jacobian_tri(locJ_tri); - geo.set_DoF_tag_tri(false); - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - - this->template add_jac_A_elem_local (geo, u, locJ_quad, locU_quad, elem, vCornerCoords); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_quad, 4); - this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords); - } - - geo.set_jacobian_quad(locJ_quad); - geo.set_DoF_tag_quad(false); - } - - - // Second call with orientation = 1: - bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! + add_jac_A_elem_local_cut(geo, u, elem, vCornerCoords); +//////////////////////////////////////////////////////////////////////////// +// (B2) Second: call of 'add_jac_A_elem_local_cut()' with orientation = -1: orientation *= -1; geo.set_orientation(orientation); + +// recompute local data on cut element due to new orientation: the local +// TFVGeom geometry data of the other part of the cut element will be computed try{ geo.update(elem, vCornerCoords, &(this->subset_handler())); }UG_CATCH_THROW("ConvectionDiffusionFV1_cutElem::update:" " Cannot update Finite Volume Geometry."); - if ( debug ) geo.print_InterfaceIDdata(); + add_jac_A_elem_local_cut(geo, u, elem, vCornerCoords); + + +} + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_jac_A_elem_local_cut(TFVGeom& geo, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + bool boundary = false; + +// shiftTag = true: in case of double DoFs on interface (for strong discontinuity on the interface) + bool shiftTag = geo.get_bScaleDoFs(); + + ReferenceObjectID roidCheck = geo.get_roid(); + int indexSize = 3; + if ( roidCheck == ROID_QUADRILATERAL ) indexSize = 4; + +// get the pointer for access and storage into 'InterfaceHandlerLocalDiffusion' class + LocalMatrix& locJ = geo.get_jacobian(roidCheck); + LocalVector& locU = geo.get_solution(roidCheck); + + locJ = 0; + +// finally: compute the local stiffness matrix on the cut element + this->template add_jac_A_elem_local (geo, u, locJ, locU, elem, vCornerCoords); - roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) +// compute the boundary condition on the interface of the cut element + if ( boundary ) { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - - this->template add_jac_A_elem_local (geo, u, locJ_tri, locU_tri, elem, vCornerCoords); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_tri, 3); - this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords); - } - - geo.set_jacobian_tri(locJ_tri); - geo.set_DoF_tag_tri(shiftTag); - - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - - this->template add_jac_A_elem_local (geo, u, locJ_quad, locU_quad, elem, vCornerCoords); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_quad, 4); - this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords); - } - - geo.set_jacobian_quad(locJ_quad); - geo.set_DoF_tag_quad(shiftTag); + geo.reset_jacobian_on_interface(locJ, indexSize); + this->template add_jac_A_elem_boundary (geo, locJ, locU, elem, vCornerCoords); } - +// write computed local stiffness matrix to data storage in class 'InterfaceHandlerLocalDiffusion' + geo.set_jacobian(locJ, roidCheck); + +// shiftTag necessary for local to global mapping + geo.set_DoF_tag(shiftTag, roidCheck); + + } template template void ConvectionDiffusionFV1_cutElem:: -add_jac_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalMatrix& J, LocalVector& locU, GridObject* elem, const MathVector vCornerCoords[]) +add_jac_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalMatrix& J, LocalVector& locU, + GridObject* elem, const MathVector vCornerCoords[]) { +//////////////////////////////////////////////////////////////////////// +// Pre-processing for assembling on cut Element: + MathMatrix diffusion; MatSet(diffusion, 0); MatDiagSet(diffusion, 1.0); LocalVector source, jump; + +// get the local data (jump, source) on the cut element + get_local_data(geo, u, u.get_indices(), locU, diffusion, jump, jump, jump); - get_local_data(geo, u, locU, diffusion, jump, jump, jump); +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// NOW: Standard ConvectionDiffusionFV1-assembling starts here: // Diff. Tensor times Gradient @@ -555,28 +528,7 @@ add_jac_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalMatrix& J, LocalVe } } -// reaction term does not explicitly depend on the associated unknown function - -//////////////////////////////// -// Singular sources and sinks -//////////////////////////////// - - if (m_sss.valid()) { - const typename TDomain::position_accessor_type& aaPos = this->domain()->position_accessor(); - const typename TDomain::grid_type& grid = *this->domain()->grid(); - const number time = this->time(); - MathVector<1> out; - for(size_t i = 0; i < geo.num_scv(); i++) { - const typename TFVGeom::SCV& scv = geo.scv(i); - const int co = scv.node_id(); - const number len = m_sss->get_contrib_of_scv((TElem*)elem, (Grid&)grid, aaPos, geo, co, time, out); - if (len == 0.0) continue; - out[0] *= len; - if (out[0] < 0.0) - // sink - J(_C_, co, _C_, co) -= out[0]; - } - } + } template @@ -584,31 +536,36 @@ template void ConvectionDiffusionFV1_cutElem:: add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) { +// get parameter double diffusion = 0.0; - if ( !geo.get_element_modus() ) diffusion = geo.get_diffusion(geo.get_boolian_for_diffusion()); else diffusion = geo.get_diffusion(); - + +// get inner boundary faces for assembling (stored in 'InterfaceHandlerLocalDiffusion' class) std::vector& vBF = geo.get_boundary_faces(); - if ( vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - - // loop integration points + UG_THROW("add_jac_A_elem_boundary(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + + if ( vBF.size() == 0 && geo.get_element_modus() ) + UG_THROW("add_jac_A_elem_boundary(): Error! If vBF.size() == 0, then the element is cut!\n"); + +//////////////////////////////////////////////////////////////////////////////// +// REMARK: NO loop integration points! +// /* for(size_t ip = 0; ip < vBF.size(); ++ip) */ +// Reason: the length of the normal is already the length of the total face (NOT the scvf!) +//////////////////////////////////////////////////////////////////////////////// + +// loop integration points for(size_t ip = 0; ip < vBF.size(); ++ip) { typename TFVGeom::BF bf = vBF[ip]; - // loop trial space + // loop trial space for(size_t sh = 0; sh < bf.num_sh(); ++sh) { - UG_LOG("bf.node_id(): " << bf.node_id() << "\n"); - UG_LOG("bf.global_grad(sh): " << bf.global_grad(sh) << "\n"); - UG_LOG("normal(): " << bf.normal() << "\n"); - - // add to local matrix + // add to local matrix J(_C_, bf.node_id(), _C_, sh) += VecDot(bf.global_grad(sh), bf.normal()); J(_C_, bf.node_id(), _C_, sh) *= diffusion; } @@ -623,7 +580,6 @@ void ConvectionDiffusionFV1_cutElem:: add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) { // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); if(!m_imMassScale.data_given()) return; @@ -641,7 +597,6 @@ add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const Mat J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip]; } -// m_imMass part does not explicitly depend on associated unknown function } template @@ -649,225 +604,126 @@ template void ConvectionDiffusionFV1_cutElem:: add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) { - bool output = false; - bool output_integral = false; - - bool debug = false; - bool boundary = false; - bool add = true; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); +// get finite volume geometry TFVGeom& geo = GeomProvider::get(m_LFEID,1); - const bool bElementIsCut = geo.get_element_modus(); - // First call with orientation = 1: - int orientation = 1; - geo.set_orientation(orientation); - - // necessary for call of 'get_solution_tri' an 'get_solution_quad': - geo.resize_local_data(u); +// get the modus of the current element + const bool bElementIsCut = geo.get_element_modus(); + std::vector imSource; if ( m_imSource.data_given() ) { for ( size_t i = 0; i < 3; ++i ) imSource.push_back(m_imSource[i]); } - // normal assembling if not cut by interface: +//////////////////////////////////////////////////////////////////////// +// (A) usual assembling for non-cut elements if ( !bElementIsCut ) { - LocalVector dummyU; - LocalIndices ind = d.get_indices(); - dummyU.resize(ind); - dummyU = 0; - LocalVector source = geo.set_source(imSource, ind, 3, false); - - if ( output ) - { - for ( size_t i = 0; i < 3; ++i) - UG_LOG("*** corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); - UG_LOG("\n" ); - } - + LocalVector dummyU = u; this->template add_def_A_elem_local (geo, u, d, dummyU, elem, vCornerCoords); number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, d, u, elem); - geo.add_to_integral(intValElem); - if ( output_integral ) - UG_LOG("------------------> usual: integral = " << sqrt(geo.get_integral()) << "\n"); - + geo.L2Error_add(intValElem); + return; } - - // get data: - LocalVector& locD_tri = geo.get_defect_tri(); - LocalVector& locD_quad = geo.get_defect_quad(); - LocalVector& locU_tri = geo.get_solution_tri(); - LocalVector& locU_quad = geo.get_solution_quad(); +///////////////////////////////////////////////////////////////////////////// +// (B) call 'add_def_A_elem_local_cut()', which handles the adaptions +// due to the cut element - // reset data: - locD_tri = 0; - locD_quad = 0; +// initialize cut element data: + geo.resize_local_data(u); + +////////////////////////////////////////////////////////////////////////////// +// (B1) First: call of 'add_def_A_elem_local_cut()' with orientation = 1: + int orientation = 1; + geo.set_orientation(orientation); - // call elem disc twice: + add_def_A_elem_local_cut (geo, u, elem, vCornerCoords); + - if ( debug ) geo.print_InterfaceIDdata(); +///////////////////////////////////////////////////////////////////////////// +// (B2) Second: call of 'add_def_A_elem_local_cut()' with orientation = -1: + orientation *= -1; + geo.set_orientation(orientation); - LocalIndices ind = d.get_indices(); +// recompute local data on cut element due to new orientation: the local +// TFVGeom geometry data of the other part of the cut element will be computed + try{ + geo.update(elem, vCornerCoords, &(this->subset_handler())); + }UG_CATCH_THROW("ConvectionDiffusionFV1_cutElem::update:" + " Cannot update Finite Volume Geometry."); + + add_def_A_elem_local_cut (geo, u, elem, vCornerCoords); + +} + +template +template +void ConvectionDiffusionFV1_cutElem:: +add_def_A_elem_local_cut(TFVGeom& geo, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) +{ + bool boundary = false; + bool add = true; + +// get data ReferenceObjectID roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - - LocalVector jump_tri = geo.set_jump_values(ind, 3); - LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); - LocalVector source_tri = geo.set_source(imSource, ind, 3, true); - - if ( output ) UG_LOG(" tri 1: orientaten: " << orientation << "\n"); - - this->template add_def_A_elem_local (geo, u, locD_tri, locU_tri, elem, vCornerCoords); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_tri, 3); - this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords); - } - - if ( output ) - { - for ( size_t i = 0; i < 3; ++i) - UG_LOG("corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); - UG_LOG("\n" ); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output_integral ) UG_LOG("------------------> tri1: integral = " << sqrt(geo.get_integral()) << "\n"); - - geo.set_defect_tri(locD_tri); - geo.set_DoF_tag_tri(false); - - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - - LocalVector jump_quad = geo.set_jump_values(ind, 4); - LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); - LocalVector source_quad = geo.set_source(imSource, ind, 4, true); - - if ( output ) UG_LOG(" quad 1: orientaten: " << orientation << "\n"); - this->template add_def_A_elem_local (geo, u, locD_quad, locU_quad, elem, vCornerCoords); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_quad, 4); - this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output_integral ) UG_LOG("------------------> quad1: integral = " << sqrt(geo.get_integral()) << "\n"); - - - geo.set_defect_quad(locD_quad); - geo.set_DoF_tag_quad(false); - - } + bool shiftTag = geo.get_bScaleDoFs(); // bScaleDoFs = true: in case of double DoFs on interface! + int indexSize = 3; + if ( roidCheck == ROID_QUADRILATERAL ) indexSize = 4; +// get the pointer for access and storage into 'InterfaceHandlerLocalDiffusion' class + LocalVector& locD = geo.get_defect(roidCheck); + LocalVector& locU = geo.get_solution(roidCheck); - // Second call with orientation = -1: - bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! + locD = 0; - orientation *= -1; - if ( output ) UG_LOG(" ____2: orientaten: " << orientation << "\n"); +// finally: compute the local defect on the cut element + this->template add_def_A_elem_local (geo, u, locD, locU, elem, vCornerCoords); - geo.set_orientation(orientation); - try{ - geo.update(elem, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1_cutElem::update:" - " Cannot update Finite Volume Geometry."); - - if ( debug ) geo.print_InterfaceIDdata(); - - roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) +// compute the boundary condition on the interface of the cut element + if ( boundary ) { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); - LocalVector source_tri = geo.set_source(imSource, ind, 3, true); - - if ( output ) UG_LOG(" tri 2: orientaten: " << orientation << "\n"); - - this->template add_def_A_elem_local (geo, u, locD_tri, locU_tri, elem, vCornerCoords); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_tri, 3); - this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output ) UG_LOG("------------------> tri2: integral = " << sqrt(geo.get_integral()) << "\n"); - - - geo.set_defect_tri(locD_tri); - geo.set_DoF_tag_tri(shiftTag); - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); - LocalVector source_quad = geo.set_source(imSource, ind, 4, true); - - if ( output ) UG_LOG(" quad 2: orientaten: " << orientation << "\n"); - - this->template add_def_A_elem_local (geo, u, locD_quad, locU_quad, elem, vCornerCoords); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_quad, 4); - this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output_integral ) UG_LOG("------------------> quad2: integral = " << sqrt(geo.get_integral()) << "\n"); - - geo.set_defect_quad(locD_quad); - geo.set_DoF_tag_quad(shiftTag); - + geo.reset_defect_on_interface(locD, indexSize); + this->template add_def_A_elem_boundary (geo, locD, locU, elem, vCornerCoords); } + +// write computed local defect to data storage in class 'InterfaceHandlerLocalDiffusion' + geo.set_defect(locD, roidCheck); + +// shiftTag necessary for local to global mapping + geo.set_DoF_tag(shiftTag, roidCheck); + +// compute the l2Error on the cut element + number intValElem = this->template add_l2error_A_elem (geo, roidCheck, locD, locU, elem); + if ( add ) geo.L2Error_add(intValElem); + } - template template void ConvectionDiffusionFV1_cutElem:: add_def_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalVector& d, LocalVector& locU, GridObject* elem, const MathVector vCornerCoords[]) { +//////////////////////////////////////////////////////////////////////// +// Pre-processing for assembling on cut Element: MathMatrix diffusion; MatSet(diffusion, 0); MatDiagSet(diffusion, 1.0); LocalVector jump, jump_grad, source; + +// get the local data (jump, jump_grad, source) on the cut element + get_local_data(geo, u, u.get_indices(), locU, diffusion, jump, jump_grad, source); - get_local_data(geo, u, locU, diffusion, jump, jump_grad, source); - +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// NOW: Standard ConvectionDiffusionFV1-assembling starts here: -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - if(m_imDiffusion.data_given() || m_imVelocity.data_given() || m_imFlux.data_given()) { // loop Sub Control Volume Faces (SCVF) @@ -904,113 +760,72 @@ add_def_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalVector& d, LocalVe // Additional diffusive Term due to jump in solution at the interface // u^+ - u^- = jump ///////////////////////////////////////////////////////////////////////////// - if ( 1 ) - { - // scale diffusion by jump in solution: - // const double jump = 2.0; - // diffusion *= jump; - - // to compute D \nabla c=Id_interface - MathVector Dgrad, grad; - // compute gradient and shape at ip - VecSet(grad, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(grad, jump(_C_,sh), scvf.global_grad(sh)); + // to compute D \nabla c=Id_interface + MathVector Dgrad, grad; - // scale by diffusion tensor - MatVecMult(Dgrad, diffusion, grad); + // compute gradient and shape at ip + VecSet(grad, 0.0); + for(size_t sh = 0; sh < scvf.num_sh(); ++sh) + VecScaleAppend(grad, jump(_C_,sh), scvf.global_grad(sh)); - // Compute flux - const number diff_flux = VecDot(Dgrad, scvf.normal()); + // scale by diffusion tensor + MatVecMult(Dgrad, diffusion, grad); - // Add to local defect - d(_C_, scvf.from()) -= diff_flux; - d(_C_, scvf.to() ) += diff_flux; + // Compute flux + const number diff_flux = VecDot(Dgrad, scvf.normal()); - } + // Add to local defect + d(_C_, scvf.from()) -= diff_flux; + d(_C_, scvf.to() ) += diff_flux; + } } ///////////////////////////////////////////////////// // add rhs during same method! - // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! + // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' + // adds the local vector otherwise! NOT functional!! ///////////////////////////////////////////////////// - if ( 1 ) - { //m_imSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv( ip ); - - // get associated node - int co = scv.node_id(); - d(_C_, co) -= source(_C_, co) * scv.volume(); +// loop integration points + for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) + { + // get current SCV + const typename TFVGeom::SCV& scv = geo.scv( ip ); - // Add to local rhs - /* if ( co > 2 ) - { - d(_C_, co) -= m_imSource[2] * scv.volume(); - UG_LOG("m_imSource[2] * scv.volume(): " << m_imSource[2] << "\n"); - UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); - } - else - { - d(_C_, co) -= m_imSource[co] * scv.volume(); - UG_LOG("m_imSource[co] * scv.volume(): " << m_imSource[co] << "\n"); - UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); - } - - */ - } + // get associated node + int co = scv.node_id(); + + // Add to local rhs + d(_C_, co) -= source(_C_, co) * scv.volume(); } + ///////////////////////////////////////////////////////////////////////////// // Additional source Term due to jump in gradient at the interface // (\nabla u^+ - \nabla u^-)\cdot n = h(x) * |n| ///////////////////////////////////////////////////////////////////////////// - if ( 1 ) + + std::vector& vBF = geo.get_boundary_faces(); + +// some checks: + if ( vBF.size() > 2 ) + UG_THROW("add_def_A_elem_local(): vBF.size() is greater than 2: " << vBF.size() << "\n"); + if ( vBF.size() == 0 && geo.get_element_modus() ) + UG_THROW("add_def_A_elem_local(): Error! If vBF.size() == 0, then the element is cut!\n"); + +// loop integration points + for(size_t ip = 0; ip < vBF.size(); ++ip) { - std::vector& vBF = geo.get_boundary_faces(); - MathVector Dgrad; - VecSet(Dgrad, 0.0); + typename TFVGeom::BF bf = vBF[ip]; - if ( vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - // loop integration points - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - typename TFVGeom::BF bf = vBF[ip]; - // Add to local rhs - d(_C_, bf.node_id()) += jump_grad(_C_,bf.node_id()) * bf.Vol; - } + // Add to local rhs + d(_C_, bf.node_id()) += jump_grad(_C_,bf.node_id()) * bf.Vol; } -//////////////////////////////// -// Singular sources and sinks -//////////////////////////////// - - if (m_sss.valid()) { - const typename TDomain::position_accessor_type& aaPos = this->domain()->position_accessor(); - const typename TDomain::grid_type& grid = *this->domain()->grid(); - const number time = this->time(); - MathVector<1> out; - for(size_t i = 0; i < geo.num_scv(); i++) { - const typename TFVGeom::SCV& scv = geo.scv(i); - const int co = scv.node_id(); - const number len = m_sss->get_contrib_of_scv((TElem*)elem, (Grid&)grid, aaPos, geo, co, time, out); - if (len == 0.0) continue; - out[0] *= len; - if (out[0] > 0.0) - // source - d(_C_, co) -= out[0]; - else - // sink - d(_C_, co) -= out[0] * locU(_C_, co); - } - } + } template @@ -1018,77 +833,60 @@ template void ConvectionDiffusionFV1_cutElem:: add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) { +// get parameter double diffusion = 0.0; - if ( !geo.get_element_modus() ) diffusion = geo.get_diffusion(geo.get_boolian_for_diffusion()); else diffusion = geo.get_diffusion(); +// get inner boundary faces for assembling (stored in 'InterfaceHandlerLocalDiffusion' class) std::vector& vBF = geo.get_boundary_faces(); - MathVector Dgrad; - VecSet(Dgrad, 0.0); - - UG_LOG("---------- vBF.size(): " << vBF.size() << "\n"); - if ( vBF.size() > 2 ) UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - // set solution - /* for(size_t sh = 0; sh < geo.num_sh(); ++sh) - { - u(_C_, sh) = 1.0; - u(_C_, sh) -= corners[sh][0]*(2*corners[sh][0] - 1.0); - u(_C_, sh) -= corners[sh][1]*(2*corners[sh][1] - 1.0); - } - */ - // u(_C_, sh) = 1 - 2*(corners[sh][0]*corners[sh][0] + corners[sh][1]*corners[sh][1]) - (corners[sh][0]+corners[sh][1]); - // u(_C_, sh) = corners[sh][1]*(2*corners[sh][1] - 1.0); - // u(_C_, sh) = (1.0 - corners[sh][0] - corners[sh][1]) * (1.0 - 2*corners[sh][0] - 2*corners[sh][1]); - // u(_C_, sh) = corners[sh][1]; - // for(size_t sh = 0; sh < geo.num_sh(); ++sh) - // u(_C_, sh) = corners[sh][0]*(2*corners[sh][0] - 1.0); //corners[sh][0]; - // u(_C_, sh) = corners[sh][0]*(2* corners[sh][0]-1); - - //////////////////////////////////////////////////////////////////////////////// - // NO loop integration points! - // /* for(size_t ip = 0; ip < vBF.size(); ++ip) */ - // Reason: the length of the normal is already the length of the total face (NOT the scvf!) - //////////////////////////////////////////////////////////////////////////////// + if ( vBF.size() == 0 && geo.get_element_modus() ) + UG_THROW("add_def_A_elem_boundary(): Error! If vBF.size() == 0, then the element is cut!\n"); + + MathVector Dgrad; + VecSet(Dgrad, 0.0); + + +//////////////////////////////////////////////////////////////////////////////// +// REMARK: NO loop integration points! +// /* for(size_t ip = 0; ip < vBF.size(); ++ip) */ +// Reason: the length of the normal is already the length of the total face (NOT the scvf!) +//////////////////////////////////////////////////////////////////////////////// - // loop integration points +// loop integration points for(size_t ip = 0; ip < vBF.size(); ++ip) { typename TFVGeom::BF bf = vBF[ip]; VecSet(Dgrad, 0.0); - // loop trial space + // loop trial space for(size_t sh = 0; sh < bf.num_sh(); ++sh) { - // Diffusion - UG_LOG("bf.num_sh(): " << bf.num_sh() << "\n"); - UG_LOG("Dgrad: " << Dgrad << "\n"); - UG_LOG("bf.normal(): " << bf.normal() << "\n"); - UG_LOG("bf.global_grad(ip, sh): " << bf.global_grad(sh) << "\n"); - - UG_LOG("u(_C_, sh): " << u(_C_, sh) << "\n"); - + // Diffusion VecScaleAppend(Dgrad, diffusion * u(_C_, sh), bf.global_grad(sh)); } - // add to local vector + // add to local vector d(_C_, bf.node_id()) += VecDot(Dgrad, bf.normal()); } - - UG_LOG("---------- end ----------- \n\n"); - + } //////////////////////////////////////////////////////////////////////////////// /// /// methods for cut element error computation via 'add_l2error_A_elem()' +/// --> hard coded c++ functions for some numerical test examples +/// (not optimal handling of user data) +/// --> the choice of different test examples can be handled via lua: +/// --> lua-call: 'elemDisc:set_testCase(int testCase)' +/// testCase-enumerator, see top of that file! /// //////////////////////////////////////////////////////////////////////////////// @@ -1098,31 +896,47 @@ number get_exact_sol_test(MathVector position) return sin(2*M_PI*position[0]) + sin(2*M_PI*position[1]); } + + template -number get_exact_sol_Gangl(MathVector position) +number get_exact_sol_Gangl(MathVector position, size_t testCase) { + MathVector<2> center(0.0); + if (testCase == GANGL_OFF_CENTER ) + { + center[0] = -0.08; + center[1] = 0.3; + } + double kappa_2 = 10.0; - double dist_x = position[0] - 0.0; - double dist_y = position[1] - 0.0; + double dist_x = position[0] - center[0]; + double dist_y = position[1] - center[1]; double sqR = 0.4*0.4; - + double sqDist = dist_x*dist_x + dist_y*dist_y; double dist = sqrt(sqDist); - + double returnValue = -4*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_2 - 1); if ( dist >= 0.4 ) returnValue = -2*kappa_2*sqDist*sqDist; - + return returnValue; } - + template -MathVector get_exact_grad_Gangl(MathVector position) +MathVector get_exact_grad_Gangl(MathVector position, size_t testCase) { + MathVector<2> center(0.0); + if (testCase == GANGL_OFF_CENTER ) + { + center[0] = -0.08; + center[1] = 0.3; + } + double kappa_2 = 10.0; - double dist_x = position[0] - 0.0; - double dist_y = position[1] - 0.0; + double dist_x = position[0] - center[0]; + double dist_y = position[1] - center[1]; double sqR = 0.4*0.4; double sqDist = dist_x*dist_x + dist_y*dist_y; @@ -1169,27 +983,6 @@ MathVector get_exact_grad_FedkiwEx5(MathVector position) return returnVector; } - -template -number get_exact_sol_FedkiwEx6(MathVector position) -{ - double center_x = 0.0; - double center_y = 0.0; - double radius = 0.5; - - double dist_x = position[0] - center_x; - double dist_y = position[1] - center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double returnValue = 0.0; - - if ( dist <= radius ) - returnValue = exp(position[0])*cos(position[1]); - - return returnValue; -} template number get_exact_sol_FedkiwEx5(MathVector position) @@ -1234,11 +1027,6 @@ number get_exact_sol_FedkiwEx3(MathVector position) return returnValue; } -template -MathVector get_exact_grad(MathVector position) -{ - -} ////////////////////////////////////////////////////////////////////// // code see ugbase/lib_disc/function_spaces/integrate.h: evaluate() for @@ -1257,10 +1045,9 @@ template number ConvectionDiffusionFV1_cutElem:: add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem) { - bool output = false; - - // number integral = 0; - + // get the flag for the choice of numerical example to be used as analytical solution + size_t testCase = get_testCase(); + std::vector > vCorner; std::vector > vGlobIP; std::vector > vLocIP; @@ -1290,13 +1077,7 @@ add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const L // remember global position of nodes for(size_t i = 0; i < rRefElem.num(0); ++i) vCorner.push_back(geo.get_corner(i)); - - if ( output ) - { - for ( size_t i = 0; i < rRefElem.num(0); ++i) - UG_LOG("vCorner" << vCorner[i][0] << " and " << vCorner[i][1] << "\n" ); - UG_LOG("\n" ); - } + // update the reference mapping for the corners mapping.update(vCorner); @@ -1305,17 +1086,11 @@ add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const L vGlobIP.resize(numIP); mapping.local_to_global(&(vGlobIP[0]), rQuadRule.points(), numIP); - if ( output ) UG_LOG("vGlobIP" << vGlobIP[0][0] << " and " << vGlobIP[0][1] << "\n" ); - if ( output ) UG_LOG("\n" ); - // compute local integration points vLocIP.resize(numIP); for(size_t ip = 0; ip < numIP; ++ip) vLocIP[ip] = rQuadRule.points()[ip]; - if ( output ) UG_LOG("vLocIP" << vLocIP[0][0] << " and " << vLocIP[0][1] << "\n" ); - if ( output ) UG_LOG("\n" ); - // compute transformation matrices vJT.resize(numIP); @@ -1330,19 +1105,28 @@ add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const L vValue.resize(numIP); vValueGrad.resize(numIP); + number exactSolIP; + MathVector exactGradIP; try { - // loop all integration points + // loop all integration points for(size_t ip = 0; ip < numIP; ++ip) { - // compute exact solution at integration point -// number exactSolIP = get_exact_sol_FedkiwEx5(vGlobIP[ip]); - number exactSolIP = get_exact_sol_Gangl(vGlobIP[ip]); + // compute exact solution at integration point + if ( testCase == GANGL_CENTER || testCase == GANGL_OFF_CENTER ) + exactSolIP = get_exact_sol_Gangl(vGlobIP[ip], testCase); + else if ( testCase == FEDKIW_EX5 ) + exactSolIP = get_exact_sol_FedkiwEx5(vGlobIP[ip]); + - // compute exact gradient at integration point - MathVector exactGradIP = get_exact_grad_FedkiwEx5(vGlobIP[ip]); + // compute exact gradient at integration point + if ( testCase == GANGL_CENTER || testCase == GANGL_OFF_CENTER ) + exactGradIP = get_exact_grad_Gangl(vGlobIP[ip], testCase); + else if ( testCase == FEDKIW_EX5 ) + exactGradIP = get_exact_grad_FedkiwEx5(vGlobIP[ip]); + - // compute approximated solution at integration point + // compute approximated solution at integration point number approxSolIP = 0.0; MathVector locTmp; VecSet(locTmp, 0.0); @@ -1350,24 +1134,24 @@ add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const L for(size_t sh = 0; sh < num_sh; ++sh) { - // add shape fct at ip * value at shape + // add shape fct at ip * value at shape approxSolIP += u(_C_,sh) * geo.get_shape(sh, vLocIP[ip], roid); - // add gradient at ip + // add gradient at ip VecScaleAppend(locTmp, u(_C_,sh), scv.local_grad(sh)); } - // get squared of difference + // get squared of difference vValue[ip] = (exactSolIP - approxSolIP); vValue[ip] *= vValue[ip]; - // compute global gradient + // compute global gradient MathVector approxGradIP; MathMatrix JTInv; Inverse(JTInv, vJT[ip]); MatVecMult(approxGradIP, JTInv, locTmp); - // get error of gradient + // get error of gradient vValueGrad[ip] = VecDistanceSq(approxGradIP, exactGradIP); @@ -1400,8 +1184,6 @@ add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const L // add to global sum - if ( output ) UG_LOG("added: " << intValElem << "\n\n"); - return intValElem; } @@ -1530,7 +1312,6 @@ add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoor // Add to local rhs d(_C_, co) += m_imSource[ip] * scv.volume(); - //UG_LOG("d(_C_, co) = " << d(_C_, co) << "; \t ip " << ip << "; \t co " << co << "; \t scv_vol " << scv.volume() << "; \t m_imSource[ip] " << m_imSource[ip] << std::endl); } } @@ -1677,7 +1458,6 @@ register_func() { ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; typedef this_type T; - static const int refDim = reference_element_traits::dim; this->clear_add_fct(id); this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); @@ -1709,3 +1489,4 @@ template class ConvectionDiffusionFV1_cutElem; } // end namespace ConvectionDiffusionPlugin } // namespace ug +#endif /* __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1_CUTELEM_IMPL */ \ No newline at end of file diff --git a/fv1_cutElem/convection_diffusion_fv1_cutElem.h b/fv1_cutElem/convection_diffusion_fv1_cutElem.h index 3715e46..0e77061 100644 --- a/fv1_cutElem/convection_diffusion_fv1_cutElem.h +++ b/fv1_cutElem/convection_diffusion_fv1_cutElem.h @@ -36,11 +36,11 @@ // ug4 headers #include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" -#include "lib_disc/spatial_disc/elem_disc/sss.h" // plugin's internal headers #include "../convection_diffusion_base.h" + #include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" #include "lib_disc/spatial_disc/disc_util/geom_provider.h" @@ -104,10 +104,7 @@ class ConvectionDiffusionFV1_cutElem : public ConvectionDiffusionBase * \param shapes upwind method */ void set_upwind(SmartPtr > shapes); - - /// set singular sources and sinks - void set_sss(SmartPtr > sss) { m_sss = sss; } - + private: /// prepares assembling virtual void prep_assemble_loop(); @@ -134,13 +131,25 @@ class ConvectionDiffusionFV1_cutElem : public ConvectionDiffusionBase template void fsh_elem_loop(); - /// assembles the local stiffness matrix using a finite volume scheme + /// wrapper method for assembly of the local stiffness matrix using a finite volume scheme template void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// adapts local data for cut element assemling and calls 'add_jac_A_elem_local_local()' and 'add_jac_A_elem_local_boundary()' + /// for the assembly of the local stiffness matrix template - void add_jac_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalMatrix& J, LocalVector& locU, GridObject* elem, const MathVector vCornerCoords[]); + void add_jac_A_elem_local_cut(TFVGeom& geo, const LocalVector& u, GridObject* elem, + const MathVector vCornerCoords[]); + + /// assembles the local stiffness matrix for locally adapted data due to a cut element + template + void add_jac_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalMatrix& J, LocalVector& locU, GridObject* elem, + const MathVector vCornerCoords[]); + + /// assembles the boundary condition on a cut element template - void add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + void add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, + const MathVector vCornerCoords[]); /// assembles the local mass matrix using a finite volume scheme @@ -148,14 +157,25 @@ class ConvectionDiffusionFV1_cutElem : public ConvectionDiffusionBase void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - /// assembles the stiffness part of the local defect + /// wrapper method for assembly of the local defect using a finite volume scheme template void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - /// assembles the stiffness part of the local defect + + /// adapts local data for cut element assembling, calls 'add_def_A_elem_local_local()', 'add_def_A_elem_local_boundary()' + /// and 'add_l2error_A_elem()' for the assembly of the local defect + template + void add_def_A_elem_local_cut(TFVGeom& geo, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// assembles the local stiffness matrix for locally adapted data due to a cut element template - void add_def_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalVector& d, LocalVector& locU, GridObject* elem, const MathVector vCornerCoords[]); + void add_def_A_elem_local(TFVGeom& geo, const LocalVector& u, LocalVector& d, LocalVector& locU, GridObject* elem, + const MathVector vCornerCoords[]); + /// assembles the boundary condition on a cut element template void add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); + + /// computes the l2 error on each element => also on the 2 parts of a cut element + /// --> used for an interface-adapted l2 error computation template number add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem); @@ -174,17 +194,19 @@ class ConvectionDiffusionFV1_cutElem : public ConvectionDiffusionBase template void add_rhs_elem_local(TFVGeom& geo, LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); - /// helper function to prepare data for 'add_def_A_elem_local()' and 'add_jac_A_elem_local()' + /// helper function to prepare local data due to a cut element for 'add_def_A_elem_local()' and 'add_jac_A_elem_local()' template - void get_local_data(TFVGeom& geo, const LocalVector& u, LocalVector& locUOut, MathMatrix diffusionOut, LocalVector& jumpOut, LocalVector& jump_gradOut, LocalVector& sourceOut); + void get_local_data(TFVGeom& geo, const LocalVector& u, const LocalIndices& ind, LocalVector& locUOut, MathMatrix& diffusionOut, LocalVector& jumpOut, LocalVector& jump_gradOut, LocalVector& sourceOut); + + public: + /// flag to set the analytical solution for the l2error computation within 'add_l2error_A_elem()' + size_t get_testCase() { return m_testCase; } + void set_testCase(size_t testCase) { m_testCase = testCase; } private: /// abbreviation for the local solution static const size_t _C_ = 0; - /// singular sources and sinks - SmartPtr > m_sss; - using base_type::m_imDiffusion; using base_type::m_imVelocity; using base_type::m_imFlux; @@ -223,6 +245,9 @@ class ConvectionDiffusionFV1_cutElem : public ConvectionDiffusionBase /// current shape function set (needed for GeomProvider::get()) LFEID m_LFEID; + /// flag to set the analytical solution for the l2error computation within 'add_l2error_A_elem()' + size_t m_testCase; + /// register utils /// \{ void register_all_funcs(bool bHang); diff --git a/fv1_cutElem/diffusion_interface/___immersed_bnd_cond_diffusion_impl.h b/fv1_cutElem/diffusion_interface/___immersed_bnd_cond_diffusion_impl.h deleted file mode 100644 index 75b1a15..0000000 --- a/fv1_cutElem/diffusion_interface/___immersed_bnd_cond_diffusion_impl.h +++ /dev/null @@ -1,952 +0,0 @@ -/* - * particle_bnd_cond_impl.h - * - * Created on: 30.01.2015 - * Author: suze - */ - -#ifndef DIFFUSION_BND_COND_IMPL_H_ -#define DIFFUSION_BND_COND_IMPL_H_ - - - -namespace ug{ -namespace MovingInterfaceDiffusion{ - -//////////////////////////////////////////////////////////////////////////////// -// Constructor - set default values -//////////////////////////////////////////////////////////////////////////////// -// see 'no_normal_stress_outflow.cpp': -template -ParticleBndCondDiffusion:: -ParticleBndCondDiffusion(SmartPtr > spMaster, - SmartPtr > localHandler) - : MovingInterface::IInterfaceBndCond(spMaster->symb_fcts(), spMaster->symb_subsets(), localHandler), - m_spMaster(spMaster), - m_spInterfaceHandlerLocal(localHandler) -{ -// update assemble functions - register_all(false); -} - -template -void ParticleBndCondDiffusion:: -prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid) -{ -// write delta t to data - number dt = 0.13; - if(this->is_time_dependent()) - { - UG_LOG("ParticleBndCondDiffusion::prepare_setting(): vorher: m_dt = " << get_time_step() << "\n"); - - set_time_dependent(true); - - // get and check current and old solution - const LocalVectorTimeSeries* vLocSol = this->local_time_solutions(); - dt = vLocSol->time(0) - vLocSol->time(1); - - set_time_step(dt); - } - -} - -// see 'NavierStokesNoNormalStressOutflowFV1::prep_elem()' -template -template -void ParticleBndCondDiffusion:: -prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) -{ - -// Update Geometry for this element - static TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); - - geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); - -} - - -//////////////////////////////////////////////////////////////////////////////// -// jacobian methods -//////////////////////////////////////////////////////////////////////////////// -// removes the equations with IDs in 'vFctID' locally assembled in the corners of 'vDofID' -template -void ParticleBndCondDiffusion:: -remove_equations(LocalMatrix& J, std::vector vFctID, std::vector vDofID) -{ - - UG_THROW("in ParticleBndCondDiffusion::remove_equations(): vFctID.size() = " << vFctID.size() << "\n"); - - for(size_t i = 0; i < vDofID.size(); ++i) - for(size_t j = 0; j < vFctID.size(); ++j) - for(size_t fct = 0; fct < J.num_all_row_fct(); ++fct) - for(size_t dof = 0; dof < J.num_all_row_dof(fct); ++dof) - J(vFctID[j], vDofID[i], fct, dof) = 0.0; - -} - - - - -// see 'NavierStokesNoNormalStressOutflowFV1::diffusive_flux_Jac()' -template -void ParticleBndCondDiffusion:: -diffusive_flux_Jac(const size_t ip, const interfaceBF& bf, LocalMatrix& J, const LocalVector& u) -{ - - MathMatrix diffFlux, tang_diffFlux; - MathVector normalStress; - - for(size_t sh = 0; sh < bf.num_sh(); ++sh) // loop shape functions - { - // 1. Compute the total flux - // - add \nabla u - MatSet (diffFlux, 0); - MatDiagSet (diffFlux, VecDot (bf.global_grad(sh), bf.normal())); - - - // - add (\nabla u)^T - if( !m_spMaster->laplace()) - for (size_t d1 = 0; d1 < (size_t)dim; ++d1) - for (size_t d2 = 0; d2 < (size_t)dim; ++d2) - diffFlux(d1,d2) += bf.global_grad(sh)[d1] * bf.normal()[d2]; - - // 2. Scale by viscosity - diffFlux *= get_kinVisc_fluid(); - - // 3. Change sign, since force acts onto particle in inverse direction: - //diffFlux *= -1.0; - - // 4. Add flux to local Jacobian - for(size_t d1 = 0; d1 < (size_t)dim; ++d1) - for(size_t d2 = 0; d2 < (size_t)dim; ++d2){ - J(d1, bf.node_id(), d2, sh) += diffFlux (d1, d2); - // if ( sh < 2 ) UG_LOG("bf.node_id(): " << bf.node_id() << "sh: " << sh << ": diff_flux added: " << diffFlux (d1, d2) << "\n"); - } - - // 5. Add pressure term to local Jacobian - for(size_t d1 = 0; d1 < (size_t)dim; ++d1) - J(d1, bf.node_id(), _P_, sh) -= bf.shape(sh) * bf.normal()[d1]; - - } - -} - - - -void copy_and_reset(LocalMatrix& cpJ, LocalMatrix& J) -{ - - UG_THROW("oha!!...in ParticleBndCondDiffusion: copy_and_reset()\n"); - - for(size_t fct1 = 0; fct1 < J.num_all_row_fct(); ++fct1) - for(size_t dof1 = 0; dof1 < J.num_all_row_dof(fct1); ++dof1) - for(size_t fct2 = 0; fct2 < J.num_all_row_fct(); ++fct2) - for(size_t dof2 = 0; dof2 < J.num_all_row_dof(fct2); ++dof2) - { - cpJ(fct1, dof1, fct2, dof2) = J(fct1, dof1, fct2, dof2); - J(fct1, dof1, fct2, dof2) = 0.0; - } -} - - -template -template -void ParticleBndCondDiffusion:: -add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - ElementModus elemModus = m_spInterfaceHandlerLocal->get_element_modus(elem); // computed via 'compute_element_modus()' during 'update_marker()' - - const LocalIndices& rowInd = J.get_row_indices(); - - //////////////////////////////////////////////////////////////////////////////// - // Remove local impuls equations for interface-corners - if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling - { - - if ( elemModus != INSIDE_DOM ) - { - // all impulse equations will be removed - std::vector vFctID(dim); - for(size_t i = 0; i < dim; ++i) vFctID[i] = i; - - // equations for interface nodes will be removed - std::vector vDoFID; vDoFID.clear(); - for(size_t i = 0; i < m_spInterfaceHandlerLocal->m_vInterfaceID.size(); ++i) - { - size_t interfaceID = m_spInterfaceHandlerLocal->m_vInterfaceID[i]; - size_t indexToRemove = interfaceID; //m_spInterfaceHandlerLocal->m_vOriginalCornerID[interfaceID]; - vDoFID.push_back(indexToRemove); - } - - remove_equations(J, vFctID, vDoFID); - } - - } - - -//////////////////////////////////////////////////////////////////////////////// -// see 'ParticleFlatTop::add_jac_A_elem_interface()' -//////////////////////////////////////////////////////////////////////////////// - -// Loop the boundary faces for new impuls equations -// --> IFF INSIDE_DOM: vBF.size() = 0 ;-) - SmartPtr > fluidDensity = m_spMaster->density(); - std::vector& vBF = m_spInterfaceHandlerLocal->get_boundary_faces(); - -// initialize data (written during call of 'diffusive_flux_Jac()': - LocalIndices ind = u.get_indices(); - rotJ_ind.resize(ind); rotJ_ind = 0.0; - rotJ_rot.resize(ind); rotJ_rot = 0.0; - - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - - interfaceBF bf = vBF[ip]; - - if ( fluidDensity->value(0, ip) != fluidDensity->value(1, ip) ) - UG_THROW("ParticleBndCondDiffusion::add_jac_M_elem(): density different for series 0 and 1: " - << fluidDensity->value(0, ip) << " != " << fluidDensity->value(1, ip) << "\n"); - - number importDensity = fluidDensity->value(0, ip); - - // The momentum equation: - if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling - diffusive_flux_Jac(ip, bf, J, u); - - // scale with deltaT ( = 1.0 for non-time-dependent) - // buffJ *= deltaT; - // ToDo --> NOT necessary, since add_def_A_elem() will be multiplied by 'dt' - // during elem_dis_assemble_util.h ??? - - // The continuity equation - if ( 1 ) //! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling - { - for(size_t sh = 0; sh < bf.num_sh(); ++sh) // loop shape functions - for (size_t d2 = 0; d2 < (size_t)dim; ++d2) - J(_P_, bf.node_id(), d2, sh) += bf.shape(sh) * bf.normal()[d2] - * importDensity; - } - - } // end vBF - - // copy rotJ_ind/rotJ_rot to m_spInterfaceHandlerLocal data for access from mapper - if ( vBF.size() > 0 ) - copy_local_couplings_jac(); - - -} - - -//////////////////////////////////////////////////////////////////////////////// -// defect methods -//////////////////////////////////////////////////////////////////////////////// - -// removes the defects with IDs in 'vFctID' locally assembled in the corners of 'vDofID' -template -void ParticleBndCondDiffusion:: -remove_equations(LocalVector& d, std::vector vFctID, std::vector vDofID) -{ - for(size_t i = 0; i < vDofID.size(); ++i) - for(size_t j = 0; j < vFctID.size(); ++j) - d(vFctID[j], vDofID[i]) = 0.0; - -} - - - -// see 'NavierStokesNoNormalStressOutflowFV1::diffusive_flux_defect()' -template -void ParticleBndCondDiffusion:: -diffusive_flux_defect(const size_t ip, const interfaceBF& bf, LocalVector& d, const LocalVector& u) -{ - MathMatrix gradVel; - MathVector diffFlux; - -// 1. Get the gradient of the velocity at ip - for(size_t d1 = 0; d1 < (size_t)dim; ++d1) - for(size_t d2 = 0; d2 < (size_t)dim; ++d2) - { - // sum up contributions of each shape - gradVel(d1, d2) = 0.0; - for(size_t sh = 0; sh < bf.num_sh(); ++sh) - gradVel(d1, d2) += bf.global_grad(sh)[d2] * u(d1, sh); - } - -// 2. Compute the total flux - -// - add (\nabla u) \cdot \vec{n} - MatVecMult(diffFlux, gradVel, bf.normal()); - -// - add (\nabla u)^T \cdot \vec{n} - if( !m_spMaster->laplace()) - TransposedMatVecMultAdd(diffFlux, gradVel, bf.normal()); - -// 3. Scale by viscosity - diffFlux *= get_kinVisc_fluid(); - -// 4. Change sign, since force acts onto particle in inverse direction: - //diffFlux *= -1.0; - -// 5. Add flux to local defect - for(size_t d1 = 0; d1 < (size_t)dim; ++d1) - d(d1, bf.node_id()) += diffFlux[d1]; - - -// 6. Add pressure term to local defect - number pressure = 0.0; - for(size_t sh = 0; sh < bf.num_sh(); ++sh) - pressure += bf.shape(sh) * u(_P_, sh); - - for(size_t d1 = 0; d1 < (size_t)dim; ++d1) - d(d1, bf.node_id()) -= pressure * bf.normal()[d1]; - -} - -template -void ParticleBndCondDiffusion:: -add_def_A_elem_Quadri_for2(LocalVector& locD, const LocalVector locU) -{ -// Loop the boundary faces to assemble impulse equations - SmartPtr > fluidDensity = m_spMaster->density(); - std::vector& vBF = m_spInterfaceHandlerLocal->get_boundary_faces(); - - if ( vBF.size() != 4 ) - UG_THROW("in 'ParticleBndCondDiffusion::add_def_A_elem_Quadri_for2(): vBF.size() should be 4 but is " << vBF.size() << "\n"); - - UG_LOG("vBF.size(): " << vBF.size() << "\n"); - -// get density - number importDensity = fluidDensity->value(0, 0); - if ( fluidDensity->value(0, 0) != fluidDensity->value(1, 0) ) - UG_THROW("ParticleBndCondDiffusion::add_def_A_elem_Quadri_for2(): density different for series 0 and 1: " - << fluidDensity->value(0, 0) << " != " << fluidDensity->value(1, 0) << "\n"); - if ( importDensity != get_density_fluid() ) - UG_THROW("ParticleBndCondDiffusion::add_def_A_elem_Quadri_for2(): importDensity = " << importDensity << " = " - "fluidDensity = " << get_density_fluid() << "\n"); - -// loop all boundary faces - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - UG_LOG("---- ip = " << ip << "\n"); - - interfaceBF bf = vBF[ip]; - - // Compute Velocity at ip - MathVector stdVel(0.0); - for(size_t d1 = 0; d1 < (size_t)dim; ++d1) - for(size_t sh = 0; sh < bf.num_sh(); ++sh) - stdVel[d1] += locU(d1, sh) * bf.shape(sh); - - // Momentum equation: - if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling - diffusive_flux_defect(ip, bf, locD, locU); - - // Continuity equation: - if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling - locD(_P_, bf.node_id()) += VecDot(stdVel, bf.normal()) * importDensity; - - } // end vBF-loop - -} - -template -void ParticleBndCondDiffusion:: -write_QuadriSol(const LocalVector origU) -{ - UG_LOG("start write_QuadriSol\n"); - -// initialize data - LocalIndices ind = origU.get_indices(); - LocalVector quadriU; - - UG_LOG("1 start write_QuadriSol\n"); - - if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 2 ) - { - for(size_t fct = 0; fct < ind.num_fct(); ++fct) - ind.resize_dof(fct, 5); - - if ( ind.num_dof(0) != 5 ) - UG_THROW("hmm: ind.num_dof(0) = " << ind.num_dof(0) << "\n"); - } - quadriU.resize(ind); - - UG_LOG("2 start write_QuadriSol\n"); - - // A. remap solution (velocity AND pressure!) of inside node - if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 2 ) - { - size_t copyID = m_spInterfaceHandlerLocal->m_vNOInterfaceID[0]; - for(size_t fct = 0; fct < dim+1; ++fct) - {quadriU(fct,4) = origU(fct,copyID); - UG_LOG("origU(fct,copyID) = " << origU(fct,copyID) << "\n");} - } - - UG_LOG("3 start write_QuadriSol: quadriU \n" << quadriU << "\n"); - - if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 2 ) - { - for ( size_t i = 0; i < m_spInterfaceHandlerLocal->m_vNOInterfaceID.size(); ++i ) - UG_THROW("m_vNOInterfaceID[" << i << "]: " << m_spInterfaceHandlerLocal->m_vNOInterfaceID[i] << "\n"); - - } - for ( size_t i = 0; i < m_spInterfaceHandlerLocal->m_vInterfaceID.size(); ++i ) - UG_LOG("m_vInterfaceID[" << i << "]: " << m_spInterfaceHandlerLocal->m_vInterfaceID[i] << "\n"); - for ( size_t i = 0; i < m_spInterfaceHandlerLocal->m_vQuadriOrigID.size(); ++i ) - UG_LOG("m_vQuadriOrigID[" << i << "]: " << m_spInterfaceHandlerLocal->m_vQuadriOrigID[i] << "\n"); - - std::vector testV; - for(size_t dof = 0; dof < 4; ++dof) - testV.push_back(1.0+0.1*dof); - - // B. remap pressure solution in all interface nodes - for(size_t fct = 0; fct < dim+1; ++fct) - for(size_t dof = 0; dof < 4; ++dof) - { - quadriU(fct,dof) = testV[m_spInterfaceHandlerLocal->m_vQuadriOrigID[dof]]; //origU(fct,m_spInterfaceHandlerLocal->m_vQuadriOrigID[dof]); - UG_LOG("quadriU(fct,dof): " << quadriU(fct,dof) << "\n"); - UG_LOG("testV[" << m_spInterfaceHandlerLocal->m_vQuadriOrigID[dof] << "]: " << testV[m_spInterfaceHandlerLocal->m_vQuadriOrigID[dof]] << "\n"); - } - - UG_LOG("start write_QuadriSol: quadriU = \n" << quadriU << "\n"); - UG_THROW("4 start write_QuadriSol\n"); - -// C. write velocities of the 2 particles: - MathVector transSol1 = m_spInterfaceHandlerLocal->get_transSol(0, 0); - MathVector rotSol1 = m_spInterfaceHandlerLocal->get_rotSol(0, 0); - MathVector transSol2 = m_spInterfaceHandlerLocal->get_transSol(1, 0); - MathVector rotSol2 = m_spInterfaceHandlerLocal->get_rotSol(1, 0); - - UG_LOG("transSol1 = " << transSol1 << "\n"); - UG_LOG("transSol2 = " << transSol2 << "\n"); - UG_LOG("rotSol1 = " << rotSol1 << "\n"); - UG_LOG("rotSol2 = " << rotSol2 << "\n"); - -// resize local data as done during 'modify_LocalSol' -// --> but there with num_co = 3 for the Triangle with inside node! - for(size_t fct = 0; fct < ind.num_fct(); ++fct) - for(size_t dof = 0; dof < 4; ++dof) - { - MathMatrix rotationMatCo = m_spInterfaceHandlerLocal->get_rotationMat(m_spInterfaceHandlerLocal->radial_at_co(dof)); - UG_LOG("write_QuadriSol: radial(" << dof << ": " << m_spInterfaceHandlerLocal->radial_at_co(dof) << "\n"); - - // write solution of particle with prtIndex = 0: - if ( dof < 2 ) - { - quadriU(fct,dof) = transSol1[fct]; - for ( int d = 0; d < dim; ++d ) - quadriU(fct,dof) += rotationMatCo[fct][d]*rotSol1[d]; - } - // write solution of particle with prtIndex = 1: - else - { - quadriU(fct,dof) = transSol2[fct]; - for ( int d = 0; d < dim; ++d ) - quadriU(fct,dof) += rotationMatCo[fct][d]*rotSol2[d]; - } - } - - - UG_LOG("after write_QuadriSol: quadriU = \n" << quadriU << "\n"); - -} - -template -void ParticleBndCondDiffusion:: -add_quadri_to_defect(LocalVector& d, const LocalVector& quadriD) -{ - const LocalIndices& ind = quadriD.get_indices(); - UG_LOG("START add_quadri_to_defect \n"); - - for ( size_t i = 0; i < m_spInterfaceHandlerLocal->m_vQuadriOrigID.size(); ++i ) - UG_LOG("m_vOrig[" << i << "] = " << m_spInterfaceHandlerLocal->m_vQuadriOrigID[i] << "\n"); - - UG_LOG("d: \n" << d << "\n"); - UG_LOG("quadriD: \n" << quadriD << "\n"); - for(size_t fct=0; fct < quadriD.num_all_fct(); ++fct) - { - UG_LOG("fct = " << fct << "quadriD.num_all_dof(fct) = " << quadriD.num_all_dof(fct) << "\n"); - - for(size_t dof=0; dof < quadriD.num_all_dof(fct); ++dof) - { - UG_LOG("0 -> dof = " << dof << "\n"); - - if ( quadriD.value(fct,dof) != quadriD.value(fct,dof)) - UG_THROW("NAN in 'add_quadri_to_defect()'!...\n"); - - bool isPrtNode = m_spInterfaceHandlerLocal->lies_onInterface(dof); - // usual assembling for fluid-dof and pressure-fct - if ( isPrtNode ) - { - size_t _dof = m_spInterfaceHandlerLocal->m_vQuadriOrigID[dof]; - UG_LOG("dof = " << dof << ", _dof = " << _dof << "\n"); - - d.value(fct,_dof) += quadriD.value(fct,dof); - UG_LOG("d = \n" << d << "\n"); - - } - - } - } - -} - - - -template -template -void ParticleBndCondDiffusion:: -add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -//////////////////////////////////////////////////////////////////////////////// -// Remove local impulse equations for interface-corners - - ElementModus elemModus = m_spInterfaceHandlerLocal->get_element_modus(elem); // computed via 'compute_element_modus()' during 'update_marker()' - if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling - { - if ( elemModus != INSIDE_DOM ) - { - // all impulse equations will be removed - std::vector vFctID(dim); - for(size_t i = 0; i < dim; ++i) vFctID[i] = i; - - // equations for interface nodes will be removed - std::vector vDoFID; vDoFID.clear(); - for(size_t i = 0; i < m_spInterfaceHandlerLocal->m_vInterfaceID.size(); ++i) - { - size_t interfaceID = m_spInterfaceHandlerLocal->m_vInterfaceID[i]; - size_t indexToRemove = interfaceID; //m_spInterfaceHandlerLocal->m_vOriginalCornerID[interfaceID]; - vDoFID.push_back(indexToRemove); - } - - remove_equations(d, vFctID, vDoFID); - - } - } - - - if ( elemModus == CUT_BY_2_INTERFACE && !m_spInterfaceHandlerLocal->StdFV_assembling()) - { - write_QuadriSol(u); - - if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 2 ) - - // case == 4: all entries (also for pressure eq) will be written newly, since only boundary faces are relevant - // => during remove_equations() only velocity equations were removed! - if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 4 ) - d = 0.0; - - // locU was written during 'ParticleMapper::modify_LocalData()': - if ( m_spInterfaceHandlerLocal->interface_id_all().size() == 4 || m_spInterfaceHandlerLocal->interface_id_all().size() == 2 ) - add_def_A_elem_Quadri_for2(d, u); - else - UG_THROW("in ParticleBndCondDiffusion::add_def_A_elem(): wrong amount of interface.size() for CUT_BY_2_INTERFACE: " << m_spInterfaceHandlerLocal->interface_id_all().size() << " ( should be 2!)\n"); - - return; - } - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// initialize data (written during call of 'diffusive_flux_Jac()': - LocalIndices ind = u.get_indices(); - rotD.resize(ind); rotD = 0.0; - - - // ToDo: if ( CUT_BY_2 && m_spInterfaceHandlerLocal->m_vInterfaceID.size() == 2 ) - // => TRIANGLE/5-Eck! => write u( , ) neu!! - -// Loop the boundary faces to assemble impulse equations - SmartPtr > fluidDensity = m_spMaster->density(); - std::vector& vBF = m_spInterfaceHandlerLocal->get_boundary_faces(); - - - if ( dim == 2 && vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - interfaceBF bf = vBF[ip]; - - // Compute Velocity at ip - MathVector stdVel(0.0); - for(size_t d1 = 0; d1 < (size_t)dim; ++d1) - for(size_t sh = 0; sh < bf.num_sh(); ++sh) - stdVel[d1] += u(d1, sh) * bf.shape(sh); - - // Momentum equation: - if ( ! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling - diffusive_flux_defect(ip, bf, d, u); - - // scale with deltaT ( = 1.0 for non-time-dependent) - // d *= deltaT; - // ToDo --> NOT necessary, since add_def_A_elem() will be multiplied by 'dt' - // during elem_dis_assemble_util.h ??? - - if ( fluidDensity->value(0, ip) != fluidDensity->value(1, ip) ) - UG_THROW("ParticleBndCondDiffusion::add_jac_M_elem(): density different for series 0 and 1: " - << fluidDensity->value(0, ip) << " != " << fluidDensity->value(1, ip) << "\n"); - number importDensity = fluidDensity->value(0, ip); - if ( importDensity != get_density_fluid() ) - UG_THROW("ParticleBndCondDiffusion::add_def_A_elem(): importDensity = " << importDensity << " != " - "fluidDensity = " << get_density_fluid() << "\n"); - - - // Continuity equation: - if ( 1 ) //! m_spInterfaceHandlerLocal->StdFV_assembling() ) // only remove, if NOT StdFVAssembling - d(_P_, bf.node_id()) += VecDot(stdVel, bf.normal()) * importDensity; - // ToDo m_massDefect += VecDot(stdVel, bf.normal()); - } - -/* if ( elemModus == CUT_BY_INTERFACE ) - if ( m_spInterfaceHandlerLocal->m_vInterfaceID.size() == 2 ) - UG_THROW("vBF.size() = " << vBF.size() << "\n"); -*/ - // copy rotJ_ind/rotJ_rot to m_spInterfaceHandlerLocal data for access from mapper - - copy_local_couplings_def(); - - -//////////////////////////////////////////////////////////////////////////////// -// instead of 'set_gravity()' during 'add_local_vec_to_global()' -//////////////////////////////////////////////////////////////////////////////// - - - //ToDo... - - -} - - -// instead of calling 'set_mass_and_inertia()' during 'add_local_mat_to_global_interface()' -template -template -void ParticleBndCondDiffusion:: -add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); - -// A. do nothing for inside elements - if ( modus == INSIDE_DOM ) - return; - -// B. for outside elements: geo.num_scv() = 0 -// => nothing added during NavierStokesFV1::add_jac_M_elem -// => nothing will be subtracted here :) - - -/////////////////////////////////////////////////////////////////////////////// -// substract part added by NavierStokesFV1::add_jac_M_elem(): -// (instead of setting scv.volume() to zero) -//////////////////////////////////////////////////////////////////////////////// - -// Only first order implementation - UG_ASSERT((TFVGeom::order == 1), "Only first order implemented."); - -// get finite volume geometry - static TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); - - SmartPtr > fluidDensity = m_spMaster->density(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int sh = scv.node_id(); - - if ( !m_spInterfaceHandlerLocal->lies_onInterface(sh) ) - continue; - - if ( fluidDensity->value(0, ip) != fluidDensity->value(1, ip) ) - UG_THROW("ParticleBndCondDiffusion::add_jac_M_elem(): density different for series 0 and 1: " - << fluidDensity->value(0, ip) << " != " << fluidDensity->value(1, ip) << "\n"); - - number importDensity = fluidDensity->value(0, ip); - - // loop velocity components - for(int d1 = 0; d1 < dim; ++d1) - { - // Add to local matrix - J(d1, sh, d1, sh) -= scv.volume() * importDensity; - } - } - - return; - - - const int prtIndex = get_prtIndex(); - const number prtDensity = get_density(prtIndex); - -// if INSIDE_DOM: do nothing! - if ( modus != INSIDE_DOM ) - { - // get data - const ReferenceObjectID roid = elem->reference_object_id(); - const DimReferenceElement& rRefElem - = ReferenceElementProvider::get(roid); - - // OUTSIDE_DOM - if ( modus == OUTSIDE_DOM ) - { - // loop corners of reference element - for(size_t sh = 0; sh < rRefElem.num(0); ++sh) - { - // loop velocity components - for(int d1 = 0; d1 < dim; ++d1) - { - // Add to local matrix - J(d1, sh, d1, sh) += geo.volume_fem_elem() * prtDensity; - // rescale volume fraction - J(d1, sh, d1, sh) *= 1.0/rRefElem.num(0); - } - } - } - // CUT_BY_INTERFACE - else if ( modus == CUT_BY_INTERFACE ) - { - // loop corners of reference element - for(size_t sh = 0; sh < rRefElem.num(0); ++sh) - { - // loop velocity components - for(int d1 = 0; d1 < dim; ++d1) - { - // Add to local matrix - J(d1, sh, d1, sh) += geo.volume_fem_elem() * prtDensity; - UG_THROW("geo.volume_fem_elem() = " << geo.volume_fem_elem() << "\n"); - // rescale volume fraction - J(d1, sh, d1, sh) *= 1.0/rRefElem.num(0); - } - } - } - else - UG_THROW("ParticleBndCondDiffusion::add_jac_M_elem()..."); - - } // end 'if ( !is_inside_elem() )' - - -} - - -template -template -void ParticleBndCondDiffusion:: -add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); - -// A. do nothing for inside elements - if ( modus == INSIDE_DOM ) - return; - -// B. for outside elements: geo.num_scv() = 0 -// => nothing added during NavierStokesFV1::add_jac_M_elem -// => nothing will be subtracted here :) - - -/////////////////////////////////////////////////////////////////////////////// -// substract part added by NavierStokesFV1::add_jac_M_elem(): -// (instead of setting scv.volume() to zero) -//////////////////////////////////////////////////////////////////////////////// - -// Only first order implementation - UG_ASSERT((TFVGeom::order == 1), "Only first order implemented."); - -// get finite volume geometry - static TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); - - SmartPtr > fluidDensity = m_spMaster->density(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int sh = scv.node_id(); - - if ( !m_spInterfaceHandlerLocal->lies_onInterface(sh) ) - continue; - - if ( fluidDensity->value(0, ip) != fluidDensity->value(1, ip) ) - UG_THROW("ParticleBndCondDiffusion::add_jac_M_elem(): density different for series 0 and 1: " - << fluidDensity->value(0, ip) << " != " << fluidDensity->value(1, ip) << "\n"); - - number importDensity = fluidDensity->value(0, ip); - - // loop velocity components - for(int d1 = 0; d1 < dim; ++d1) - { - // Add to local matrix - d(d1, sh) -= u(d1, sh) * scv.volume() * importDensity; - } - } - - -} - - -// here gravity force -> independent of velocity solution! -template -template -void ParticleBndCondDiffusion:: -add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) -{ - return; - - - ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); - -// A. do nothing for inside elements - if ( modus == INSIDE_DOM ) - return; - -// B. for outside elements: geo.num_scv() = 0 -// => nothing added during NavierStokesFV1::add_jac_M_elem -// => nothing will be subtracted here :) - - -/////////////////////////////////////////////////////////////////////////////// -// substract part added by NavierStokesFV1::add_rgh_elem(): -// (instead of setting scv.volume() to zero) -//////////////////////////////////////////////////////////////////////////////// - -// Only first order implementation - UG_ASSERT((TFVGeom::order == 1), "Only first order implemented."); - -// get finite volume geometry - static TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int sh = scv.node_id(); - - if ( !m_spInterfaceHandlerLocal->lies_onInterface(sh) ) - continue; - - // Add to local matrix - d(0, sh) -= scv.volume() * (-9.81); - - } - - -} - - - -//////////////////////////////////////////////////////////////////////////////// -// register assemble functions -//////////////////////////////////////////////////////////////////////////////// - -#ifdef UG_DIM_1 -template<> -void ParticleBndCondDiffusion:: -register_all(bool bHang) -{ -// switch assemble functions - if(!bHang) - { - register_func > >(); - -// register_func >(); - } - else - { - UG_THROW("ParticleBndCondDiffusion: Hanging Nodes not implemented.") - } -} -#endif - -#ifdef UG_DIM_2 -template<> -void ParticleBndCondDiffusion:: -register_all(bool bHang) -{ -// switch assemble functions - if(!bHang) - { - register_func > >(); -/* - register_func >(); - register_func >(); - */ - } - else - { - UG_THROW("ParticleBndCondDiffusion: Hanging Nodes not implemented.") - } -} -#endif - -#ifdef UG_DIM_3 -template<> -void ParticleBndCondDiffusion:: -register_all(bool bHang) -{ -// switch assemble functions - if(!bHang) - { - register_func > >(); -/* - register_func >(); - register_func >(); - register_func >(); - register_func >(); - */ - } - else - { - UG_THROW("ParticleBndCondDiffusion: Hanging Nodes not implemented.") - } -} -#endif - -template -template -void -ParticleBndCondDiffusion:: -register_func() -{ - ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; - typedef ParticleBndCondDiffusion T; - - this->clear_add_fct(id); - this->set_prep_elem_loop_fct( id, &T::template prep_elem_loop); - this->set_prep_elem_fct( id, &T::template prep_elem); - this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); - this->set_add_jac_A_elem_fct( id, &T::template add_jac_A_elem); - this->set_add_jac_M_elem_fct( id, &T::template add_jac_M_elem); - this->set_add_def_A_elem_fct( id, &T::template add_def_A_elem); - this->set_add_def_M_elem_fct( id, &T::template add_def_M_elem); - this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); -} - - -//////////////////////////////////////////////////////////////////////////////// -// explicit template instantiations -//////////////////////////////////////////////////////////////////////////////// - -#ifdef UG_DIM_1 -template class ParticleBndCondDiffusion; -#endif -#ifdef UG_DIM_2 -template class ParticleBndCondDiffusion; -#endif -#ifdef UG_DIM_3 -template class ParticleBndCondDiffusion; -#endif - - -} // end namespace MovingInterfaceDiffusion -} // end namespace ug - - -#endif /* DIFFUSION_BND_COND_IMPL_H_ */ diff --git a/fv1_cutElem/diffusion_interface/diffusion_interface Kopie.h b/fv1_cutElem/diffusion_interface/diffusion_interface Kopie.h deleted file mode 100644 index 14bf174..0000000 --- a/fv1_cutElem/diffusion_interface/diffusion_interface Kopie.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * diffusion_interface.h - * - * Created on: 24.08.2017 - * Author: suze - */ - -#ifndef DIFFUSION_INTERFACE_DIFFUSION_H_ -#define DIFFUSION_INTERFACE_DIFFUSION_H_ - - -#ifdef UG_PARALLEL - #include "lib_grid/parallelization/load_balancer_util.h" -#endif - -#include "../../../../ConvectionDiffusion/fv1/convection_diffusion_fv1.h" -#include "../../../../ConvectionDiffusion/convection_diffusion_base.h" -#include "interface_handler_diffusion.h" -#include "loc_to_glob_mapper_diffusion.h" -#include "../immersed_interface_base/immersed_interface_base.h" - -namespace ug{ -namespace MovingInterfaceDiffusion{ - - - -template < typename TDomain, typename TAlgebra> -class MovingInterfaceDiffusion - : public MovingInterfaceBase::IMovingInterface -{ - public: - /// world Dimension - static const int dim = TDomain::dim; - - /// Algebra type - typedef TAlgebra algebra_type; - - /// Type of algebra matrix - typedef typename algebra_type::matrix_type matrix_type; - - /// Type of algebra vector - typedef typename algebra_type::vector_type vector_type; - - typedef typename domain_traits::grid_base_object grid_base_object; - - MovingInterfaceDiffusion( - SmartPtr > ass, - SmartPtr > spMaster, - SmartPtr > interfaceProvider, - SmartPtr > cutElementHandler); - - void set_StdFV_assembling(bool bValue) { m_spInterfaceHandlerLocal->set_StdFV_assembling(bValue);} - bool StdFV_assembling() { return m_spInterfaceHandlerLocal->StdFV_assembling(); } - - - // destructor - ~MovingInterfaceDiffusion(){}; - - /// called via .lua: - void initialize_threshold(TDomain& domain, const int baseLevel, const int topLevel); - void set_threshold(size_t level, const number threshold) - { m_spCutElementHandler->set_threshold(level, threshold); } - - ////////////////////////////////////////////////////////////////////////////////// - /// Info - 'initialize_interface()': - /// - /// computes vertices on intersection of cut element edges and interface: - /// for 2d: instead of computing intersections: count number of cut elements! - /// -> #cutElements == #m_vertices - /// -> called during init() - ////////////////////////////////////////////////////////////////////////////////// - - const size_t initialize_interface(vector_type& u, ConstSmartPtr dd); - const size_t initialize_interface_Nitsche(vector_type& u, ConstSmartPtr dd); - - number MeanElementDiameter(TDomain& domain, int level); - - ////////////////////////////////////////////////////////////////////////////////// - // ---> .lua: update(u, deltaT, u:grid_level()): update global indices (transInd...) - // => A. copy_solution(topLev) - // B. update(baseLev-topLev) - // C. update_solution(topLev) - ////////////////////////////////////////////////////////////////////////////////// - // write solution to nodes outside fluid with particle velocities - // --> call method vie .lua BEFORE 'solTimeSeries:push_discard_oldest(oldestSol, time)': - // => in case that outside nodes are inside AFTER update_prtCoords: NO solution defined here! - - - /// call of the method via lua to set the real velocity values within the particle domain - void adjust_global_solution(vector_type& u, const int topLevel); - void fill_particle_solution(vector_type& u, const int topLevel, const number time); - void update(vector_type& u, SmartPtr > spApproxSpace, const int baseLevel, const int topLevel, const number time) - { - int topLev = spApproxSpace->num_levels()-1; - if ( topLev != topLevel ) - UG_THROW("update: parameter 'topLevel' = " << topLevel << " != " - << topLev << "current top leven! \n"); - - // fill particle nodes with their real solution - fill_particle_solution(u, topLevel, time); - - // update data: bool_marker - ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); - m_spCutElementHandler->template init(dd, baseLevel, topLevel); - - } - - void set_interface_values(vector_type& u, const int numDoFs, const int num_newDoFs) - { - double value = 20.0*0.4*0.4*0.4*0.4; - DoFIndex index; - - for (size_t i = 0; i < num_newDoFs; ++i) - { - index = DoFIndex(numDoFs + i,0); - // DoFRef(u, index) = value; - } - } - void set_analytic_solution(vector_type& u, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel); - void adjust_for_error(vector_type& u, vector_type& uCopy, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel); - - double compute_solution_value(const MathVector& vrtPos); - - number get_integral() - { return m_spInterfaceHandlerLocal->get_integral(); } - - void set_Nitsche(bool bNitsche) - { return m_spInterfaceHandlerLocal->set_Nitsche(bNitsche); } - - void init(vector_type& u, SmartPtr > spApproxSpace, const int baseLevel, const int topLevel, bool bScaleDoFs) - { - m_spApproxSpace = spApproxSpace; - - ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); - - m_spInterfaceMapper->set_numDoFs(u.size()); - - size_t numDoFs = u.size(); - UG_LOG("domain disc: numDoFs = " << numDoFs << "\n"); - size_t num_newDoFs = initialize_interface(u, dd); - UG_LOG("________________ num_newDoFs = " << initialize_interface(u, dd) << "\n"); - m_spInterfaceMapper->set_numNewDoFs(num_newDoFs); - - - if ( m_spInterfaceHandlerLocal->get_Nitsche() ) - { - const size_t buffer = initialize_interface_Nitsche(u, dd); - UG_LOG(" buffer = " << buffer << "\n"); - - const size_t num_NitscheDoFs = m_spInterfaceHandlerLocal->get_num_NitscheDoFs(); - UG_LOG(" num_NitscheDoFs = " << num_NitscheDoFs << "\n"); - - num_newDoFs = num_NitscheDoFs; - m_spInterfaceMapper->set_numNewDoFs(num_newDoFs); - - for ( size_t i = 0; i < num_NitscheDoFs; ++i ) - { - size_t global_index = m_spInterfaceHandlerLocal->get_global_index_Nitsche(i); - UG_LOG(" global_index = " << global_index << "\n"); - } - } - - // values for new DoFs are set to 0.0 by the 'resize()'-method (see vector.h): - if ( bScaleDoFs ) - u.resize(numDoFs + 2*num_newDoFs); - else - u.resize(numDoFs + num_newDoFs); - - UG_LOG("AGAIN: in init(): numDoFs = " << u.size() << "\n"); - - m_spInterfaceMapper->set_bScaleDoFs(bScaleDoFs); - m_spInterfaceHandlerLocal->set_bScaleDoFs(bScaleDoFs); - - m_spInterfaceHandlerLocal->init_integral(); - - // lieber in jedem Schritt über 'modify_GlobalSol()' (mapper!) setzten! - //set_interface_values(u, numDoFs, num_newDoFs); - - // not necessary anymore: only local evaluations within diffusion problem! - //m_spCutElementHandler->template init_marker(dd, baseLevel, topLevel); - } - - /// checks if grid data is updated and returns 'levIndex'-pair for 'gridLevel' in 'm_Map' - int get_Index(const GridLevel& gridLevel) - { - ConstSmartPtr dd = m_spApproxSpace->dof_distribution(gridLevel); - - const int levIndex = m_spCutElementHandler->get_Index(gridLevel, dd); - - return levIndex; - } - - //ToDo: method needed? - void update_interface( const int topLevel, number deltaT); - - bool is_time_dependent() { return m_spInterfaceHandlerLocal->is_time_dependent();} - - /// helper functions for compute_error_on_circle() - void interpolate_point(ConstSmartPtr dd, const vector_type& u, - const MathVector& evalPos, MathVector& interpolation); - void compute_error_on_circle(const vector_type& u, const int topLevel, number radius); - - void print_deltaP(const vector_type& u, const int topLevel); - void print_pressure(const vector_type& u, const int topLevel); - void print_pressure_nodal(const vector_type& u, const int topLevel); - - /// writing data to file; called via .lua - void print_velocity(const vector_type& u, const int topLevel, number time, const char* filename); - void print_velocity_many_particles(const vector_type& u, const int topLevel, number time, const char* filename); - - size_t get_numDoFs(const vector_type& u) {return u.size(); } - - private: - /// current ApproxSpace - SmartPtr > m_spApproxSpace; - - SmartPtr > m_spInterfaceProvider; - SmartPtr > m_spCutElementHandler; - SmartPtr > m_spInterfaceHandlerLocal; - - SmartPtr > m_spInterfaceMapper; - -}; - -} // end namespace MovingInterfaceDiffusion -} // end namespace ug - - -#include "diffusion_interface_impl.h" - -#endif /* DIFFUSION_INTERFACE_DIFFUSION_H_ */ - - - - diff --git a/fv1_cutElem/diffusion_interface/diffusion_interface.h b/fv1_cutElem/diffusion_interface/diffusion_interface.h index 30968c9..0eda600 100644 --- a/fv1_cutElem/diffusion_interface/diffusion_interface.h +++ b/fv1_cutElem/diffusion_interface/diffusion_interface.h @@ -5,8 +5,8 @@ * Author: suze */ -#ifndef DIFFUSION_INTERFACE_DIFFUSION_H_ -#define DIFFUSION_INTERFACE_DIFFUSION_H_ +#ifndef IMMERSED_INTERFACE_DIFFUSION_H_ +#define IMMERSED_INTERFACE_DIFFUSION_H_ #ifdef UG_PARALLEL @@ -24,8 +24,8 @@ namespace ConvectionDiffusionPlugin{ template < typename TDomain, typename TAlgebra> -class MovingInterfaceDiffusion - : public IMovingInterface +class ImmersedInterfaceDiffusion + : public IImmersedInterface { public: /// world Dimension @@ -42,187 +42,126 @@ class MovingInterfaceDiffusion typedef typename domain_traits::grid_base_object grid_base_object; - MovingInterfaceDiffusion( + ImmersedInterfaceDiffusion( SmartPtr > ass, SmartPtr > spMaster, SmartPtr > interfaceProvider, - SmartPtr > cutElementHandler); - - void set_StdFV_assembling(bool bValue) { m_spInterfaceHandlerLocal->set_StdFV_assembling(bValue);} - bool StdFV_assembling() { return m_spInterfaceHandlerLocal->StdFV_assembling(); } - + SmartPtr > cutElementHandler); // destructor - ~MovingInterfaceDiffusion(){}; - - /// called via .lua: - void initialize_threshold(TDomain& domain, const int baseLevel, const int topLevel); - void set_threshold(size_t level, const number threshold) - { m_spCutElementHandler->set_threshold(level, threshold); } - - ////////////////////////////////////////////////////////////////////////////////// - /// Info - 'initialize_interface()': - /// - /// computes vertices on intersection of cut element edges and interface: - /// for 2d: instead of computing intersections: count number of cut elements! - /// -> #cutElements == #m_vertices - /// -> called during init() - ////////////////////////////////////////////////////////////////////////////////// - - const size_t initialize_interface(vector_type& u, ConstSmartPtr dd); + virtual ~ImmersedInterfaceDiffusion(){}; + + ////////////////////////////////////////////////////////////////////////////////////////// + // main methods + ////////////////////////////////////////////////////////////////////////////////////////// + + // general initialisation of set up data; + // most important: call of + // (1) 'initialize_interface()' and + // (2) 'update_interface_data()' to mark the cut elements and interface vertices + void init(vector_type& u, SmartPtr > spApproxSpace, const int baseLevel, + const int topLevel, bool bScaleDoFs); + + // mainly updates the BoolMarker for elements and vertices + void update(vector_type& u, SmartPtr > spApproxSpace, + const int baseLevel, const int topLevel, const number time); + + ////////////////////////////////////////////////////////////////////////////////////////// + // helper methods for init() and update() + ////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////////////// + /// Info - 'initialize_interface()': Main infos: see CutElementHandler + /// Important for call here: + /// --> counts number of cut elements! + /// --> called during init() + ////////////////////////////////////////////////////////////////////////////////////////// + + const size_t initialize_interface(ConstSmartPtr dd) + { return m_spCutElementHandler->initialize_interface(dd); } const size_t initialize_interface_Nitsche(vector_type& u, ConstSmartPtr dd); - number MeanElementDiameter(TDomain& domain, int level); - - ////////////////////////////////////////////////////////////////////////////////// - // ---> .lua: update(u, deltaT, u:grid_level()): update global indices (transInd...) - // => A. copy_solution(topLev) - // B. update(baseLev-topLev) - // C. update_solution(topLev) - ////////////////////////////////////////////////////////////////////////////////// - // write solution to nodes outside fluid with particle velocities - // --> call method vie .lua BEFORE 'solTimeSeries:push_discard_oldest(oldestSol, time)': - // => in case that outside nodes are inside AFTER update_prtCoords: NO solution defined here! - - - /// call of the method via lua to set the real velocity values within the particle domain - void adjust_global_solution(vector_type& u, const int topLevel); - void fill_particle_solution(vector_type& u, const int topLevel, const number time); - void update(vector_type& u, SmartPtr > spApproxSpace, const int baseLevel, const int topLevel, const number time) - { - int topLev = spApproxSpace->num_levels()-1; - if ( topLev != topLevel ) - UG_THROW("update: parameter 'topLevel' = " << topLevel << " != " - << topLev << "current top leven! \n"); - - // fill particle nodes with their real solution - fill_particle_solution(u, topLevel, time); - - // update data: bool_marker - ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); - m_spCutElementHandler->template init(dd, baseLevel, topLevel); - - } - - void set_interface_values(vector_type& u, const int numDoFs, const int num_newDoFs) - { - double value = 20.0*0.4*0.4*0.4*0.4; - DoFIndex index; - - for (size_t i = 0; i < num_newDoFs; ++i) - { - index = DoFIndex(numDoFs + i,0); - // DoFRef(u, index) = value; - } - } - void set_analytic_solution(vector_type& u, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel); - void adjust_for_error(vector_type& u, vector_type& uCopy, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel); - - double compute_solution_value(const MathVector& vrtPos); - - number get_integral() - { return m_spInterfaceHandlerLocal->get_integral(); } - - void set_Nitsche(bool bNitsche) - { return m_spInterfaceHandlerLocal->set_Nitsche(bNitsche); } - - void init(vector_type& u, SmartPtr > spApproxSpace, const int baseLevel, const int topLevel, bool bScaleDoFs, bool bBndFct) - { - m_spApproxSpace = spApproxSpace; - - ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); - - m_spInterfaceMapper->set_numDoFs(u.size()); - - size_t numDoFs = u.size(); - UG_LOG("domain disc: numDoFs = " << numDoFs << "\n"); - size_t num_newDoFs = initialize_interface(u, dd); - UG_LOG("________________ num_newDoFs = " << initialize_interface(u, dd) << "\n"); - m_spInterfaceMapper->set_numNewDoFs(num_newDoFs); - - - if ( m_spInterfaceHandlerLocal->get_Nitsche() ) - { - const size_t buffer = initialize_interface_Nitsche(u, dd); - UG_LOG(" buffer = " << buffer << "\n"); - - const size_t num_NitscheDoFs = m_spInterfaceHandlerLocal->get_num_NitscheDoFs(); - UG_LOG(" num_NitscheDoFs = " << num_NitscheDoFs << "\n"); - - num_newDoFs = num_NitscheDoFs; - m_spInterfaceMapper->set_numNewDoFs(num_newDoFs); - - for ( size_t i = 0; i < num_NitscheDoFs; ++i ) - { - size_t global_index = m_spInterfaceHandlerLocal->get_global_index_Nitsche(i); - UG_LOG(" global_index = " << global_index << "\n"); - } - } - - // values for new DoFs are set to 0.0 by the 'resize()'-method (see vector.h): - if ( bScaleDoFs ) - u.resize(numDoFs + 2*num_newDoFs); - else - u.resize(numDoFs + num_newDoFs); - - UG_LOG("AGAIN: in init(): numDoFs = " << u.size() << "\n"); - - m_spInterfaceMapper->set_bScaleDoFs(bScaleDoFs); - m_spInterfaceHandlerLocal->set_bScaleDoFs(bScaleDoFs); - - m_spInterfaceHandlerLocal->check_interface_data(bBndFct); - - m_spInterfaceHandlerLocal->init_integral(); - - // lieber in jedem Schritt über 'modify_GlobalSol()' (mapper!) setzten! - //set_interface_values(u, numDoFs, num_newDoFs); - - // not necessary anymore: only local evaluations within diffusion problem! - //m_spCutElementHandler->template init_marker(dd, baseLevel, topLevel); - } - - void set_source_data(const number interfaceSourceVal) { m_spInterfaceHandlerLocal->set_source_lua(interfaceSourceVal); } - void set_jump_data(const number interfaceJumpVal) { m_spInterfaceHandlerLocal->set_jump_lua(interfaceJumpVal); } - void set_jump_grad_data(const MathVector<2>& interfaceJumpGradVal) { m_spInterfaceHandlerLocal->set_jump_grad_lua(interfaceJumpGradVal); } - void set_diffusion_data(const MathVector<2>& diffusionCoeffs) { m_spInterfaceHandlerLocal->set_diffusion_coeff_lua(diffusionCoeffs); } + ////////////////////////////////////////////////////////////////////////////////////////// + /// methods for writing the source term and boundary conditions on the interface + ////////////////////////////////////////////////////////////////////////////////////////// + void set_source_data_lua(const number interfaceSourceVal) + { m_spInterfaceHandlerLocal->set_source_data_lua(interfaceSourceVal); } + void set_jump_data_lua(const number interfaceJumpVal) + { m_spInterfaceHandlerLocal->set_jump_data_lua(interfaceJumpVal); } + void set_jump_grad_data_lua(const MathVector<2>& interfaceJumpGradVal) + { m_spInterfaceHandlerLocal->set_jump_grad_data_lua(interfaceJumpGradVal); } + void set_diffusion_data_lua(const MathVector<2>& diffusionCoeffs) + { m_spInterfaceHandlerLocal->set_diffusion_coeff_data_lua(diffusionCoeffs); } - /// checks if grid data is updated and returns 'levIndex'-pair for 'gridLevel' in 'm_Map' - int get_Index(const GridLevel& gridLevel) - { - ConstSmartPtr dd = m_spApproxSpace->dof_distribution(gridLevel); - - const int levIndex = m_spCutElementHandler->get_Index(gridLevel, dd); - - return levIndex; - } + ////////////////////////////////////////////////////////////////////////////////////////// + /// lua-methods for set up: + ////////////////////////////////////////////////////////////////////////////////////////// - //ToDo: method needed? - void update_interface( const int topLevel, number deltaT); - - bool is_time_dependent() { return m_spInterfaceHandlerLocal->is_time_dependent();} - - /// helper functions for compute_error_on_circle() - void interpolate_point(ConstSmartPtr dd, const vector_type& u, - const MathVector& evalPos, MathVector& interpolation); - void compute_error_on_circle(const vector_type& u, const int topLevel, number radius); - - void print_deltaP(const vector_type& u, const int topLevel); - void print_pressure(const vector_type& u, const int topLevel); - void print_pressure_nodal(const vector_type& u, const int topLevel); + // the 'threshold' defines the bandwidth around the immersed interface, in which a node + // counts as 'OUTSIDE' or 'ON_INTERFACE' during call of 'CutElementHandler::is_outside()', + // 'CutElementHandler::is_nearInterface() + void initialize_threshold(TDomain& domain, const int baseLevel, const int topLevel); + void set_threshold(size_t level, const number threshold) + { m_spCutElementHandler->set_threshold(level, threshold); } + number MeanElementDiameter(TDomain& domain, int level); + + // If StdFV-assembling is ON, NO new 'vCornerCoords' will be computed on the cut elements. + // The original nodes ACCROSS the interface (and ON the euclidian mesh) will be chosen for the + // computation of the solution of the interface + // ==> the standard shape functions as in common 'ficticious domain' methods will be used + // ==> the shape functions will NOT be 1 ON the interface and the gradient will NOT + // point normal to the interface + void set_StdFV_assembling(bool bValue) { m_spInterfaceHandlerLocal->set_StdFV_assembling(bValue);} + bool StdFV_assembling() { return m_spInterfaceHandlerLocal->StdFV_assembling(); } - /// writing data to file; called via .lua - void print_velocity(const vector_type& u, const int topLevel, number time, const char* filename); - void print_velocity_many_particles(const vector_type& u, const int topLevel, number time, const char* filename); + + ////////////////////////////////////////////////////////////////////////////////////////// + /// lua-methods for output + ////////////////////////////////////////////////////////////////////////////////////////// + + void set_analytic_solution(vector_type& u, SmartPtr > spApproxSpace, + SmartPtr mg, const int topLevel); + + // adjustment of solution vector in order to compute the error WITHOUT nodes near the interface: + // ==> (1) remove additional nodes ON the interface, not lying on the original grid + // (2) set solution in nodes lying NEAR the interface, but IN the original grid to zero + void adjust_for_error(vector_type& u, vector_type& uCopy, SmartPtr > spApproxSpace, + SmartPtr mg, const int topLevel); - size_t get_numDoFs(const vector_type& u) {return u.size(); } + double compute_solution_value(const MathVector& vrtPos); + + // returns the interface adapted l2 error, computed during 'ConvectionDiffusionFV1_cutElem::add_def_A_elem()': + number get_L2Error() { return m_spInterfaceHandlerLocal->get_L2Error(); } + + // returns the number of DoFs on the original grid + size_t get_numDoFs() { return m_spInterfaceMapper->get_numDoFs(); } + + // boolian used for perform the Nitsche-method (i.e. CutElem-method) for the treatment of the immersed interface + void set_Nitsche(bool bNitsche) { return m_spInterfaceHandlerLocal->set_Nitsche(bNitsche); } + + // setting and getting flag for printing of cut-element data into file: + void set_print_cutElemData(bool bValue) { m_spInterfaceHandlerLocal->set_print_cutElemData(bValue); } + + // returns the number of DoFs on the original grid + size_t get_numCutElements(const int gridlevel, const size_t prtIndex) + { + ConstSmartPtr dd = m_spApproxSpace->dof_distribution(GridLevel(gridlevel, GridLevel::LEVEL)); + const int levIndex = m_spCutElementHandler->get_Index(gridlevel, dd); + + return m_spCutElementHandler->get_numCutElements(levIndex); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + /// class member + ////////////////////////////////////////////////////////////////////////////////////////// private: /// current ApproxSpace SmartPtr > m_spApproxSpace; SmartPtr > m_spInterfaceProvider; - SmartPtr > m_spCutElementHandler; + SmartPtr > m_spCutElementHandler; SmartPtr > m_spInterfaceHandlerLocal; SmartPtr > m_spInterfaceMapper; @@ -235,7 +174,7 @@ class MovingInterfaceDiffusion #include "diffusion_interface_impl.h" -#endif /* DIFFUSION_INTERFACE_DIFFUSION_H_ */ +#endif /* IMMERSED_INTERFACE_DIFFUSION_H_ */ diff --git a/fv1_cutElem/diffusion_interface/diffusion_interface_impl Kopie.h b/fv1_cutElem/diffusion_interface/diffusion_interface_impl Kopie.h deleted file mode 100644 index 7d300f3..0000000 --- a/fv1_cutElem/diffusion_interface/diffusion_interface_impl Kopie.h +++ /dev/null @@ -1,371 +0,0 @@ - -/* - * moving_interface_diffusion_impl.h - * - * Created on: 24.08.2017 - * Author: suze - */ - -#ifndef DIFFUSION_INTERFACE_IMPL_H_ -#define DIFFUSION_INTERFACE_IMPL_H_ - - -namespace ug { -namespace MovingInterfaceDiffusion { - -/////////////////////////////////////////////////////////// -// Implementation of the methods class -// 'MovingInterfaceDiffusion' -/////////////////////////////////////////////////////////// - - -template -MovingInterfaceDiffusion::MovingInterfaceDiffusion( - SmartPtr > ass, - SmartPtr > spMaster, - SmartPtr > interfaceProvider, - SmartPtr > cutElementHandler) : - m_spInterfaceHandlerLocal(new InterfaceHandlerLocalDiffusion(interfaceProvider, cutElementHandler)), - m_spInterfaceProvider(interfaceProvider), - m_spCutElementHandler(cutElementHandler), - m_spInterfaceMapper(new DiffusionInterfaceMapper (m_spInterfaceHandlerLocal)) -{ - if (interfaceProvider->num_particles() == 0) - UG_THROW("MovingParticle::Constructor(): no particles initializen in 'globalHandler\n"); - - // initialize singleton and set local handler - typedef DimFV1CutGeometry > TFVGeom; - TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); - geo.set_interface_handler(m_spInterfaceHandlerLocal); - - // initialize mapper within domainDisc: - SmartPtr > assAdapt = ass->ass_tuner(); - assAdapt->set_mapping(m_spInterfaceMapper.get()); - - assAdapt->enable_modify_solution(true); - // => assTuner->modify_LocSol() = mapper->modify_LocSol() - // see: ass_tuner.h: 114 - - -} - -template -double MovingInterfaceDiffusion:: -compute_solution_value(const MathVector& vrtPos) -{ - double kappa_1 = 1.0; - double kappa_2 = 10.0; - double sqR = 0.4*0.4; - double dist_x = vrtPos[0] - 0.1; - double dist_y = vrtPos[1] - 0.2; - double sqDist = dist_x*dist_x+dist_y*dist_y; - - double value = -4*kappa_1*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_1*kappa_2 - 1); - - double dist = sqrt(sqDist); - if ( dist > 0.4 ) - { - value = -2*kappa_2*sqDist*sqDist; - UG_LOG("value = " << value << "\n"); - } - return value; -} - -template -void MovingInterfaceDiffusion:: -set_analytic_solution(vector_type& u, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel) -{ - ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); - - typedef MathVector position_type; - typedef Attachment position_attachment_type; - typedef Grid::VertexAttachmentAccessor position_accessor_type; - - //SmartPtr m_spMG = mg.operator->(); - position_attachment_type m_aPos = GetDefaultPositionAttachment(); - position_accessor_type m_aaPos; - - if(!mg->has_attachment(m_aPos)) - mg->attach_to(m_aPos); - m_aaPos.access(*mg, m_aPos); - - typedef typename domain_traits::grid_base_object grid_base_object; - - typename DoFDistribution::traits::const_iterator iter, iterEnd; - iter = dd->template begin(); - iterEnd = dd->template end(); - - // loop elements in order to compute the volume and set rhs: - for( ; iter != iterEnd; iter++) - { - // get element - grid_base_object* elem = *iter; - std::vector > vCornerCoords; - CollectCornerCoordinates(vCornerCoords, *elem, m_aaPos); - - std::vector ind; - dd->dof_indices(elem, 0, ind); - - // loop vertices - for(size_t i = 0; i < elem->num_vertices(); ++i) - { - // get vertex - Vertex* vrt = elem->vertex(i); - double value = compute_solution_value(vCornerCoords[i]); - DoFRef(u, ind[i]) = value; - } - } - -} - -template -void MovingInterfaceDiffusion:: -adjust_for_error(vector_type& u, vector_type& uCopy, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel) -{ - - - size_t numDoFs = u.size(); - UG_LOG("domain disc: numDoFs = " << numDoFs << "\n"); - size_t numDoFsCopy = uCopy.size(); - UG_LOG("domain disc: numDoFsCopy = " << numDoFsCopy << "\n"); - - u.resize(numDoFsCopy); - - numDoFs = u.size(); - UG_LOG("**domain disc: numDoFs = " << numDoFs << "\n"); - - - - ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); - - typedef MathVector position_type; - typedef Attachment position_attachment_type; - typedef Grid::VertexAttachmentAccessor position_accessor_type; - - //SmartPtr m_spMG = mg.operator->(); - position_attachment_type m_aPos = GetDefaultPositionAttachment(); - position_accessor_type m_aaPos; - - if(!mg->has_attachment(m_aPos)) - mg->attach_to(m_aPos); - m_aaPos.access(*mg, m_aPos); - - typedef typename domain_traits::grid_base_object grid_base_object; - - typename DoFDistribution::traits::const_iterator iter, iterEnd; - iter = dd->template begin(); - iterEnd = dd->template end(); - - // loop elements in order to compute the volume and set rhs: - for( ; iter != iterEnd; iter++) - { - // get element - grid_base_object* elem = *iter; - - ElementModus elemModus = m_spInterfaceHandlerLocal->compute_element_modus(elem, 1); - bool do_adjust = false; - - switch(elemModus) - { - case INSIDE_DOM: break; - case OUTSIDE_DOM: break; - - case CUT_BY_INTERFACE: do_adjust = true; break; - default: - throw(UGError("Error in InterfaceHandlerLocalDiffusion::update(): switch(m_elemModus)!")); - } - - - std::vector > vCornerCoords; - CollectCornerCoordinates(vCornerCoords, *elem, m_aaPos); - - std::vector ind; - dd->dof_indices(elem, 0, ind); - - // loop vertices - for(size_t i = 0; i < elem->num_vertices(); ++i) - { - // get vertex - Vertex* vrt = elem->vertex(i); - - if (do_adjust) DoFRef(u, ind[i]) = 0.0; - } - - } - -} - -template -const size_t MovingInterfaceDiffusion:: -initialize_interface_Nitsche(vector_type& u, ConstSmartPtr dd) -{ - m_spInterfaceHandlerLocal->m_MapInserted_Nitsche.clear(); - - typedef typename domain_traits::grid_base_object grid_base_object; - - typename DoFDistribution::traits::const_iterator iter, iterEnd; - iter = dd->template begin(); - iterEnd = dd->template end(); - - size_t num_cutElements = 0; - - // loop elements in order to compute the volume and set rhs: - for( ; iter != iterEnd; iter++) - { - // get element - grid_base_object* elem = *iter; - - ElementModus elemModus = m_spCutElementHandler->compute_element_modus(elem, 1); - - if ( elemModus == CUT_BY_INTERFACE ) - { - num_cutElements += 1; - - // get global indices - LocalIndices ind; - dd->indices(elem, ind, false); - - // fill 'm_MapInserted_Nitsche' with global indices: - for(size_t i = 0; i < 3; ++i) - m_spInterfaceHandlerLocal->get_or_insert_indexPair_Nitsche(ind.index(0, i)); - - } - } - - return num_cutElements; - -} - -template -const size_t MovingInterfaceDiffusion:: -initialize_interface(vector_type& u, ConstSmartPtr dd) -{ - typedef typename domain_traits::grid_base_object grid_base_object; - - typename DoFDistribution::traits::const_iterator iter, iterEnd; - iter = dd->template begin(); - iterEnd = dd->template end(); - - size_t num_cutElements = 0; - - // loop elements in order to compute the volume and set rhs: - for( ; iter != iterEnd; iter++) - { - // get element - grid_base_object* elem = *iter; - - ElementModus elemModus = m_spCutElementHandler->compute_element_modus(elem, 1); - - if ( elemModus == CUT_BY_INTERFACE ) - num_cutElements += 1; - - } - - return num_cutElements; - -} - -template -number MovingInterfaceDiffusion:: -MeanElementDiameter(TDomain& domain, int level) -{ - typedef typename domain_traits::grid_base_object TElem; - typedef typename geometry_traits::iterator ListIter; - - ListIter iter = domain.grid()->template begin(level); - ListIter iterEnd = domain.grid()->template end(level); - - number mean = 0.0; - size_t numIter = 0; - for (; iter != iterEnd; ++iter) { - mean += ElementDiameterSq(*domain.grid(), domain.position_accessor(), - *iter); - numIter++; - } - - mean = mean / numIter; - -#ifdef UG_PARALLEL - // share value between all procs - pcl::ProcessCommunicator com; - // ToDO: PCL_RO_MIN oder MAX oder doch mean noch berechnen m.H.v. /numProcs??? - //UG_THROW("in MeanElementDiameter(): was macht 'allredue' im Parallelen???\n"); - mean = com.allreduce(mean, PCL_RO_MIN); -#endif - - UG_LOG("nach com.allreduce: mean = " << std::sqrt(mean) << "\n"); - return std::sqrt(mean); -} - -template -void MovingInterfaceDiffusion:: -initialize_threshold(TDomain& domain, const int baseLevel, const int topLevel) -{ - UG_LOG("----------------- START initialize_threshold() ---------------- \n"); - - if (baseLevel < 0) - UG_THROW( - "initialize_threshold(): no cast of baselevel from 'int' tp 'size_t' possible! \n"); - if (topLevel < 0) - UG_THROW( - "initialize_threshold(): no cast of toplevel from 'int' tp 'size_t' possible! \n"); - -// compute level-dependent value for threshold: - for (size_t lev = baseLevel; lev <= (size_t) topLevel; ++lev) { - const number maxLength = MaxElementDiameter(domain, lev); - const number meanLength = MeanElementDiameter(domain, lev); - UG_LOG("maxLength = " << maxLength << "\n"); - UG_LOG("meanLength = " << meanLength << "\n"); - UG_LOG("threshold_max = " << maxLength*maxLength << "\n"); - UG_LOG("threshold_mean = " << meanLength*meanLength << "\n"); - -// set_threshold(lev, meanLength * meanLength); - set_threshold(lev, 0.25 * meanLength*meanLength); - } - - UG_LOG("----------------- END initialize_threshold() ---------------- \n"); - -} - -template -void MovingInterfaceDiffusion:: -update_interface( const int topLevel, number deltaT) -{ - if ( deltaT == 0.0 ) - UG_THROW("InterfaceProvider:update_prtCoords: deltaT = " << deltaT << " => no update necessary!\n"); - -// get level index - const int levIndex = get_Index(GridLevel(topLevel, GridLevel::LEVEL)); - UG_LOG("update_prtCoords() for levIndex = " << levIndex << "\n"); - UG_LOG("update_prtCoords() for deltaT = " << deltaT << "\n"); - -// update center - for (size_t p = 0; p < m_spInterfaceProvider->num_particles(); ++p) - { -#ifdef UG_PARALLEL - std::vector ElemList = m_spCutElementHandler->m_vvvElemListCut[levIndex][p]; -// std::vector ElemList = m_vvvElemListCut[levIndex][p]; - UG_LOG("1_ update_prtCoords() ElemList.size(): " << ElemList.size() << "\n"); - if ( ElemList.size() == 0 ) { - UG_LOG("2_ update_prtCoords() ElemList.size(): " << ElemList.size() << " => skip assembling! \n"); - continue; - } -#endif - - // get data: - MathVector centerNew = m_spInterfaceProvider->get_center(p); - number soution = m_spInterfaceProvider->get_solution(p, 0); - UG_LOG(" solution = " << soution << "\n"); - UG_LOG("deltaT = " << deltaT << "\n"); - -// ToDo: Hier das interface irgendwie updaten?? - - - } // end particle loop - -} - -} // end namespace MovingParticle -} // end namespace ug - -#endif /* DIFFUSION_INTERFACE_IMPL_H_ */ diff --git a/fv1_cutElem/diffusion_interface/diffusion_interface_impl.h b/fv1_cutElem/diffusion_interface/diffusion_interface_impl.h index 8422631..baf1895 100644 --- a/fv1_cutElem/diffusion_interface/diffusion_interface_impl.h +++ b/fv1_cutElem/diffusion_interface/diffusion_interface_impl.h @@ -1,13 +1,13 @@ /* - * moving_interface_diffusion_impl.h + * diffusion_interface_impl.h * * Created on: 24.08.2017 * Author: suze */ -#ifndef DIFFUSION_INTERFACE_IMPL_H_ -#define DIFFUSION_INTERFACE_IMPL_H_ +#ifndef IMMERSED_INTERFACE_DIFFUSION_IMPL_H_ +#define IMMERSED_INTERFACE_DIFFUSION_IMPL_H_ #include "lib_disc/spatial_disc/disc_util/geom_provider.h" @@ -16,42 +16,111 @@ namespace ConvectionDiffusionPlugin { /////////////////////////////////////////////////////////// // Implementation of the methods class -// 'MovingInterfaceDiffusion' +// 'ImmersedInterfaceDiffusion' /////////////////////////////////////////////////////////// template -MovingInterfaceDiffusion::MovingInterfaceDiffusion( +ImmersedInterfaceDiffusion::ImmersedInterfaceDiffusion( SmartPtr > ass, SmartPtr > spMaster, SmartPtr > interfaceProvider, - SmartPtr > cutElementHandler) : - m_spInterfaceHandlerLocal(new InterfaceHandlerLocalDiffusion(interfaceProvider, cutElementHandler)), + SmartPtr > cutElementHandler) : m_spInterfaceProvider(interfaceProvider), m_spCutElementHandler(cutElementHandler), + m_spInterfaceHandlerLocal(new InterfaceHandlerLocalDiffusion(interfaceProvider, cutElementHandler)), m_spInterfaceMapper(new DiffusionInterfaceMapper (m_spInterfaceHandlerLocal)) { if (interfaceProvider->num_particles() == 0) - UG_THROW("MovingInterfaceDiffusion::Constructor(): no particles initializen in 'globalHandler\n"); + UG_THROW("ImmersedInterfaceDiffusion::Constructor(): no particles initializen in 'globalHandler\n"); - // initialize singleton and set local handler +// initialize singleton and set local handler typedef DimFV1CutGeometry > TFVGeom; TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); geo.set_interface_handler(m_spInterfaceHandlerLocal); - // initialize mapper within domainDisc: +// initialize mapper within domainDisc: SmartPtr > assAdapt = ass->ass_tuner(); assAdapt->set_mapping(m_spInterfaceMapper.get()); +// needs to be enabled, in order to call 'spAssTuner->modify_LocalData()' during element disc assembling assAdapt->enable_modify_solution(true); - // => assTuner->modify_LocSol() = mapper->modify_LocSol() - // see: ass_tuner.h: 114 } + +template +void ImmersedInterfaceDiffusion:: +init(vector_type& u, SmartPtr > spApproxSpace, const int baseLevel, + const int topLevel, bool bScaleDoFs) +{ + // get data + m_spApproxSpace = spApproxSpace; + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + + // get the level Index ONLY for the toplevel in order to resize the data for the toplevel + // --> not implemented for multigrid already! + const int levIndex = m_spCutElementHandler->get_Index(topLevel, dd); + + // initialize the orientation of the interface: = 1, i.e. inside the circle line is outside the domain + m_spCutElementHandler->set_orientation(1); + +// call of 'update_interface_data()' (via init() of CutElementHandler): +// sets the marker (INSIDE, OUTSIDE, CUT_BY_INTERFACE) to each element +// and fills the lists of cut elements + m_spCutElementHandler->template init(dd, baseLevel, topLevel); + +// store the number of regular DoFs (u.size()) and additional DoFs on the immersed interface: + size_t numDoFs = u.size(); + size_t num_newDoFs = m_spCutElementHandler->get_numCutElements(levIndex); + m_spInterfaceMapper->set_numDoFs(numDoFs); + m_spInterfaceMapper->set_numNewDoFs(num_newDoFs); + + + if ( m_spInterfaceHandlerLocal->get_Nitsche() ) + { + initialize_interface_Nitsche(u, dd); + const size_t num_NitscheDoFs = m_spInterfaceHandlerLocal->get_num_NitscheDoFs(); + + num_newDoFs = num_NitscheDoFs; + m_spInterfaceMapper->set_numNewDoFs(num_newDoFs); + + } + +// initialize the scaling of new DoFs: *2 for jumping values (strong discontinuity) at interface +// => 1 DoFs is defined for the solution on each side of the interface +// values for new DoFs are set to 0.0 by the 'resize()'-method (see vector.h): + if ( bScaleDoFs ) u.resize(numDoFs + 2*num_newDoFs); + else u.resize(numDoFs + num_newDoFs); + + m_spInterfaceMapper->set_bScaleDoFs(bScaleDoFs); + m_spInterfaceHandlerLocal->set_bScaleDoFs(bScaleDoFs); + +// initialize the value for the l2 error computaton + m_spInterfaceHandlerLocal->L2Error_init(); + +} + template -double MovingInterfaceDiffusion:: +void ImmersedInterfaceDiffusion:: +update(vector_type& u, SmartPtr > spApproxSpace, + const int baseLevel, const int topLevel, const number time) +{ +// get data + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + int topLev = spApproxSpace->num_levels()-1; + if ( topLev != topLevel ) + UG_THROW("update: parameter 'topLevel' = " << topLevel << " != " + << topLev << "current top leven! \n"); + +// update data: update BoolMarker and cut element lists + m_spCutElementHandler->template init(dd, baseLevel, topLevel); + +} + +template +double ImmersedInterfaceDiffusion:: compute_solution_value(const MathVector& vrtPos) { double kappa_1 = 1.0; @@ -65,15 +134,13 @@ compute_solution_value(const MathVector& vrtPos) double dist = sqrt(sqDist); if ( dist > 0.4 ) - { value = -2*kappa_2*sqDist*sqDist; - UG_LOG("value = " << value << "\n"); - } + return value; } template -void MovingInterfaceDiffusion:: +void ImmersedInterfaceDiffusion:: set_analytic_solution(vector_type& u, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel) { ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); @@ -82,7 +149,6 @@ set_analytic_solution(vector_type& u, SmartPtr > spA typedef Attachment position_attachment_type; typedef Grid::VertexAttachmentAccessor position_accessor_type; - //SmartPtr m_spMG = mg.operator->(); position_attachment_type m_aPos = GetDefaultPositionAttachment(); position_accessor_type m_aaPos; @@ -110,8 +176,6 @@ set_analytic_solution(vector_type& u, SmartPtr > spA // loop vertices for(size_t i = 0; i < elem->num_vertices(); ++i) { - // get vertex - Vertex* vrt = elem->vertex(i); double value = compute_solution_value(vCornerCoords[i]); DoFRef(u, ind[i]) = value; } @@ -120,84 +184,73 @@ set_analytic_solution(vector_type& u, SmartPtr > spA } template -void MovingInterfaceDiffusion:: -adjust_for_error(vector_type& u, vector_type& uCopy, SmartPtr > spApproxSpace, SmartPtr mg, const int topLevel) +void ImmersedInterfaceDiffusion:: +adjust_for_error(vector_type& u, vector_type& uCopy, SmartPtr > spApproxSpace, + SmartPtr mg, const int topLevel) { - - - size_t numDoFs = u.size(); - UG_LOG("domain disc: numDoFs = " << numDoFs << "\n"); - size_t numDoFsCopy = uCopy.size(); - UG_LOG("domain disc: numDoFsCopy = " << numDoFsCopy << "\n"); - +// (1) remove additional nodes ON the interface, not lying on the original grid +// --> resize vector 'u' to original size, i.e. decrease size + size_t numDoFsCopy = uCopy.size(); + u.resize(numDoFsCopy); - numDoFs = u.size(); - UG_LOG("**domain disc: numDoFs = " << numDoFs << "\n"); - - - - ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); +// get data typedef MathVector position_type; typedef Attachment position_attachment_type; typedef Grid::VertexAttachmentAccessor position_accessor_type; - //SmartPtr m_spMG = mg.operator->(); - position_attachment_type m_aPos = GetDefaultPositionAttachment(); + position_attachment_type m_aPos = GetDefaultPositionAttachment(); position_accessor_type m_aaPos; - if(!mg->has_attachment(m_aPos)) - mg->attach_to(m_aPos); + if(!mg->has_attachment(m_aPos)) mg->attach_to(m_aPos); m_aaPos.access(*mg, m_aPos); - typedef typename domain_traits::grid_base_object grid_base_object; + ConstSmartPtr dd = spApproxSpace->dof_distribution(GridLevel(topLevel, GridLevel::LEVEL)); + typedef typename domain_traits::grid_base_object grid_base_object; typename DoFDistribution::traits::const_iterator iter, iterEnd; iter = dd->template begin(); iterEnd = dd->template end(); - // loop elements in order to compute the volume and set rhs: +// (2) set solution to zero in near-interface nodes +// --> loop elements in order to set solution to zero on cut element nodes of vector 'u': for( ; iter != iterEnd; iter++) { // get element grid_base_object* elem = *iter; - ElementModus elemModus = m_spInterfaceHandlerLocal->compute_element_modus(elem, 1); - bool do_adjust = false; + ElementModus elemModus = m_spInterfaceHandlerLocal->compute_element_modus(elem); + // choose only cut elements for adjustment + bool do_adjust = false; switch(elemModus) { - case INSIDE_DOM: break; - case OUTSIDE_DOM: break; + case INSIDE_DOM: break; + case OUTSIDE_DOM: break; - case CUT_BY_INTERFACE: do_adjust = true; break; + case CUT_BY_INTERFACE: do_adjust = true; + break; default: throw(UGError("Error in InterfaceHandlerLocalDiffusion::update(): switch(m_elemModus)!")); } + + if ( !do_adjust ) continue; - - std::vector > vCornerCoords; - CollectCornerCoordinates(vCornerCoords, *elem, m_aaPos); - + // get local indices std::vector ind; dd->dof_indices(elem, 0, ind); - - // loop vertices + + // loop vertices and set solution to zero for(size_t i = 0; i < elem->num_vertices(); ++i) - { - // get vertex - Vertex* vrt = elem->vertex(i); - - if (do_adjust) DoFRef(u, ind[i]) = 0.0; - } + DoFRef(u, ind[i]) = 0.0; } } template -const size_t MovingInterfaceDiffusion:: +const size_t ImmersedInterfaceDiffusion:: initialize_interface_Nitsche(vector_type& u, ConstSmartPtr dd) { m_spInterfaceHandlerLocal->m_MapInserted_Nitsche.clear(); @@ -216,7 +269,7 @@ initialize_interface_Nitsche(vector_type& u, ConstSmartPtr dd) // get element grid_base_object* elem = *iter; - ElementModus elemModus = m_spCutElementHandler->compute_element_modus(elem, 1); + ElementModus elemModus = m_spCutElementHandler->compute_element_modus(elem); if ( elemModus == CUT_BY_INTERFACE ) { @@ -237,37 +290,9 @@ initialize_interface_Nitsche(vector_type& u, ConstSmartPtr dd) } -template -const size_t MovingInterfaceDiffusion:: -initialize_interface(vector_type& u, ConstSmartPtr dd) -{ - typedef typename domain_traits::grid_base_object grid_base_object; - - typename DoFDistribution::traits::const_iterator iter, iterEnd; - iter = dd->template begin(); - iterEnd = dd->template end(); - - size_t num_cutElements = 0; - - // loop elements in order to compute the volume and set rhs: - for( ; iter != iterEnd; iter++) - { - // get element - grid_base_object* elem = *iter; - - ElementModus elemModus = m_spCutElementHandler->compute_element_modus(elem, 1); - - if ( elemModus == CUT_BY_INTERFACE ) - num_cutElements += 1; - - } - - return num_cutElements; - -} template -number MovingInterfaceDiffusion:: +number ImmersedInterfaceDiffusion:: MeanElementDiameter(TDomain& domain, int level) { typedef typename domain_traits::grid_base_object TElem; @@ -287,22 +312,21 @@ MeanElementDiameter(TDomain& domain, int level) mean = mean / numIter; #ifdef UG_PARALLEL - // share value between all procs +// share value between all procs pcl::ProcessCommunicator com; - // ToDO: PCL_RO_MIN oder MAX oder doch mean noch berechnen m.H.v. /numProcs??? - //UG_THROW("in MeanElementDiameter(): was macht 'allredue' im Parallelen???\n"); +// ToDO: PCL_RO_MIN oder MAX oder doch mean noch berechnen m.H.v. /numProcs??? +//UG_THROW("in MeanElementDiameter(): was macht 'allredue' im Parallelen???\n"); mean = com.allreduce(mean, PCL_RO_MIN); #endif - UG_LOG("nach com.allreduce: mean = " << std::sqrt(mean) << "\n"); return std::sqrt(mean); } template -void MovingInterfaceDiffusion:: +void ImmersedInterfaceDiffusion:: initialize_threshold(TDomain& domain, const int baseLevel, const int topLevel) { - UG_LOG("----------------- START initialize_threshold() ---------------- \n"); + UG_THROW("initialize_threshold(): not tested for diffusion case! \n"); if (baseLevel < 0) UG_THROW( @@ -312,61 +336,20 @@ initialize_threshold(TDomain& domain, const int baseLevel, const int topLevel) "initialize_threshold(): no cast of toplevel from 'int' tp 'size_t' possible! \n"); // compute level-dependent value for threshold: - for (size_t lev = baseLevel; lev <= (size_t) topLevel; ++lev) { - const number maxLength = MaxElementDiameter(domain, lev); + for (size_t lev = baseLevel; lev <= (size_t) topLevel; ++lev) + { + //const number maxLength = MaxElementDiameter(domain, lev); const number meanLength = MeanElementDiameter(domain, lev); - UG_LOG("maxLength = " << maxLength << "\n"); - UG_LOG("meanLength = " << meanLength << "\n"); - UG_LOG("threshold_max = " << maxLength*maxLength << "\n"); - UG_LOG("threshold_mean = " << meanLength*meanLength << "\n"); // set_threshold(lev, meanLength * meanLength); set_threshold(lev, 0.25 * meanLength*meanLength); } - UG_LOG("----------------- END initialize_threshold() ---------------- \n"); } -template -void MovingInterfaceDiffusion:: -update_interface( const int topLevel, number deltaT) -{ - if ( deltaT == 0.0 ) - UG_THROW("InterfaceProvider:update_prtCoords: deltaT = " << deltaT << " => no update necessary!\n"); - -// get level index - const int levIndex = get_Index(GridLevel(topLevel, GridLevel::LEVEL)); - UG_LOG("update_prtCoords() for levIndex = " << levIndex << "\n"); - UG_LOG("update_prtCoords() for deltaT = " << deltaT << "\n"); - -// update center - for (size_t p = 0; p < m_spInterfaceProvider->num_particles(); ++p) - { -#ifdef UG_PARALLEL - std::vector ElemList = m_spCutElementHandler->m_vvvElemListCut[levIndex][p]; -// std::vector ElemList = m_vvvElemListCut[levIndex][p]; - UG_LOG("1_ update_prtCoords() ElemList.size(): " << ElemList.size() << "\n"); - if ( ElemList.size() == 0 ) { - UG_LOG("2_ update_prtCoords() ElemList.size(): " << ElemList.size() << " => skip assembling! \n"); - continue; - } -#endif - - // get data: - MathVector centerNew = m_spInterfaceProvider->get_center(p); - number soution = m_spInterfaceProvider->get_solution(p, 0); - UG_LOG(" solution = " << soution << "\n"); - UG_LOG("deltaT = " << deltaT << "\n"); - -// ToDo: Hier das interface irgendwie updaten?? - - - } // end particle loop - -} } // end namespace ConvectionDiffusionPlugin } // end namespace ug -#endif /* DIFFUSION_INTERFACE_IMPL_H_ */ +#endif /* IMMERSED_INTERFACE_DIFFUSION_IMPL_H_ */ diff --git a/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion.h b/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion.h index 8655399..42c0f6c 100644 --- a/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion.h +++ b/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion.h @@ -36,88 +36,126 @@ class DiffusionInterfaceMapper : public IInterfaceMapper DiffusionInterfaceMapper(){}; DiffusionInterfaceMapper(SmartPtr > localHandler) - : m_spInterfaceHandlerLocal(localHandler), - m_numDoFs(0), + : m_numGridNodes(0), + m_numNewDoFs(0), m_resized(false), m_resized_defect(false), - m_scaleDoFs(false) + m_scaleDoFs(false), + m_spInterfaceHandlerLocal(localHandler) {} virtual ~DiffusionInterfaceMapper() {} - - /// send local entries to global rhs + /////////////////////////////////////////////////////////////////////////////// + /// + /// base class methods not needed for 'DiffusionInterfaceMapper' class + /// + /////////////////////////////////////////////////////////////////////////////// + + /// modifies local solution vector for adapted defect computation + void modify_LocalData(LocalMatrix& locJ, LocalVector& locU, + ConstSmartPtr dd){}; + void modify_LocalData(LocalVectorTimeSeries& uT, LocalMatrix& locJ, LocalVector& locU, + ConstSmartPtr dd){}; + + void modify_LocalData(LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd){}; + void modify_LocalData(LocalVectorTimeSeries& uT, LocalVector& locD, LocalVector& tmpLocD, + LocalVector& locU, ConstSmartPtr dd, size_t t){}; + + /////////////////////////////////////////////////////////////////////////////// + /// + /// base class methods and helper methods called by them + /// + /////////////////////////////////////////////////////////////////////////////// + + /// base method: send local entries to global rhs void add_local_vec_to_global(vector_type& vec, const LocalVector& lvec, ConstSmartPtr dd); + /// methods called by base method for cut element case: special mapping due to new DoFs! void add_local_vec_to_global_interface(vector_type& vec, const LocalVector& lvec, ConstSmartPtr dd); + /// methods called by base method for Nitsche-treatment on cut elements void add_local_vec_to_global_Nitsche(vector_type& vec, const LocalVector& lvec, ConstSmartPtr dd); - /// send local entries to global matrix + /// base method: send local entries to global matrix void add_local_mat_to_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd); + /// methods called by base method for cut element case: special mapping due to new DoFs! void add_local_mat_to_global_interface(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd); void add_local_mat_to_global_Nitsche(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd); - + + /// sets all non-DoFs to identity rows + /// --> or diffusion, iff only INSIDE circle-computation only! ==> all other DoFs set to Dirichlet! void adjust_mat_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd); - /// modifies local solution vector for adapted defect computation - void modify_LocalData(LocalMatrix& locJ, LocalVector& locU, - ConstSmartPtr dd){}; - void modify_LocalData(LocalVectorTimeSeries& uT, LocalMatrix& locJ, LocalVector& locU, - ConstSmartPtr dd){}; - void modify_LocalData(LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, - ConstSmartPtr dd){}; - void modify_LocalData(LocalVectorTimeSeries& uT, LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, - ConstSmartPtr dd, size_t t){}; + /////////////////////////////////////////////////////////////////////////////// + /// REMARK: + /// During DomainDiscretization::assemble_jacobian: + /// calling + /// ---> m_spAssTuner->modify_GlobalSol(pModifyMemory, vSol, dd); + /////////////////////////////////////////////////////////////////////////////// - /// modifies global solution vector for adapted defect computation - void modify_GlobalSol(vector_type& vecMod, const vector_type& vec, + /// instead of modifying global data: the computed values at the interface DoFs get + /// written/stored into data of class 'InterfaceHandlerLocalDiffusion::m_verticesValue' + /// via call of 'set_interface_values()' (for each call of domainDisc, i.e. newton step) + + void modify_GlobalSol(vector_type& vecMod, const vector_type& vec, ConstSmartPtr dd); - void modify_GlobalSol(SmartPtr > vSolMod, + void modify_GlobalSol(SmartPtr > vSolMod, ConstSmartPtr > vSol, ConstSmartPtr dd){}; /////////////////////////////////////////////////////////////// /// new methods: /////////////////////////////////////////////////////////////// - void set_identity_mat_constraint(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd); - - LocalMatrix& get_local_jacobian_tri() - { return m_spInterfaceHandlerLocal->get_local_jacobian_tri(); } - LocalMatrix& get_local_jacobian_quad() - { return m_spInterfaceHandlerLocal->get_local_jacobian_quad(); } - - LocalVector& get_local_defect_tri() - { return m_spInterfaceHandlerLocal->get_local_defect_tri(); } - LocalVector& get_local_defect_quad() - { return m_spInterfaceHandlerLocal->get_local_defect_quad(); } - - void write_solution(const std::vector verticesValues) - { m_spInterfaceHandlerLocal->write_solution(verticesValues); } - - // called during init() of diffusionInterface: - void set_numDoFs(const size_t numDoFs) - { m_numDoFs = numDoFs;} - void set_numNewDoFs(const size_t numNewDoFs) - { m_numNewDoFs = numNewDoFs;} + + /// sets dirichlet rows for non-DoFs (not yet needed here) + void set_identity_mat_constraint(matrix_type& mat, const LocalMatrix& lmat, + ConstSmartPtr dd); + + // access methods to local data stored in class 'InterfaceHandlerLocalDiffusion' + // REMARK: the contribution of the boundary condition on the immersed interface + // were assembled within the ElemDisc 'ConvectionDiffusionFV1_cutElem' + // and stored in 'InterfaceHandlerLocalDiffusion' to access it here for + // performing the local-to-global mapping + LocalMatrix& get_local_jacobian(const ReferenceObjectID roid) + { return m_spInterfaceHandlerLocal->get_local_jacobian(roid); } + LocalVector& get_local_defect(const ReferenceObjectID roid) + { return m_spInterfaceHandlerLocal->get_local_defect(roid); } + + + + // writes the solution in the interface nodes, i.e. the NEW DoFs, + // into data of 'InterfaceHandlerLocalDiffusion' + void set_interface_values(const std::vector verticesValues) + { m_spInterfaceHandlerLocal->set_interface_values(verticesValues); } + + // called during 'InterfaceHandlerLocalDiffusion::init() + void set_numDoFs(const size_t numDoFs) { m_numGridNodes = numDoFs;} + size_t get_numDoFs() { return m_numGridNodes;} + void set_numNewDoFs(const size_t numNewDoFs) { m_numNewDoFs = numNewDoFs;} + + // returns the value, by which the global matrix and vector needs to be resized + // REMARK: for a jump in the solution, 2 new DoFs will be placed for each interface node + const size_t get_resize_measure(const size_t numDoFs); void set_bScaleDoFs(bool bScaleDoF) { m_scaleDoFs = bScaleDoF; } private: - SmartPtr > m_spInterfaceHandlerLocal; - // number of DoFs in global matrix - size_t m_numDoFs; - size_t m_numNewDoFs; + size_t m_numGridNodes; // number of grid nodes, i.e. of DoFs WITHOUT interface nodes + size_t m_numNewDoFs; // number of interface nodes, i.e. additional DoFs bool m_resized; bool m_resized_defect; - bool m_scaleDoFs; + bool m_scaleDoFs; // if m_scaleDoFs = true: 2 new DoFs will be placed for + // each interface node (for jump in value) + SmartPtr > m_spInterfaceHandlerLocal; }; diff --git a/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion_impl.h b/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion_impl.h index afe088a..ae0fd5e 100644 --- a/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion_impl.h +++ b/fv1_cutElem/diffusion_interface/loc_to_glob_mapper_diffusion_impl.h @@ -26,7 +26,8 @@ set_identity_mat_constraint(matrix_type& mat, const LocalMatrix& lmat, ConstSmar const size_t rowIndex = rowInd.index(fct1, dof1); const size_t rowComp = rowInd.comp(fct1, dof1); - if ( fabs(lmat.value(fct1, dof1, fct1, dof1)) < 0.000001 && BlockRef(mat(rowIndex, rowIndex), rowComp, rowComp) == 0.0 ) + if ( fabs(lmat.value(fct1, dof1, fct1, dof1)) < 0.000001 + && BlockRef(mat(rowIndex, rowIndex), rowComp, rowComp) == 0.0 ) BlockRef(mat(rowIndex, rowIndex), rowComp, rowComp) = 1.0; } @@ -39,8 +40,9 @@ adjust_mat_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr:: modify_GlobalSol(vector_type& vecMod, const vector_type& vec, ConstSmartPtr dd) { size_t numDoFs = vecMod.size(); - const size_t numNewDoFs = numDoFs - m_numDoFs; + const size_t numNewDoFs = numDoFs - m_numGridNodes; UG_LOG("---------------modify_GlobalSol--------------\n"); UG_LOG(" vecMod.size(): " << numDoFs << "\n"); - UG_LOG("m_numDoFs: " << m_numDoFs << "\n"); + UG_LOG(" m_numGridNodes: " << m_numGridNodes << "\n"); UG_LOG(" computed numNewDoFs: " << numNewDoFs << "\n"); UG_LOG(" m_numNewDoFs: " << m_numNewDoFs << "\n"); @@ -64,84 +66,71 @@ modify_GlobalSol(vector_type& vecMod, const vector_type& vec, ConstSmartPtr verticesValue; verticesValue.clear(); + // loop all interface nodes, i.e new DoFs, and store the values in + // member 'm_verticesValue' of class 'InterfaceHandlerLocalDiffusion': for (size_t i = 0; i < numNewDoFs; ++i) { - index = DoFIndex(m_numDoFs + i,0); - // if vrt on interface == DoF: get value from vec - // if vrt on interface != DoF: written via 'compute_values()' - double value; - if ( 1 ) - { value = DoFRef(vec, index); } - else - { - value = 0.0; //m_spInterfaceHandlerLocal->compute_value(m_spInterfaceHandlerLocal->m_verticesPos[i]); - } - - verticesValue.push_back(value); + // get GLOBAL index of the interface nodes + index = DoFIndex(m_numGridNodes + i,0); + // write value to local data + verticesValue.push_back(DoFRef(vec, index)); } - // call InterfaceHandlerLocal-method: - // no not doing it! Done locally in add_def: locU_tri and locU_quad: - write_solution(verticesValue); +// write solution values to member 'm_verticesValue' of class 'InterfaceHandlerLocalDiffusion': + set_interface_values(verticesValue); } +template +const size_t DiffusionInterfaceMapper:: +get_resize_measure(const size_t numDoFs) +{ + size_t numAllDoFs = m_numGridNodes + m_numNewDoFs; + + // if m_scaleDoFs = true: 2 new DoFs will be placed for each interface node + if ( m_scaleDoFs ) + numAllDoFs = m_numGridNodes + 2*m_numNewDoFs; + + return numAllDoFs - numDoFs; + +} + template void DiffusionInterfaceMapper:: add_local_mat_to_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) { - const LocalIndices& rowInd = lmat.get_row_indices(); - const LocalIndices& colInd = lmat.get_col_indices(); - - DoFIndex indexRow, indexCol; - - bool print = false; +// reset print modus for cut element data to 'false' +// => only printed during assemling of defect, i.e. ONE loop over all element + m_spInterfaceHandlerLocal->set_print_cutElemData(false); + + size_t numAllDoFs = m_numGridNodes + m_numNewDoFs; // resize global matrix dynamically: - const size_t numDoFs = mat.num_rows(); - - if ( print ) UG_LOG("*** vorher: vec.size(): " << numDoFs << "\n"); - - size_t numAllDoFs = m_numDoFs + m_numNewDoFs; - if ( m_scaleDoFs ) - numAllDoFs = m_numDoFs + 2*m_numNewDoFs; - - const int diffDoFs = numAllDoFs - numDoFs; - -// resize global defect ONCE: + const size_t diffDoFs = get_resize_measure(mat.num_rows()); + +// resize global defect only ONCE: if ( diffDoFs > 0 ) { mat.resize_and_keep_values(numAllDoFs, numAllDoFs); - if ( print ) - { - UG_LOG("*** m_numDoFs: " << m_numDoFs << "\n"); - UG_LOG("*** m_numNewDoFs: " << m_numNewDoFs << "\n"); - UG_LOG("*** numAllDoFs: " << numAllDoFs << "\n"); - UG_LOG("*** nachher: mat.num_rows(): " << mat.num_rows() << "\n"); - } } else if ( diffDoFs == 0 ) - { if ( print ) UG_LOG("no resizing!\n");} + { // no resizing + } else if ( diffDoFs < 0 ) - { - if ( print ) UG_LOG("diffDoFs = " << diffDoFs << "\n"); - UG_THROW("error in add_local_mat_to_global: diffDofs < 0\n"); - } + { UG_THROW("error in add_local_mat_to_global: diffDofs < 0\n"); } ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); switch(modus) { - case OUTSIDE_DOM: + case OUTSIDE_DOM: // call usual local-to-global-mapping AddLocalMatrixToGlobal(mat, lmat); break; - case INSIDE_DOM: + case INSIDE_DOM: // call usual local-to-global-mapping AddLocalMatrixToGlobal(mat, lmat); - //set_identity_mat_constraint(mat, lmat, dd); break; - case CUT_BY_INTERFACE: - //AddLocalMatrixToGlobal(mat, lmat); + case CUT_BY_INTERFACE: // call adapted local-to-global-mapping if ( m_spInterfaceHandlerLocal->get_Nitsche() ) add_local_mat_to_global_Nitsche(mat, lmat, dd); else @@ -159,60 +148,35 @@ template void DiffusionInterfaceMapper:: add_local_vec_to_global(vector_type& vec, const LocalVector& lvec, ConstSmartPtr dd) { - bool print = false; - - const size_t numDoFs = vec.size(); - - if ( print ) UG_LOG("*** vorher: vec.size(): " << numDoFs << "\n"); - - size_t numAllDoFs = m_numDoFs + m_numNewDoFs; - if ( m_scaleDoFs ) - numAllDoFs = m_numDoFs + 2*m_numNewDoFs; - - const int diffDoFs = numAllDoFs - numDoFs; + size_t numAllDoFs = m_numGridNodes + m_numNewDoFs; +// resize global vector dynamically: + const size_t diffDoFs = get_resize_measure(vec.size()); + // resize global defect ONCE: if ( diffDoFs > 0 ) { vec.resize(numAllDoFs, true); vec.set(0.0); -/* - bool bJac = m_spInterfaceHandlerLocal->get_jac_bool(); - if ( !bJac ) - { - // vec.set(0.0); - m_spInterfaceHandlerLocal->set_jac_bool(true); - } -*/ - if ( print ) - { - UG_LOG("*** m_numDoFs: " << m_numDoFs << "\n"); - UG_LOG("*** m_numNewDoFs: " << m_numNewDoFs << "\n"); - UG_LOG("*** numAllDoFs: " << numAllDoFs << "\n"); - UG_LOG("*** nachher: vec.size(): " << vec.size() << "\n"); - } } else if ( diffDoFs == 0 ) - { if ( print ) UG_LOG("no resizing!\n");} + { // no resizing + } else if ( diffDoFs < 0 ) - { - if ( print ) UG_LOG("diffDoFs = " << diffDoFs << "\n"); - UG_THROW("error in add_local_vec_to_global: diffDofs < 0\n"); - } + { UG_THROW("error in add_local_vec_to_global: diffDofs < 0\n"); } ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); switch(modus) { - case OUTSIDE_DOM: + case OUTSIDE_DOM: // call usual local-to-global-mapping AddLocalVector(vec, lvec); break; - case INSIDE_DOM: + case INSIDE_DOM: // call usual local-to-global-mapping AddLocalVector(vec, lvec); break; - case CUT_BY_INTERFACE: - // AddLocalVector(vec, lvec); + case CUT_BY_INTERFACE: // call adapted local-to-global-mapping if ( m_spInterfaceHandlerLocal->get_Nitsche() ) add_local_vec_to_global_Nitsche(vec, lvec, dd); else @@ -228,27 +192,25 @@ template void DiffusionInterfaceMapper:: add_local_mat_to_global_Nitsche(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) { - - UG_LOG("------------------------ START DiffusionInterfaceMapper - Nitsche ------------------------\n"); - const LocalIndices& rowInd = lmat.get_row_indices(); const LocalIndices& colInd = lmat.get_col_indices(); DoFIndex indexRow, indexCol; - /////////////////////////////////////////////////////////////// - /// FIRST: add loc to glob for locJ_tri: - /////////////////////////////////////////////////////////////// - const LocalMatrix& locJ_tri = get_local_jacobian_tri(); +/////////////////////////////////////////////////////////////// +/// FIRST: add loc to glob for locJ_tri: +/////////////////////////////////////////////////////////////// + + LocalMatrix locJ_tri = get_local_jacobian(ROID_TRIANGLE); const bool shift_global_index_tri = m_spInterfaceHandlerLocal->get_index_shift_tri(); if ( lmat.num_all_row_dof(0) != locJ_tri.num_all_row_dof(0) ) UG_THROW("in 'add_local_mat_to_global_Nitsche': non-consistent sizees!\n"); - size_t numAllDoFs = m_numDoFs; + size_t numAllDoFs = m_numGridNodes; if ( shift_global_index_tri ) - numAllDoFs = m_numDoFs + m_numNewDoFs; + numAllDoFs = m_numGridNodes + m_numNewDoFs; for (size_t dof1 = 0; dof1 < locJ_tri.num_all_row_dof(0); ++dof1) { @@ -276,23 +238,14 @@ add_local_mat_to_global_Nitsche(matrix_type& mat, const LocalMatrix& lmat, Const } } - indexRow = DoFIndex(3, 0); - indexCol = DoFIndex(0, 0); - number value = DoFRef(mat, indexRow, indexCol); - - if ( DoFRef(mat, indexRow, indexCol) > 0 ) - UG_LOG("waiting...\n"); - UG_LOG("value: " << value << "\n"); - - - /////////////////////////////////////////////////////////////// - /// SECOND: add loc to glob for locJ_tri: - /// -> same as FIRST, but: - /// (1) lmat instead of locJ_tri - /// (2) if ( !m_spInterfaceHandlerLocal->lies_onInterface(dof) ) - /// instead of - /// if ( m_spInterfaceHandlerLocal->lies_onInterface(dof) ) - /////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// +/// SECOND: add loc to glob for locJ_tri: +/// -> same as FIRST, but: +/// (1) lmat instead of locJ_tri +/// (2) if ( !m_spInterfaceHandlerLocal->lies_onInterface(dof) ) +/// instead of +/// if ( m_spInterfaceHandlerLocal->lies_onInterface(dof) ) +/////////////////////////////////////////////////////////////// for (size_t dof1 = 0; dof1 < lmat.num_all_row_dof(0); ++dof1) { @@ -331,42 +284,42 @@ template void DiffusionInterfaceMapper:: add_local_mat_to_global_interface(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) { - // UG_LOG("------------------------ START DiffusionInterfaceMapper ------------------------\n"); - const LocalIndices& rowInd = lmat.get_row_indices(); const LocalIndices& colInd = lmat.get_col_indices(); DoFIndex indexRow, indexCol; - /////////////////////////////////////////////////////////////// - /// FIRST: add loc to glob for locJ_tri: - /////////////////////////////////////////////////////////////// - const LocalMatrix& locJ_tri = get_local_jacobian_tri(); +///////////////////////////////////////////////////////////////////////////////// +/// FIRST: add the boundary contribution stored in 'locJ_tri' to global matrix: +///////////////////////////////////////////////////////////////////////////////// + + LocalMatrix locJ_tri = get_local_jacobian(ROID_TRIANGLE); const bool shift_global_index_tri = m_spInterfaceHandlerLocal->get_index_shift_tri(); - size_t numAllDoFs = m_numDoFs; + size_t numAllDoFs = m_numGridNodes; if ( shift_global_index_tri ) - numAllDoFs = m_numDoFs + m_numNewDoFs; - -// UG_LOG("in DiffusionInterfaceMapper::add_loc_mat(): locJ_tri = " << locJ_tri << "\n"); - + numAllDoFs = m_numGridNodes + m_numNewDoFs; +// loop all entries for mapping for (size_t dof1 = 0; dof1 < locJ_tri.num_all_row_dof(0); ++dof1) { + // get the real index: this data was stored in 'InterfaceHandlerDiffusion::m_vRealCornerID_' + // case1: node lies on interface => real_dof = entry within map 'InterfaceHandlerDiffusion::m_MapNearVertices' + // case2: node lies on an original mesh node: => real_dof = usual, local index of vertex const size_t dof1_real = m_spInterfaceHandlerLocal->real_index_tri(dof1); - // if dof1_real is index of m_vertex: compute global index: + // case1: dof1_real is index of m_vertex (i.e. interface-DoF): compute global index: if ( m_spInterfaceHandlerLocal->lies_onInterface_tri(dof1) ) indexRow = DoFIndex(numAllDoFs + dof1_real, 0); - else + else // case2: use dof1_real as local index indexRow = DoFIndex(rowInd.index(0, dof1_real), rowInd.comp(0, dof1_real)); for (size_t dof2 = 0; dof2 < locJ_tri.num_all_col_dof(0); ++dof2) { const size_t dof2_real = m_spInterfaceHandlerLocal->real_index_tri(dof2); - // if dof1_real is index of m_vertex: compute global index: + // if dof1_real is index of m_vertex (i.e. interface-DoF): compute global index: if ( m_spInterfaceHandlerLocal->lies_onInterface_tri(dof2) ) indexCol = DoFIndex(numAllDoFs + dof2_real, 0); else @@ -374,34 +327,30 @@ add_local_mat_to_global_interface(matrix_type& mat, const LocalMatrix& lmat, Con // finally add loc to glob: DoFRef(mat, indexRow, indexCol) += locJ_tri.value(0, dof1, 0, dof2); - - if ( indexRow[0] == 0 || indexRow[0] == 30 ){ - UG_LOG("------------------------ tri: += " << locJ_tri.value(0, dof1, 0, dof2) << "\n"); - UG_LOG("(indexRow, indexCol) = " << indexRow[0] << "," << indexCol[0] << "\n"); - } } } - /////////////////////////////////////////////////////////////// - /// SECOND: add loc to glob for locJ_tri: - /////////////////////////////////////////////////////////////// - const LocalMatrix& locJ_quad = get_local_jacobian_quad(); +//////////////////////////////////////////////////////////////////////////////////// +/// SECOND: add the boundary contribution stored in 'locJ_quad' to global matrix: +//////////////////////////////////////////////////////////////////////////////////// + + LocalMatrix locJ_quad = get_local_jacobian(ROID_QUADRILATERAL); const bool shift_global_index_quad = m_spInterfaceHandlerLocal->get_index_shift_quad(); - // reset numAllDoFs! - numAllDoFs = m_numDoFs; +// reset numAllDoFs! + numAllDoFs = m_numGridNodes; if ( shift_global_index_quad ) - numAllDoFs = m_numDoFs + m_numNewDoFs; - -// UG_LOG("in DiffusionInterfaceMapper::add_loc_mat(): locJ_quad = " << locJ_quad << "\n"); + numAllDoFs = m_numGridNodes + m_numNewDoFs; +// loop all entries for mapping for (size_t dof1 = 0; dof1 < locJ_quad.num_all_row_dof(0); ++dof1) { size_t dof1_real = m_spInterfaceHandlerLocal->real_index_quad(dof1); - // if dof1_real is index of m_vertex: compute global index: - if ( m_spInterfaceHandlerLocal->lies_onInterface_quad(dof1) && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof1, -1) ) + // if dof1_real is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface_quad(dof1) + && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof1, -1) ) indexRow = DoFIndex(numAllDoFs + dof1_real, 0); else indexRow = DoFIndex(rowInd.index(0, dof1_real), rowInd.comp(0, dof1_real)); @@ -410,8 +359,9 @@ add_local_mat_to_global_interface(matrix_type& mat, const LocalMatrix& lmat, Con { size_t dof2_real = m_spInterfaceHandlerLocal->real_index_quad(dof2); - // if dof1_real is index of m_vertex: compute global index: - if ( m_spInterfaceHandlerLocal->lies_onInterface_quad(dof2) && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof2, -1) ) + // if dof1_real is index of m_vertex: compute global index: + if ( m_spInterfaceHandlerLocal->lies_onInterface_quad(dof2) + && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof2, -1) ) indexCol = DoFIndex(numAllDoFs + dof2_real, 0); else indexCol = DoFIndex(colInd.index(0, dof2_real), colInd.comp(0, dof2_real)); @@ -419,15 +369,9 @@ add_local_mat_to_global_interface(matrix_type& mat, const LocalMatrix& lmat, Con // finally add loc to glob: DoFRef(mat, indexRow, indexCol) += locJ_quad.value(0, dof1, 0, dof2); - if ( indexRow[0] == 0 || indexRow[0] == 30){ - UG_LOG("------------------------ quad: += " << locJ_quad.value(0, dof1, 0, dof2) << "\n"); - UG_LOG("(indexRow, indexCol) = " << indexRow[0] << "," << indexCol[0] << "\n"); - } } } - //UG_LOG("------------------------ END DiffusionInterfaceMapper ------------------------\n"); - } @@ -441,16 +385,16 @@ add_local_vec_to_global_Nitsche(vector_type& vec, const LocalVector& lvec, Const /////////////////////////////////////////////////////////////// /// FIRST: add loc to glob for 'locD_tri': /////////////////////////////////////////////////////////////// - const LocalVector& locD_tri = get_local_defect_tri(); + LocalVector locD_tri = get_local_defect(ROID_TRIANGLE); const bool shift_global_index_tri = m_spInterfaceHandlerLocal->get_index_shift_tri(); if ( lvec.num_all_dof(0) != locD_tri.num_all_dof(0) ) UG_THROW("in 'add_local_vec_to_global_Nitsche': non-consistent sizees!\n"); - size_t numAllDoFs = m_numDoFs; + size_t numAllDoFs = m_numGridNodes; if ( shift_global_index_tri ) - { numAllDoFs = m_numDoFs + m_numNewDoFs; + { numAllDoFs = m_numGridNodes + m_numNewDoFs; } for (size_t dof = 0; dof < locD_tri.num_all_dof(0); ++dof) @@ -499,34 +443,29 @@ template void DiffusionInterfaceMapper:: add_local_vec_to_global_interface(vector_type& vec, const LocalVector& lvec, ConstSmartPtr dd) { - - bool print = false; DoFIndex index_print; const LocalIndices& ind = lvec.get_indices(); DoFIndex index; - /////////////////////////////////////////////////////////////// - /// FIRST: add loc to glob for locD_tri: - /////////////////////////////////////////////////////////////// - const LocalVector& locD_tri = get_local_defect_tri(); +/////////////////////////////////////////////////////////////////////////////////// +/// FIRST: add the boundary contribution stored in 'locD_tri' to global defect: +/////////////////////////////////////////////////////////////////////////////////// + + LocalVector locD_tri = get_local_defect(ROID_TRIANGLE); const bool shift_global_index_tri = m_spInterfaceHandlerLocal->get_index_shift_tri(); - size_t numAllDoFs = m_numDoFs; + size_t numAllDoFs = m_numGridNodes; if ( shift_global_index_tri ) - { numAllDoFs = m_numDoFs + m_numNewDoFs; - UG_LOG("it is shifted!\n"); - } + numAllDoFs = m_numGridNodes + m_numNewDoFs; + // UG_LOG("in DiffusionInterfaceMapper::add_loc_vec(): locD_tri = " << locD_tri << "\n"); for (size_t dof = 0; dof < locD_tri.num_all_dof(0); ++dof) { const size_t dof_real = m_spInterfaceHandlerLocal->real_index_tri(dof); - if ( (numAllDoFs + dof_real) > 352 ) - { print = true;index_print = DoFIndex(numAllDoFs + dof_real,0);} - // if dof_real is index of m_vertex: compute global index: if ( m_spInterfaceHandlerLocal->lies_onInterface_tri(dof) && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof, 1) ) index = DoFIndex(numAllDoFs + dof_real,0); @@ -539,17 +478,18 @@ add_local_vec_to_global_interface(vector_type& vec, const LocalVector& lvec, Con } - /////////////////////////////////////////////////////////////// - /// SECOND: add loc to glob for locU_quad: - /////////////////////////////////////////////////////////////// - const LocalVector& locD_quad = get_local_defect_quad(); +///////////////////////////////////////////////////////////////////////////////// +/// SECOND: add the boundary contribution stored in 'locD_quad' to global defect: +///////////////////////////////////////////////////////////////////////////////// + + LocalVector locD_quad = get_local_defect(ROID_QUADRILATERAL); const bool shift_global_index_quad = m_spInterfaceHandlerLocal->get_index_shift_quad(); // reset numAllDoFs! - numAllDoFs = m_numDoFs; + numAllDoFs = m_numGridNodes; if ( shift_global_index_quad ) - numAllDoFs = m_numDoFs + m_numNewDoFs; + numAllDoFs = m_numGridNodes + m_numNewDoFs; // UG_LOG("in DiffusionInterfaceMapper::add_loc_vec(): locD_quad = " << locD_quad << "\n"); @@ -557,11 +497,9 @@ add_local_vec_to_global_interface(vector_type& vec, const LocalVector& lvec, Con { size_t dof_real = m_spInterfaceHandlerLocal->real_index_quad(dof); - if ( (numAllDoFs + dof_real) > 352 ) - { print = true;index_print = DoFIndex(numAllDoFs + dof_real,0);} - // if dof_real is index of m_vertex: compute global index: - if ( m_spInterfaceHandlerLocal->lies_onInterface_quad(dof) && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof, 1) ) + if ( m_spInterfaceHandlerLocal->lies_onInterface_quad(dof) + && !m_spInterfaceHandlerLocal->check_vertex_modus(ON_INTERFACE, dof, 1) ) index = DoFIndex(numAllDoFs + dof_real,0); else index = DoFIndex(ind.index(0, dof_real), ind.comp(0, dof_real)); From 05f101e7088fec3e92843611c7de9b1941438129 Mon Sep 17 00:00:00 2001 From: Susanne Date: Wed, 25 Sep 2019 15:49:15 +0200 Subject: [PATCH 3/3] deleted old files of fv1_cutElem feature --- .../convection_diffusion_fv1_Nitsche_Juli.cpp | 2165 --------------- .../convection_diffusion_fv1_Nitsche_Juli.h | 326 --- .../convection_diffusion_fv1_last.cpp | 2377 ----------------- .../convection_diffusion_fv1_last.h | 325 --- .../convection_diffusion_fv1_mitJump.cpp | 1828 ------------- .../convection_diffusion_fv1_mitJump.h | 316 --- 6 files changed, 7337 deletions(-) delete mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.cpp delete mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.h delete mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.cpp delete mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.h delete mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.cpp delete mode 100644 fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.h diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.cpp b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.cpp deleted file mode 100644 index 115d1d7..0000000 --- a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.cpp +++ /dev/null @@ -1,2165 +0,0 @@ -/* - * convection_diffusion_fv1.cpp - * - * Created on: 26.02.2010 - * Author: andreasvogel - */ - -#include "convection_diffusion_fv1.h" - -#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" - -#include "lib_disc/spatial_disc/disc_util/geom_provider.h" -//#include "lib_disc/spatial_disc/disc_util/fv1_geom.h" -//#include "lib_disc/spatial_disc/disc_util/hfv1_geom.h" -#include "lib_disc/spatial_disc/disc_util/conv_shape.h" - -namespace ug{ -namespace ConvectionDiffusionPlugin{ - -//////////////////////////////////////////////////////////////////////////////// -// general -//////////////////////////////////////////////////////////////////////////////// - -template -ConvectionDiffusionFV1:: -ConvectionDiffusionFV1(const char* functions, const char* subsets) - : ConvectionDiffusionBase(functions,subsets), - m_spConvShape(new ConvectionShapesNoUpwind), - m_bNonRegularGrid(false) -{ - register_all_funcs(m_bNonRegularGrid); -} - - -template -void ConvectionDiffusionFV1:: -prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid) -{ -// check number - if(vLfeID.size() != 1) - UG_THROW("ConvectionDiffusion: Wrong number of functions given. " - "Need exactly "<<1); - - if(vLfeID[0].order() != 1 || vLfeID[0].type() != LFEID::LAGRANGE) - UG_THROW("ConvectionDiffusion FV Scheme only implemented for 1st order."); - -// remember - m_bNonRegularGrid = bNonRegularGrid; - - m_LFEID = vLfeID[0]; - -// update assemble functions - register_all_funcs(m_bNonRegularGrid); -} - -template -bool ConvectionDiffusionFV1:: -use_hanging() const -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// Assembling functions -//////////////////////////////////////////////////////////////////////////////// - -template -template -void ConvectionDiffusionFV1:: -prep_elem_loop(const ReferenceObjectID roid, const int si) -{ - // Only first order implementation - if(!(TFVGeom::order == 1)) - UG_THROW("Only first order implementation, but other Finite Volume" - " Geometry set."); - -// check, that upwind has been set - if(m_spConvShape.invalid()) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Upwind has not been set."); - -// set local positions - if(!TFVGeom::usesHangingNodes && TFVGeom::staticLocalData) - { - static const int refDim = TElem::dim; - TFVGeom& geo = GeomProvider::get(); -// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); - const MathVector* vSCVFip = geo.scvf_local_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_local_ips(); - const size_t numSCVip = geo.num_scv_ips(); - m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip, false); - m_imVelocity.template set_local_ips(vSCVFip,numSCVFip, false); - m_imFlux.template set_local_ips(vSCVFip,numSCVFip, false); - m_imSource.template set_local_ips(vSCVip,numSCVip, false); - m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip, false); - m_imReactionRate.template set_local_ips(vSCVip,numSCVip, false); - m_imReaction.template set_local_ips(vSCVip,numSCVip, false); - m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imReactionExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imSourceExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imMassScale.template set_local_ips(vSCVip,numSCVip, false); - m_imMass.template set_local_ips(vSCVip,numSCVip, false); - - // init upwind for element type - if(!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Cannot init upwind for element type."); - } -} - -template -template -void ConvectionDiffusionFV1:: -fsh_elem_loop() -{} - -template -template -void ConvectionDiffusionFV1:: -prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) -{ -// Update Geometry for this element - //static TFVGeom& geo = GeomProvider::get(); -// TFVGeom& geo = GeomProvider::get(m_LFEID,1); - TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); - -// TFVGeom& geo = GeomProvider::get(); -// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); - - // fix: set orientation initially globally! - geo.set_orientation(-1); - - try{ - geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::prep_elem:" - " Cannot update Finite Volume Geometry."); -// set local positions - if(TFVGeom::usesHangingNodes || !TFVGeom::staticLocalData) - { - const int refDim = TElem::dim; - const MathVector* vSCVFip = geo.scvf_local_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_local_ips(); - const size_t numSCVip = geo.num_scv_ips(); - m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip); - m_imVelocity.template set_local_ips(vSCVFip,numSCVFip); - m_imFlux.template set_local_ips(vSCVFip,numSCVFip); - m_imSource.template set_local_ips(vSCVip,numSCVip); - m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip); - m_imReactionRate.template set_local_ips(vSCVip,numSCVip); - m_imReaction.template set_local_ips(vSCVip,numSCVip); - m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip); - m_imReactionExpl.template set_local_ips(vSCVip,numSCVip); - m_imSourceExpl.template set_local_ips(vSCVip,numSCVip); - m_imMassScale.template set_local_ips(vSCVip,numSCVip); - m_imMass.template set_local_ips(vSCVip,numSCVip); -/* - if(m_spConvShape.valid()) - if(!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Cannot init upwind for element type."); - */ - } - - // set global positions - const MathVector* vSCVFip = geo.scvf_global_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_global_ips(); - const size_t numSCVip = geo.num_scv_ips(); - - m_imDiffusion. set_global_ips(vSCVFip, numSCVFip); - m_imVelocity. set_global_ips(vSCVFip, numSCVFip); - m_imFlux. set_global_ips(vSCVFip, numSCVFip); - m_imSource. set_global_ips(vSCVip, numSCVip); - m_imVectorSource. set_global_ips(vSCVFip, numSCVFip); - m_imReactionRate. set_global_ips(vSCVip, numSCVip); - m_imReactionRateExpl. set_global_ips(vSCVip, numSCVip); - m_imReactionExpl. set_global_ips(vSCVip, numSCVip); - m_imSourceExpl. set_global_ips(vSCVip, numSCVip); - m_imReaction. set_global_ips(vSCVip, numSCVip); - m_imMassScale. set_global_ips(vSCVip, numSCVip); - m_imMass. set_global_ips(vSCVip, numSCVip); - -} - - -template -static TVector CalculateCenter(GridObject* o, const TVector* coords) -{ - TVector v; - VecSet(v, 0); - - size_t numCoords = 0; - switch(o->base_object_id()){ - case VERTEX: numCoords = 1; break; - case EDGE: numCoords = static_cast(o)->num_vertices(); break; - case FACE: numCoords = static_cast(o)->num_vertices(); break; - case VOLUME: numCoords = static_cast(o)->num_vertices(); break; - default: UG_THROW("Unknown element type."); break; - } - - for(size_t i = 0; i < numCoords; ++i) - VecAdd(v, v, coords[i]); - - if(numCoords > 0) - VecScale(v, v, 1. / (number)numCoords); - - return v; -} - -void LU(MathMatrix<3, 3>& R, MathMatrix<3, 3>& L, MathMatrix<3, 3> A) -{ - // n-1 Iterationsschritte - for ( size_t i = 1; i < 2; ++i) - { - for ( size_t k = i+1; i < 3; ++i) - { - L[k][i] = R[k][i] / R[i][i]; - - for ( size_t j = i; i < 3; ++i) - R[k][j] = R[k][j] - L[k][i] * R[i][j]; - } - } - -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - - bool debug = false; - bool boundary = false; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); - TFVGeom& geo = GeomProvider::get(m_LFEID,1); - bool bElementIsCut = geo.get_element_modus(); - - // First call with orientation = 1: - int orientation = 1; - geo.set_orientation(orientation); - - if ( !bElementIsCut ) - { - this->template add_jac_A_elem_local (geo, J, u, elem, vCornerCoords, bElementIsCut); - return; - } - - this->template add_jac_A_elem_local (geo, J, u, elem, vCornerCoords, bElementIsCut); - -// get data: - geo.resize_local_data(u); - LocalMatrix& locJ_tri = geo.get_jacobian_tri(); - - LocalVector& locU_tri = geo.get_solution_tri(); - -// reset data: - locJ_tri = 0; - - orientation *= -1; - geo.set_orientation(orientation); - try{ - geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" - " Cannot update Finite Volume Geometry."); - - this->template add_jac_A_elem_local (geo, locJ_tri, u, elem, vCornerCoords, bElementIsCut); - -// locJ_tri = 0; - - geo.set_jacobian_tri(locJ_tri); - -} - - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsCut) -{ - ug::MathMatrix diffusion = m_imDiffusion[0]; - diffusion *= 1.0; - - number areaElem = 0.0; - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - areaElem += geo.scv(ip).volume(); - - number areaScale = 1.0; - - if ( bElementIsCut ) - { - areaScale = geo.Area()/areaElem; - - UG_LOG("check area: areaElem = " << areaElem << " geo.AreaOrig() = " << geo.AreaOrig() << "\n"); - - if ( fabs(areaScale - geo.AreaScale()) > 0.00001 ) - UG_THROW("error for area: areaScale = " << areaScale << " geo.AreaScale() = " << geo.AreaScale() << "\n"); - } - - //areaScale = 1.0; - - const number kappa_1 = areaScale; - const number alpha_1 = 1.0; - const number scaleFactor = alpha_1 * kappa_1; - -// Diff. Tensor times Gradient - MathVector Dgrad; - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// Diffusion and Velocity Term - if(m_imDiffusion.data_given() || m_imVelocity.data_given()) - { - // loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCV - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - //////////////////////////////////////////////////// - // Diffusive Term - //////////////////////////////////////////////////// - if(m_imDiffusion.data_given()) - { - number add = 0.0; - - // loop shape functions - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - { - // Compute Diffusion Tensor times Gradient - MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); - - // Compute flux at IP - const number D_diff_flux = VecDot(Dgrad, scvf.normal()); - - UG_LOG("sh = " << sh << " D_diff_flux = " << D_diff_flux << "\n"); - - J(_C_, scvf.from(), _C_, sh) -= areaScale * D_diff_flux; - J(_C_, scvf.to() , _C_, sh) += areaScale * D_diff_flux; - } - - } - - } // end ip-loop - - //////////////////////////////////////////////////// - // Boundary Terms - //////////////////////////////////////////////////// - - if ( bElementIsCut ) - { - // loop trial space - MathVector NormalToFace = geo.NormalToFace(); - - const typename TFVGeom::SCVF& scvf = geo.scvf(0); - for(size_t j = 0; j < geo.num_sh(); ++j) - { - // Diffusion - if(m_imDiffusion.data_given()) - MatVecMult(Dgrad, m_imDiffusion[0], scvf.global_grad(j)); - else - VecSet(Dgrad, 0.0); - - // loop test space - for(size_t i = 0; i < geo.num_sh(); ++i) - { - // multiply by integral along Gamma of shape fct \phi_i - number integrand = VecDot(Dgrad, NormalToFace) * geo.IntegralGamma(i); - UG_LOG("geo.IntegralGamma(i): " << geo.IntegralGamma(i) << "\n"); - - // SUBTRACT to local matrix - J(_C_, i, _C_, j) -= scaleFactor * integrand; // = (grad(U), phi_i) - J(_C_, j, _C_, i) -= scaleFactor * integrand; // = (U, grad(phi_j)) - - } // end i-loop - - } // end j-loop - - } - - } - -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - double diffusion = 10.0; - - if ( bElementIsOutside ) - diffusion = 1.0; - - std::vector& vBF = geo.get_boundary_faces(); - - if ( vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - -// loop integration points - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - typename TFVGeom::BF bf = vBF[ip]; - - // loop trial space - for(size_t sh = 0; sh < bf.num_sh(); ++sh) - { - UG_LOG("bf.node_id(): " << bf.node_id() << "\n"); - UG_LOG("bf.global_grad(sh): " << bf.global_grad(sh) << "\n"); - UG_LOG("normal(): " << bf.normal() << "\n"); - - // add to local matrix - J(_C_, bf.node_id(), _C_, sh) += VecDot(bf.global_grad(sh), bf.normal()); - J(_C_, bf.node_id(), _C_, sh) *= diffusion; - } - } - -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - if(!m_imMassScale.data_given()) return; - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local matrix - J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip]; - } - -// m_imMass part does not explicitly depend on associated unknown function -} - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - bool debug = false; - bool boundary = false; - bool add = true; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); - TFVGeom& geo = GeomProvider::get(m_LFEID,1); - bool bElementIsCut = geo.get_element_modus(); - - // First call with orientation = 1: - int orientation = 1; - geo.set_orientation(orientation); - - if ( bElementIsCut ) - { - geo.print_Nitsche_Data(); - - for(size_t i = 0; i < 3; ++i) - { - UG_LOG("vAlpha(i,0): " << geo.vAlpha(i,0) << "\n"); - UG_LOG("vAlpha(i,1): " << geo.vAlpha(i,1) << "\n"); - UG_LOG("Integral(i): " << geo.IntegralGamma(i) << "\n"); - } - - UG_LOG("m_vIntersectionPnts(0): " << geo.vIntersectionPnts(0) << "\n"); - UG_LOG("m_vIntersectionPnts(1): " << geo.vIntersectionPnts(1) << "\n"); - UG_LOG("m_vShapeValues: " << geo.ShapeValues() << "\n"); - UG_LOG("m_NormalToFace: " << geo.NormalToFace() << "\n"); - UG_LOG("m_Gamma: " << geo.Gamma() << "\n"); - UG_LOG("m_Area: " << geo.Area() << "\n"); - } - - if ( !bElementIsCut ) - { - this->template add_def_A_elem_local (geo, d, u, elem, vCornerCoords, bElementIsCut); - return; - } - - this->template add_def_A_elem_local (geo, d, u, elem, vCornerCoords, bElementIsCut); - -// get data: - geo.resize_local_data(u); - LocalVector& locD_tri = geo.get_defect_tri(); - - LocalVector& locU_tri = geo.get_solution_tri(); - -// reset data: - locD_tri = 0; - - orientation*= -1; - geo.set_orientation(orientation); - try{ - geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" - " Cannot update Finite Volume Geometry."); - - this->template add_def_A_elem_local (geo, locD_tri, u, elem, vCornerCoords, bElementIsCut); - - geo.set_defect_tri(locD_tri); - -} - -template -number get_exact_sol_test(MathVector position) -{ - return sin(2*M_PI*position[0]) + sin(2*M_PI*position[1]); -} - -template -number get_exact_sol_Gangl(MathVector position) -{ - double kappa_2 = 10.0; - double dist_x = position[0] - 0.1; - double dist_y = position[1] - 0.2; - double sqR = 0.4*0.4; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double returnValue = -4*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_2 - 1); - - if ( dist >= 0.4 ) - returnValue = -2*kappa_2*sqDist*sqDist; - - return returnValue; -} - -template -MathVector get_exact_grad_Gangl(MathVector position) -{ - double kappa_2 = 10.0; - double dist_x = position[0] - 0.1; - double dist_y = position[1] - 0.2; - double sqR = 0.4*0.4; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double factor = -8*kappa_2*kappa_2*sqR; - - if ( dist >= 0.4 ) - factor = -8*kappa_2*sqDist; - - MathVector returnVector; - returnVector[0] = factor*dist_x; - returnVector[1] = factor*dist_y; - - return returnVector; -} - -template -MathVector get_exact_grad_FedkiwEx5(MathVector position) -{ - double center_x = 0.0; - double center_y = 0.0; - double radius = 0.5; - - double dist_x = position[0] - center_x; - double dist_y = position[1] - center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double absValue = position[0]*position[0] + position[1]* position[1]; - - MathVector returnVector; - returnVector[0] = 0.0; - returnVector[1] = 0.0; - - double factor = 1.0/absValue; - if ( dist >= radius ) - { - returnVector[0] = factor*position[0]; - returnVector[1] = factor*position[1]; - } - - return returnVector; - -} - -template -number get_exact_sol_FedkiwEx6(MathVector position) -{ - double center_x = 0.0; - double center_y = 0.0; - double radius = 0.5; - - double dist_x = position[0] - center_x; - double dist_y = position[1] - center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double returnValue = 0.0; - - if ( dist <= radius ) - returnValue = exp(position[0])*cos(position[1]); - - return returnValue; -} - -template -number get_exact_sol_FedkiwEx5(MathVector position) -{ - double center_x = 0.0; - double center_y = 0.0; - - double dist_x = position[0]-center_x; - double dist_y = position[1]-center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double returnValue = 1.0; - - if ( dist > 0.5 ) - returnValue = 1.0 + log(2*dist); - - return returnValue; -} - -template -number get_exact_sol_FedkiwEx3(MathVector position) -{ - double center_x = 0.5; - double center_y = 0.5; - double radius = 0.25; - - double dist_x = position[0] - center_x; - double dist_y = position[1] - center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double absValue = position[0]*position[0] + position[1]* position[1]; - - double returnValue = 0.0; - - if ( dist <= radius ) - returnValue = exp(-absValue); - - return returnValue; -} - -template -MathVector get_exact_grad(MathVector position) -{ - -} - -////////////////////////////////////////////////////////////////////// -// code see ugbase/lib_disc/function_spaces/integrate.h: evaluate() for -// --> L2ErrorIntegrand (for value) -// --> H1ErrorIntegrand (for gradient): lines 1873-1910 -// -// called bei Integrate() via method 'integrand.values': -// integrand.values(&(vValue[0]), &(vGlobIP[0]), -// pElem, &vCorner[0], rQuadRule.points(), -// &(vJT[0]), -// numIP); -// -////////////////////////////////////////////////////////////////////// -template -template -number ConvectionDiffusionFV1:: -add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem) -{ - number integral = 0; - - std::vector > vCorner; - std::vector > vGlobIP; - std::vector > vLocIP; - std::vector > vJT; - std::vector vValue; - std::vector vValueGrad; - - QuadType type = GetQuadratureType("best"); - - const QuadratureRule& rQuadRule - = QuadratureRuleProvider::get(roid, 1, type); - -// get reference element mapping by reference object id - DimReferenceMapping& mapping - = ReferenceMappingProvider::get(roid); - -// number of integration points - const size_t numIP = rQuadRule.size(); - -// get all corner coordinates -// CollectCornerCoordinates(vCorner, *pElem, aaPos, true); - - const DimReferenceElement& rRefElem - = ReferenceElementProvider::get(roid); - - vCorner.clear(); -// remember global position of nodes - for(size_t i = 0; i < rRefElem.num(0); ++i) - vCorner.push_back(geo.get_corner(i)); - - for ( size_t i = 0; i < rRefElem.num(0); ++i) - UG_LOG("vCorner" << vCorner[i][0] << " and " << vCorner[i][1] << "\n" ); - UG_LOG("\n" ); - -// update the reference mapping for the corners - mapping.update(vCorner); - -// compute global integration points - vGlobIP.resize(numIP); - mapping.local_to_global(&(vGlobIP[0]), rQuadRule.points(), numIP); - - UG_LOG("vGlobIP" << vGlobIP[0][0] << " and " << vGlobIP[0][1] << "\n" ); - UG_LOG("\n" ); - -// compute local integration points - vLocIP.resize(numIP); - for(size_t ip = 0; ip < numIP; ++ip) - vLocIP[ip] = rQuadRule.points()[ip]; - - UG_LOG("vLocIP" << vLocIP[0][0] << " and " << vLocIP[0][1] << "\n" ); - UG_LOG("\n" ); - - -// compute transformation matrices - vJT.resize(numIP); - mapping.jacobian_transposed(&(vJT[0]), rQuadRule.points(), numIP); - - const size_t num_sh = geo.num_scvf(); - - if ( num_sh != rRefElem.num(0) ) - UG_THROW("wrong number of corners: sh = " << num_sh << ", but rRefElem.num(0) = " << rRefElem.num(0) << "\n"); - -// compute integrand values at integration points - vValue.resize(numIP); - vValueGrad.resize(numIP); - - try - { - // loop all integration points - for(size_t ip = 0; ip < numIP; ++ip) - { - // compute exact solution at integration point - number exactSolIP = get_exact_sol_Gangl(vGlobIP[ip]); - - // compute exact gradient at integration point - MathVector exactGradIP = get_exact_grad_FedkiwEx5(vGlobIP[ip]); - - // compute approximated solution at integration point - number approxSolIP = 0.0; - MathVector locTmp; VecSet(locTmp, 0.0); - - const typename TFVGeom::SCV& scv = geo.scv(ip); - - for(size_t sh = 0; sh < num_sh; ++sh) - { - // add shape fct at ip * value at shape - approxSolIP += u(_C_,sh) * geo.get_shape(sh, vLocIP[ip], roid); - - // add gradient at ip - VecScaleAppend(locTmp, u(_C_,sh), scv.local_grad(sh)); - } - - // get squared of difference - vValue[ip] = (exactSolIP - approxSolIP); - vValue[ip] *= vValue[ip]; - - // compute global gradient - MathVector approxGradIP; - MathMatrix JTInv; - Inverse(JTInv, vJT[ip]); - MatVecMult(approxGradIP, JTInv, locTmp); - - // get error of gradient - vValueGrad[ip] = VecDistanceSq(approxGradIP, exactGradIP); - - - } -/* integrand.values(&(vValue[0]), &(vGlobIP[0]), - pElem, &vCorner[0], rQuadRule.points(), - &(vJT[0]), - numIP); -*/ - } - UG_CATCH_THROW("Unable to compute values of integrand at integration point."); - -// reset contribution of this element - number intValElem = 0; - -// loop integration points - for(size_t ip = 0; ip < numIP; ++ip) - { - // get quadrature weight - const number weightIP = rQuadRule.weight(ip); - - // get determinate of mapping - const number det = SqrtGramDeterminant(vJT[ip]); - - // add contribution of integration point - intValElem += vValue[ip] * weightIP * det; -// intValElem += vValueGrad[ip] * weightIP * det; - - } - -// add to global sum - - UG_LOG("added: " << intValElem << "\n\n"); - - return intValElem; -} - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - double diffusion = 10.0; - - if ( bElementIsOutside ) - diffusion = 1.0; - - std::vector& vBF = geo.get_boundary_faces(); - MathVector Dgrad; - VecSet(Dgrad, 0.0); - - UG_LOG("---------- vBF.size(): " << vBF.size() << "\n"); - - if ( vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - -// set solution -/* for(size_t sh = 0; sh < geo.num_sh(); ++sh) - { - u(_C_, sh) = 1.0; - u(_C_, sh) -= corners[sh][0]*(2*corners[sh][0] - 1.0); - u(_C_, sh) -= corners[sh][1]*(2*corners[sh][1] - 1.0); - } -*/ -// u(_C_, sh) = 1 - 2*(corners[sh][0]*corners[sh][0] + corners[sh][1]*corners[sh][1]) - (corners[sh][0]+corners[sh][1]); -// u(_C_, sh) = corners[sh][1]*(2*corners[sh][1] - 1.0); -// u(_C_, sh) = (1.0 - corners[sh][0] - corners[sh][1]) * (1.0 - 2*corners[sh][0] - 2*corners[sh][1]); -// u(_C_, sh) = corners[sh][1]; -// for(size_t sh = 0; sh < geo.num_sh(); ++sh) -// u(_C_, sh) = corners[sh][0]*(2*corners[sh][0] - 1.0); //corners[sh][0]; - // u(_C_, sh) = corners[sh][0]*(2* corners[sh][0]-1); - -//////////////////////////////////////////////////////////////////////////////// -// NO loop integration points! -// /* for(size_t ip = 0; ip < vBF.size(); ++ip) */ -// Reason: the length of the normal is already the length of the total face (NOT the scvf!) -//////////////////////////////////////////////////////////////////////////////// - -// loop integration points - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - typename TFVGeom::BF bf = vBF[ip]; - VecSet(Dgrad, 0.0); - - // loop trial space - for(size_t sh = 0; sh < bf.num_sh(); ++sh) - { - // Diffusion - UG_LOG("bf.num_sh(): " << bf.num_sh() << "\n"); - UG_LOG("Dgrad: " << Dgrad << "\n"); - UG_LOG("bf.normal(): " << bf.normal() << "\n"); - UG_LOG("bf.global_grad(ip, sh): " << bf.global_grad(sh) << "\n"); - - UG_LOG("u(_C_, sh): " << u(_C_, sh) << "\n"); - - VecScaleAppend(Dgrad, diffusion * u(_C_, sh), bf.global_grad(sh)); - } - - // add to local vector - d(_C_, bf.node_id()) += VecDot(Dgrad, bf.normal()); - - } - - UG_LOG("---------- end ----------- \n\n"); - -} - - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsCut) -{ - ug::MathMatrix diffusion = m_imDiffusion[0]; - diffusion *= 1.0; - - number areaElem = 0.0; - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - areaElem += geo.scv(ip).volume(); - - number areaScale = 1.0; - - if ( bElementIsCut ) - { - areaScale = geo.Area()/areaElem; - UG_LOG("check area: areaElem = " << areaElem << " geo.AreaOrig() = " << geo.AreaOrig() << "\n"); - - if ( fabs(areaScale - geo.AreaScale()) > 0.00001 ) - UG_LOG("error for area: areaScale = " << areaScale << " geo.AreaScale() = " << geo.AreaScale() << "\n"); - } - - const number kappa_1 = areaScale; - const number alpha_1 = 1.0; - const number scaleFactor = alpha_1 * kappa_1; - - // loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - ///////////////////////////////////////////////////// - // Diffusive Term - ///////////////////////////////////////////////////// - if(m_imDiffusion.data_given()) - { - // to compute D \nabla c - MathVector Dgrad_c, grad_c; - MathVector Dgrad_debug, grad_debug; - - // compute gradient and shape at ip - VecSet(grad_c, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - { - VecScaleAppend(grad_c, u(_C_,sh), scvf.global_grad(sh)); - UG_LOG("u(_C_,sh) " << u(_C_,sh) << "\n"); - } - // scale by diffusion tensor - MatVecMult(Dgrad_c, diffusion, grad_c); - - // Compute flux - const number diff_flux = VecDot(Dgrad_c, scvf.normal()); - - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - { - VecSet(grad_debug, 0.0); - VecScaleAppend(grad_debug, 1.0, scvf.global_grad(sh)); - MatVecMult(Dgrad_debug, diffusion, grad_debug); - const number diff_flux_debug = VecDot(Dgrad_debug, scvf.normal()); - - UG_LOG("sh: " << sh << "diff_flux_debug = " << diff_flux_debug << "\n"); - } - - // Add to local defect - d(_C_, scvf.from()) -= areaScale * diff_flux; - d(_C_, scvf.to() ) += areaScale * diff_flux; - - } - - } // end ip-loop - - //////////////////////////////////////////////////// - // Boundary Terms - //////////////////////////////////////////////////// - - if ( bElementIsCut ) - { - // loop trial space - MathVector NormalToFace = geo.NormalToFace(); - - MathVector Dgrad, grad; - VecSet(grad, 0.0); - - const typename TFVGeom::SCVF& scvf = geo.scvf(0); - //////////////////////////////////////////////////// - // FIRST TERM OF BOUNDARY - for(size_t j = 0; j < geo.num_sh(); ++j) - VecScaleAppend(grad, u(_C_,j), scvf.global_grad(j)); - - MatVecMult(Dgrad, diffusion, grad); - - number integrand1_1 = VecDot(Dgrad, NormalToFace); - - // loop test space - for(size_t i = 0; i < geo.num_sh(); ++i) - { - // multiply by integral along Gamma of shape fct \phi_i - number integrand2_1 = geo.IntegralGamma(i); - UG_LOG("geo.IntegralGamma(i): " << geo.IntegralGamma(i) << "\n"); - - // SUBTRACT to local defect - d(_C_, i) -= scaleFactor * integrand1_1 * integrand2_1; - - } // end i-loop - - - //////////////////////////////////////////////////// - // SECOND TERM OF BOUNDARY - - number integrand2_1 = 0.0; - for(size_t j = 0; j < geo.num_sh(); ++j) - integrand2_1 += u(_C_,j) * geo.IntegralGamma(j); - - // loop test space - for(size_t i = 0; i < geo.num_sh(); ++i) - { - VecSet(grad, 0.0); - VecSet(Dgrad, 0.0); - - MatVecMult(Dgrad, diffusion, scvf.global_grad(i)); - number integrand2_2 = VecDot(Dgrad, NormalToFace); - - // SUBTRACT to local defect - d(_C_, i) -= scaleFactor * integrand2_1 * integrand2_2; - // da jump [U] = 0! - } // end i-loop - } - - - ////////////////////////////////////////////////////////////// - // Source Term - NOT added during 'add_rhs_elm()': - // during elem_disc_assemble: rhs is NOT added anymore!! - ////////////////////////////////////////////////////////////// - - if ( m_imSource.data_given() ) - { - for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv( ip ); - - // get associated node - const int co = scv.node_id(); - - // Add to local rhs - d(_C_, co) += areaScale * m_imSource[ip] * scv.volume(); - UG_LOG("scv.volume() = " << scv.volume() << "\n"); - } - } - -} - - -template -template -void ConvectionDiffusionFV1:: -add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - -// reaction rate - if(m_imReactionRateExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local defect - d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume(); - } - } - -// reaction - if(m_imReactionExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local defect - d(_C_, co) += m_imReactionExpl[ip] * scv.volume(); - } - } - - if(m_imSourceExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local rhs - d(_C_, co) -= m_imSourceExpl[ip] * scv.volume(); - } - } -} - -template -template -void ConvectionDiffusionFV1:: -add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - if(!m_imMassScale.data_given() && !m_imMass.data_given()) return; - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // mass value - number val = 0.0; - - // multiply by scaling - if(m_imMassScale.data_given()) - val += m_imMassScale[ip] * u(_C_, co); - - // add mass - if(m_imMass.data_given()) - val += m_imMass[ip]; - - // Add to local defect - d(_C_, co) += val * scv.volume(); - } -} - - -template -template -void ConvectionDiffusionFV1:: -add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) -{ - ///////////////////////////////////////////////////// - // add rhs ALLREADY(!) during 'add_def_A_elem_local()' method! - // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! - ///////////////////////////////////////////////////// - - return; - - // get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - // loop Sub Control Volumes (SCV) - if ( m_imSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv( ip ); - - // get associated node - const int co = scv.node_id(); - - // Add to local rhs - d(_C_, co) += m_imSource[ip] * scv.volume(); - } - } - - // loop Sub Control Volumes (SCVF) - if ( m_imVectorSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); - - // Add to local rhs - d(_C_, scvf.from()) -= VecDot(m_imVectorSource[ip], scvf.normal() ); - d(_C_, scvf.to() ) += VecDot(m_imVectorSource[ip], scvf.normal() ); - } - } -} - - -//////////////////////////////////// -/// error estimation (begin) /// - -// prepares the loop over all elements of one type for the computation of the error estimator -template -template -void ConvectionDiffusionFV1:: -prep_err_est_elem_loop(const ReferenceObjectID roid, const int si) -{ - // get the error estimator data object and check that it is of the right type - // we check this at this point in order to be able to dispense with this check later on - // (i.e. in prep_err_est_elem and compute_err_est_A_elem()) - if (this->m_spErrEstData.get() == NULL) - { - UG_THROW("No ErrEstData object has been given to this ElemDisc!"); - } - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (!err_est_data) - { - UG_THROW("Dynamic cast to SideAndElemErrEstData failed." - << std::endl << "Make sure you handed the correct type of ErrEstData to this discretization."); - } - - -// check that upwind has been set - if (m_spConvShape.invalid()) - UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " - "Upwind has not been set."); - -// set local positions - if (!TFVGeom::usesHangingNodes) - { - static const int refDim = TElem::dim; - - // get local IPs - size_t numSideIPs, numElemIPs; - const MathVector* sideIPs; - const MathVector* elemIPs; - try - { - numSideIPs = err_est_data->num_all_side_ips(roid); - numElemIPs = err_est_data->num_elem_ips(roid); - sideIPs = err_est_data->template side_local_ips(roid); - elemIPs = err_est_data->template elem_local_ips(roid); - - if (!sideIPs || !elemIPs) return; // are NULL if TElem is not of the same dim as TDomain - } - UG_CATCH_THROW("Integration points for error estimator cannot be set."); - - // set local IPs in imports - m_imDiffusion.template set_local_ips(sideIPs, numSideIPs, false); - m_imVelocity.template set_local_ips(sideIPs, numSideIPs, false); - m_imFlux.template set_local_ips(sideIPs, numSideIPs, false); - m_imSource.template set_local_ips(elemIPs, numElemIPs, false); - m_imVectorSource.template set_local_ips(sideIPs, numSideIPs, false); - m_imReactionRate.template set_local_ips(elemIPs, numElemIPs, false); - m_imReaction.template set_local_ips(elemIPs, numElemIPs, false); - m_imMassScale.template set_local_ips(elemIPs, numElemIPs, false); - m_imMass.template set_local_ips(elemIPs, numElemIPs, false); - - // init upwind for element type - TFVGeom& geo = GeomProvider::get(); - if (!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " - "Cannot init upwind for element type."); - - // store values of shape functions in local IPs - LagrangeP1::reference_element_type> trialSpace - = Provider::reference_element_type> >::get(); - - m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh()); - for (size_t ip = 0; ip < numElemIPs; ip++) - trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]); - for (size_t ip = 0; ip < numSideIPs; ip++) - trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]); - } -} - -template -template -void ConvectionDiffusionFV1:: -prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{} - -// computes the error estimator contribution (stiffness part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ - typedef typename reference_element_traits::reference_element_type ref_elem_type; - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - -// request geometry - static const TFVGeom& geo = GeomProvider::get(); - -//////////////// -// SIDE TERMS // -//////////////// - -// get the sides of the element - // We have to cast elem to a pointer of type SideAndElemErrEstData::elem_type - // for the SideAndElemErrEstData::operator() to work properly. - // This cannot generally be achieved by casting to TElem*, since this method is also registered for - // lower-dimensional types TElem, and must therefore be compilable, even if it is never EVER to be executed. - // The way we achieve this here, is by calling associated_elements_sorted() which has an implementation for - // all possible types. Whatever comes out of it is of course complete nonsense if (and only if) - // SideAndElemErrEstData::elem_type != TElem. To be on the safe side, we throw an error if the number of - // entries in the list is not as it should be. - - typename MultiGrid::traits::side_type>::secure_container side_list; - pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); - if (side_list.size() != (size_t) ref_elem_type::numSides) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// some help variables - MathVector fluxDensity, gradC, normal; - -// calculate grad u (take grad from first scvf ip (grad u is constant on the entire element)) - if (geo.num_scvf() < 1) {UG_THROW("Element has no SCVFs!");} - const typename TFVGeom::SCVF& scvf = geo.scvf(0); - - VecSet(gradC, 0.0); - for (size_t j=0; j(normal, side, vCornerCoords); - VecNormalize(normal, normal); - - try - { - for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) - { - size_t ip = passedIPs + sip; - - VecSet(fluxDensity, 0.0); - - ////// diffusion ////// - if (m_imDiffusion.data_given()) - MatVecScaleMultAppend(fluxDensity, -1.0, m_imDiffusion[0], gradC); - - ////// convection ////// - if (m_imVelocity.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtSideIP(sh,sip); - - VecScaleAppend(fluxDensity, val, m_imVelocity[ip]); - } - - ////// general flux ////// - if (m_imFlux.data_given()) - VecAppend(fluxDensity, m_imFlux[ip]); - - (*err_est_data)(side_list[side],sip) += scale * VecDot(fluxDensity, normal); - } - - passedIPs += err_est_data->num_side_ips(side_list[side]); - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); - } - -////////////////// -// VOLUME TERMS // -////////////////// - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - { - number total = 0.0; - - ////// diffusion ////// TODO ONLY FOR (PIECEWISE) CONSTANT DIFFUSION TENSOR SO FAR! - // div(D*grad(c)) = div(v)*u + v*grad(c) - // nothing to do, as u is piecewise linear and div(D*grad(c)) disappears - - ////// convection ////// TODO ONLY FOR CONSTANT VELOCITY FIELDS SO FAR! - // div(v*c) = div(v)*u + v*grad(c) -- gradC has been calculated above - if (m_imVelocity.data_given()) - total += VecDot(m_imVelocity[ip], gradC); - - ////// general flux ////// TODO ONLY FOR DIVERGENCE-FREE FLUX FIELD SO FAR! - // nothing to do - - ////// reaction ////// - if (m_imReactionRate.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < geo.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); - - total += m_imReactionRate[ip] * val; - } - - if (m_imReaction.data_given()) - { - total += m_imReaction[ip]; - } - - (*err_est_data)(elem_list[0],ip) += scale * total; - } - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// computes the error estimator contribution (mass part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ -// note: mass parts only enter volume term - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// request geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop integration points - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - { - number total = 0.0; - - ////// mass scale ////// - if (m_imMassScale.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < geo.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); - - total += m_imMassScale[ip] * val; - } - - ////// mass ////// - if (m_imMass.data_given()) - { - total += m_imMass[ip]; - } - - (*err_est_data)(elem_list[0],ip) += scale * total; - } - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// computes the error estimator contribution (rhs part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ - typedef typename reference_element_traits::reference_element_type ref_elem_type; - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - -//////////////// -// SIDE TERMS // -//////////////// -// get the sides of the element - typename MultiGrid::traits::side_type>::secure_container side_list; - pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); - if (side_list.size() != (size_t) ref_elem_type::numSides) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// loop sides - size_t passedIPs = 0; - for (size_t side = 0; side < (size_t) ref_elem_type::numSides; side++) - { - // normal on side - MathVector normal; - SideNormal(normal, side, vCornerCoords); - VecNormalize(normal, normal); - - try - { - for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) - { - size_t ip = passedIPs + sip; - - ////// vector source ////// - if (m_imVectorSource.data_given()) - (*err_est_data)(side_list[side],sip) += scale * VecDot(m_imVectorSource[ip], normal); - } - - passedIPs += err_est_data->num_side_ips(side_list[side]); - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); - } - -////////////////// -// VOLUME TERMS // -////////////////// - if (!m_imSource.data_given()) return; - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -////// source ////// - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - (*err_est_data)(elem_list[0],ip) += scale * m_imSource[ip]; - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// postprocesses the loop over all elements of one type in the computation of the error estimator -template -template -void ConvectionDiffusionFV1:: -fsh_err_est_elem_loop() -{ -// finish the element loop in the same way as the actual discretization - this->template fsh_elem_loop (); -}; - -/// error estimation (end) /// -//////////////////////////////////// - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -lin_def_velocity(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // sum up contributions of convection shapes - MathVector linDefect; - VecSet(linDefect, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(linDefect, u(_C_,sh), convShape.D_vel(ip, sh)); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] += linDefect; - vvvLinDef[ip][_C_][scvf.to()] -= linDefect; - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -lin_def_diffusion(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // compute gradient at ip - MathVector grad_u; VecSet(grad_u, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(grad_u, u(_C_,sh), scvf.global_grad(sh)); - - // compute the lin defect at this ip - MathMatrix linDefect; - - // part coming from -\nabla u * \vec{n} - for(size_t k=0; k < (size_t)dim; ++k) - for(size_t j = 0; j < (size_t)dim; ++j) - linDefect(j,k) = (scvf.normal())[j] * grad_u[k]; - - // add contribution from convection shapes - if(convShape.non_zero_deriv_diffusion()) - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - MatAdd(linDefect, convShape.D_diffusion(ip, sh), u(_C_, sh)); - - // add contributions - vvvLinDef[ip][_C_][scvf.from()] -= linDefect; - vvvLinDef[ip][_C_][scvf.to() ] += linDefect; - } -} - -template -template -void ConvectionDiffusionFV1:: -lin_def_flux(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] += scvf.normal(); - vvvLinDef[ip][_C_][scvf.to()] -= scvf.normal(); - } -} -// computes the linearized defect w.r.t to the reaction rate -template -template -void ConvectionDiffusionFV1:: -lin_def_reaction_rate(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = u(_C_, co) * scv.volume(); - } -} - -// computes the linearized defect w.r.t to the reaction -template -template -void ConvectionDiffusionFV1:: -lin_def_reaction(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the source -template -template -void ConvectionDiffusionFV1:: -lin_def_source(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the vector source -// (in analogy to velocity) -template -template -void ConvectionDiffusionFV1:: -lin_def_vector_source(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ - // get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - - // loop Sub Control Volumes Faces (SCVF) - for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] -= scvf.normal(); - vvvLinDef[ip][_C_][scvf.to()] += scvf.normal(); - } -} - -// computes the linearized defect w.r.t to the mass scale -template -template -void ConvectionDiffusionFV1:: -lin_def_mass_scale(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t co = 0; co < geo.num_scv(); ++co) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(co); - - // Check associated node - UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); - - // set lin defect - vvvLinDef[co][_C_][co] = u(_C_, co) * scv.volume(); - } -} - -// computes the linearized defect w.r.t to the mass scale -template -template -void ConvectionDiffusionFV1:: -lin_def_mass(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t co = 0; co < geo.num_scv(); ++co) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(co); - - // Check associated node - UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); - - // set lin defect - vvvLinDef[co][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -ex_value(number vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > vvvDeriv[]) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reference element - typedef typename reference_element_traits::reference_element_type - ref_elem_type; - -// number of shape functions - static const size_t numSH = ref_elem_type::numCorners; - -// FV1 SCVF ip - if(vLocIP == geo.scvf_local_ips()) - { - // Loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // Get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // compute concentration at ip - vValue[ip] = 0.0; - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vValue[ip] += u(_C_, sh) * scvf.shape(sh); - - // compute derivative w.r.t. to unknowns iff needed - if(bDeriv) - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vvvDeriv[ip][_C_][sh] = scvf.shape(sh); - } - } -// FV1 SCV ip - else if(vLocIP == geo.scv_local_ips()) - { - // solution at ip - for(size_t sh = 0; sh < numSH; ++sh) - vValue[sh] = u(_C_, sh); - - // set derivatives if needed - if(bDeriv) - for(size_t sh = 0; sh < numSH; ++sh) - for(size_t sh2 = 0; sh2 < numSH; ++sh2) - vvvDeriv[sh][_C_][sh2] = (sh==sh2) ? 1.0 : 0.0; - } -// general case - else - { - // get trial space - LagrangeP1& rTrialSpace = Provider >::get(); - - // storage for shape function at ip - number vShape[numSH]; - - // loop ips - for(size_t ip = 0; ip < nip; ++ip) - { - // evaluate at shapes at ip - rTrialSpace.shapes(vShape, vLocIP[ip]); - - // compute concentration at ip - vValue[ip] = 0.0; - for(size_t sh = 0; sh < numSH; ++sh) - vValue[ip] += u(_C_, sh) * vShape[sh]; - - // compute derivative w.r.t. to unknowns iff needed - // \todo: maybe store shapes directly in vvvDeriv - if(bDeriv) - for(size_t sh = 0; sh < numSH; ++sh) - vvvDeriv[ip][_C_][sh] = vShape[sh]; - } - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -ex_grad(MathVector vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > > vvvDeriv[]) -{ -// Get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reference element - typedef typename reference_element_traits::reference_element_type - ref_elem_type; - -// reference dimension - static const int refDim = ref_elem_type::dim; - -// number of shape functions - static const size_t numSH = ref_elem_type::numCorners; - -// FV1 SCVF ip - if(vLocIP == geo.scvf_local_ips()) - { - // Loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // Get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - VecSet(vValue[ip], 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(vValue[ip], u(_C_, sh), scvf.global_grad(sh)); - - if(bDeriv) - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vvvDeriv[ip][_C_][sh] = scvf.global_grad(sh); - } - } -// general case - else - { - // get trial space - LagrangeP1& rTrialSpace = Provider >::get(); - - // storage for shape function at ip - MathVector vLocGrad[numSH]; - MathVector locGrad; - - // Reference Mapping - MathMatrix JTInv; - ReferenceMapping mapping(vCornerCoords); - - // loop ips - for(size_t ip = 0; ip < nip; ++ip) - { - // evaluate at shapes at ip - rTrialSpace.grads(vLocGrad, vLocIP[ip]); - - // compute grad at ip - VecSet(locGrad, 0.0); - for(size_t sh = 0; sh < numSH; ++sh) - VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]); - - // compute global grad - mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]); - MatVecMult(vValue[ip], JTInv, locGrad); - - // compute derivative w.r.t. to unknowns iff needed - if(bDeriv) - for(size_t sh = 0; sh < numSH; ++sh) - MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); - } - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// upwind -//////////////////////////////////////////////////////////////////////////////// - -template -void ConvectionDiffusionFV1:: -set_upwind(SmartPtr > shapes) {m_spConvShape = shapes;} - -// computes the linearized defect w.r.t to the velocity -template -const typename ConvectionDiffusionFV1::conv_shape_type& -ConvectionDiffusionFV1:: -get_updated_conv_shapes(const FVGeometryBase& geo) -{ -// compute upwind shapes for transport equation -// \todo: we should move this computation into the preparation part of the -// disc, to only compute the shapes once, reusing them several times. - if(m_imVelocity.data_given()) - { - // get diffusion at ips - const MathMatrix* vDiffusion = NULL; - if(m_imDiffusion.data_given()) vDiffusion = m_imDiffusion.values(); - - // update convection shapes - if(!m_spConvShape->update(&geo, m_imVelocity.values(), vDiffusion, true)) - { - UG_LOG("ERROR in 'ConvectionDiffusionFV1::add_jac_A_elem': " - "Cannot compute convection shapes.\n"); - } - } - -// return a const (!!) reference to the upwind - return *const_cast*>(m_spConvShape.get()); -} - - -//////////////////////////////////////////////////////////////////////////////// -// register assemble functions -//////////////////////////////////////////////////////////////////////////////// - -#ifdef UG_DIM_1 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - - - /* -// switch assemble functions - if(!bHang) - { - register_func >(); - } - else - { - register_func >(); - } -*/ -} -#endif - -#ifdef UG_DIM_2 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - - /* -// switch assemble functions - if(!bHang) - { - register_func >(); - register_func >(); - register_func >(); - } - else - { - register_func >(); - register_func >(); - register_func >(); - } - */ -} -#endif - -#ifdef UG_DIM_3 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - - /* -// switch assemble functions - if(!bHang) - { - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - } - else - { - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - } - */ -} -#endif - -template -template -void ConvectionDiffusionFV1:: -register_func() -{ - ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; - typedef this_type T; - static const int refDim = reference_element_traits::dim; - - this->clear_add_fct(id); - this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); - this->set_prep_elem_fct( id, &T::template prep_elem); - this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); - this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem); - this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem); - this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem); - this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem); - this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem); - this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); - -// error estimator parts -/* this->set_prep_err_est_elem_loop(id, &T::template prep_err_est_elem_loop); - this->set_prep_err_est_elem(id, &T::template prep_err_est_elem); - this->set_compute_err_est_A_elem(id, &T::template compute_err_est_A_elem); - this->set_compute_err_est_M_elem(id, &T::template compute_err_est_M_elem); - this->set_compute_err_est_rhs_elem(id, &T::template compute_err_est_rhs_elem); - this->set_fsh_err_est_elem_loop(id, &T::template fsh_err_est_elem_loop); -*/ -// set computation of linearized defect w.r.t velocity - m_imDiffusion.set_fct(id, this, &T::template lin_def_diffusion); - m_imVelocity. set_fct(id, this, &T::template lin_def_velocity); - m_imFlux.set_fct(id, this, &T::template lin_def_flux); - m_imReactionRate. set_fct(id, this, &T::template lin_def_reaction_rate); - m_imReaction. set_fct(id, this, &T::template lin_def_reaction); - m_imSource. set_fct(id, this, &T::template lin_def_source); - m_imVectorSource.set_fct(id, this, &T::template lin_def_vector_source); - m_imMassScale.set_fct(id, this, &T::template lin_def_mass_scale); - m_imMass. set_fct(id, this, &T::template lin_def_mass); - -// exports - m_exValue-> template set_fct(id, this, &T::template ex_value); - m_exGrad->template set_fct(id, this, &T::template ex_grad); -} - -//////////////////////////////////////////////////////////////////////////////// -// explicit template instantiations -//////////////////////////////////////////////////////////////////////////////// -#ifdef UG_DIM_1 -template class ConvectionDiffusionFV1; -#endif -#ifdef UG_DIM_2 -template class ConvectionDiffusionFV1; -#endif -#ifdef UG_DIM_3 -template class ConvectionDiffusionFV1; -#endif - -} // end namespace ConvectionDiffusionPlugin -} // namespace ug - diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.h b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.h deleted file mode 100644 index f457dee..0000000 --- a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_Nitsche_Juli.h +++ /dev/null @@ -1,326 +0,0 @@ -/* - * convection_diffusion_fv1.h - * - * Created on: 26.02.2010 - * Author: andreasvogel - */ - -#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ -#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ - -// library intern headers -#include "../convection_diffusion_base.h" -#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" - -namespace ug{ -namespace ConvectionDiffusionPlugin{ - -// \ingroup lib_disc_elem_disc -/// \addtogroup convection_diffusion -/// \{ - -/// Discretization for the Convection-Diffusion Equation -/** - * This class implements the IElemDisc interface to provide element local - * assemblings for the convection diffusion equation. - * The Equation has the form - * \f[ - * \partial_t (m1*c + m2) - \nabla \left( D \nabla c - \vec{v} c \right - \vec{F}) + - * r1 \cdot c + r2 = f + f2 - * \f] - * with - *
    - *
  • \f$ c \f$ is the unknown solution - *
  • \f$ m1 \equiv m(\vec{x},t) \f$ is the Mass Scaling Term - *
  • \f$ m2 \equiv m(\vec{x},t) \f$ is the Mass Term - *
  • \f$ D \equiv D(\vec{x},t) \f$ is the Diffusion Tensor - *
  • \f$ v \equiv \vec{v}(\vec{x},t) \f$ is the Velocity Field - *
  • \f$ F \equiv \vec{F}(\vec{x},t) \f$ is the Flux - *
  • \f$ r1 \equiv r(\vec{x},t) \f$ is the Reaction Rate - *
  • \f$ r2 \equiv r(\vec{x},t) \f$ is a Reaction Term - *
  • \f$ f \equiv f(\vec{x},t) \f$ is a Source Term - *
  • \f$ f2 \equiv f_2(\vec{x},t) \f$ is a Vector Source Term - *
- * - * \tparam TDomain Domain - * \tparam TAlgebra Algebra - */ -template< typename TDomain> -class ConvectionDiffusionFV1 : public ConvectionDiffusionBase -{ - private: - /// Base class type - typedef ConvectionDiffusionBase base_type; - - /// Own type - typedef ConvectionDiffusionFV1 this_type; - - /// error estimator type - typedef SideAndElemErrEstData err_est_type; - - public: - /// World dimension - static const int dim = base_type::dim; - - public: - /// Constructor - ConvectionDiffusionFV1(const char* functions, const char* subsets); - - /// set the upwind method - /** - * This method sets the upwind method used to upwind the convection. - * - * \param shapes upwind method - */ - void set_upwind(SmartPtr > shapes); - - private: - /// prepares the loop over all elements - /** - * This method prepares the loop over all elements. It resizes the Position - * array for the corner coordinates and schedules the local ip positions - * at the data imports. - */ - template - void prep_elem_loop(const ReferenceObjectID roid, const int si); - - /// prepares the element for assembling - /** - * This methods prepares an element for the assembling. The Positions of - * the Element Corners are read and the Finite Volume Geometry is updated. - * The global ip positions are scheduled at the data imports. - */ - template - void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]); - - /// finishes the loop over all elements - template - void fsh_elem_loop(); - - /// assembles the local stiffness matrix using a finite volume scheme - template - void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - template - void add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsCut); - - template - void add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - - /// assembles the local mass matrix using a finite volume scheme - template - void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the stiffness part of the local defect - template - void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the stiffness part of the local defect - template - void add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsCut); - - template - void add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - - template - number add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem); - - /// assembles the stiffness part of the local defect explicit reaction, reaction_rate and source - template - void add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the mass part of the local defect - template - void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the local right hand side - template - void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); - template - void add_rhs_elem_local(TFVGeom& geo, LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); - - /// prepares the loop over all elements of one type for the computation of the error estimator - template - void prep_err_est_elem_loop(const ReferenceObjectID roid, const int si); - - /// prepares the element for assembling the error estimator - template - void prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// computes the error estimator contribution for one element - template - void compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// computes the error estimator contribution for one element - template - void compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// computes the error estimator contribution for one element - template - void compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// postprocesses the loop over all elements of one type in the computation of the error estimator - template - void fsh_err_est_elem_loop(); - - protected: - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_velocity(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_diffusion(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_flux(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the reaction - template - void lin_def_reaction(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the reaction - template - void lin_def_reaction_rate(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the source term - template - void lin_def_source(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the vector source term - template - void lin_def_vector_source(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the mass scale term - template - void lin_def_mass_scale(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the mass scale term - template - void lin_def_mass(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - private: - /// abbreviation for the local solution - static const size_t _C_ = 0; - - using base_type::m_imDiffusion; - using base_type::m_imVelocity; - using base_type::m_imFlux; - using base_type::m_imSource; - using base_type::m_imSourceExpl; - using base_type::m_imVectorSource; - using base_type::m_imReactionRate; - using base_type::m_imReactionRateExpl; - using base_type::m_imReaction; - using base_type::m_imReactionExpl; - using base_type::m_imMassScale; - using base_type::m_imMass; - - using base_type::m_exGrad; - using base_type::m_exValue; - - protected: - /// method to compute the upwind shapes - SmartPtr > m_spConvShape; - - /// returns the updated convection shapes - typedef IConvectionShapes conv_shape_type; - const IConvectionShapes& get_updated_conv_shapes(const FVGeometryBase& geo); - - /// computes the concentration - template - void ex_value(number vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > vvvDeriv[]); - - /// computes the gradient of the concentration - template - void ex_grad(MathVector vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > > vvvDeriv[]); - - public: - /// type of trial space for each function used - virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid); - - /// returns if hanging nodes are needed - virtual bool use_hanging() const; - - protected: - /// current regular grid flag - bool m_bNonRegularGrid; - - /// current shape function set (needed for GeomProvider::get()) - LFEID m_LFEID; - - /// register utils - /// \{ - void register_all_funcs(bool bHang); - template void register_func(); - /// \} - - private: - /// struct holding values of shape functions in IPs - struct ShapeValues - { - public: - void resize(std::size_t nEip, std::size_t nSip, std::size_t _nSh) - { - nSh = _nSh; - elemVals.resize(nEip); - sideVals.resize(nSip); - for (std::size_t i = 0; i < nEip; i++) elemVals[i].resize(nSh); - for (std::size_t i = 0; i < nSip; i++) sideVals[i].resize(nSh); - } - number& shapeAtElemIP(std::size_t sh, std::size_t ip) {return elemVals[ip][sh];} - number& shapeAtSideIP(std::size_t sh, std::size_t ip) {return sideVals[ip][sh];} - number* shapesAtElemIP(std::size_t ip) {return &elemVals[ip][0];} - number* shapesAtSideIP(std::size_t ip) {return &sideVals[ip][0];} - std::size_t num_sh() {return nSh;} - private: - std::size_t nSh; - std::vector > elemVals; - std::vector > sideVals; - } m_shapeValues; -}; - -// end group convection_diffusion -/// \} - -} // end ConvectionDiffusionPlugin -} // end namespace ug - - -#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__*/ diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.cpp b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.cpp deleted file mode 100644 index b0f1331..0000000 --- a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.cpp +++ /dev/null @@ -1,2377 +0,0 @@ -/* - * convection_diffusion_fv1.cpp - * - * Created on: 26.02.2010 - * Author: andreasvogel - */ - -#include "convection_diffusion_fv1.h" - -#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" - -#include "lib_disc/spatial_disc/disc_util/geom_provider.h" -//#include "lib_disc/spatial_disc/disc_util/fv1_geom.h" -//#include "lib_disc/spatial_disc/disc_util/hfv1_geom.h" -#include "lib_disc/spatial_disc/disc_util/conv_shape.h" - -namespace ug{ -namespace ConvectionDiffusionPlugin{ - -//////////////////////////////////////////////////////////////////////////////// -// general -//////////////////////////////////////////////////////////////////////////////// - -template -ConvectionDiffusionFV1:: -ConvectionDiffusionFV1(const char* functions, const char* subsets) - : ConvectionDiffusionBase(functions,subsets), - m_spConvShape(new ConvectionShapesNoUpwind), - m_bNonRegularGrid(false) -{ - register_all_funcs(m_bNonRegularGrid); -} - - -template -void ConvectionDiffusionFV1:: -prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid) -{ -// check number - if(vLfeID.size() != 1) - UG_THROW("ConvectionDiffusion: Wrong number of functions given. " - "Need exactly "<<1); - - if(vLfeID[0].order() != 1 || vLfeID[0].type() != LFEID::LAGRANGE) - UG_THROW("ConvectionDiffusion FV Scheme only implemented for 1st order."); - -// remember - m_bNonRegularGrid = bNonRegularGrid; - - m_LFEID = vLfeID[0]; - -// update assemble functions - register_all_funcs(m_bNonRegularGrid); -} - -template -bool ConvectionDiffusionFV1:: -use_hanging() const -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// Assembling functions -//////////////////////////////////////////////////////////////////////////////// - -template -template -void ConvectionDiffusionFV1:: -prep_elem_loop(const ReferenceObjectID roid, const int si) -{ - // Only first order implementation - if(!(TFVGeom::order == 1)) - UG_THROW("Only first order implementation, but other Finite Volume" - " Geometry set."); - -// check, that upwind has been set - if(m_spConvShape.invalid()) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Upwind has not been set."); - -// set local positions - if(!TFVGeom::usesHangingNodes && TFVGeom::staticLocalData) - { - static const int refDim = TElem::dim; - TFVGeom& geo = GeomProvider::get(); -// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); - const MathVector* vSCVFip = geo.scvf_local_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_local_ips(); - const size_t numSCVip = geo.num_scv_ips(); - m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip, false); - m_imVelocity.template set_local_ips(vSCVFip,numSCVFip, false); - m_imFlux.template set_local_ips(vSCVFip,numSCVFip, false); - m_imSource.template set_local_ips(vSCVip,numSCVip, false); - m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip, false); - m_imReactionRate.template set_local_ips(vSCVip,numSCVip, false); - m_imReaction.template set_local_ips(vSCVip,numSCVip, false); - m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imReactionExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imSourceExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imMassScale.template set_local_ips(vSCVip,numSCVip, false); - m_imMass.template set_local_ips(vSCVip,numSCVip, false); - - // init upwind for element type - if(!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Cannot init upwind for element type."); - } -} - -template -template -void ConvectionDiffusionFV1:: -fsh_elem_loop() -{} - -template -template -void ConvectionDiffusionFV1:: -prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) -{ -// Update Geometry for this element - //static TFVGeom& geo = GeomProvider::get(); -// TFVGeom& geo = GeomProvider::get(m_LFEID,1); - TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); - -// TFVGeom& geo = GeomProvider::get(); -// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); - - // fix: set orientation initially globally! - geo.set_orientation(1); - - try{ - geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::prep_elem:" - " Cannot update Finite Volume Geometry."); - -// set local positions - if(TFVGeom::usesHangingNodes || !TFVGeom::staticLocalData) - { - const int refDim = TElem::dim; - const MathVector* vSCVFip = geo.scvf_local_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_local_ips(); - const size_t numSCVip = geo.num_scv_ips(); - m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip); - m_imVelocity.template set_local_ips(vSCVFip,numSCVFip); - m_imFlux.template set_local_ips(vSCVFip,numSCVFip); - m_imSource.template set_local_ips(vSCVip,numSCVip); - m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip); - m_imReactionRate.template set_local_ips(vSCVip,numSCVip); - m_imReaction.template set_local_ips(vSCVip,numSCVip); - m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip); - m_imReactionExpl.template set_local_ips(vSCVip,numSCVip); - m_imSourceExpl.template set_local_ips(vSCVip,numSCVip); - m_imMassScale.template set_local_ips(vSCVip,numSCVip); - m_imMass.template set_local_ips(vSCVip,numSCVip); -/* - if(m_spConvShape.valid()) - if(!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Cannot init upwind for element type."); - */ - } - - // set global positions - const MathVector* vSCVFip = geo.scvf_global_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_global_ips(); - const size_t numSCVip = geo.num_scv_ips(); - - m_imDiffusion. set_global_ips(vSCVFip, numSCVFip); - m_imVelocity. set_global_ips(vSCVFip, numSCVFip); - m_imFlux. set_global_ips(vSCVFip, numSCVFip); - m_imSource. set_global_ips(vSCVip, numSCVip); - m_imVectorSource. set_global_ips(vSCVFip, numSCVFip); - m_imReactionRate. set_global_ips(vSCVip, numSCVip); - m_imReactionRateExpl. set_global_ips(vSCVip, numSCVip); - m_imReactionExpl. set_global_ips(vSCVip, numSCVip); - m_imSourceExpl. set_global_ips(vSCVip, numSCVip); - m_imReaction. set_global_ips(vSCVip, numSCVip); - m_imMassScale. set_global_ips(vSCVip, numSCVip); - m_imMass. set_global_ips(vSCVip, numSCVip); - -} - - -template -static TVector CalculateCenter(GridObject* o, const TVector* coords) -{ - TVector v; - VecSet(v, 0); - - size_t numCoords = 0; - switch(o->base_object_id()){ - case VERTEX: numCoords = 1; break; - case EDGE: numCoords = static_cast(o)->num_vertices(); break; - case FACE: numCoords = static_cast(o)->num_vertices(); break; - case VOLUME: numCoords = static_cast(o)->num_vertices(); break; - default: UG_THROW("Unknown element type."); break; - } - - for(size_t i = 0; i < numCoords; ++i) - VecAdd(v, v, coords[i]); - - if(numCoords > 0) - VecScale(v, v, 1. / (number)numCoords); - - return v; -} - -void LU(MathMatrix<3, 3>& R, MathMatrix<3, 3>& L, MathMatrix<3, 3> A) -{ - // n-1 Iterationsschritte - for ( size_t i = 1; i < 2; ++i) - { - for ( size_t k = i+1; i < 3; ++i) - { - L[k][i] = R[k][i] / R[i][i]; - - for ( size_t j = i; i < 3; ++i) - R[k][j] = R[k][j] - L[k][i] * R[i][j]; - } - } - -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - - bool debug = false; - bool boundary = false; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); - TFVGeom& geo = GeomProvider::get(m_LFEID,1); - const bool bElementIsCut = geo.get_element_modus(); - const bool bElementIsOutside = geo.get_boolian_for_diffusion(); - - // First call with orientation = 1: - int orientation = 1; - geo.set_orientation(orientation); - - geo.init_integral(); - - UG_LOG("------------------> jac = " << geo.get_integral() << "\n"); - -// normal assembling if not cut by interface: - if ( !bElementIsCut ) - { - LocalVector dummyU; - LocalIndices ind = u.get_indices(); - dummyU.resize(ind); - dummyU = 0; - - this->template add_jac_A_elem_local (geo, J, u, dummyU, elem, vCornerCoords, bElementIsOutside); - return; - } - -// get data: - geo.resize_local_data(u); - LocalMatrix& locJ_tri = geo.get_jacobian_tri(); - LocalMatrix& locJ_quad = geo.get_jacobian_quad(); - - LocalVector& locU_tri = geo.get_solution_tri(); - LocalVector& locU_quad = geo.get_solution_quad(); - -// reset data: - locJ_tri = 0; - locJ_quad = 0; - - LocalIndices ind = u.get_indices(); - - // call elem disc twice: - - if ( debug ) geo.print_InterfaceIDdata(); - - ReferenceObjectID roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - - this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, false); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_tri, 3); - this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords, false); - } - - geo.set_jacobian_tri(locJ_tri); - geo.set_DoF_tag_tri(false); - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - - this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, false); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_quad, 4); - this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords, false); - } - - geo.set_jacobian_quad(locJ_quad); - geo.set_DoF_tag_quad(false); - } - - -// Second call with orientation = 1: - bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! - - orientation *= -1; - geo.set_orientation(orientation); - try{ - geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" - " Cannot update Finite Volume Geometry."); - - if ( debug ) geo.print_InterfaceIDdata(); - - roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - - this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, true); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_tri, 3); - this->template add_jac_A_elem_boundary (geo, locJ_tri, locU_tri, elem, vCornerCoords, true); - } - - geo.set_jacobian_tri(locJ_tri); - geo.set_DoF_tag_tri(shiftTag); - - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - - this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, true); - - if ( boundary ) - { - geo.reset_jacobian_on_interface(locJ_quad, 4); - this->template add_jac_A_elem_boundary (geo, locJ_quad, locU_quad, elem, vCornerCoords, true); - } - - geo.set_jacobian_quad(locJ_quad); - geo.set_DoF_tag_quad(shiftTag); - } - - -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - ug::MathMatrix diffusion = m_imDiffusion[0]; - diffusion *= 1.0; - - if ( bElementIsOutside ) // = inside circle line!! - diffusion *= 1.0; - -// Diff. Tensor times Gradient - MathVector Dgrad; - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// Diffusion and Velocity Term - if(m_imDiffusion.data_given() || m_imVelocity.data_given()) - { - - // loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCV - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - //////////////////////////////////////////////////// - // Diffusive Term - //////////////////////////////////////////////////// - if(m_imDiffusion.data_given()) - { - // loop shape functions - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - { - // Compute Diffusion Tensor times Gradient - MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); - - // Compute flux at IP - const number D_diff_flux = VecDot(Dgrad, scvf.normal()); - - J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; - J(_C_, scvf.to() , _C_, sh) += D_diff_flux; - } - } - - ///////////////////////////////////////////////////////////////////////////// - // Additional diffusive Term due to jump in solution at the interface - // u^+ - u^- = jump - ///////////////////////////////////////////////////////////////////////////// - if ( 0 ) - { - // loop shape functions - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - { - // Compute Diffusion Tensor times Gradient - MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); - - // Compute flux at IP - const number D_diff_flux = jump(_C_,sh) * VecDot(Dgrad, scvf.normal()); - - J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; - J(_C_, scvf.to() , _C_, sh) += D_diff_flux; - } - - } - //////////////////////////////////////////////////// - // Convective Term - //////////////////////////////////////////////////// - if(m_imVelocity.data_given()) - { - // Add Flux contribution - for(size_t sh = 0; sh < convShape.num_sh(); ++sh) - { - const number D_conv_flux = convShape(ip, sh); - - // Add flux term to local matrix - J(_C_, scvf.from(), _C_, sh) += D_conv_flux; - J(_C_, scvf.to(), _C_, sh) -= D_conv_flux; - } - } - - // no explicit dependency on flux import - } - } - - -//////////////////////////////////////////////////// -// Reaction Term (using lumping) -//////////////////////////////////////////////////// - -// if no data for reaction rate given, return - if(!m_imReactionRate.data_given()) return; - -// loop Sub Control Volume (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local matrix - J(_C_, co, _C_, co) += m_imReactionRate[ip] * scv.volume(); - } - -// reaction term does not explicitly depend on the associated unknown function -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - double diffusion = 10.0; - - if ( bElementIsOutside ) - diffusion = 1.0; - - std::vector& vBF = geo.get_boundary_faces(); - - if ( vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - -// loop integration points - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - typename TFVGeom::BF bf = vBF[ip]; - - // loop trial space - for(size_t sh = 0; sh < bf.num_sh(); ++sh) - { - UG_LOG("bf.node_id(): " << bf.node_id() << "\n"); - UG_LOG("bf.global_grad(sh): " << bf.global_grad(sh) << "\n"); - UG_LOG("normal(): " << bf.normal() << "\n"); - - // add to local matrix - J(_C_, bf.node_id(), _C_, sh) += VecDot(bf.global_grad(sh), bf.normal()); - J(_C_, bf.node_id(), _C_, sh) *= diffusion; - } - } - -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - if(!m_imMassScale.data_given()) return; - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local matrix - J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip]; - } - -// m_imMass part does not explicitly depend on associated unknown function -} - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - bool output = false; - bool output_integral = true; - - bool debug = false; - bool boundary = false; - bool add = true; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); - TFVGeom& geo = GeomProvider::get(m_LFEID,1); - const bool bElementIsCut = geo.get_element_modus(); - const bool bElementIsOutside = geo.get_boolian_for_diffusion(); - - // First call with orientation = 1: - int orientation = 1; - geo.set_orientation(orientation); - - // necessary for call of 'get_solution_tri' an 'get_solution_quad': - geo.resize_local_data(u); - std::vector imSource; - if ( m_imSource.data_given() ) { - for ( size_t i = 0; i < 3; ++i ) - imSource.push_back(m_imSource[i]); - } - - -// normal assembling if not cut by interface: - if ( !bElementIsCut ) - { - LocalVector dummyU; - LocalIndices ind = d.get_indices(); - dummyU.resize(ind); - dummyU = 0; - LocalVector source = geo.set_source(imSource, ind, 3, true); - - if ( output ) - { - for ( size_t i = 0; i < 3; ++i) - UG_LOG("*** corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); - UG_LOG("\n" ); - } - - this->template add_def_A_elem_local (geo, d, u, dummyU, dummyU, source, elem, vCornerCoords, bElementIsOutside); - - number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, d, u, elem); - geo.add_to_integral(intValElem); - if ( output_integral ) - UG_LOG("------------------> usual: integral = " << sqrt(geo.get_integral()) << "\n"); - - - - return; - } - -// get data: - LocalVector& locD_tri = geo.get_defect_tri(); - LocalVector& locD_quad = geo.get_defect_quad(); - - LocalVector& locU_tri = geo.get_solution_tri(); - LocalVector& locU_quad = geo.get_solution_quad(); - -// reset data: - locD_tri = 0; - locD_quad = 0; - - // call elem disc twice: - - if ( debug ) geo.print_InterfaceIDdata(); - - LocalIndices ind = d.get_indices(); - - ReferenceObjectID roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - - LocalVector jump_tri = geo.set_jump_values(ind, 3); - LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); - LocalVector source_tri = geo.set_source(imSource, ind, 3, false); - - if ( output ) UG_LOG(" tri 1: orientaten: " << orientation << "\n"); - - this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords, false); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_tri, 3); - this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords, false); - } - - if ( output ) - { - for ( size_t i = 0; i < 3; ++i) - UG_LOG("corner" << vCornerCoords[i][0] << " and " << vCornerCoords[i][1] << "\n" ); - UG_LOG("\n" ); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output_integral ) UG_LOG("------------------> tri1: integral = " << sqrt(geo.get_integral()) << "\n"); - - geo.set_defect_tri(locD_tri); - geo.set_DoF_tag_tri(false); - - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - - LocalVector jump_quad = geo.set_jump_values(ind, 4); - LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); - LocalVector source_quad = geo.set_source(imSource, ind, 4, false); - - if ( output ) UG_LOG(" quad 1: orientaten: " << orientation << "\n"); - this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem, vCornerCoords, false); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_quad, 4); - this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords, false); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output_integral ) UG_LOG("------------------> quad1: integral = " << sqrt(geo.get_integral()) << "\n"); - - - geo.set_defect_quad(locD_quad); - geo.set_DoF_tag_quad(false); - - } - - -// Second call with orientation = -1: - bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! - - orientation *= -1; - if ( output ) UG_LOG(" ____2: orientaten: " << orientation << "\n"); - - geo.set_orientation(orientation); - try{ - geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" - " Cannot update Finite Volume Geometry."); - - if ( debug ) geo.print_InterfaceIDdata(); - - roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); - LocalVector source_tri = geo.set_source(imSource, ind, 3, false); - - if ( output ) UG_LOG(" tri 2: orientaten: " << orientation << "\n"); - - this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords, true); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_tri, 3); - this->template add_def_A_elem_boundary (geo, locD_tri, locU_tri, elem, vCornerCoords, true); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_TRIANGLE, locD_tri, locU_tri, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output ) UG_LOG("------------------> tri2: integral = " << sqrt(geo.get_integral()) << "\n"); - - - geo.set_defect_tri(locD_tri); - geo.set_DoF_tag_tri(shiftTag); - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); - LocalVector source_quad = geo.set_source(imSource, ind, 4, false); - - if ( output ) UG_LOG(" quad 2: orientaten: " << orientation << "\n"); - - this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem, vCornerCoords, true); - - if ( boundary ) - { - geo.reset_defect_on_interface(locD_quad, 4); - this->template add_def_A_elem_boundary (geo, locD_quad, locU_quad, elem, vCornerCoords, true); - } - - number intValElem = this->template add_l2error_A_elem (geo, ROID_QUADRILATERAL, locD_quad, locU_quad, elem); - if ( add ) geo.add_to_integral(intValElem); - - if ( output_integral ) UG_LOG("------------------> quad2: integral = " << sqrt(geo.get_integral()) << "\n"); - - geo.set_defect_quad(locD_quad); - geo.set_DoF_tag_quad(shiftTag); - - } -} - -template -number get_exact_sol_test(MathVector position) -{ - return sin(2*M_PI*position[0]) + sin(2*M_PI*position[1]); -} - -template -number get_exact_sol_Gangl(MathVector position) -{ - double kappa_2 = 10.0; - double dist_x = position[0] - 0.1; - double dist_y = position[1] - 0.2; - double sqR = 0.4*0.4; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double returnValue = -4*kappa_2*kappa_2*sqR*sqDist + 2*sqR*sqR*kappa_2*(2*kappa_2 - 1); - - if ( dist >= 0.4 ) - returnValue = -2*kappa_2*sqDist*sqDist; - - return returnValue; -} - -template -MathVector get_exact_grad_Gangl(MathVector position) -{ - double kappa_2 = 10.0; - double dist_x = position[0] - 0.1; - double dist_y = position[1] - 0.2; - double sqR = 0.4*0.4; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double factor = -8*kappa_2*kappa_2*sqR; - - if ( dist >= 0.4 ) - factor = -8*kappa_2*sqDist; - - MathVector returnVector; - returnVector[0] = factor*dist_x; - returnVector[1] = factor*dist_y; - - return returnVector; -} - -template -MathVector get_exact_grad_FedkiwEx5(MathVector position) -{ - double center_x = 0.0; - double center_y = 0.0; - double radius = 0.5; - - double dist_x = position[0] - center_x; - double dist_y = position[1] - center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double absValue = position[0]*position[0] + position[1]* position[1]; - - MathVector returnVector; - returnVector[0] = 0.0; - returnVector[1] = 0.0; - - double factor = 1.0/absValue; - if ( dist >= radius ) - { - returnVector[0] = factor*position[0]; - returnVector[1] = factor*position[1]; - } - - return returnVector; - -} - -template -number get_exact_sol_FedkiwEx6(MathVector position) -{ - double center_x = 0.0; - double center_y = 0.0; - double radius = 0.5; - - double dist_x = position[0] - center_x; - double dist_y = position[1] - center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double returnValue = 0.0; - - if ( dist <= radius ) - returnValue = exp(position[0])*cos(position[1]); - - return returnValue; -} - -template -number get_exact_sol_FedkiwEx5(MathVector position) -{ - double center_x = 0.0; - double center_y = 0.0; - - double dist_x = position[0]-center_x; - double dist_y = position[1]-center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double returnValue = 1.0; - - if ( dist > 0.5 ) - returnValue = 1.0 + log(2*dist); - - return returnValue; -} - -template -number get_exact_sol_FedkiwEx3(MathVector position) -{ - double center_x = 0.5; - double center_y = 0.5; - double radius = 0.25; - - double dist_x = position[0] - center_x; - double dist_y = position[1] - center_y; - - double sqDist = dist_x*dist_x + dist_y*dist_y; - double dist = sqrt(sqDist); - - double absValue = position[0]*position[0] + position[1]* position[1]; - - double returnValue = 0.0; - - if ( dist <= radius ) - returnValue = exp(-absValue); - - return returnValue; -} - -template -MathVector get_exact_grad(MathVector position) -{ - -} - -////////////////////////////////////////////////////////////////////// -// code see ugbase/lib_disc/function_spaces/integrate.h: evaluate() for -// --> L2ErrorIntegrand (for value) -// --> H1ErrorIntegrand (for gradient): lines 1873-1910 -// -// called bei Integrate() via method 'integrand.values': -// integrand.values(&(vValue[0]), &(vGlobIP[0]), -// pElem, &vCorner[0], rQuadRule.points(), -// &(vJT[0]), -// numIP); -// -////////////////////////////////////////////////////////////////////// -template -template -number ConvectionDiffusionFV1:: -add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem) -{ - bool output = false; - - number integral = 0; - - std::vector > vCorner; - std::vector > vGlobIP; - std::vector > vLocIP; - std::vector > vJT; - std::vector vValue; - std::vector vValueGrad; - - QuadType type = GetQuadratureType("best"); - - const QuadratureRule& rQuadRule - = QuadratureRuleProvider::get(roid, 1, type); - -// get reference element mapping by reference object id - DimReferenceMapping& mapping - = ReferenceMappingProvider::get(roid); - -// number of integration points - const size_t numIP = rQuadRule.size(); - -// get all corner coordinates -// CollectCornerCoordinates(vCorner, *pElem, aaPos, true); - - const DimReferenceElement& rRefElem - = ReferenceElementProvider::get(roid); - - vCorner.clear(); -// remember global position of nodes - for(size_t i = 0; i < rRefElem.num(0); ++i) - vCorner.push_back(geo.get_corner(i)); - - if ( output ) - { - for ( size_t i = 0; i < rRefElem.num(0); ++i) - UG_LOG("vCorner" << vCorner[i][0] << " and " << vCorner[i][1] << "\n" ); - UG_LOG("\n" ); - } - -// update the reference mapping for the corners - mapping.update(vCorner); - -// compute global integration points - vGlobIP.resize(numIP); - mapping.local_to_global(&(vGlobIP[0]), rQuadRule.points(), numIP); - - if ( output ) UG_LOG("vGlobIP" << vGlobIP[0][0] << " and " << vGlobIP[0][1] << "\n" ); - if ( output ) UG_LOG("\n" ); - -// compute local integration points - vLocIP.resize(numIP); - for(size_t ip = 0; ip < numIP; ++ip) - vLocIP[ip] = rQuadRule.points()[ip]; - - if ( output ) UG_LOG("vLocIP" << vLocIP[0][0] << " and " << vLocIP[0][1] << "\n" ); - if ( output ) UG_LOG("\n" ); - - -// compute transformation matrices - vJT.resize(numIP); - mapping.jacobian_transposed(&(vJT[0]), rQuadRule.points(), numIP); - - const size_t num_sh = geo.num_scvf(); - - if ( num_sh != rRefElem.num(0) ) - UG_THROW("wrong number of corners: sh = " << num_sh << ", but rRefElem.num(0) = " << rRefElem.num(0) << "\n"); - -// compute integrand values at integration points - vValue.resize(numIP); - vValueGrad.resize(numIP); - - try - { - // loop all integration points - for(size_t ip = 0; ip < numIP; ++ip) - { - // compute exact solution at integration point - number exactSolIP = get_exact_sol_FedkiwEx5(vGlobIP[ip]); - - // compute exact gradient at integration point - MathVector exactGradIP = get_exact_grad_FedkiwEx5(vGlobIP[ip]); - - // compute approximated solution at integration point - number approxSolIP = 0.0; - MathVector locTmp; VecSet(locTmp, 0.0); - - const typename TFVGeom::SCV& scv = geo.scv(ip); - - for(size_t sh = 0; sh < num_sh; ++sh) - { - // add shape fct at ip * value at shape - approxSolIP += u(_C_,sh) * geo.get_shape(sh, vLocIP[ip], roid); - - // add gradient at ip - VecScaleAppend(locTmp, u(_C_,sh), scv.local_grad(sh)); - } - - // get squared of difference - vValue[ip] = (exactSolIP - approxSolIP); - vValue[ip] *= vValue[ip]; - - // compute global gradient - MathVector approxGradIP; - MathMatrix JTInv; - Inverse(JTInv, vJT[ip]); - MatVecMult(approxGradIP, JTInv, locTmp); - - // get error of gradient - vValueGrad[ip] = VecDistanceSq(approxGradIP, exactGradIP); - - - } -/* integrand.values(&(vValue[0]), &(vGlobIP[0]), - pElem, &vCorner[0], rQuadRule.points(), - &(vJT[0]), - numIP); -*/ - } - UG_CATCH_THROW("Unable to compute values of integrand at integration point."); - -// reset contribution of this element - number intValElem = 0; - -// loop integration points - for(size_t ip = 0; ip < numIP; ++ip) - { - // get quadrature weight - const number weightIP = rQuadRule.weight(ip); - - // get determinate of mapping - const number det = SqrtGramDeterminant(vJT[ip]); - - // add contribution of integration point - intValElem += vValue[ip] * weightIP * det; -// intValElem += vValueGrad[ip] * weightIP * det; - - } - -// add to global sum - - if ( output ) UG_LOG("added: " << intValElem << "\n\n"); - - return intValElem; -} - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - double diffusion = 10.0; - - if ( bElementIsOutside ) - diffusion = 1.0; - - std::vector& vBF = geo.get_boundary_faces(); - MathVector Dgrad; - VecSet(Dgrad, 0.0); - - UG_LOG("---------- vBF.size(): " << vBF.size() << "\n"); - - if ( vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - -// set solution -/* for(size_t sh = 0; sh < geo.num_sh(); ++sh) - { - u(_C_, sh) = 1.0; - u(_C_, sh) -= corners[sh][0]*(2*corners[sh][0] - 1.0); - u(_C_, sh) -= corners[sh][1]*(2*corners[sh][1] - 1.0); - } -*/ -// u(_C_, sh) = 1 - 2*(corners[sh][0]*corners[sh][0] + corners[sh][1]*corners[sh][1]) - (corners[sh][0]+corners[sh][1]); -// u(_C_, sh) = corners[sh][1]*(2*corners[sh][1] - 1.0); -// u(_C_, sh) = (1.0 - corners[sh][0] - corners[sh][1]) * (1.0 - 2*corners[sh][0] - 2*corners[sh][1]); -// u(_C_, sh) = corners[sh][1]; -// for(size_t sh = 0; sh < geo.num_sh(); ++sh) -// u(_C_, sh) = corners[sh][0]*(2*corners[sh][0] - 1.0); //corners[sh][0]; - // u(_C_, sh) = corners[sh][0]*(2* corners[sh][0]-1); - -//////////////////////////////////////////////////////////////////////////////// -// NO loop integration points! -// /* for(size_t ip = 0; ip < vBF.size(); ++ip) */ -// Reason: the length of the normal is already the length of the total face (NOT the scvf!) -//////////////////////////////////////////////////////////////////////////////// - -// loop integration points - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - typename TFVGeom::BF bf = vBF[ip]; - VecSet(Dgrad, 0.0); - - // loop trial space - for(size_t sh = 0; sh < bf.num_sh(); ++sh) - { - // Diffusion - UG_LOG("bf.num_sh(): " << bf.num_sh() << "\n"); - UG_LOG("Dgrad: " << Dgrad << "\n"); - UG_LOG("bf.normal(): " << bf.normal() << "\n"); - UG_LOG("bf.global_grad(ip, sh): " << bf.global_grad(sh) << "\n"); - - UG_LOG("u(_C_, sh): " << u(_C_, sh) << "\n"); - - VecScaleAppend(Dgrad, diffusion * u(_C_, sh), bf.global_grad(sh)); - } - - // add to local vector - d(_C_, bf.node_id()) += VecDot(Dgrad, bf.normal()); - - } - - UG_LOG("---------- end ----------- \n\n"); - -} - - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - ug::MathMatrix diffusion = m_imDiffusion[0]; - diffusion *= 1.0; - double diffCoeff = 1.0; - - if ( bElementIsOutside ) // = inside circle line!! - { diffusion *= 1.0; diffCoeff = 1.0;} - - // loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - ///////////////////////////////////////////////////// - // Diffusive Term - ///////////////////////////////////////////////////// - if(m_imDiffusion.data_given()) - { - // to compute D \nabla c - MathVector Dgrad_c, grad_c; - - // compute gradient and shape at ip - VecSet(grad_c, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(grad_c, u(_C_,sh), scvf.global_grad(sh)); - - // scale by diffusion tensor - MatVecMult(Dgrad_c, diffusion, grad_c); - - // Compute flux - const number diff_flux = VecDot(Dgrad_c, scvf.normal()); - - // Add to local defect - d(_C_, scvf.from()) -= diff_flux; - d(_C_, scvf.to() ) += diff_flux; - - } - - ///////////////////////////////////////////////////////////////////////////// - // Additional diffusive Term due to jump in solution at the interface - // u^+ - u^- = jump - ///////////////////////////////////////////////////////////////////////////// - if ( 1 ) - { - // scale diffusion by jump in solution: - // const double jump = 2.0; - // diffusion *= jump; - - // to compute D \nabla c=Id_interface - MathVector Dgrad, grad; - - // compute gradient and shape at ip - VecSet(grad, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(grad, jump(_C_,sh), scvf.global_grad(sh)); - - // scale by diffusion tensor - MatVecMult(Dgrad, diffusion, grad); - - // Compute flux - const number diff_flux = VecDot(Dgrad, scvf.normal()); - - // Add to local defect - d(_C_, scvf.from()) -= diff_flux; - d(_C_, scvf.to() ) += diff_flux; - - } - } - - ///////////////////////////////////////////////////// - // add rhs during same method! - // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! - ///////////////////////////////////////////////////// - - if ( 1 ) - { //m_imSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv( ip ); - - // get associated node - int co = scv.node_id(); - d(_C_, co) -= source(_C_, co) * scv.volume(); - - // Add to local rhs -/* if ( co > 2 ) - { - d(_C_, co) -= m_imSource[2] * scv.volume(); - UG_LOG("m_imSource[2] * scv.volume(): " << m_imSource[2] << "\n"); - UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); - } - else - { - d(_C_, co) -= m_imSource[co] * scv.volume(); - UG_LOG("m_imSource[co] * scv.volume(): " << m_imSource[co] << "\n"); - UG_LOG("source(_C_, co) * scv.volume(): " << source(_C_, co) << "\n"); - } - - */ - } - } - ///////////////////////////////////////////////////////////////////////////// - // Additional source Term due to jump in gradient at the interface - // (\nabla u^+ - \nabla u^-)\cdot n = h(x) * |n| - ///////////////////////////////////////////////////////////////////////////// - if ( 1 ) - { - std::vector& vBF = geo.get_boundary_faces(); - MathVector Dgrad; - VecSet(Dgrad, 0.0); - - if ( vBF.size() > 2 ) - UG_THROW("add_def_A_elem(): vBF.size() is greater than 2: " << vBF.size() << "\n"); - // loop integration points - for(size_t ip = 0; ip < vBF.size(); ++ip) - { - typename TFVGeom::BF bf = vBF[ip]; - // Add to local rhs - d(_C_, bf.node_id()) += jump_grad(_C_,bf.node_id()) * bf.Vol; - } - } - -} - - -template -template -void ConvectionDiffusionFV1:: -add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - -// reaction rate - if(m_imReactionRateExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local defect - d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume(); - } - } - -// reaction - if(m_imReactionExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local defect - d(_C_, co) += m_imReactionExpl[ip] * scv.volume(); - } - } - - if(m_imSourceExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local rhs - d(_C_, co) -= m_imSourceExpl[ip] * scv.volume(); - } - } -} - -template -template -void ConvectionDiffusionFV1:: -add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - if(!m_imMassScale.data_given() && !m_imMass.data_given()) return; - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // mass value - number val = 0.0; - - // multiply by scaling - if(m_imMassScale.data_given()) - val += m_imMassScale[ip] * u(_C_, co); - - // add mass - if(m_imMass.data_given()) - val += m_imMass[ip]; - - // Add to local defect - d(_C_, co) += val * scv.volume(); - } -} - - -template -template -void ConvectionDiffusionFV1:: -add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) -{ - ///////////////////////////////////////////////////// - // add rhs ALLREADY(!) during 'add_def_A_elem_local()' method! - // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! - ///////////////////////////////////////////////////// - - return; - - // get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - // loop Sub Control Volumes (SCV) - if ( m_imSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv( ip ); - - // get associated node - const int co = scv.node_id(); - - // Add to local rhs - d(_C_, co) += m_imSource[ip] * scv.volume(); - } - } - - // loop Sub Control Volumes (SCVF) - if ( m_imVectorSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); - - // Add to local rhs - d(_C_, scvf.from()) -= VecDot(m_imVectorSource[ip], scvf.normal() ); - d(_C_, scvf.to() ) += VecDot(m_imVectorSource[ip], scvf.normal() ); - } - } -} - - -//////////////////////////////////// -/// error estimation (begin) /// - -// prepares the loop over all elements of one type for the computation of the error estimator -template -template -void ConvectionDiffusionFV1:: -prep_err_est_elem_loop(const ReferenceObjectID roid, const int si) -{ - // get the error estimator data object and check that it is of the right type - // we check this at this point in order to be able to dispense with this check later on - // (i.e. in prep_err_est_elem and compute_err_est_A_elem()) - if (this->m_spErrEstData.get() == NULL) - { - UG_THROW("No ErrEstData object has been given to this ElemDisc!"); - } - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (!err_est_data) - { - UG_THROW("Dynamic cast to SideAndElemErrEstData failed." - << std::endl << "Make sure you handed the correct type of ErrEstData to this discretization."); - } - - -// check that upwind has been set - if (m_spConvShape.invalid()) - UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " - "Upwind has not been set."); - -// set local positions - if (!TFVGeom::usesHangingNodes) - { - static const int refDim = TElem::dim; - - // get local IPs - size_t numSideIPs, numElemIPs; - const MathVector* sideIPs; - const MathVector* elemIPs; - try - { - numSideIPs = err_est_data->num_all_side_ips(roid); - numElemIPs = err_est_data->num_elem_ips(roid); - sideIPs = err_est_data->template side_local_ips(roid); - elemIPs = err_est_data->template elem_local_ips(roid); - - if (!sideIPs || !elemIPs) return; // are NULL if TElem is not of the same dim as TDomain - } - UG_CATCH_THROW("Integration points for error estimator cannot be set."); - - // set local IPs in imports - m_imDiffusion.template set_local_ips(sideIPs, numSideIPs, false); - m_imVelocity.template set_local_ips(sideIPs, numSideIPs, false); - m_imFlux.template set_local_ips(sideIPs, numSideIPs, false); - m_imSource.template set_local_ips(elemIPs, numElemIPs, false); - m_imVectorSource.template set_local_ips(sideIPs, numSideIPs, false); - m_imReactionRate.template set_local_ips(elemIPs, numElemIPs, false); - m_imReaction.template set_local_ips(elemIPs, numElemIPs, false); - m_imMassScale.template set_local_ips(elemIPs, numElemIPs, false); - m_imMass.template set_local_ips(elemIPs, numElemIPs, false); - - // init upwind for element type - TFVGeom& geo = GeomProvider::get(); - if (!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " - "Cannot init upwind for element type."); - - // store values of shape functions in local IPs - LagrangeP1::reference_element_type> trialSpace - = Provider::reference_element_type> >::get(); - - m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh()); - for (size_t ip = 0; ip < numElemIPs; ip++) - trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]); - for (size_t ip = 0; ip < numSideIPs; ip++) - trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]); - } -} - -template -template -void ConvectionDiffusionFV1:: -prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{} - -// computes the error estimator contribution (stiffness part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ - typedef typename reference_element_traits::reference_element_type ref_elem_type; - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - -// request geometry - static const TFVGeom& geo = GeomProvider::get(); - -//////////////// -// SIDE TERMS // -//////////////// - -// get the sides of the element - // We have to cast elem to a pointer of type SideAndElemErrEstData::elem_type - // for the SideAndElemErrEstData::operator() to work properly. - // This cannot generally be achieved by casting to TElem*, since this method is also registered for - // lower-dimensional types TElem, and must therefore be compilable, even if it is never EVER to be executed. - // The way we achieve this here, is by calling associated_elements_sorted() which has an implementation for - // all possible types. Whatever comes out of it is of course complete nonsense if (and only if) - // SideAndElemErrEstData::elem_type != TElem. To be on the safe side, we throw an error if the number of - // entries in the list is not as it should be. - - typename MultiGrid::traits::side_type>::secure_container side_list; - pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); - if (side_list.size() != (size_t) ref_elem_type::numSides) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// some help variables - MathVector fluxDensity, gradC, normal; - -// calculate grad u (take grad from first scvf ip (grad u is constant on the entire element)) - if (geo.num_scvf() < 1) {UG_THROW("Element has no SCVFs!");} - const typename TFVGeom::SCVF& scvf = geo.scvf(0); - - VecSet(gradC, 0.0); - for (size_t j=0; j(normal, side, vCornerCoords); - VecNormalize(normal, normal); - - try - { - for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) - { - size_t ip = passedIPs + sip; - - VecSet(fluxDensity, 0.0); - - ////// diffusion ////// - if (m_imDiffusion.data_given()) - MatVecScaleMultAppend(fluxDensity, -1.0, m_imDiffusion[0], gradC); - - ////// convection ////// - if (m_imVelocity.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtSideIP(sh,sip); - - VecScaleAppend(fluxDensity, val, m_imVelocity[ip]); - } - - ////// general flux ////// - if (m_imFlux.data_given()) - VecAppend(fluxDensity, m_imFlux[ip]); - - (*err_est_data)(side_list[side],sip) += scale * VecDot(fluxDensity, normal); - } - - passedIPs += err_est_data->num_side_ips(side_list[side]); - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); - } - -////////////////// -// VOLUME TERMS // -////////////////// - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - { - number total = 0.0; - - ////// diffusion ////// TODO ONLY FOR (PIECEWISE) CONSTANT DIFFUSION TENSOR SO FAR! - // div(D*grad(c)) = div(v)*u + v*grad(c) - // nothing to do, as u is piecewise linear and div(D*grad(c)) disappears - - ////// convection ////// TODO ONLY FOR CONSTANT VELOCITY FIELDS SO FAR! - // div(v*c) = div(v)*u + v*grad(c) -- gradC has been calculated above - if (m_imVelocity.data_given()) - total += VecDot(m_imVelocity[ip], gradC); - - ////// general flux ////// TODO ONLY FOR DIVERGENCE-FREE FLUX FIELD SO FAR! - // nothing to do - - ////// reaction ////// - if (m_imReactionRate.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < geo.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); - - total += m_imReactionRate[ip] * val; - } - - if (m_imReaction.data_given()) - { - total += m_imReaction[ip]; - } - - (*err_est_data)(elem_list[0],ip) += scale * total; - } - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// computes the error estimator contribution (mass part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ -// note: mass parts only enter volume term - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// request geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop integration points - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - { - number total = 0.0; - - ////// mass scale ////// - if (m_imMassScale.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < geo.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); - - total += m_imMassScale[ip] * val; - } - - ////// mass ////// - if (m_imMass.data_given()) - { - total += m_imMass[ip]; - } - - (*err_est_data)(elem_list[0],ip) += scale * total; - } - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// computes the error estimator contribution (rhs part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ - typedef typename reference_element_traits::reference_element_type ref_elem_type; - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - -//////////////// -// SIDE TERMS // -//////////////// -// get the sides of the element - typename MultiGrid::traits::side_type>::secure_container side_list; - pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); - if (side_list.size() != (size_t) ref_elem_type::numSides) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// loop sides - size_t passedIPs = 0; - for (size_t side = 0; side < (size_t) ref_elem_type::numSides; side++) - { - // normal on side - MathVector normal; - SideNormal(normal, side, vCornerCoords); - VecNormalize(normal, normal); - - try - { - for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) - { - size_t ip = passedIPs + sip; - - ////// vector source ////// - if (m_imVectorSource.data_given()) - (*err_est_data)(side_list[side],sip) += scale * VecDot(m_imVectorSource[ip], normal); - } - - passedIPs += err_est_data->num_side_ips(side_list[side]); - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); - } - -////////////////// -// VOLUME TERMS // -////////////////// - if (!m_imSource.data_given()) return; - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -////// source ////// - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - (*err_est_data)(elem_list[0],ip) += scale * m_imSource[ip]; - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// postprocesses the loop over all elements of one type in the computation of the error estimator -template -template -void ConvectionDiffusionFV1:: -fsh_err_est_elem_loop() -{ -// finish the element loop in the same way as the actual discretization - this->template fsh_elem_loop (); -}; - -/// error estimation (end) /// -//////////////////////////////////// - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -lin_def_velocity(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // sum up contributions of convection shapes - MathVector linDefect; - VecSet(linDefect, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(linDefect, u(_C_,sh), convShape.D_vel(ip, sh)); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] += linDefect; - vvvLinDef[ip][_C_][scvf.to()] -= linDefect; - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -lin_def_diffusion(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // compute gradient at ip - MathVector grad_u; VecSet(grad_u, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(grad_u, u(_C_,sh), scvf.global_grad(sh)); - - // compute the lin defect at this ip - MathMatrix linDefect; - - // part coming from -\nabla u * \vec{n} - for(size_t k=0; k < (size_t)dim; ++k) - for(size_t j = 0; j < (size_t)dim; ++j) - linDefect(j,k) = (scvf.normal())[j] * grad_u[k]; - - // add contribution from convection shapes - if(convShape.non_zero_deriv_diffusion()) - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - MatAdd(linDefect, convShape.D_diffusion(ip, sh), u(_C_, sh)); - - // add contributions - vvvLinDef[ip][_C_][scvf.from()] -= linDefect; - vvvLinDef[ip][_C_][scvf.to() ] += linDefect; - } -} - -template -template -void ConvectionDiffusionFV1:: -lin_def_flux(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] += scvf.normal(); - vvvLinDef[ip][_C_][scvf.to()] -= scvf.normal(); - } -} -// computes the linearized defect w.r.t to the reaction rate -template -template -void ConvectionDiffusionFV1:: -lin_def_reaction_rate(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = u(_C_, co) * scv.volume(); - } -} - -// computes the linearized defect w.r.t to the reaction -template -template -void ConvectionDiffusionFV1:: -lin_def_reaction(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the source -template -template -void ConvectionDiffusionFV1:: -lin_def_source(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the vector source -// (in analogy to velocity) -template -template -void ConvectionDiffusionFV1:: -lin_def_vector_source(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ - // get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - - // loop Sub Control Volumes Faces (SCVF) - for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] -= scvf.normal(); - vvvLinDef[ip][_C_][scvf.to()] += scvf.normal(); - } -} - -// computes the linearized defect w.r.t to the mass scale -template -template -void ConvectionDiffusionFV1:: -lin_def_mass_scale(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t co = 0; co < geo.num_scv(); ++co) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(co); - - // Check associated node - UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); - - // set lin defect - vvvLinDef[co][_C_][co] = u(_C_, co) * scv.volume(); - } -} - -// computes the linearized defect w.r.t to the mass scale -template -template -void ConvectionDiffusionFV1:: -lin_def_mass(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t co = 0; co < geo.num_scv(); ++co) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(co); - - // Check associated node - UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); - - // set lin defect - vvvLinDef[co][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -ex_value(number vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > vvvDeriv[]) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reference element - typedef typename reference_element_traits::reference_element_type - ref_elem_type; - -// number of shape functions - static const size_t numSH = ref_elem_type::numCorners; - -// FV1 SCVF ip - if(vLocIP == geo.scvf_local_ips()) - { - // Loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // Get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // compute concentration at ip - vValue[ip] = 0.0; - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vValue[ip] += u(_C_, sh) * scvf.shape(sh); - - // compute derivative w.r.t. to unknowns iff needed - if(bDeriv) - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vvvDeriv[ip][_C_][sh] = scvf.shape(sh); - } - } -// FV1 SCV ip - else if(vLocIP == geo.scv_local_ips()) - { - // solution at ip - for(size_t sh = 0; sh < numSH; ++sh) - vValue[sh] = u(_C_, sh); - - // set derivatives if needed - if(bDeriv) - for(size_t sh = 0; sh < numSH; ++sh) - for(size_t sh2 = 0; sh2 < numSH; ++sh2) - vvvDeriv[sh][_C_][sh2] = (sh==sh2) ? 1.0 : 0.0; - } -// general case - else - { - // get trial space - LagrangeP1& rTrialSpace = Provider >::get(); - - // storage for shape function at ip - number vShape[numSH]; - - // loop ips - for(size_t ip = 0; ip < nip; ++ip) - { - // evaluate at shapes at ip - rTrialSpace.shapes(vShape, vLocIP[ip]); - - // compute concentration at ip - vValue[ip] = 0.0; - for(size_t sh = 0; sh < numSH; ++sh) - vValue[ip] += u(_C_, sh) * vShape[sh]; - - // compute derivative w.r.t. to unknowns iff needed - // \todo: maybe store shapes directly in vvvDeriv - if(bDeriv) - for(size_t sh = 0; sh < numSH; ++sh) - vvvDeriv[ip][_C_][sh] = vShape[sh]; - } - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -ex_grad(MathVector vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > > vvvDeriv[]) -{ -// Get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reference element - typedef typename reference_element_traits::reference_element_type - ref_elem_type; - -// reference dimension - static const int refDim = ref_elem_type::dim; - -// number of shape functions - static const size_t numSH = ref_elem_type::numCorners; - -// FV1 SCVF ip - if(vLocIP == geo.scvf_local_ips()) - { - // Loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // Get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - VecSet(vValue[ip], 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(vValue[ip], u(_C_, sh), scvf.global_grad(sh)); - - if(bDeriv) - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vvvDeriv[ip][_C_][sh] = scvf.global_grad(sh); - } - } -// general case - else - { - // get trial space - LagrangeP1& rTrialSpace = Provider >::get(); - - // storage for shape function at ip - MathVector vLocGrad[numSH]; - MathVector locGrad; - - // Reference Mapping - MathMatrix JTInv; - ReferenceMapping mapping(vCornerCoords); - - // loop ips - for(size_t ip = 0; ip < nip; ++ip) - { - // evaluate at shapes at ip - rTrialSpace.grads(vLocGrad, vLocIP[ip]); - - // compute grad at ip - VecSet(locGrad, 0.0); - for(size_t sh = 0; sh < numSH; ++sh) - VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]); - - // compute global grad - mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]); - MatVecMult(vValue[ip], JTInv, locGrad); - - // compute derivative w.r.t. to unknowns iff needed - if(bDeriv) - for(size_t sh = 0; sh < numSH; ++sh) - MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); - } - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// upwind -//////////////////////////////////////////////////////////////////////////////// - -template -void ConvectionDiffusionFV1:: -set_upwind(SmartPtr > shapes) {m_spConvShape = shapes;} - -// computes the linearized defect w.r.t to the velocity -template -const typename ConvectionDiffusionFV1::conv_shape_type& -ConvectionDiffusionFV1:: -get_updated_conv_shapes(const FVGeometryBase& geo) -{ -// compute upwind shapes for transport equation -// \todo: we should move this computation into the preparation part of the -// disc, to only compute the shapes once, reusing them several times. - if(m_imVelocity.data_given()) - { - // get diffusion at ips - const MathMatrix* vDiffusion = NULL; - if(m_imDiffusion.data_given()) vDiffusion = m_imDiffusion.values(); - - // update convection shapes - if(!m_spConvShape->update(&geo, m_imVelocity.values(), vDiffusion, true)) - { - UG_LOG("ERROR in 'ConvectionDiffusionFV1::add_jac_A_elem': " - "Cannot compute convection shapes.\n"); - } - } - -// return a const (!!) reference to the upwind - return *const_cast*>(m_spConvShape.get()); -} - - -//////////////////////////////////////////////////////////////////////////////// -// register assemble functions -//////////////////////////////////////////////////////////////////////////////// - -#ifdef UG_DIM_1 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - - - /* -// switch assemble functions - if(!bHang) - { - register_func >(); - } - else - { - register_func >(); - } -*/ -} -#endif - -#ifdef UG_DIM_2 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - - /* -// switch assemble functions - if(!bHang) - { - register_func >(); - register_func >(); - register_func >(); - } - else - { - register_func >(); - register_func >(); - register_func >(); - } - */ -} -#endif - -#ifdef UG_DIM_3 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - - /* -// switch assemble functions - if(!bHang) - { - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - } - else - { - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - } - */ -} -#endif - -template -template -void ConvectionDiffusionFV1:: -register_func() -{ - ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; - typedef this_type T; - static const int refDim = reference_element_traits::dim; - - this->clear_add_fct(id); - this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); - this->set_prep_elem_fct( id, &T::template prep_elem); - this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); - this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem); - this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem); - this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem); - this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem); - this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem); - this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); - -// error estimator parts -/* this->set_prep_err_est_elem_loop(id, &T::template prep_err_est_elem_loop); - this->set_prep_err_est_elem(id, &T::template prep_err_est_elem); - this->set_compute_err_est_A_elem(id, &T::template compute_err_est_A_elem); - this->set_compute_err_est_M_elem(id, &T::template compute_err_est_M_elem); - this->set_compute_err_est_rhs_elem(id, &T::template compute_err_est_rhs_elem); - this->set_fsh_err_est_elem_loop(id, &T::template fsh_err_est_elem_loop); -*/ -// set computation of linearized defect w.r.t velocity - m_imDiffusion.set_fct(id, this, &T::template lin_def_diffusion); - m_imVelocity. set_fct(id, this, &T::template lin_def_velocity); - m_imFlux.set_fct(id, this, &T::template lin_def_flux); - m_imReactionRate. set_fct(id, this, &T::template lin_def_reaction_rate); - m_imReaction. set_fct(id, this, &T::template lin_def_reaction); - m_imSource. set_fct(id, this, &T::template lin_def_source); - m_imVectorSource.set_fct(id, this, &T::template lin_def_vector_source); - m_imMassScale.set_fct(id, this, &T::template lin_def_mass_scale); - m_imMass. set_fct(id, this, &T::template lin_def_mass); - -// exports - m_exValue-> template set_fct(id, this, &T::template ex_value); - m_exGrad->template set_fct(id, this, &T::template ex_grad); -} - -//////////////////////////////////////////////////////////////////////////////// -// explicit template instantiations -//////////////////////////////////////////////////////////////////////////////// -#ifdef UG_DIM_1 -template class ConvectionDiffusionFV1; -#endif -#ifdef UG_DIM_2 -template class ConvectionDiffusionFV1; -#endif -#ifdef UG_DIM_3 -template class ConvectionDiffusionFV1; -#endif - -} // end namespace ConvectionDiffusionPlugin -} // namespace ug - diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.h b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.h deleted file mode 100644 index 6afb1eb..0000000 --- a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_last.h +++ /dev/null @@ -1,325 +0,0 @@ -/* - * convection_diffusion_fv1.h - * - * Created on: 26.02.2010 - * Author: andreasvogel - */ - -#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ -#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ - -// library intern headers -#include "../convection_diffusion_base.h" -#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" - -namespace ug{ -namespace ConvectionDiffusionPlugin{ - -// \ingroup lib_disc_elem_disc -/// \addtogroup convection_diffusion -/// \{ - -/// Discretization for the Convection-Diffusion Equation -/** - * This class implements the IElemDisc interface to provide element local - * assemblings for the convection diffusion equation. - * The Equation has the form - * \f[ - * \partial_t (m1*c + m2) - \nabla \left( D \nabla c - \vec{v} c \right - \vec{F}) + - * r1 \cdot c + r2 = f + f2 - * \f] - * with - *
    - *
  • \f$ c \f$ is the unknown solution - *
  • \f$ m1 \equiv m(\vec{x},t) \f$ is the Mass Scaling Term - *
  • \f$ m2 \equiv m(\vec{x},t) \f$ is the Mass Term - *
  • \f$ D \equiv D(\vec{x},t) \f$ is the Diffusion Tensor - *
  • \f$ v \equiv \vec{v}(\vec{x},t) \f$ is the Velocity Field - *
  • \f$ F \equiv \vec{F}(\vec{x},t) \f$ is the Flux - *
  • \f$ r1 \equiv r(\vec{x},t) \f$ is the Reaction Rate - *
  • \f$ r2 \equiv r(\vec{x},t) \f$ is a Reaction Term - *
  • \f$ f \equiv f(\vec{x},t) \f$ is a Source Term - *
  • \f$ f2 \equiv f_2(\vec{x},t) \f$ is a Vector Source Term - *
- * - * \tparam TDomain Domain - * \tparam TAlgebra Algebra - */ -template< typename TDomain> -class ConvectionDiffusionFV1 : public ConvectionDiffusionBase -{ - private: - /// Base class type - typedef ConvectionDiffusionBase base_type; - - /// Own type - typedef ConvectionDiffusionFV1 this_type; - - /// error estimator type - typedef SideAndElemErrEstData err_est_type; - - public: - /// World dimension - static const int dim = base_type::dim; - - public: - /// Constructor - ConvectionDiffusionFV1(const char* functions, const char* subsets); - - /// set the upwind method - /** - * This method sets the upwind method used to upwind the convection. - * - * \param shapes upwind method - */ - void set_upwind(SmartPtr > shapes); - - private: - /// prepares the loop over all elements - /** - * This method prepares the loop over all elements. It resizes the Position - * array for the corner coordinates and schedules the local ip positions - * at the data imports. - */ - template - void prep_elem_loop(const ReferenceObjectID roid, const int si); - - /// prepares the element for assembling - /** - * This methods prepares an element for the assembling. The Positions of - * the Element Corners are read and the Finite Volume Geometry is updated. - * The global ip positions are scheduled at the data imports. - */ - template - void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]); - - /// finishes the loop over all elements - template - void fsh_elem_loop(); - - /// assembles the local stiffness matrix using a finite volume scheme - template - void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - template - void add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - - template - void add_jac_A_elem_boundary(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - - /// assembles the local mass matrix using a finite volume scheme - template - void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the stiffness part of the local defect - template - void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - /// assembles the stiffness part of the local defect - template - void add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - - template - void add_def_A_elem_boundary(TFVGeom& geo, LocalVector& d, LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - - template - number add_l2error_A_elem(TFVGeom& geo, ReferenceObjectID roid, LocalVector& d, const LocalVector& u, GridObject* elem); - - /// assembles the stiffness part of the local defect explicit reaction, reaction_rate and source - template - void add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the mass part of the local defect - template - void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the local right hand side - template - void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); - template - void add_rhs_elem_local(TFVGeom& geo, LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); - - /// prepares the loop over all elements of one type for the computation of the error estimator - template - void prep_err_est_elem_loop(const ReferenceObjectID roid, const int si); - - /// prepares the element for assembling the error estimator - template - void prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// computes the error estimator contribution for one element - template - void compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// computes the error estimator contribution for one element - template - void compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// computes the error estimator contribution for one element - template - void compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// postprocesses the loop over all elements of one type in the computation of the error estimator - template - void fsh_err_est_elem_loop(); - - protected: - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_velocity(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_diffusion(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_flux(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the reaction - template - void lin_def_reaction(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the reaction - template - void lin_def_reaction_rate(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the source term - template - void lin_def_source(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the vector source term - template - void lin_def_vector_source(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the mass scale term - template - void lin_def_mass_scale(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the mass scale term - template - void lin_def_mass(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - private: - /// abbreviation for the local solution - static const size_t _C_ = 0; - - using base_type::m_imDiffusion; - using base_type::m_imVelocity; - using base_type::m_imFlux; - using base_type::m_imSource; - using base_type::m_imSourceExpl; - using base_type::m_imVectorSource; - using base_type::m_imReactionRate; - using base_type::m_imReactionRateExpl; - using base_type::m_imReaction; - using base_type::m_imReactionExpl; - using base_type::m_imMassScale; - using base_type::m_imMass; - - using base_type::m_exGrad; - using base_type::m_exValue; - - protected: - /// method to compute the upwind shapes - SmartPtr > m_spConvShape; - - /// returns the updated convection shapes - typedef IConvectionShapes conv_shape_type; - const IConvectionShapes& get_updated_conv_shapes(const FVGeometryBase& geo); - - /// computes the concentration - template - void ex_value(number vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > vvvDeriv[]); - - /// computes the gradient of the concentration - template - void ex_grad(MathVector vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > > vvvDeriv[]); - - public: - /// type of trial space for each function used - virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid); - - /// returns if hanging nodes are needed - virtual bool use_hanging() const; - - protected: - /// current regular grid flag - bool m_bNonRegularGrid; - - /// current shape function set (needed for GeomProvider::get()) - LFEID m_LFEID; - - /// register utils - /// \{ - void register_all_funcs(bool bHang); - template void register_func(); - /// \} - - private: - /// struct holding values of shape functions in IPs - struct ShapeValues - { - public: - void resize(std::size_t nEip, std::size_t nSip, std::size_t _nSh) - { - nSh = _nSh; - elemVals.resize(nEip); - sideVals.resize(nSip); - for (std::size_t i = 0; i < nEip; i++) elemVals[i].resize(nSh); - for (std::size_t i = 0; i < nSip; i++) sideVals[i].resize(nSh); - } - number& shapeAtElemIP(std::size_t sh, std::size_t ip) {return elemVals[ip][sh];} - number& shapeAtSideIP(std::size_t sh, std::size_t ip) {return sideVals[ip][sh];} - number* shapesAtElemIP(std::size_t ip) {return &elemVals[ip][0];} - number* shapesAtSideIP(std::size_t ip) {return &sideVals[ip][0];} - std::size_t num_sh() {return nSh;} - private: - std::size_t nSh; - std::vector > elemVals; - std::vector > sideVals; - } m_shapeValues; -}; - -// end group convection_diffusion -/// \} - -} // end ConvectionDiffusionPlugin -} // end namespace ug - - -#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__*/ diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.cpp b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.cpp deleted file mode 100644 index cb5858c..0000000 --- a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.cpp +++ /dev/null @@ -1,1828 +0,0 @@ -/* - * convection_diffusion_fv1.cpp - * - * Created on: 26.02.2010 - * Author: andreasvogel - */ - -#include "convection_diffusion_fv1.h" - -#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" - -#include "lib_disc/spatial_disc/disc_util/geom_provider.h" -//#include "lib_disc/spatial_disc/disc_util/fv1_geom.h" -//#include "lib_disc/spatial_disc/disc_util/hfv1_geom.h" -#include "lib_disc/spatial_disc/disc_util/conv_shape.h" - -namespace ug{ -namespace ConvectionDiffusionPlugin{ - -//////////////////////////////////////////////////////////////////////////////// -// general -//////////////////////////////////////////////////////////////////////////////// - -template -ConvectionDiffusionFV1:: -ConvectionDiffusionFV1(const char* functions, const char* subsets) - : ConvectionDiffusionBase(functions,subsets), - m_spConvShape(new ConvectionShapesNoUpwind), - m_bNonRegularGrid(false) -{ - register_all_funcs(m_bNonRegularGrid); -} - - -template -void ConvectionDiffusionFV1:: -prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid) -{ -// check number - if(vLfeID.size() != 1) - UG_THROW("ConvectionDiffusion: Wrong number of functions given. " - "Need exactly "<<1); - - if(vLfeID[0].order() != 1 || vLfeID[0].type() != LFEID::LAGRANGE) - UG_THROW("ConvectionDiffusion FV Scheme only implemented for 1st order."); - -// remember - m_bNonRegularGrid = bNonRegularGrid; - - m_LFEID = vLfeID[0]; - -// update assemble functions - register_all_funcs(m_bNonRegularGrid); -} - -template -bool ConvectionDiffusionFV1:: -use_hanging() const -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// Assembling functions -//////////////////////////////////////////////////////////////////////////////// - -template -template -void ConvectionDiffusionFV1:: -prep_elem_loop(const ReferenceObjectID roid, const int si) -{ - // Only first order implementation - if(!(TFVGeom::order == 1)) - UG_THROW("Only first order implementation, but other Finite Volume" - " Geometry set."); - -// check, that upwind has been set - if(m_spConvShape.invalid()) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Upwind has not been set."); - -// set local positions - if(!TFVGeom::usesHangingNodes && TFVGeom::staticLocalData) - { - static const int refDim = TElem::dim; - TFVGeom& geo = GeomProvider::get(); -// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); - const MathVector* vSCVFip = geo.scvf_local_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_local_ips(); - const size_t numSCVip = geo.num_scv_ips(); - m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip, false); - m_imVelocity.template set_local_ips(vSCVFip,numSCVFip, false); - m_imFlux.template set_local_ips(vSCVFip,numSCVFip, false); - m_imSource.template set_local_ips(vSCVip,numSCVip, false); - m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip, false); - m_imReactionRate.template set_local_ips(vSCVip,numSCVip, false); - m_imReaction.template set_local_ips(vSCVip,numSCVip, false); - m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imReactionExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imSourceExpl.template set_local_ips(vSCVip,numSCVip, false); - m_imMassScale.template set_local_ips(vSCVip,numSCVip, false); - m_imMass.template set_local_ips(vSCVip,numSCVip, false); - - // init upwind for element type - if(!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Cannot init upwind for element type."); - } -} - -template -template -void ConvectionDiffusionFV1:: -fsh_elem_loop() -{} - -template -template -void ConvectionDiffusionFV1:: -prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]) -{ -// Update Geometry for this element - //static TFVGeom& geo = GeomProvider::get(); -// TFVGeom& geo = GeomProvider::get(m_LFEID,1); - TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1),1); - -// TFVGeom& geo = GeomProvider::get(); -// TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); - - // fix: set orientation initially globally! - geo.set_orientation(1); - - try{ - geo.update(elem, roid, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::prep_elem:" - " Cannot update Finite Volume Geometry."); - -// set local positions - if(TFVGeom::usesHangingNodes || !TFVGeom::staticLocalData) - { - const int refDim = TElem::dim; - const MathVector* vSCVFip = geo.scvf_local_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_local_ips(); - const size_t numSCVip = geo.num_scv_ips(); - m_imDiffusion.template set_local_ips(vSCVFip,numSCVFip); - m_imVelocity.template set_local_ips(vSCVFip,numSCVFip); - m_imFlux.template set_local_ips(vSCVFip,numSCVFip); - m_imSource.template set_local_ips(vSCVip,numSCVip); - m_imVectorSource.template set_local_ips(vSCVFip,numSCVFip); - m_imReactionRate.template set_local_ips(vSCVip,numSCVip); - m_imReaction.template set_local_ips(vSCVip,numSCVip); - m_imReactionRateExpl.template set_local_ips(vSCVip,numSCVip); - m_imReactionExpl.template set_local_ips(vSCVip,numSCVip); - m_imSourceExpl.template set_local_ips(vSCVip,numSCVip); - m_imMassScale.template set_local_ips(vSCVip,numSCVip); - m_imMass.template set_local_ips(vSCVip,numSCVip); -/* - if(m_spConvShape.valid()) - if(!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:" - " Cannot init upwind for element type."); - */ - } - - // set global positions - const MathVector* vSCVFip = geo.scvf_global_ips(); - const size_t numSCVFip = geo.num_scvf_ips(); - const MathVector* vSCVip = geo.scv_global_ips(); - const size_t numSCVip = geo.num_scv_ips(); - - m_imDiffusion. set_global_ips(vSCVFip, numSCVFip); - m_imVelocity. set_global_ips(vSCVFip, numSCVFip); - m_imFlux. set_global_ips(vSCVFip, numSCVFip); - m_imSource. set_global_ips(vSCVip, numSCVip); - m_imVectorSource. set_global_ips(vSCVFip, numSCVFip); - m_imReactionRate. set_global_ips(vSCVip, numSCVip); - m_imReactionRateExpl. set_global_ips(vSCVip, numSCVip); - m_imReactionExpl. set_global_ips(vSCVip, numSCVip); - m_imSourceExpl. set_global_ips(vSCVip, numSCVip); - m_imReaction. set_global_ips(vSCVip, numSCVip); - m_imMassScale. set_global_ips(vSCVip, numSCVip); - m_imMass. set_global_ips(vSCVip, numSCVip); - -} - - -template -static TVector CalculateCenter(GridObject* o, const TVector* coords) -{ - TVector v; - VecSet(v, 0); - - size_t numCoords = 0; - switch(o->base_object_id()){ - case VERTEX: numCoords = 1; break; - case EDGE: numCoords = static_cast(o)->num_vertices(); break; - case FACE: numCoords = static_cast(o)->num_vertices(); break; - case VOLUME: numCoords = static_cast(o)->num_vertices(); break; - default: UG_THROW("Unknown element type."); break; - } - - for(size_t i = 0; i < numCoords; ++i) - VecAdd(v, v, coords[i]); - - if(numCoords > 0) - VecScale(v, v, 1. / (number)numCoords); - - return v; -} - -void LU(MathMatrix<3, 3>& R, MathMatrix<3, 3>& L, MathMatrix<3, 3> A) -{ - // n-1 Iterationsschritte - for ( size_t i = 1; i < 2; ++i) - { - for ( size_t k = i+1; i < 3; ++i) - { - L[k][i] = R[k][i] / R[i][i]; - - for ( size_t j = i; i < 3; ++i) - R[k][j] = R[k][j] - L[k][i] * R[i][j]; - } - } - -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - - bool debug = false; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); - TFVGeom& geo = GeomProvider::get(m_LFEID,1); - const bool bElementIsCut = geo.get_element_modus(); - const bool bElementIsOutside = geo.get_boolian_for_diffusion(); - - // First call with orientation = 1: - size_t orientation = 1; - geo.set_orientation(orientation); - - -// normal assembling if not cut by interface: - if ( !bElementIsCut ) - { - LocalVector dummyU; - LocalIndices ind = u.get_indices(); - dummyU.resize(ind); - dummyU = 0; - - this->template add_jac_A_elem_local (geo, J, u, dummyU, elem, vCornerCoords, bElementIsOutside); - return; - } - -// get data: - geo.resize_local_data(u); - LocalMatrix& locJ_tri = geo.get_jacobian_tri(); - LocalMatrix& locJ_quad = geo.get_jacobian_quad(); - - LocalVector& locU_tri = geo.get_solution_tri(); - LocalVector& locU_quad = geo.get_solution_quad(); - -// reset data: - locJ_tri = 0; - locJ_quad = 0; - - LocalIndices ind = u.get_indices(); - - // call elem disc twice: - - if ( debug ) geo.print_InterfaceIDdata(); - - ReferenceObjectID roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - - this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, true); - - geo.set_jacobian_tri(locJ_tri); - geo.set_DoF_tag_tri(false); - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - - this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, true); - geo.set_jacobian_quad(locJ_quad); - geo.set_DoF_tag_quad(false); - } - - -// Second call with orientation = 1: - bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! - - orientation *= -1; - geo.set_orientation(orientation); - try{ - geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" - " Cannot update Finite Volume Geometry."); - - if ( debug ) geo.print_InterfaceIDdata(); - - roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - - this->template add_jac_A_elem_local (geo, locJ_tri, locU_tri, jump_tri, elem, vCornerCoords, false); - geo.set_jacobian_tri(locJ_tri); - geo.set_DoF_tag_tri(shiftTag); - - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - - this->template add_jac_A_elem_local (geo, locJ_quad, locU_quad, jump_quad, elem, vCornerCoords, false); - - geo.set_jacobian_quad(locJ_quad); - geo.set_DoF_tag_quad(shiftTag); - } - - -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - ug::MathMatrix diffusion = m_imDiffusion[0]; - if ( bElementIsOutside ) - diffusion *= 1.0; - -// Diff. Tensor times Gradient - MathVector Dgrad; - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// Diffusion and Velocity Term - if(m_imDiffusion.data_given() || m_imVelocity.data_given()) - { - - // loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - //////////////////////////////////////////////////// - // Diffusive Term - //////////////////////////////////////////////////// - if(m_imDiffusion.data_given()) - { - // loop shape functions - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - { - // Compute Diffusion Tensor times Gradient - MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); - - // Compute flux at IP - const number D_diff_flux = VecDot(Dgrad, scvf.normal()); - - // Add flux term to local matrix // HIER MATRIXINDIZES!!! - /* UG_ASSERT((scvf.from() < J.num_row_dof(_C_)) && (scvf.to() < J.num_col_dof(_C_)), - "Bad local dof-index on element with object-id " << elem->base_object_id() - << " with center: " << CalculateCenter(elem, vCornerCoords)); -*/ - J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; - J(_C_, scvf.to() , _C_, sh) += D_diff_flux; - } - } - - ///////////////////////////////////////////////////////////////////////////// - // Additional diffusive Term due to jump in solution at the interface - // u^+ - u^- = jump - ///////////////////////////////////////////////////////////////////////////// - if ( 1 ) - { - // loop shape functions - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - { - // Compute Diffusion Tensor times Gradient - MatVecMult(Dgrad, diffusion, scvf.global_grad(sh)); - - // Compute flux at IP - const number D_diff_flux = jump(_C_,sh)*VecDot(Dgrad, scvf.normal()); - - J(_C_, scvf.from(), _C_, sh) -= D_diff_flux; - J(_C_, scvf.to() , _C_, sh) += D_diff_flux; - } - - } - //////////////////////////////////////////////////// - // Convective Term - //////////////////////////////////////////////////// - if(m_imVelocity.data_given()) - { - // Add Flux contribution - for(size_t sh = 0; sh < convShape.num_sh(); ++sh) - { - const number D_conv_flux = convShape(ip, sh); - - // Add flux term to local matrix - J(_C_, scvf.from(), _C_, sh) += D_conv_flux; - J(_C_, scvf.to(), _C_, sh) -= D_conv_flux; - } - } - - // no explicit dependency on flux import - } - } - - -//////////////////////////////////////////////////// -// Reaction Term (using lumping) -//////////////////////////////////////////////////// - -// if no data for reaction rate given, return - if(!m_imReactionRate.data_given()) return; - -// loop Sub Control Volume (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local matrix - J(_C_, co, _C_, co) += m_imReactionRate[ip] * scv.volume(); - } - -// reaction term does not explicitly depend on the associated unknown function -} - -template -template -void ConvectionDiffusionFV1:: -add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - if(!m_imMassScale.data_given()) return; - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local matrix - J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip]; - } - -// m_imMass part does not explicitly depend on associated unknown function -} - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ - bool debug = true; - - // get finite volume geometry - // static const TFVGeom& geo = GeomProvider::get(); - TFVGeom& geo = GeomProvider::get(m_LFEID,1); - const bool bElementIsCut = geo.get_element_modus(); - const bool bElementIsOutside = geo.get_boolian_for_diffusion(); - - // First call with orientation = 1: - size_t orientation = 1; - geo.set_orientation(orientation); - - // necessary for call of 'get_solution_tri' an 'get_solution_quad': - geo.resize_local_data(u); - std::vector imSource; - if ( m_imSource.data_given() ) { - for ( size_t i = 0; i < 3; ++i ) - imSource.push_back(m_imSource[i]); - } - -// normal assembling if not cut by interface: - if ( !bElementIsCut ) - { - LocalVector dummyU; - LocalIndices ind = d.get_indices(); - dummyU.resize(ind); - dummyU = 0; - LocalVector source = geo.set_source(imSource, ind, 3); - - this->template add_def_A_elem_local (geo, d, u, dummyU, dummyU, source, elem, vCornerCoords, bElementIsOutside); - - return; - } - -// get data: - LocalVector& locD_tri = geo.get_defect_tri(); - LocalVector& locD_quad = geo.get_defect_quad(); - - LocalVector& locU_tri = geo.get_solution_tri(); - LocalVector& locU_quad = geo.get_solution_quad(); - -// reset data: - locD_tri = 0; - locD_quad = 0; - - // call elem disc twice: - - if ( debug ) geo.print_InterfaceIDdata(); - - LocalIndices ind = d.get_indices(); - - ReferenceObjectID roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - - LocalVector jump_tri = geo.set_jump_values(ind, 3); - LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); - LocalVector source_tri = geo.set_source(imSource, ind, 3); - - this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords, true); - - geo.set_defect_tri(locD_tri); - geo.set_DoF_tag_tri(false); - - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - - LocalVector jump_quad = geo.set_jump_values(ind, 4); - LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); - LocalVector source_quad = geo.set_source(imSource, ind, 4); - - this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem, vCornerCoords, true); - geo.set_defect_quad(locD_quad); - geo.set_DoF_tag_quad(false); - - } - - -// Second call with orientation = -1: - bool shiftTag = geo.get_bScaleDoFs(); // shiftTag = true in case of double DoFs on interface! - - orientation *= -1; - geo.set_orientation(orientation); - try{ - geo.update(elem, ROID_UNKNOWN, vCornerCoords, &(this->subset_handler())); - }UG_CATCH_THROW("ConvectionDiffusionFV1::update:" - " Cannot update Finite Volume Geometry."); - - if ( debug ) geo.print_InterfaceIDdata(); - - roidCheck = geo.get_roid(); - if ( roidCheck == ROID_TRIANGLE ) - { - geo.set_local_sol(locU_tri, 3, u, orientation); - LocalVector jump_tri = geo.set_jump_values(ind, 3); - LocalVector jump_tri_grad = geo.set_jump_grad_values(ind, 3); - LocalVector source_tri = geo.set_source(imSource, ind, 3); - - this->template add_def_A_elem_local (geo, locD_tri, locU_tri, jump_tri, jump_tri_grad, source_tri, elem, vCornerCoords, false); - geo.set_defect_tri(locD_tri); - geo.set_DoF_tag_tri(shiftTag); - } - if ( roidCheck == ROID_QUADRILATERAL ) - { - geo.set_local_sol(locU_quad, 4, u, orientation); - LocalVector jump_quad = geo.set_jump_values(ind, 4); - LocalVector jump_quad_grad = geo.set_jump_grad_values(ind, 4); - LocalVector source_quad = geo.set_source(imSource, ind, 4); - - this->template add_def_A_elem_local (geo, locD_quad, locU_quad, jump_quad, jump_quad_grad, source_quad, elem, vCornerCoords, false); - geo.set_defect_quad(locD_quad); - geo.set_DoF_tag_quad(shiftTag); - - } -} - -template -template -void ConvectionDiffusionFV1:: -add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside) -{ - ug::MathMatrix diffusion = m_imDiffusion[0]; - if ( bElementIsOutside ) - diffusion *= 1.0; - - // loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - ///////////////////////////////////////////////////// - // Diffusive Term - ///////////////////////////////////////////////////// - if(m_imDiffusion.data_given()) - { - // to compute D \nabla c - MathVector Dgrad_c, grad_c; - - // compute gradient and shape at ip - VecSet(grad_c, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(grad_c, u(_C_,sh), scvf.global_grad(sh)); - - // scale by diffusion tensor - MatVecMult(Dgrad_c, diffusion, grad_c); - - // Compute flux - const number diff_flux = VecDot(Dgrad_c, scvf.normal()); - - // Add to local defect - d(_C_, scvf.from()) -= diff_flux; - d(_C_, scvf.to() ) += diff_flux; - - } - - ///////////////////////////////////////////////////////////////////////////// - // Additional diffusive Term due to jump in solution at the interface - // u^+ - u^- = jump - ///////////////////////////////////////////////////////////////////////////// - if ( 1 ) - { - // scale diffusion by jump in solution: - // const double jump = 2.0; - // diffusion *= jump; - - // to compute D \nabla c=Id_interface - MathVector Dgrad, grad; - - // compute gradient and shape at ip - VecSet(grad, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - { VecScaleAppend(grad, jump(_C_,sh), scvf.global_grad(sh)); - UG_LOG("jump(_C_,sh): " << jump(_C_,sh) << "\n"); - } - // scale by diffusion tensor - MatVecMult(Dgrad, diffusion, grad); - - // Compute flux - const number diff_flux = VecDot(Dgrad, scvf.normal()); - - // Add to local defect - d(_C_, scvf.from()) -= diff_flux; - d(_C_, scvf.to() ) += diff_flux; - - } - } - - ///////////////////////////////////////////////////// - // add rhs during same method! - // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! - ///////////////////////////////////////////////////// - - if ( 1 ) { //m_imSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { - - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv( ip ); - - // get associated node - int co = scv.node_id(); - - // Add to local rhs -/* if ( co > 2 ) - d(_C_, co) -= m_imSource[2] * scv.volume(); - else - d(_C_, co) -= m_imSource[co] * scv.volume(); -*/ - d(_C_, co) -= source(_C_, co) * scv.volume(); - UG_LOG("source: " << source(_C_, co) << "\n"); - UG_LOG("d(_C_, co): " << d(_C_, co) << "\n"); - - //if ( fabs(scv.volume()-0.00260416) > 0.00001 ) - } - } - ///////////////////////////////////////////////////////////////////////////// - // Additional source Term due to jump in gradient at the interface - // (\nabla u^+ - \nabla u^-)\cdot n = h(x) * |n| - ///////////////////////////////////////////////////////////////////////////// - if ( 1 ) - { - // Add to local rhs - for ( size_t sh = 0; sh < geo.num_scv(); ++sh ) - d(_C_, sh) -= jump_grad(_C_,sh); - } - -} - -template -template -void ConvectionDiffusionFV1:: -add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - -// reaction rate - if(m_imReactionRateExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local defect - d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume(); - } - } - -// reaction - if(m_imReactionExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local defect - d(_C_, co) += m_imReactionExpl[ip] * scv.volume(); - } - } - - if(m_imSourceExpl.data_given()) - { - // loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // Add to local rhs - d(_C_, co) -= m_imSourceExpl[ip] * scv.volume(); - } - } -} - -template -template -void ConvectionDiffusionFV1:: -add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{ -// get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - if(!m_imMassScale.data_given() && !m_imMass.data_given()) return; - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // mass value - number val = 0.0; - - // multiply by scaling - if(m_imMassScale.data_given()) - val += m_imMassScale[ip] * u(_C_, co); - - // add mass - if(m_imMass.data_given()) - val += m_imMass[ip]; - - // Add to local defect - d(_C_, co) += val * scv.volume(); - } -} - - -template -template -void ConvectionDiffusionFV1:: -add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) -{ - ///////////////////////////////////////////////////// - // add rhs ALLREADY(!) during 'add_def_A_elem_local()' method! - // --> in elem_disc_assemble_util, the method 'add_rhs_elem()' adds the local vector otherwise! NOT functional!! - ///////////////////////////////////////////////////// - - return; - - // get finite volume geometry -// static const TFVGeom& geo = GeomProvider::get(); - static const TFVGeom& geo = GeomProvider::get(m_LFEID,1); - - // loop Sub Control Volumes (SCV) - if ( m_imSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv( ip ); - - // get associated node - const int co = scv.node_id(); - - // Add to local rhs - d(_C_, co) += m_imSource[ip] * scv.volume(); - } - } - - // loop Sub Control Volumes (SCVF) - if ( m_imVectorSource.data_given() ) { - for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); - - // Add to local rhs - d(_C_, scvf.from()) -= VecDot(m_imVectorSource[ip], scvf.normal() ); - d(_C_, scvf.to() ) += VecDot(m_imVectorSource[ip], scvf.normal() ); - } - } -} - - -//////////////////////////////////// -/// error estimation (begin) /// - -// prepares the loop over all elements of one type for the computation of the error estimator -template -template -void ConvectionDiffusionFV1:: -prep_err_est_elem_loop(const ReferenceObjectID roid, const int si) -{ - // get the error estimator data object and check that it is of the right type - // we check this at this point in order to be able to dispense with this check later on - // (i.e. in prep_err_est_elem and compute_err_est_A_elem()) - if (this->m_spErrEstData.get() == NULL) - { - UG_THROW("No ErrEstData object has been given to this ElemDisc!"); - } - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (!err_est_data) - { - UG_THROW("Dynamic cast to SideAndElemErrEstData failed." - << std::endl << "Make sure you handed the correct type of ErrEstData to this discretization."); - } - - -// check that upwind has been set - if (m_spConvShape.invalid()) - UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " - "Upwind has not been set."); - -// set local positions - if (!TFVGeom::usesHangingNodes) - { - static const int refDim = TElem::dim; - - // get local IPs - size_t numSideIPs, numElemIPs; - const MathVector* sideIPs; - const MathVector* elemIPs; - try - { - numSideIPs = err_est_data->num_all_side_ips(roid); - numElemIPs = err_est_data->num_elem_ips(roid); - sideIPs = err_est_data->template side_local_ips(roid); - elemIPs = err_est_data->template elem_local_ips(roid); - - if (!sideIPs || !elemIPs) return; // are NULL if TElem is not of the same dim as TDomain - } - UG_CATCH_THROW("Integration points for error estimator cannot be set."); - - // set local IPs in imports - m_imDiffusion.template set_local_ips(sideIPs, numSideIPs, false); - m_imVelocity.template set_local_ips(sideIPs, numSideIPs, false); - m_imFlux.template set_local_ips(sideIPs, numSideIPs, false); - m_imSource.template set_local_ips(elemIPs, numElemIPs, false); - m_imVectorSource.template set_local_ips(sideIPs, numSideIPs, false); - m_imReactionRate.template set_local_ips(elemIPs, numElemIPs, false); - m_imReaction.template set_local_ips(elemIPs, numElemIPs, false); - m_imMassScale.template set_local_ips(elemIPs, numElemIPs, false); - m_imMass.template set_local_ips(elemIPs, numElemIPs, false); - - // init upwind for element type - TFVGeom& geo = GeomProvider::get(); - if (!m_spConvShape->template set_geometry_type(geo)) - UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: " - "Cannot init upwind for element type."); - - // store values of shape functions in local IPs - LagrangeP1::reference_element_type> trialSpace - = Provider::reference_element_type> >::get(); - - m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh()); - for (size_t ip = 0; ip < numElemIPs; ip++) - trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]); - for (size_t ip = 0; ip < numSideIPs; ip++) - trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]); - } -} - -template -template -void ConvectionDiffusionFV1:: -prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]) -{} - -// computes the error estimator contribution (stiffness part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ - typedef typename reference_element_traits::reference_element_type ref_elem_type; - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - -// request geometry - static const TFVGeom& geo = GeomProvider::get(); - -//////////////// -// SIDE TERMS // -//////////////// - -// get the sides of the element - // We have to cast elem to a pointer of type SideAndElemErrEstData::elem_type - // for the SideAndElemErrEstData::operator() to work properly. - // This cannot generally be achieved by casting to TElem*, since this method is also registered for - // lower-dimensional types TElem, and must therefore be compilable, even if it is never EVER to be executed. - // The way we achieve this here, is by calling associated_elements_sorted() which has an implementation for - // all possible types. Whatever comes out of it is of course complete nonsense if (and only if) - // SideAndElemErrEstData::elem_type != TElem. To be on the safe side, we throw an error if the number of - // entries in the list is not as it should be. - - typename MultiGrid::traits::side_type>::secure_container side_list; - pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); - if (side_list.size() != (size_t) ref_elem_type::numSides) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// some help variables - MathVector fluxDensity, gradC, normal; - -// calculate grad u (take grad from first scvf ip (grad u is constant on the entire element)) - if (geo.num_scvf() < 1) {UG_THROW("Element has no SCVFs!");} - const typename TFVGeom::SCVF& scvf = geo.scvf(0); - - VecSet(gradC, 0.0); - for (size_t j=0; j(normal, side, vCornerCoords); - VecNormalize(normal, normal); - - try - { - for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) - { - size_t ip = passedIPs + sip; - - VecSet(fluxDensity, 0.0); - - ////// diffusion ////// - if (m_imDiffusion.data_given()) - MatVecScaleMultAppend(fluxDensity, -1.0, m_imDiffusion[0], gradC); - - ////// convection ////// - if (m_imVelocity.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtSideIP(sh,sip); - - VecScaleAppend(fluxDensity, val, m_imVelocity[ip]); - } - - ////// general flux ////// - if (m_imFlux.data_given()) - VecAppend(fluxDensity, m_imFlux[ip]); - - (*err_est_data)(side_list[side],sip) += scale * VecDot(fluxDensity, normal); - } - - passedIPs += err_est_data->num_side_ips(side_list[side]); - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); - } - -////////////////// -// VOLUME TERMS // -////////////////// - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - { - number total = 0.0; - - ////// diffusion ////// TODO ONLY FOR (PIECEWISE) CONSTANT DIFFUSION TENSOR SO FAR! - // div(D*grad(c)) = div(v)*u + v*grad(c) - // nothing to do, as u is piecewise linear and div(D*grad(c)) disappears - - ////// convection ////// TODO ONLY FOR CONSTANT VELOCITY FIELDS SO FAR! - // div(v*c) = div(v)*u + v*grad(c) -- gradC has been calculated above - if (m_imVelocity.data_given()) - total += VecDot(m_imVelocity[ip], gradC); - - ////// general flux ////// TODO ONLY FOR DIVERGENCE-FREE FLUX FIELD SO FAR! - // nothing to do - - ////// reaction ////// - if (m_imReactionRate.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < geo.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); - - total += m_imReactionRate[ip] * val; - } - - if (m_imReaction.data_given()) - { - total += m_imReaction[ip]; - } - - (*err_est_data)(elem_list[0],ip) += scale * total; - } - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// computes the error estimator contribution (mass part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ -// note: mass parts only enter volume term - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// request geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop integration points - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - { - number total = 0.0; - - ////// mass scale ////// - if (m_imMassScale.data_given()) - { - number val = 0.0; - for (size_t sh = 0; sh < geo.num_sh(); sh++) - val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); - - total += m_imMassScale[ip] * val; - } - - ////// mass ////// - if (m_imMass.data_given()) - { - total += m_imMass[ip]; - } - - (*err_est_data)(elem_list[0],ip) += scale * total; - } - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// computes the error estimator contribution (rhs part) for one element -template -template -void ConvectionDiffusionFV1:: -compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale) -{ - typedef typename reference_element_traits::reference_element_type ref_elem_type; - - err_est_type* err_est_data = dynamic_cast(this->m_spErrEstData.get()); - - if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} - MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); - -//////////////// -// SIDE TERMS // -//////////////// -// get the sides of the element - typename MultiGrid::traits::side_type>::secure_container side_list; - pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); - if (side_list.size() != (size_t) ref_elem_type::numSides) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -// loop sides - size_t passedIPs = 0; - for (size_t side = 0; side < (size_t) ref_elem_type::numSides; side++) - { - // normal on side - MathVector normal; - SideNormal(normal, side, vCornerCoords); - VecNormalize(normal, normal); - - try - { - for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) - { - size_t ip = passedIPs + sip; - - ////// vector source ////// - if (m_imVectorSource.data_given()) - (*err_est_data)(side_list[side],sip) += scale * VecDot(m_imVectorSource[ip], normal); - } - - passedIPs += err_est_data->num_side_ips(side_list[side]); - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); - } - -////////////////// -// VOLUME TERMS // -////////////////// - if (!m_imSource.data_given()) return; - - typename MultiGrid::traits::elem_type>::secure_container elem_list; - pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); - if (elem_list.size() != 1) - UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'"); - -////// source ////// - try - { - for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) - (*err_est_data)(elem_list[0],ip) += scale * m_imSource[ip]; - } - UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl - << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); -} - -// postprocesses the loop over all elements of one type in the computation of the error estimator -template -template -void ConvectionDiffusionFV1:: -fsh_err_est_elem_loop() -{ -// finish the element loop in the same way as the actual discretization - this->template fsh_elem_loop (); -}; - -/// error estimation (end) /// -//////////////////////////////////// - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -lin_def_velocity(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // sum up contributions of convection shapes - MathVector linDefect; - VecSet(linDefect, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(linDefect, u(_C_,sh), convShape.D_vel(ip, sh)); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] += linDefect; - vvvLinDef[ip][_C_][scvf.to()] -= linDefect; - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -lin_def_diffusion(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// get conv shapes - const IConvectionShapes& convShape = get_updated_conv_shapes(geo); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // compute gradient at ip - MathVector grad_u; VecSet(grad_u, 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(grad_u, u(_C_,sh), scvf.global_grad(sh)); - - // compute the lin defect at this ip - MathMatrix linDefect; - - // part coming from -\nabla u * \vec{n} - for(size_t k=0; k < (size_t)dim; ++k) - for(size_t j = 0; j < (size_t)dim; ++j) - linDefect(j,k) = (scvf.normal())[j] * grad_u[k]; - - // add contribution from convection shapes - if(convShape.non_zero_deriv_diffusion()) - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - MatAdd(linDefect, convShape.D_diffusion(ip, sh), u(_C_, sh)); - - // add contributions - vvvLinDef[ip][_C_][scvf.from()] -= linDefect; - vvvLinDef[ip][_C_][scvf.to() ] += linDefect; - } -} - -template -template -void ConvectionDiffusionFV1:: -lin_def_flux(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - -// loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] += scvf.normal(); - vvvLinDef[ip][_C_][scvf.to()] -= scvf.normal(); - } -} -// computes the linearized defect w.r.t to the reaction rate -template -template -void ConvectionDiffusionFV1:: -lin_def_reaction_rate(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = u(_C_, co) * scv.volume(); - } -} - -// computes the linearized defect w.r.t to the reaction -template -template -void ConvectionDiffusionFV1:: -lin_def_reaction(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the source -template -template -void ConvectionDiffusionFV1:: -lin_def_source(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t ip = 0; ip < geo.num_scv(); ++ip) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(ip); - - // get associated node - const int co = scv.node_id(); - - // set lin defect - vvvLinDef[ip][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the vector source -// (in analogy to velocity) -template -template -void ConvectionDiffusionFV1:: -lin_def_vector_source(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip) -{ - // get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reset the values for the linearized defect - for(size_t ip = 0; ip < nip; ++ip) - for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) - for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) - vvvLinDef[ip][c][sh] = 0.0; - - // loop Sub Control Volumes Faces (SCVF) - for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) { - // get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf( ip ); - - // add parts for both sides of scvf - vvvLinDef[ip][_C_][scvf.from()] -= scvf.normal(); - vvvLinDef[ip][_C_][scvf.to()] += scvf.normal(); - } -} - -// computes the linearized defect w.r.t to the mass scale -template -template -void ConvectionDiffusionFV1:: -lin_def_mass_scale(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t co = 0; co < geo.num_scv(); ++co) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(co); - - // Check associated node - UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); - - // set lin defect - vvvLinDef[co][_C_][co] = u(_C_, co) * scv.volume(); - } -} - -// computes the linearized defect w.r.t to the mass scale -template -template -void ConvectionDiffusionFV1:: -lin_def_mass(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// loop Sub Control Volumes (SCV) - for(size_t co = 0; co < geo.num_scv(); ++co) - { - // get current SCV - const typename TFVGeom::SCV& scv = geo.scv(co); - - // Check associated node - UG_ASSERT(co == scv.node_id(), "Only one shape per SCV"); - - // set lin defect - vvvLinDef[co][_C_][co] = scv.volume(); - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -ex_value(number vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > vvvDeriv[]) -{ -// get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reference element - typedef typename reference_element_traits::reference_element_type - ref_elem_type; - -// number of shape functions - static const size_t numSH = ref_elem_type::numCorners; - -// FV1 SCVF ip - if(vLocIP == geo.scvf_local_ips()) - { - // Loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // Get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - // compute concentration at ip - vValue[ip] = 0.0; - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vValue[ip] += u(_C_, sh) * scvf.shape(sh); - - // compute derivative w.r.t. to unknowns iff needed - if(bDeriv) - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vvvDeriv[ip][_C_][sh] = scvf.shape(sh); - } - } -// FV1 SCV ip - else if(vLocIP == geo.scv_local_ips()) - { - // solution at ip - for(size_t sh = 0; sh < numSH; ++sh) - vValue[sh] = u(_C_, sh); - - // set derivatives if needed - if(bDeriv) - for(size_t sh = 0; sh < numSH; ++sh) - for(size_t sh2 = 0; sh2 < numSH; ++sh2) - vvvDeriv[sh][_C_][sh2] = (sh==sh2) ? 1.0 : 0.0; - } -// general case - else - { - // get trial space - LagrangeP1& rTrialSpace = Provider >::get(); - - // storage for shape function at ip - number vShape[numSH]; - - // loop ips - for(size_t ip = 0; ip < nip; ++ip) - { - // evaluate at shapes at ip - rTrialSpace.shapes(vShape, vLocIP[ip]); - - // compute concentration at ip - vValue[ip] = 0.0; - for(size_t sh = 0; sh < numSH; ++sh) - vValue[ip] += u(_C_, sh) * vShape[sh]; - - // compute derivative w.r.t. to unknowns iff needed - // \todo: maybe store shapes directly in vvvDeriv - if(bDeriv) - for(size_t sh = 0; sh < numSH; ++sh) - vvvDeriv[ip][_C_][sh] = vShape[sh]; - } - } -} - -// computes the linearized defect w.r.t to the velocity -template -template -void ConvectionDiffusionFV1:: -ex_grad(MathVector vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > > vvvDeriv[]) -{ -// Get finite volume geometry - static const TFVGeom& geo = GeomProvider::get(); - -// reference element - typedef typename reference_element_traits::reference_element_type - ref_elem_type; - -// reference dimension - static const int refDim = ref_elem_type::dim; - -// number of shape functions - static const size_t numSH = ref_elem_type::numCorners; - -// FV1 SCVF ip - if(vLocIP == geo.scvf_local_ips()) - { - // Loop Sub Control Volume Faces (SCVF) - for(size_t ip = 0; ip < geo.num_scvf(); ++ip) - { - // Get current SCVF - const typename TFVGeom::SCVF& scvf = geo.scvf(ip); - - VecSet(vValue[ip], 0.0); - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - VecScaleAppend(vValue[ip], u(_C_, sh), scvf.global_grad(sh)); - - if(bDeriv) - for(size_t sh = 0; sh < scvf.num_sh(); ++sh) - vvvDeriv[ip][_C_][sh] = scvf.global_grad(sh); - } - } -// general case - else - { - // get trial space - LagrangeP1& rTrialSpace = Provider >::get(); - - // storage for shape function at ip - MathVector vLocGrad[numSH]; - MathVector locGrad; - - // Reference Mapping - MathMatrix JTInv; - ReferenceMapping mapping(vCornerCoords); - - // loop ips - for(size_t ip = 0; ip < nip; ++ip) - { - // evaluate at shapes at ip - rTrialSpace.grads(vLocGrad, vLocIP[ip]); - - // compute grad at ip - VecSet(locGrad, 0.0); - for(size_t sh = 0; sh < numSH; ++sh) - VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]); - - // compute global grad - mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]); - MatVecMult(vValue[ip], JTInv, locGrad); - - // compute derivative w.r.t. to unknowns iff needed - if(bDeriv) - for(size_t sh = 0; sh < numSH; ++sh) - MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); - } - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// upwind -//////////////////////////////////////////////////////////////////////////////// - -template -void ConvectionDiffusionFV1:: -set_upwind(SmartPtr > shapes) {m_spConvShape = shapes;} - -// computes the linearized defect w.r.t to the velocity -template -const typename ConvectionDiffusionFV1::conv_shape_type& -ConvectionDiffusionFV1:: -get_updated_conv_shapes(const FVGeometryBase& geo) -{ -// compute upwind shapes for transport equation -// \todo: we should move this computation into the preparation part of the -// disc, to only compute the shapes once, reusing them several times. - if(m_imVelocity.data_given()) - { - // get diffusion at ips - const MathMatrix* vDiffusion = NULL; - if(m_imDiffusion.data_given()) vDiffusion = m_imDiffusion.values(); - - // update convection shapes - if(!m_spConvShape->update(&geo, m_imVelocity.values(), vDiffusion, true)) - { - UG_LOG("ERROR in 'ConvectionDiffusionFV1::add_jac_A_elem': " - "Cannot compute convection shapes.\n"); - } - } - -// return a const (!!) reference to the upwind - return *const_cast*>(m_spConvShape.get()); -} - - -//////////////////////////////////////////////////////////////////////////////// -// register assemble functions -//////////////////////////////////////////////////////////////////////////////// - -#ifdef UG_DIM_1 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - - - /* -// switch assemble functions - if(!bHang) - { - register_func >(); - } - else - { - register_func >(); - } -*/ -} -#endif - -#ifdef UG_DIM_2 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - - /* -// switch assemble functions - if(!bHang) - { - register_func >(); - register_func >(); - register_func >(); - } - else - { - register_func >(); - register_func >(); - register_func >(); - } - */ -} -#endif - -#ifdef UG_DIM_3 -template<> -void ConvectionDiffusionFV1:: -register_all_funcs(bool bHang) -{ - register_func > >(); - - /* -// switch assemble functions - if(!bHang) - { - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - } - else - { - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - register_func >(); - } - */ -} -#endif - -template -template -void ConvectionDiffusionFV1:: -register_func() -{ - ReferenceObjectID id = geometry_traits::REFERENCE_OBJECT_ID; - typedef this_type T; - static const int refDim = reference_element_traits::dim; - - this->clear_add_fct(id); - this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop); - this->set_prep_elem_fct( id, &T::template prep_elem); - this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop); - this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem); - this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem); - this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem); - this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem); - this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem); - this->set_add_rhs_elem_fct( id, &T::template add_rhs_elem); - -// error estimator parts -/* this->set_prep_err_est_elem_loop(id, &T::template prep_err_est_elem_loop); - this->set_prep_err_est_elem(id, &T::template prep_err_est_elem); - this->set_compute_err_est_A_elem(id, &T::template compute_err_est_A_elem); - this->set_compute_err_est_M_elem(id, &T::template compute_err_est_M_elem); - this->set_compute_err_est_rhs_elem(id, &T::template compute_err_est_rhs_elem); - this->set_fsh_err_est_elem_loop(id, &T::template fsh_err_est_elem_loop); -*/ -// set computation of linearized defect w.r.t velocity - m_imDiffusion.set_fct(id, this, &T::template lin_def_diffusion); - m_imVelocity. set_fct(id, this, &T::template lin_def_velocity); - m_imFlux.set_fct(id, this, &T::template lin_def_flux); - m_imReactionRate. set_fct(id, this, &T::template lin_def_reaction_rate); - m_imReaction. set_fct(id, this, &T::template lin_def_reaction); - m_imSource. set_fct(id, this, &T::template lin_def_source); - m_imVectorSource.set_fct(id, this, &T::template lin_def_vector_source); - m_imMassScale.set_fct(id, this, &T::template lin_def_mass_scale); - m_imMass. set_fct(id, this, &T::template lin_def_mass); - -// exports - m_exValue-> template set_fct(id, this, &T::template ex_value); - m_exGrad->template set_fct(id, this, &T::template ex_grad); -} - -//////////////////////////////////////////////////////////////////////////////// -// explicit template instantiations -//////////////////////////////////////////////////////////////////////////////// -#ifdef UG_DIM_1 -template class ConvectionDiffusionFV1; -#endif -#ifdef UG_DIM_2 -template class ConvectionDiffusionFV1; -#endif -#ifdef UG_DIM_3 -template class ConvectionDiffusionFV1; -#endif - -} // end namespace ConvectionDiffusionPlugin -} // namespace ug - diff --git a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.h b/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.h deleted file mode 100644 index 8b3dea8..0000000 --- a/fv1_cutElem/ug4-Versions__instead_merge_changes_into_fv1_original___/convection_diffusion_fv1_mitJump.h +++ /dev/null @@ -1,316 +0,0 @@ -/* - * convection_diffusion_fv1.h - * - * Created on: 26.02.2010 - * Author: andreasvogel - */ - -#ifndef __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ -#define __H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__ - -// library intern headers -#include "../convection_diffusion_base.h" -#include "lib_disc/spatial_disc/disc_util/conv_shape_interface.h" - -namespace ug{ -namespace ConvectionDiffusionPlugin{ - -// \ingroup lib_disc_elem_disc -/// \addtogroup convection_diffusion -/// \{ - -/// Discretization for the Convection-Diffusion Equation -/** - * This class implements the IElemDisc interface to provide element local - * assemblings for the convection diffusion equation. - * The Equation has the form - * \f[ - * \partial_t (m1*c + m2) - \nabla \left( D \nabla c - \vec{v} c \right - \vec{F}) + - * r1 \cdot c + r2 = f + f2 - * \f] - * with - *
    - *
  • \f$ c \f$ is the unknown solution - *
  • \f$ m1 \equiv m(\vec{x},t) \f$ is the Mass Scaling Term - *
  • \f$ m2 \equiv m(\vec{x},t) \f$ is the Mass Term - *
  • \f$ D \equiv D(\vec{x},t) \f$ is the Diffusion Tensor - *
  • \f$ v \equiv \vec{v}(\vec{x},t) \f$ is the Velocity Field - *
  • \f$ F \equiv \vec{F}(\vec{x},t) \f$ is the Flux - *
  • \f$ r1 \equiv r(\vec{x},t) \f$ is the Reaction Rate - *
  • \f$ r2 \equiv r(\vec{x},t) \f$ is a Reaction Term - *
  • \f$ f \equiv f(\vec{x},t) \f$ is a Source Term - *
  • \f$ f2 \equiv f_2(\vec{x},t) \f$ is a Vector Source Term - *
- * - * \tparam TDomain Domain - * \tparam TAlgebra Algebra - */ -template< typename TDomain> -class ConvectionDiffusionFV1 : public ConvectionDiffusionBase -{ - private: - /// Base class type - typedef ConvectionDiffusionBase base_type; - - /// Own type - typedef ConvectionDiffusionFV1 this_type; - - /// error estimator type - typedef SideAndElemErrEstData err_est_type; - - public: - /// World dimension - static const int dim = base_type::dim; - - public: - /// Constructor - ConvectionDiffusionFV1(const char* functions, const char* subsets); - - /// set the upwind method - /** - * This method sets the upwind method used to upwind the convection. - * - * \param shapes upwind method - */ - void set_upwind(SmartPtr > shapes); - - private: - /// prepares the loop over all elements - /** - * This method prepares the loop over all elements. It resizes the Position - * array for the corner coordinates and schedules the local ip positions - * at the data imports. - */ - template - void prep_elem_loop(const ReferenceObjectID roid, const int si); - - /// prepares the element for assembling - /** - * This methods prepares an element for the assembling. The Positions of - * the Element Corners are read and the Finite Volume Geometry is updated. - * The global ip positions are scheduled at the data imports. - */ - template - void prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector vCornerCoords[]); - - /// finishes the loop over all elements - template - void fsh_elem_loop(); - - /// assembles the local stiffness matrix using a finite volume scheme - template - void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - template - void add_jac_A_elem_local(TFVGeom& geo, LocalMatrix& J, const LocalVector& u, const LocalVector& jump, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - - /// assembles the local mass matrix using a finite volume scheme - template - void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the stiffness part of the local defect - template - void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - /// assembles the stiffness part of the local defect - template - void add_def_A_elem_local(TFVGeom& geo, LocalVector& d, const LocalVector& u, const LocalVector& jump, const LocalVector& jump_grad, const LocalVector& source, GridObject* elem, const MathVector vCornerCoords[], const bool bElementIsOutside); - - /// assembles the stiffness part of the local defect explicit reaction, reaction_rate and source - template - void add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the mass part of the local defect - template - void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// assembles the local right hand side - template - void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); - template - void add_rhs_elem_local(TFVGeom& geo, LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]); - - /// prepares the loop over all elements of one type for the computation of the error estimator - template - void prep_err_est_elem_loop(const ReferenceObjectID roid, const int si); - - /// prepares the element for assembling the error estimator - template - void prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[]); - - /// computes the error estimator contribution for one element - template - void compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// computes the error estimator contribution for one element - template - void compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// computes the error estimator contribution for one element - template - void compute_err_est_rhs_elem(GridObject* elem, const MathVector vCornerCoords[], const number& scale); - - /// postprocesses the loop over all elements of one type in the computation of the error estimator - template - void fsh_err_est_elem_loop(); - - protected: - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_velocity(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_diffusion(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the velocity - template - void lin_def_flux(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the reaction - template - void lin_def_reaction(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the reaction - template - void lin_def_reaction_rate(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the source term - template - void lin_def_source(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the vector source term - template - void lin_def_vector_source(const LocalVector& u, - std::vector > > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the mass scale term - template - void lin_def_mass_scale(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - /// computes the linearized defect w.r.t to the mass scale term - template - void lin_def_mass(const LocalVector& u, - std::vector > vvvLinDef[], - const size_t nip); - - private: - /// abbreviation for the local solution - static const size_t _C_ = 0; - - using base_type::m_imDiffusion; - using base_type::m_imVelocity; - using base_type::m_imFlux; - using base_type::m_imSource; - using base_type::m_imSourceExpl; - using base_type::m_imVectorSource; - using base_type::m_imReactionRate; - using base_type::m_imReactionRateExpl; - using base_type::m_imReaction; - using base_type::m_imReactionExpl; - using base_type::m_imMassScale; - using base_type::m_imMass; - - using base_type::m_exGrad; - using base_type::m_exValue; - - protected: - /// method to compute the upwind shapes - SmartPtr > m_spConvShape; - - /// returns the updated convection shapes - typedef IConvectionShapes conv_shape_type; - const IConvectionShapes& get_updated_conv_shapes(const FVGeometryBase& geo); - - /// computes the concentration - template - void ex_value(number vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > vvvDeriv[]); - - /// computes the gradient of the concentration - template - void ex_grad(MathVector vValue[], - const MathVector vGlobIP[], - number time, int si, - const LocalVector& u, - GridObject* elem, - const MathVector vCornerCoords[], - const MathVector vLocIP[], - const size_t nip, - bool bDeriv, - std::vector > > vvvDeriv[]); - - public: - /// type of trial space for each function used - virtual void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid); - - /// returns if hanging nodes are needed - virtual bool use_hanging() const; - - protected: - /// current regular grid flag - bool m_bNonRegularGrid; - - /// current shape function set (needed for GeomProvider::get()) - LFEID m_LFEID; - - /// register utils - /// \{ - void register_all_funcs(bool bHang); - template void register_func(); - /// \} - - private: - /// struct holding values of shape functions in IPs - struct ShapeValues - { - public: - void resize(std::size_t nEip, std::size_t nSip, std::size_t _nSh) - { - nSh = _nSh; - elemVals.resize(nEip); - sideVals.resize(nSip); - for (std::size_t i = 0; i < nEip; i++) elemVals[i].resize(nSh); - for (std::size_t i = 0; i < nSip; i++) sideVals[i].resize(nSh); - } - number& shapeAtElemIP(std::size_t sh, std::size_t ip) {return elemVals[ip][sh];} - number& shapeAtSideIP(std::size_t sh, std::size_t ip) {return sideVals[ip][sh];} - number* shapesAtElemIP(std::size_t ip) {return &elemVals[ip][0];} - number* shapesAtSideIP(std::size_t ip) {return &sideVals[ip][0];} - std::size_t num_sh() {return nSh;} - private: - std::size_t nSh; - std::vector > elemVals; - std::vector > sideVals; - } m_shapeValues; -}; - -// end group convection_diffusion -/// \} - -} // end ConvectionDiffusionPlugin -} // end namespace ug - - -#endif /*__H__UG__LIB_DISC__CONVECTION_DIFFUSION__CONVECTION_DIFFUSION_FV1__*/