diff --git a/doc/lua_api.md b/doc/lua_api.md index 67c03cca57ed28f74775bc29e649c3cf5fbcab86..409abc65f8e8419bf9f065b493387cc153e20979 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -125,10 +125,18 @@ Currently, only a surface current condition is available: None. ### Callbacks +- `before_start()`: if defined, the solver calls this function just before beginning the timestepping. - `on_timestep(ts)`: if defined, the solver calls this function at every timestep. The solver passes the current timestep number in the parameter `ts`. The function is called **before** the solver state is advanced. - `electric_initial_condition(x, y, z)`: if defined, the solver calls this function at the beginning of the simulation in order to initialize the electric field. The parameters `x`, `y` and `z` represent the point at which the field needs to be evaluated. The function has to return a triple specifying the three field components, i.e. `return Ex, Ey, Ez`. - `magnetic_initial_condition(x, y, z)`: if defined, the solver calls this function at the beginning of the simulation in order to initialize the magnetic field. The parameters `x`, `y` and `z` represent the point at which the field needs to be evaluated. The function has to return a triple specifying the three field components, i.e. `return Hx, Hy, Hz`. +### Data types +- `point`: a three dimensional point + +### Variables +- `internal.model`: opaque reference to the internal representation of the GMSH model. Valid only after the solver is fully initialized, i.e. inside the callback functions. +- `internal.state`: opaque reference to the internal representation of the solver state. Valid only after the solver is fully initialized, i.e. inside the callback functions. + ### Postprocessing The export of the fields E, H and J to Silo is controlled using the appropriate sections in the `postpro` table. - `postpro["E"].silo_mode` controls the export of the electric field E. Possible values are `"none"` (no export), `"nodal"` (export as a Silo nodal variable) and `"zonal"` (export as a Silo zonal variable) diff --git a/include/param_loader.h b/include/param_loader.h index 6e2afd77f3c40dfd7850168c9bed186296fd3e28..358c209763871d373283797d8282b727606b2f8d 100644 --- a/include/param_loader.h +++ b/include/param_loader.h @@ -64,6 +64,9 @@ public: void source_was_cleared(void); void call_timestep_callback(size_t); + void call_initialization_callback(); + + sol::state& lua_state(void) { return lua; } }; diff --git a/src/maxwell_solver.cpp b/src/maxwell_solver.cpp index 60887a56de3783fc1e78895bca943132613e6934..72ac3c5b636055881a8f57b437afcc12a013c5d0 100644 --- a/src/maxwell_solver.cpp +++ b/src/maxwell_solver.cpp @@ -68,21 +68,21 @@ void initialize_solver(const model& mod, State& state, const maxwell::parameter_ init_matparams(mod, state, mpl); } -class line_integrator +class integration_line { std::vector<size_t> element_tags; std::vector<point_3d> sampling_points_phys; std::vector<point_3d> sampling_points_ref; - point_3d increment; + point_3d sampling_increment; public: - line_integrator(const point_3d& start, + integration_line(const point_3d& start, const point_3d& end, size_t samples) { - increment = (end - start)/samples; + sampling_increment = (end - start)/samples; for (size_t i = 0; i < samples; i++) { - point_3d sp = start + increment*(i+0.5); + point_3d sp = start + sampling_increment*(i+0.5); sampling_points_phys.push_back(sp); size_t etag; @@ -97,39 +97,95 @@ public: } } - double integrate(const model& mod, const vecxd& dofs) + size_t sampling_points() const { - double integral_val = 0.0; - for (size_t i = 0; i < sampling_points_phys.size(); i++) - { - auto [entnum, ofs] = mod.lookup_tag(element_tags.at(i)); - auto& e = mod.entity_at(entnum); - auto& pe = e.cell(ofs); - auto& re = e.cell_refelem(pe); - auto dof_ofs = e.cell_global_dof_offset(ofs); - auto dof_num = re.num_basis_functions(); - vecxd phi = re.basis_functions( sampling_points_ref[i] ); - vecxd sol = dofs.segment(dof_ofs, dof_num); - integral_val += sol.dot(phi) * increment.x(); - } + assert(element_tags.size() == sampling_points_phys.size()); + assert(element_tags.size() == sampling_points_ref.size()); + return element_tags.size(); + } + + std::tuple<size_t, point_3d, point_3d> + operator[](size_t pos) + { + assert(element_tags.size() == sampling_points_phys.size()); + assert(element_tags.size() == sampling_points_ref.size()); + assert(pos < element_tags.size()); + + return std::make_tuple( + element_tags[pos], + sampling_points_phys[pos], + sampling_points_ref[pos] + ); + } - return integral_val; + point_3d increment() const + { + return sampling_increment; } + }; double -integrate(const model& mod, const maxwell::solver_state& state, line_integrator& lint) +integrate_electric_field(const model& mod, const maxwell::solver_state& state, + integration_line& iline) { - return lint.integrate(mod, state.emf_curr.Ex); + double integral_val = 0.0; + auto si = iline.increment(); + + for (size_t i = 0; i < iline.sampling_points(); i++) + { + auto [tag, physp, refp] = iline[i]; + auto [entnum, ofs] = mod.lookup_tag(tag); + auto& e = mod.entity_at(entnum); + auto& pe = e.cell(ofs); + auto& re = e.cell_refelem(pe); + auto dof_ofs = e.cell_global_dof_offset(ofs); + auto dof_num = re.num_basis_functions(); + vecxd phi = re.basis_functions( refp ); + vecxd locEx = state.emf_curr.Ex.segment(dof_ofs, dof_num); + vecxd locEy = state.emf_curr.Ey.segment(dof_ofs, dof_num); + vecxd locEz = state.emf_curr.Ez.segment(dof_ofs, dof_num); + integral_val += locEx.dot(phi) * si.x() + + locEy.dot(phi) * si.y() + + locEz.dot(phi) * si.z(); + } + + return integral_val; } +#ifdef ENABLE_GPU_SOLVER double -integrate(const model& mod, const maxwell::solver_state_gpu& state, line_integrator& lint) +integrate(const model& mod, const maxwell::solver_state_gpu& state, integration_line& lint) { - maxwell::field f; - f.resize( mod.num_dofs() ); - state.emf_curr.copyout(f); - return lint.integrate(mod, f.Ex); + return 0.0; +} +#endif + +void +reinit_materials(const model& mod, maxwell::solver_state& state, maxwell::parameter_loader& mpl) +{ + for (auto& e : mod) + { + auto tag = e.gmsh_tag(); + for (size_t iT = 0; iT < e.num_cells(); iT++) + { + auto& pe = e.cell(iT); + auto& re = e.cell_refelem(pe); + auto bar = pe.barycenter(); + auto epsilon = mpl.epsilon(tag, bar); + //auto mu = mpl.mu(tag, bar); + auto sigma = mpl.sigma(tag, bar); + auto ofs = e.cell_global_dof_offset(iT); + + for (size_t iD = 0; iD < re.num_basis_functions(); iD++) + { + //state.matparams.inv_epsilon(ofs+iD) = 1./epsilon; + //state.matparams.inv_mu(ofs+iD) = 1./mu; + state.matparams.sigma(ofs+iD) = sigma; + state.matparams.sigma_over_epsilon(ofs+iD) = sigma/epsilon; + } + } + } } template<typename State> @@ -152,11 +208,12 @@ void test_it(const model& mod, State& state, maxwell::parameter_loader& mpl) std::cout << "s each." << std::endl; std::cout << "Time integrator: " << mpl.sim_timeIntegratorName() << std::endl; - point_3d start(-46e-9, 0.0, 38e-9); - point_3d end(46e-9, 0.0, 38e-9); - line_integrator lint(start, end, 50); + mpl.call_initialization_callback(); + + auto relmat = [&](){ reinit_materials(mod, state, mpl); }; - std::ofstream ofs("voltage.dat"); + sol::state& lua = mpl.lua_state(); + lua["relmat"] = relmat; timecounter tc; tc.tic(); @@ -179,11 +236,43 @@ void test_it(const model& mod, State& state, maxwell::parameter_loader& mpl) std::cout << "Cycle " << i << ": t = " << state.curr_time << " s"; std::cout << ", DOFs/s: " << (mod.num_dofs()*6*cycle_print_rate)/(time) << std::endl; tc.tic(); - ofs << state.curr_time << " " << integrate(mod, state, lint) << std::endl; } } } +void +register_lua_usertypes(maxwell::parameter_loader& mpl) +{ + sol::state& lua = mpl.lua_state(); + sol::usertype<point_3d> point_3d_ut = lua.new_usertype<point_3d>("point", + sol::constructors<point_3d(), point_3d(double, double, double)>() + ); + + sol::usertype<integration_line> line_integrator_ut = + lua.new_usertype<integration_line>("integration_line", + sol::constructors<integration_line(const point_3d&, const point_3d&, size_t)>() + ); +} + +void +register_lua_usertypes_bystate(maxwell::parameter_loader& mpl, + model& mod, maxwell::solver_state& state) +{ + sol::state& lua = mpl.lua_state(); + + lua["internal"] = lua.create_table(); + lua["internal"]["model"] = &mod; + lua["internal"]["state"] = &state; + lua["integrate_E"] = integrate_electric_field; +} + +#ifdef ENABLE_GPU_SOLVER +void +register_lua_usertypes_bystate(maxwell::parameter_loader& mpl, + model& mod, maxwell::solver_state_gpu& state) +{} +#endif + int main(int argc, const char *argv[]) { gmsh::initialize(); @@ -198,6 +287,8 @@ int main(int argc, const char *argv[]) } maxwell::parameter_loader mpl; + register_lua_usertypes(mpl); + if ( not mpl.load_file( argv[1] ) ) { std::cout << "Configuration problem, exiting" << std::endl; @@ -230,6 +321,7 @@ int main(int argc, const char *argv[]) { #ifdef ENABLE_GPU_SOLVER maxwell::solver_state_gpu state_g; + register_lua_usertypes_bystate(mpl, mod, state_g); test_it(mod, state_g, mpl); #else std::cout << "GPU solver not compiled. Exiting." << std::endl; @@ -238,6 +330,7 @@ int main(int argc, const char *argv[]) else { maxwell::solver_state state_c; + register_lua_usertypes_bystate(mpl, mod, state_c); test_it(mod, state_c, mpl); } diff --git a/src/param_loader.cpp b/src/param_loader.cpp index 5399e34058333bc2b6ba4c313623cabf06f31631..eb9b97127e14d262dd3c981a3ea70db52230f038 100644 --- a/src/param_loader.cpp +++ b/src/param_loader.cpp @@ -211,6 +211,21 @@ parameter_loader_base::call_timestep_callback(size_t timestep) } } +void +parameter_loader_base::call_initialization_callback() +{ + if ( lua["before_start"].valid() ) + { + try { + lua["before_start"](); + } + catch (...) + { + std::cout << "An error was thrown calling before_start()" << std::endl; + } + } +} + bool parameter_loader_base::source_has_changed_state(void) const {