From a1ca0ecf39267c32633655d175cb5aa3db91ae2a Mon Sep 17 00:00:00 2001 From: Matteo Cicuttin <datafl4sh@toxicnet.eu> Date: Wed, 5 May 2021 17:47:05 +0200 Subject: [PATCH] Parametrizing the solver with Lua: initial conditions. --- CMakeLists.txt | 1 + include/connectivity.h | 8 ++ include/gmsh_io.h | 24 +++++ include/param_loader.h | 49 ++++++++++ src/gmsh_io.cpp | 106 ++++++++++++++++++--- src/maxwell_solver.cpp | 63 ++++++++----- src/param_loader.cpp | 192 +++++++++++++++++++++++++++++++++++++++ src/physical_element.cpp | 3 + 8 files changed, 412 insertions(+), 34 deletions(-) create mode 100644 include/param_loader.h create mode 100644 src/param_loader.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c07aab..99ca31b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -256,6 +256,7 @@ set(LIBGMSHDG_SOURCES src/gmsh_io.cpp src/maxwell_cpu.cpp src/maxwell_gpu.cpp src/maxwell_kernels_cuda.cu + src/param_loader.cpp ) add_library(gmshdg SHARED ${LIBGMSHDG_SOURCES}) diff --git a/include/connectivity.h b/include/connectivity.h index 352d8eb..16be7ca 100644 --- a/include/connectivity.h +++ b/include/connectivity.h @@ -164,6 +164,14 @@ public: return std::make_pair(neighbour_descriptor(), false); /* Silence the compiler */ } + size_t + num_neighbours(const FaceKey& fk) + { + size_t nn = face_cell_adj.at(fk).num_neighbours(); + assert(nn == 1 or nn == 2); + return nn; + } + std::set<ConnData> neighbours(size_t iE, size_t iT) const { diff --git a/include/gmsh_io.h b/include/gmsh_io.h index c569808..24434c0 100644 --- a/include/gmsh_io.h +++ b/include/gmsh_io.h @@ -26,6 +26,23 @@ std::string basis_grad_name(int); using face_key = std::array<size_t, 3>; +enum class face_type +{ + NONE, + INTERFACE, + BOUNDARY +}; + +struct boundary_descriptor +{ + face_type type; + int gmsh_entity; + + boundary_descriptor() + : type(face_type::NONE), gmsh_entity(0) + {} +}; + class model { int geometric_order; @@ -33,6 +50,7 @@ class model std::vector<entity> entities; std::map<size_t, std::vector<element_key>> boundary_map; + std::vector<boundary_descriptor> bnd_descriptors; element_connectivity<element_key> conn; void map_boundaries(void); @@ -54,6 +72,11 @@ public: return conn; } + const std::vector<boundary_descriptor>& boundary_descriptors() const + { + return bnd_descriptors; + } + std::vector<element_key> get_bnd(size_t which) { return boundary_map.at(which); @@ -62,6 +85,7 @@ public: size_t num_dofs() const; size_t num_fluxes() const; size_t num_cells() const; + size_t num_faces() const; size_t num_entities() const; std::vector<entity>::const_iterator begin() const; diff --git a/include/param_loader.h b/include/param_loader.h new file mode 100644 index 0000000..e0f15d9 --- /dev/null +++ b/include/param_loader.h @@ -0,0 +1,49 @@ +#pragma once + +#include "sol/sol.hpp" +#include "gmsh_io.h" + +class parameter_loader +{ +protected: + sol::state lua; + +private: + void init(void); + bool validate_simulation_params(void) const; + +public: + parameter_loader(); + + bool load_file(const std::string&); + + int approx_order(void) const; + int geom_order(void) const; + std::string simulation_name(void) const; + double delta_t(void) const; + size_t timesteps(void) const; + std::string gmsh_model_filename(void) const; + bool use_gpu(void) const; + size_t silo_output_rate(void) const; +}; + +class maxwell_parameter_loader : public parameter_loader +{ + void init(void); + + bool validate_materials(const std::string&, int); + +public: + maxwell_parameter_loader(); + + bool validate_model_params(const model&); + double epsilon(int, const point_3d&) const; + double mu(int, const point_3d&) const; + double sigma(int, const point_3d&) const; + + bool initial_Efield_defined(void) const; + vec3d Efield(const point_3d&) const; + + bool initial_Hfield_defined(void) const; + vec3d Hfield(const point_3d&) const; +}; \ No newline at end of file diff --git a/src/gmsh_io.cpp b/src/gmsh_io.cpp index 24ec863..8ec1a0b 100644 --- a/src/gmsh_io.cpp +++ b/src/gmsh_io.cpp @@ -75,9 +75,31 @@ model::remesh() { gmm::generate( DIMENSION(3) ); gmm::setOrder( geometric_order ); + + gvp_t gmsh_entities; + + /* Create a table mapping the tag of a boundary to the list of + * its face keys. This must happen before import_gmsh_entities() + * because otherwise you get spurious 2D entities (and this in + * turn because the constructor of entity calls addDiscreteEntity() + * to get all the element faces) .*/ + std::map<size_t, std::vector<face_key>> boundaries_elemTags; + gm::getEntities(gmsh_entities, DIMENSION(2)); + for (auto [dim, tag] : gmsh_entities) + { + std::vector<int> elemTypes; + gmm::getElementTypes(elemTypes, dim, tag); + assert(elemTypes.size() == 1); + for (auto& elemType : elemTypes) + { + element_key_factory ekf(DIMENSION(2), tag, elemType); + boundary_map[tag] = ekf.get_keys(); + } + } + entities.clear(); import_gmsh_entities(); - map_boundaries(); + map_boundaries(); /* This must happen after import_gmsh_entities(). */ } void @@ -153,6 +175,16 @@ model::num_cells(void) const return ret; } +size_t +model::num_faces(void) const +{ + size_t ret = 0; + for (const auto& e : entities) + ret += e.num_faces(); + + return ret; +} + size_t model::num_entities(void) const { @@ -216,20 +248,68 @@ model::import_gmsh_entities(void) void model::map_boundaries(void) { - gvp_t entities; - /* Create a table mapping the tag of a boundary to the list of - * its face keys */ - std::map<size_t, std::vector<face_key>> boundaries_elemTags; - gm::getEntities(entities, DIMENSION(2)); - for (auto [dim, tag] : entities) + /* Make a vector mapping element_key to entity tag */ + using bfk_t = std::pair<element_key, int>; + std::vector<bfk_t> bfk; + for (auto& [tag, keys] : boundary_map) + for (auto& k : keys) + bfk.push_back( std::make_pair(k, tag) ); + + /* Sort it for lookups */ + auto comp = [](const bfk_t& a, const bfk_t& b) -> bool { + return a.first < b.first; + }; + std::sort(bfk.begin(), bfk.end(), comp); + + bnd_descriptors.resize( num_faces() ); + size_t fbase = 0; + /* For each entity */ + for (auto& e : entities) { - std::vector<int> elemTypes; - gmm::getElementTypes(elemTypes, dim, tag); - assert(elemTypes.size() == 1); - for (auto& elemType : elemTypes) + /* and for each face */ + for (size_t iF = 0; iF < e.num_faces(); iF++) { - element_key_factory ekf(DIMENSION(2), tag, elemType); - boundary_map[tag] = ekf.get_keys(); + /* get the element key */ + element_key fk(e.face(iF)); + auto lbcomp = [](const bfk_t& a, const element_key& b) -> bool { + return a.first < b; + }; + /* and lookup it in the vector we created before. */ + auto itor = std::lower_bound(bfk.begin(), bfk.end(), fk, lbcomp); + if ( (itor == bfk.end()) or ((*itor).first != fk) ) + continue; + + /* If found */ + boundary_descriptor bd; + /* determine if it is an interface or a boundary */ + if (conn.num_neighbours(fk) == 1) + bd.type = face_type::BOUNDARY; + else + bd.type = face_type::INTERFACE; + /* and store the gmsh tag in the descriptor. */ + bd.gmsh_entity = (*itor).second; + + /* Finally, put the descriptor in the global array of faces. */ + bnd_descriptors.at(fbase + iF) = bd; + } + fbase += e.num_faces(); + } + + /* + size_t normal = 0; + size_t interface = 0; + size_t boundary = 0; + for (auto& bd : boundary_descriptors) + { + switch (bd.type) + { + case face_type::NONE: normal++; break; + case face_type::INTERFACE: interface++; break; + case face_type::BOUNDARY: boundary++; break; } } + + std::cout << bfk.size() << " " << boundary_descriptors.size() << std::endl; + std::cout << normal << " " << interface << " " << boundary << std::endl; + */ } \ No newline at end of file diff --git a/src/maxwell_solver.cpp b/src/maxwell_solver.cpp index e8c6208..a820347 100644 --- a/src/maxwell_solver.cpp +++ b/src/maxwell_solver.cpp @@ -1,6 +1,7 @@ #include "gmsh.h" #include "silo_output.hpp" #include "maxwell_interface.h" +#include "param_loader.h" static void make_geometry(int order, double mesh_h) @@ -29,34 +30,37 @@ make_geometry(int order, double mesh_h) } template<typename State> -void test_it(const model& mod, State& state) +void test_it(const model& mod, State& state, const maxwell_parameter_loader& mpl) { - auto E = [](const point_3d& pt) -> vec3d { - vec3d ret; - ret(0) = 0; - ret(1) = 0; - ret(2) = std::sin(M_PI*pt.x()) * std::sin(M_PI*pt.y()); - return ret; - }; - maxwell::init_from_model(mod, state); - maxwell::init_E_field(mod, state, E); + + if ( mpl.initial_Efield_defined() ) + { + auto E = [&](const point_3d& pt) -> vec3d { return mpl.Efield(pt); }; + maxwell::init_E_field(mod, state, E); + } + + if ( mpl.initial_Hfield_defined() ) + { + auto H = [&](const point_3d& pt) -> vec3d { return mpl.Hfield(pt); }; + maxwell::init_H_field(mod, state, H); + } - state.delta_t = 0.001; + state.delta_t = mpl.delta_t(); + auto num_timesteps = mpl.timesteps(); + auto silo_output_rate = mpl.silo_output_rate(); - for(size_t i = 0; i < 10000; i++) + for(size_t i = 0; i < num_timesteps; i++) { timestep(state); std::stringstream ss; ss << "maxwell_" << i << ".silo"; - if (i%10 == 0) + if (i%silo_output_rate == 0) maxwell::export_to_silo(mod, state, ss.str()); std::swap(state.emf_curr, state.emf_next); } - - } int main(int argc, const char *argv[]) @@ -64,13 +68,30 @@ int main(int argc, const char *argv[]) gmsh::initialize(); make_geometry(1, 0.1); - model mod(1,3); - - maxwell::solver_state state_c; - test_it(mod, state_c); + maxwell_parameter_loader mpl; + if ( not mpl.load_file("params.lua") ) + { + std::cout << "Configuration problem, exiting" << std::endl; + return 1; + } + + model mod( mpl.geom_order(), mpl.approx_order() ); + if ( not mpl.validate_model_params(mod) ) + { + std::cout << "Configuration problem, exiting" << std::endl; + return 1; + } - //maxwell::solver_state_gpu state_g; - //test_it(mod, state_g); + if ( mpl.use_gpu() ) + { + maxwell::solver_state_gpu state_g; + test_it(mod, state_g, mpl); + } + else + { + maxwell::solver_state state_c; + test_it(mod, state_c, mpl); + } //gmsh::finalize(); diff --git a/src/param_loader.cpp b/src/param_loader.cpp new file mode 100644 index 0000000..aa89fea --- /dev/null +++ b/src/param_loader.cpp @@ -0,0 +1,192 @@ +#include <iostream> +#include "param_loader.h" + +parameter_loader::parameter_loader() +{ + lua.open_libraries(sol::lib::base, sol::lib::math); + init(); +} + +void +parameter_loader::init(void) +{ + lua["const"] = lua.create_table(); + lua["const"]["eps0"] = 8.8541878128e-12; + lua["const"]["mu0"] = 4e-7*M_PI; + + lua["sim"] = lua.create_table(); + lua["sim"]["approx_order"] = 1; + lua["sim"]["geom_order"] = 1; + lua["sim"]["use_gpu"] = 0; + //lua["sim"]["name"]; + //lua["sim"]["dt"]; + //lua["sim"]["timesteps"]; + //lua["sim"]["gmsh_model"]; + + lua["materials"] = lua.create_table(); + lua["bndconds"] = lua.create_table(); + lua["ifaceconds"] = lua.create_table(); + + lua["postpro"] = lua.create_table(); + lua["postpro"]["silo_output_rate"] = 0; +} + +bool +parameter_loader::validate_simulation_params(void) const +{ + bool success = true; + + auto sim_name = lua["sim"]["name"]; + if (not sim_name.valid()) + { + std::cout << "[CONFIG] 'sim.name' not set" << std::endl; + success = false; + } + + auto sim_dt = lua["sim"]["dt"]; + if (not sim_dt.valid()) + { + std::cout << "[CONFIG] 'sim.dt' not set" << std::endl; + success = false; + } + + auto sim_timesteps = lua["sim"]["timesteps"]; + if (not sim_timesteps.valid()) + { + std::cout << "[CONFIG] 'sim.timesteps' not set" << std::endl; + success = false; + } + + auto sim_gmshmodel = lua["sim"]["gmsh_model"]; + if (not sim_gmshmodel.valid()) + { + std::cout << "[CONFIG] 'sim.gmsh_model' not set" << std::endl; + success = false; + } + + return success; +} + +bool +parameter_loader::load_file(const std::string& fn) +{ + auto script = lua.script_file(fn); + if (not script.valid()) + return false; + + return validate_simulation_params(); +} + +int +parameter_loader::approx_order(void) const +{ + return lua["sim"]["approx_order"]; +} + +int +parameter_loader::geom_order(void) const +{ + return lua["sim"]["geom_order"]; +} + +double +parameter_loader::delta_t(void) const +{ + return lua["sim"]["dt"]; +} + +size_t +parameter_loader::timesteps(void) const +{ + return lua["sim"]["timesteps"]; +} + +std::string +parameter_loader::simulation_name(void) const +{ + return lua["sim"]["name"]; +} + +bool +parameter_loader::use_gpu(void) const +{ + return lua["sim"]["use_gpu"]; +} + +size_t +parameter_loader::silo_output_rate(void) const +{ + return lua["postpro"]["silo_output_rate"]; +} + +maxwell_parameter_loader::maxwell_parameter_loader() +{} + +bool +maxwell_parameter_loader::validate_materials(const std::string& mpn, int tag) +{ + auto mfun = lua["materials"][mpn]; + if ( mfun.valid() ) + return true; + + auto mparams = lua["materials"][tag]; + if ( mparams.valid() ) + { + auto matparams_mpn = lua["materials"][tag][mpn]; + if ( matparams_mpn.valid() ) + return true; + } + + std::cout << "[CONFIG] 'materials[" << tag << "]." << mpn << "' not defined and "; + std::cout << "'materials." << mpn << "(tag,x,y,z)' not present." << std::endl; + return false; +} + +bool +maxwell_parameter_loader::validate_model_params(const model& mod) +{ + bool success = true; + for (auto& e : mod) + { + auto tag = e.gmsh_tag(); + bool eps_valid = validate_materials("epsilon", tag); + bool mu_valid = validate_materials("mu", tag); + bool sigma_valid = validate_materials("sigma", tag); + if ( (not eps_valid) or (not mu_valid) or (not sigma_valid) ) + success = false; + } + + return success; +} + +bool +maxwell_parameter_loader::initial_Efield_defined(void) const +{ + auto eic = lua["electric_initial_condition"]; + return eic.valid(); +} + +vec3d +maxwell_parameter_loader::Efield(const point_3d& pt) const +{ + vec3d ret; + sol::tie(ret(0), ret(1), ret(2)) = + lua["electric_initial_condition"](pt.x(), pt.y(), pt.z()); + return ret; +} + +bool +maxwell_parameter_loader::initial_Hfield_defined(void) const +{ + auto mic = lua["magnetic_initial_condition"]; + return mic.valid(); +} + +vec3d +maxwell_parameter_loader::Hfield(const point_3d& pt) const +{ + vec3d ret; + sol::tie(ret(0), ret(1), ret(2)) = + lua["magnetic_initial_condition"](pt.x(), pt.y(), pt.z()); + return ret; +} \ No newline at end of file diff --git a/src/physical_element.cpp b/src/physical_element.cpp index 5859b58..b871a2e 100644 --- a/src/physical_element.cpp +++ b/src/physical_element.cpp @@ -312,6 +312,9 @@ element_key_factory::element_key_factory(int dim, int tag, int etype) ekeys.push_back( ek ); } std::sort(ekeys.begin(), ekeys.end()); + + /* Not sure why there are duplicates */ + ekeys.erase( std::unique(ekeys.begin(), ekeys.end()), ekeys.end() ); } std::vector<element_key> -- GitLab