diff --git a/doc/lua_api.md b/doc/lua_api.md index 46e30ab76b3f3488e4d887d9bc938071d5013c9b..6ab8f7fc6bf68dd5556d406d2d0935e399f05a4f 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -144,7 +144,7 @@ None. ### Debug and validation The solver has some facilities to allow validation and comparison with analytical solutions. Those facilities are accessed via the `debug` table. In the current implementation the `debug` table is undefined by default, so it must be initialized explicitly in the configuration with a statement `debug = {}`. Possible members of the `debug` table are: -- `analytical_solution(tag, x, y, z, t)`: define the analytical solution of the problem. If defined, the numerical solution is compared with the analytical solution at each timestep in the whole domain. The function has to return 6 values, namely `Ex`, `Ey`, `Ez`, `Hx`, `Hy` and `Hz`. +- `analytical_solution`: a function `f(tag, x, y, z, t)` defining the analytical solution of the problem. If defined, it can be used to compare the numerical solution with the analytical solution during the timestepping. The function has to return 6 values, namely `Ex`, `Ey`, `Ez`, `Hx`, `Hy` and `Hz`. - `dump_cell_ranks` (bool): if true, and if the solver has MPI support compiled in, add to the Silo output a variable named `cell_ranks` showing the cell-to-rank mapping. ### Postprocessing diff --git a/include/libgmshdg/gmsh_io.h b/include/libgmshdg/gmsh_io.h index 629356b70cbdfa118ecbcc515ba1888864573de1..81d959b50f647796988a042dad898b3a5a9f8453 100644 --- a/include/libgmshdg/gmsh_io.h +++ b/include/libgmshdg/gmsh_io.h @@ -29,8 +29,6 @@ std::string quadrature_name(int); std::string basis_func_name(int); std::string basis_grad_name(int); -using face_key = std::array<size_t, 3>; - enum class face_type : int { NONE = 0, diff --git a/include/maxwell/maxwell_interface.h b/include/maxwell/maxwell_interface.h index 00662a72f2b6ee8a79b3fdcb32da73d4091abbcf..0fb3af3d17f51c1aa6d579210f59ff83d7926c1a 100644 --- a/include/maxwell/maxwell_interface.h +++ b/include/maxwell/maxwell_interface.h @@ -435,4 +435,42 @@ void decompress_bndsrc(const solver_state_gpu& state, const field_gpu& csrcs, #endif /* ENABLE_GPU_SOLVER */ + + + + +struct field_values { + double Ex; + double Ey; + double Ez; + double Hx; + double Hy; + double Hz; + + field_values(); + field_values(const vec3d&, const vec3d&); + + field_values(double, double, double, double, double, double); + + field_values& operator+=(const field_values&); + field_values operator+(const field_values&) const; + field_values& operator-=(const field_values&); + field_values operator-(const field_values&) const; + field_values& operator*=(const field_values&); + field_values operator*(const field_values&) const; + field_values& operator/=(const field_values&); + field_values operator/(const field_values&) const; + + field_values& operator*=(double); + field_values operator*(double) const; + field_values& operator/=(double); + field_values operator/(double) const; +}; + +field_values operator*(double, const field_values&); +std::ostream& operator<<(std::ostream&, const field_values&); + +field_values sqrt(const field_values&); +double hsum(const field_values& m); + } // namespace maxwell diff --git a/include/maxwell/maxwell_postpro.h b/include/maxwell/maxwell_postpro.h new file mode 100644 index 0000000000000000000000000000000000000000..75e94cf99060336e194caa671bfa9e857760dbe6 --- /dev/null +++ b/include/maxwell/maxwell_postpro.h @@ -0,0 +1,11 @@ +#pragma once + +#include "maxwell/maxwell_interface.h" + +namespace maxwell { + +field_values eval_field(const field&, size_t, size_t, const vecxd&); +field_values compute_error(const model&, const solver_state&, const parameter_loader&); +field_values compute_energy(const model&, const solver_state&, const parameter_loader&); + +} // namespace maxwell \ No newline at end of file diff --git a/share/capacitor/capacitor.geo b/share/capacitor/capacitor.geo deleted file mode 100644 index 9fd46c5cb2c3301f13cdf5a84d5953f30b4b94de..0000000000000000000000000000000000000000 --- a/share/capacitor/capacitor.geo +++ /dev/null @@ -1,15 +0,0 @@ -l = 0.02; -d = 0.001; -t = 0.0003; -sh = 2*t+d; - -SetFactory("OpenCASCADE"); -Mesh.Algorithm3D = 10; - -Box(1) = {-l/2, -l/2, -sh/2, l, l, t}; -Box(2) = {-l/2, -l/2, -sh/2 + t, l, l, d}; -Box(3) = {-l/2, -l/2, -sh/2 + t+d, l, l, t}; -Sphere(4) = {0, 0, 0, l, -Pi/2, Pi/2, 2*Pi}; -Coherence; - -MeshSize{ PointsOf{ Volume{1,2,3}; } } = 0.0008; diff --git a/share/capacitor/capacitor.m b/share/capacitor/capacitor.m deleted file mode 100644 index f7abfbaf6ce246f4494f8b90ef456222bbfe0ee9..0000000000000000000000000000000000000000 --- a/share/capacitor/capacitor.m +++ /dev/null @@ -1,16 +0,0 @@ -l = 0.02; -d = 0.001; -epsilon = 10 * 8.85e-12; -t = 1e-13; -J = 1; - -A = l*l; -I = J*A; - -C = epsilon*A/d; -Q = I*t; - -V = Q/C -E = V/d - -Q*d/(epsilon*l*A) diff --git a/share/capacitor/params_capacitor.lua b/share/capacitor/params_capacitor.lua deleted file mode 100644 index bfba7ec06d02a3b2a45a53d167983274389032e1..0000000000000000000000000000000000000000 --- a/share/capacitor/params_capacitor.lua +++ /dev/null @@ -1,66 +0,0 @@ -sim.name = "capacitor" -- simulation name -sim.dt = 1e-13 -- timestep size -sim.timesteps = 100000 -- num of iterations -sim.gmsh_model = "capacitor.geo" -- gmsh model filename -sim.use_gpu = 0 -- 0: cpu, 1: gpu -sim.approx_order = 1 -- approximation order -sim.time_integrator = "leapfrog" -postpro.silo_output_rate = 10 -- rate at which to write silo files -postpro.cycle_print_rate = 10 -- console print rate - -local alu = {1, 3} -for i,v in ipairs(alu) do - materials[v] = {} - materials[v].epsilon = 1 - materials[v].mu = 1 - materials[v].sigma = 3.69e7 -end - -local diel = { 2 } -for i,v in ipairs(diel) do - materials[v] = {} - materials[v].epsilon = 10 - materials[v].mu = 1 - materials[v].sigma = 0 -end - -local air = { 4 } -for i,v in ipairs(air) do - materials[v] = {} - materials[v].epsilon = 1 - materials[v].mu = 1 - materials[v].sigma = 0 -end - --- ** Boundary conditions ** -local absorbing_bcs = {1} -for i,v in ipairs(absorbing_bcs) do - bndconds[v] = {} - bndconds[v].kind = "impedance" -end - -function interp(t, t0, t1, y0, y1) - return (t-t0)*(y1-y0)/(t1-t0) + y0 -end - -local current_shape = { {0, 1}, {10*sim.dt, 1} } - - -function discharge_source(tag, x, y, z, t) - for ii = 1,(#current_shape-1) do - local t0 = current_shape[ii][1] - local c0 = current_shape[ii][2] - local t1 = current_shape[ii+1][1] - local c1 = current_shape[ii+1][2] - if (t >= t0 and t < t1) then - Ez = interp(t, t0, t1, c0, c1) - return 0, 0, Ez - end - end - return 0, 0, 0 -end - -sources[2] = discharge_source - - - diff --git a/share/examples/capacitor/capacitor.geo b/share/examples/capacitor/capacitor.geo new file mode 100644 index 0000000000000000000000000000000000000000..3a2306b212ef89647147b81b13ab669689d57781 --- /dev/null +++ b/share/examples/capacitor/capacitor.geo @@ -0,0 +1,14 @@ +R = 0.01; // disk radius +d = 0.001; // dielectric thickness +t = 0.0003; // disk thickness + +SetFactory("OpenCASCADE"); +Mesh.Algorithm3D = 10; + +Cylinder(1) = {0, 0, d/2, 0, 0, t, R}; +Cylinder(2) = {0, 0, -d/2, 0, 0, d, R}; +Cylinder(3) = {0, 0, -d/2-t, 0, 0, t, R}; +Sphere(4) = {0, 0, 0, 2*R, -Pi/2, Pi/2, 2*Pi}; +Coherence; + +MeshSize{ PointsOf{ Volume{2}; } } = 0.0003; diff --git a/share/examples/capacitor/params_capacitor.lua b/share/examples/capacitor/params_capacitor.lua new file mode 100644 index 0000000000000000000000000000000000000000..b694a17e95827437c7cbf831154c707e779b2f45 --- /dev/null +++ b/share/examples/capacitor/params_capacitor.lua @@ -0,0 +1,98 @@ +sim.name = "capacitor" -- simulation name +sim.dt = 1e-14 -- timestep size +sim.timesteps = 301 -- num of iterations +sim.gmsh_model = "capacitor.geo" -- gmsh model filename +sim.use_gpu = 0 -- 0: cpu, 1: gpu +sim.approx_order = 1 -- approximation order +sim.time_integrator = "leapfrog" -- time integration method +postpro.silo_output_rate = 10 -- rate at which to write silo files +postpro.cycle_print_rate = 10 -- console print rate + +local diel_epsr = 10 -- Permittivity of the capacitor dielectric + +-- Aluminum plates material parameters +local alu = {1, 3} +for i,v in ipairs(alu) do + materials[v] = {} + materials[v].epsilon = 1 + materials[v].mu = 1 + materials[v].sigma = 3.69e7 +end + +-- Dielectric parameters +local diel = { 2 } +for i,v in ipairs(diel) do + materials[v] = {} + materials[v].epsilon = diel_epsr + materials[v].mu = 1 + materials[v].sigma = 0 +end + +-- Air parameters +local air = { 4 } +for i,v in ipairs(air) do + materials[v] = {} + materials[v].epsilon = 1 + materials[v].mu = 1 + materials[v].sigma = 0 +end + +-- ** Boundary conditions ** +local absorbing_bcs = {1} +for i,v in ipairs(absorbing_bcs) do + bndconds[v] = {} + bndconds[v].kind = "impedance" +end + +function interp(t, t0, t1, y0, y1) + return (t-t0)*(y1-y0)/(t1-t0) + y0 +end + +local R = 0.01 -- Capacitor disk radius (must match capacitor.geo) +local d = 0.001 -- Dielectric thickness (must match capacitor.geo) +local tV = 1 -- Target capacitor voltage +local cts = 100 -- Charging current pulse timesteps + +local ct = cts*sim.dt +local eps = const.eps0 * diel_epsr +local A = math.pi*R*R +local C = eps*A/d +local J = tV*eps/(ct*d) +local I = J*A +local Q = I*ct + +local E = Q/(eps*A) -- Expected capacitor field (should equal tV/d) + +local do_IO = (not parallel) or (parallel and parallel.comm_rank == 0) + +if ( do_IO ) then + print("\x1b[1mExpected capacitor field: " .. E .. " V/m") + print("Charge: " .. Q .. " C") + print("Current density: " .. J .. " A/m^2\x1b[0m") +end + +-- Define the shape of charging current density in terms of +-- {time, current density} pairs. Linear interpolation between +-- pairs is used +local current_shape = { {0, J}, {ct, J} } + +-- Define the function evaluating the current source +function current_source(tag, x, y, z, t) + for ii = 1,(#current_shape-1) do + local t0 = current_shape[ii][1] + local c0 = current_shape[ii][2] + local t1 = current_shape[ii+1][1] + local c1 = current_shape[ii+1][2] + if (t >= t0 and t < t1) then + Ez = interp(t, t0, t1, c0, c1) + return 0, 0, Ez + end + end + return 0, 0, 0 +end + +-- Apply the current source to entity 2 +sources[2] = current_source + + + diff --git a/share/microwave_oven/oven.geo b/share/examples/microwave_oven/oven.geo similarity index 100% rename from share/microwave_oven/oven.geo rename to share/examples/microwave_oven/oven.geo diff --git a/share/microwave_oven/params_oven.lua b/share/examples/microwave_oven/params_oven.lua similarity index 99% rename from share/microwave_oven/params_oven.lua rename to share/examples/microwave_oven/params_oven.lua index 1f0459ae7b66c85593c304167ebc73175738f7e4..99d88da514f1ded3dbad3136ab13d7952f3ca449 100644 --- a/share/microwave_oven/params_oven.lua +++ b/share/examples/microwave_oven/params_oven.lua @@ -33,4 +33,3 @@ bndconds[100].kind = "plane_wave_E" bndconds[100].source = source - diff --git a/share/modeconv/modeconv.geo b/share/examples/modeconv/modeconv.geo similarity index 99% rename from share/modeconv/modeconv.geo rename to share/examples/modeconv/modeconv.geo index b1f7b5d11266daa3eee4cb4dfe59cca69f9bcd19..2c5c74181e0807c5529b0c64080066f721a595be 100644 --- a/share/modeconv/modeconv.geo +++ b/share/examples/modeconv/modeconv.geo @@ -13,7 +13,7 @@ z_base = 0; wg_xlen = 0.14; wg_ylen = 0.0229; -wg_zlen = 0.005; +wg_zlen = 0.01; rods_start_x = 0.12; diff --git a/share/modeconv/modeconv.i1 b/share/examples/modeconv/modeconv.i1 similarity index 100% rename from share/modeconv/modeconv.i1 rename to share/examples/modeconv/modeconv.i1 diff --git a/share/modeconv/params_modeconv.lua b/share/examples/modeconv/params_modeconv.lua similarity index 95% rename from share/modeconv/params_modeconv.lua rename to share/examples/modeconv/params_modeconv.lua index 20d3c8e99f1610a9bcb8cb7add0a1013108f56f2..bdf106cdf852de7ddd5ab90eba90f1e580e6ced7 100644 --- a/share/modeconv/params_modeconv.lua +++ b/share/examples/modeconv/params_modeconv.lua @@ -7,7 +7,7 @@ sim.timesteps = 50000 -- num of iterations sim.gmsh_model = "modeconv.geo" -- gmsh model filename sim.use_gpu = 0 -- 0: cpu, 1: gpu sim.approx_order = 2 -- approximation order ---sim_geom_order = 1 -- geometric order, only 1 for now +sim.time_integrator = "rk4" postpro.silo_output_rate = 100 -- rate at which to write silo files postpro.cycle_print_rate = 10 -- console print rate diff --git a/share/yagi/params_yagi.lua b/share/examples/yagi/params_yagi.lua similarity index 87% rename from share/yagi/params_yagi.lua rename to share/examples/yagi/params_yagi.lua index e3d17fdad4abcd9c9a422b5ef7ce4a50415e67d6..5e545ec6b0d0dafdc54e5699593c265dbc8c1648 100644 --- a/share/yagi/params_yagi.lua +++ b/share/examples/yagi/params_yagi.lua @@ -3,11 +3,11 @@ ]]-- sim.name = "yagi" -- simulation name sim.dt = 1e-12 -- timestep size -sim.timesteps = 2000 -- num of iterations +sim.timesteps = 20000 -- num of iterations sim.gmsh_model = "yagi.geo" -- gmsh model filename -sim.use_gpu = 1 -- 0: cpu, 1: gpu +sim.use_gpu = 0 -- 0: cpu, 1: gpu sim.approx_order = 1 -- approximation order ---sim_geom_order = 1 -- geometric order, only 1 for now +sim.time_integrator = "leapfrog" postpro.silo_output_rate = 100 -- rate at which to write silo files postpro.cycle_print_rate = 10 -- console print rate diff --git a/share/yagi/yagi.geo b/share/examples/yagi/yagi.geo similarity index 100% rename from share/yagi/yagi.geo rename to share/examples/yagi/yagi.geo diff --git a/share/yagi_rad/params_yagi_rad.lua b/share/examples/yagi_rad/params_yagi_rad.lua similarity index 74% rename from share/yagi_rad/params_yagi_rad.lua rename to share/examples/yagi_rad/params_yagi_rad.lua index de966b78518e76ccfac3d90223b98860353b2359..2090af836ae781570502060765f3167ca696f10d 100644 --- a/share/yagi_rad/params_yagi_rad.lua +++ b/share/examples/yagi_rad/params_yagi_rad.lua @@ -3,15 +3,14 @@ The source is modeled as a volumetric current between the two halves of the radiator. --]] -sim.name = "yagi_rad" -- simulation name +sim.name = "yagi_rad" -- simulation name sim.dt = 1e-13 -- timestep size -sim.timesteps = 50000 -- num of iterations -sim.gmsh_model = "yagi_rad.geo" -- gmsh model filename -sim.use_gpu = 1 -- 0: cpu, 1: gpu +sim.timesteps = 50000 -- num of iterations +sim.gmsh_model = "yagi_rad.geo" -- gmsh model filename +sim.use_gpu = 0 -- 0: cpu, 1: gpu sim.approx_order = 2 -- approximation order ---sim_geom_order = 1 -- geometric order, only 1 for now sim.time_integrator = "leapfrog" -postpro.silo_output_rate = 500 -- rate at which to write silo files +postpro.silo_output_rate = 500 -- rate at which to write silo files postpro.cycle_print_rate = 10 -- console print rate postpro["H"].silo_mode = "none" @@ -24,7 +23,7 @@ for i,v in ipairs(alu) do materials[v] = {} materials[v].epsilon = 1 materials[v].mu = 1 - materials[v].sigma = 3.69e7 + materials[v].sigma = 3.69e7 end local air = {4, 7} diff --git a/share/yagi_rad/yagi_rad.geo b/share/examples/yagi_rad/yagi_rad.geo similarity index 100% rename from share/yagi_rad/yagi_rad.geo rename to share/examples/yagi_rad/yagi_rad.geo diff --git a/src/libgmshdg/gmsh_io.cpp b/src/libgmshdg/gmsh_io.cpp index 5c805974d627e0af69d989812198d4038d6212bc..23f5fb7225fb0b35689990da4999362e00b1eb97 100644 --- a/src/libgmshdg/gmsh_io.cpp +++ b/src/libgmshdg/gmsh_io.cpp @@ -410,6 +410,15 @@ model::map_boundaries(void) #endif /* USE_MPI */ std::vector<bfk_t> bfk = get_facekey_tag_pairs(); + for (size_t i = 1; i < bfk.size(); i++) + { + if ( bfk[i-1].first == bfk[i].first ) + { + std::cout << bfk[i-1].second << " " << bfk[i].second << std::endl; + throw 42; + } + } + bnd_descriptors.resize( num_faces() ); size_t fbase = 0; /* For each entity */ diff --git a/src/maxwell/CMakeLists.txt b/src/maxwell/CMakeLists.txt index e4f2fba6de7d1bd5f9de3f31bca84809453ddd36..00e2876a280c917563397dcb91ad086d415e16f2 100644 --- a/src/maxwell/CMakeLists.txt +++ b/src/maxwell/CMakeLists.txt @@ -2,6 +2,7 @@ set(MAXWELL_SOURCES maxwell_interface.cpp maxwell_cpu.cpp maxwell_common.cpp maxwell_solver.cpp + maxwell_postpro.cpp ) if (OPT_ENABLE_GPU_SOLVER) diff --git a/src/maxwell/maxwell_interface.cpp b/src/maxwell/maxwell_interface.cpp index b04e16ea468a643a19585f433b6cb8bc7d57cf53..ca5526a836e5734e6edf37b0b733c1cc54e1eae1 100644 --- a/src/maxwell/maxwell_interface.cpp +++ b/src/maxwell/maxwell_interface.cpp @@ -86,6 +86,179 @@ void receive_field(field& f, int src, int tag, size_t offset, size_t length, MPI } #endif /* USE_MPI */ +field_values::field_values() + : Ex(0.0), Ey(0.0), Ez(0.0), + Hx(0.0), Hy(0.0), Hz(0.0) +{} + +field_values::field_values(const vec3d& E, const vec3d& H) + : Ex( E(0) ), Ey( E(1) ), Ez( E(2) ), + Hx( H(0) ), Hy( H(1) ), Hz( H(2) ) +{} + +field_values::field_values(double pEx, double pEy, double pEz, + double pHx, double pHy, double pHz) + : Ex(pEx), Ey(pEy), Ez(pEz), Hx(pHx), Hy(pHy), Hz(pHz) +{} + +field_values& +field_values::operator+=(const field_values& other) +{ + Ex += other.Ex; + Ey += other.Ey; + Ez += other.Ez; + Hx += other.Hx; + Hy += other.Hy; + Hz += other.Hz; + return *this; +} + +field_values +field_values::operator+(const field_values& other) const +{ + field_values ret = *this; + ret += other; + return ret; +} + +field_values& +field_values::operator-=(const field_values& other) +{ + Ex -= other.Ex; + Ey -= other.Ey; + Ez -= other.Ez; + Hx -= other.Hx; + Hy -= other.Hy; + Hz -= other.Hz; + return *this; +} + +field_values +field_values::operator-(const field_values& other) const +{ + field_values ret = *this; + ret -= other; + return ret; +} + +field_values& +field_values::operator*=(const field_values& other) +{ + Ex *= other.Ex; + Ey *= other.Ey; + Ez *= other.Ez; + Hx *= other.Hx; + Hy *= other.Hy; + Hz *= other.Hz; + return *this; +} + +field_values +field_values::operator*(const field_values& other) const +{ + field_values ret = *this; + ret *= other; + return ret; +} + +field_values& +field_values::operator/=(const field_values& other) +{ + Ex /= other.Ex; + Ey /= other.Ey; + Ez /= other.Ez; + Hx /= other.Hx; + Hy /= other.Hy; + Hz /= other.Hz; + return *this; +} + +field_values +field_values::operator/(const field_values& other) const +{ + field_values ret = *this; + ret /= other; + return ret; +} + +field_values& +field_values::operator*=(double other) +{ + Ex *= other; + Ey *= other; + Ez *= other; + Hx *= other; + Hy *= other; + Hz *= other; + return *this; +} + +field_values +field_values::operator*(double other) const +{ + field_values ret = *this; + ret *= other; + return ret; +} + +field_values& +field_values::operator/=(double other) +{ + Ex /= other; + Ey /= other; + Ez /= other; + Hx /= other; + Hy /= other; + Hz /= other; + return *this; +} + +field_values +field_values::operator/(double other) const +{ + field_values ret = *this; + ret /= other; + return ret; +} + +field_values +operator*(double d, const field_values& m) +{ + return m*d; +} + +std::ostream& +operator<<(std::ostream& os, const field_values& m) +{ + os << m.Ex << " " << m.Ey << " " << m.Ez << " "; + os << m.Hx << " " << m.Hy << " " << m.Hz; + return os; +} + +field_values +sqrt(const field_values& m) +{ + field_values ret; + ret.Ex = std::sqrt(m.Ex); + ret.Ey = std::sqrt(m.Ey); + ret.Ez = std::sqrt(m.Ez); + ret.Hx = std::sqrt(m.Hx); + ret.Hy = std::sqrt(m.Hy); + ret.Hz = std::sqrt(m.Hz); + return ret; +} + +double +hsum(const field_values& m) +{ + return m.Ex + m.Ey + m.Ez + m.Hx + m.Hy + m.Hz; +} + + + + + + #ifdef ENABLE_GPU_SOLVER pinned_field::pinned_field() @@ -239,7 +412,6 @@ field_gpu::copyout(field& emf) const } - material_params_gpu::raw_ptrs material_params_gpu::data(void) { diff --git a/src/maxwell/maxwell_postpro.cpp b/src/maxwell/maxwell_postpro.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d9d603bd61e1ac6277c3736389af2d9c9b1d97c --- /dev/null +++ b/src/maxwell/maxwell_postpro.cpp @@ -0,0 +1,116 @@ + +#ifdef USE_MPI +#include <mpi.h> +#endif /* USE_MPI */ + +#include "maxwell/maxwell_postpro.h" + +namespace maxwell { + +field_values +eval_field(const field& f, size_t ofs, size_t cbs, const vecxd& phi) +{ + assert(ofs+cbs <= f.num_dofs); + field_values ret; + ret.Ex = f.Ex.segment(ofs, cbs).dot(phi); + ret.Ey = f.Ey.segment(ofs, cbs).dot(phi); + ret.Ez = f.Ez.segment(ofs, cbs).dot(phi); + ret.Hx = f.Hx.segment(ofs, cbs).dot(phi); + ret.Hy = f.Hy.segment(ofs, cbs).dot(phi); + ret.Hz = f.Hz.segment(ofs, cbs).dot(phi); + return ret; +} + +field_values +compute_error(const model& mod, const solver_state& state, const parameter_loader& mpl) +{ + field_values err; + + if (not mpl.has_analytical_solution()) + throw std::invalid_argument("analytical solution not defined in the Lua configuration"); + + for (auto& e : mod) + { + for (size_t iT = 0; iT < e.num_cells(); iT++) + { + const auto& pe = e.cell(iT); + const auto& re = e.cell_refelem(pe); + + const auto pqps = pe.integration_points(); + const auto dets = pe.determinants(); + + const auto ofs = e.cell_model_dof_offset(iT); + const auto cbs = re.num_basis_functions(); + + assert(pqps.size() == dets.size()); + for (size_t iQp = 0; iQp < pqps.size(); iQp++) + { + const auto& pqp = pqps[iQp]; + const vecxd phi = re.basis_functions(iQp); + + field_values Fh = eval_field(state.emf_curr, ofs, cbs, phi); + + auto [E, H] = mpl.eval_analytical_solution(e.material_tag(), + pqp.point(), state.curr_time); + field_values F(E,H); + field_values Fdiff = F - Fh; + err += Fdiff*Fdiff*pqp.weight(); + } + } + } + +#ifdef USE_MPI + MPI_Allreduce(MPI_IN_PLACE, &err, 6, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +#endif /* USE_MPI */ + return sqrt(err); +} + +field_values +compute_energy(const model& mod, const solver_state& state, const parameter_loader& mpl) +{ + field_values energy; + + for (auto& e : mod) + { + for (size_t iT = 0; iT < e.num_cells(); iT++) + { + const auto& pe = e.cell(iT); + const auto& re = e.cell_refelem(pe); + + const auto pqps = pe.integration_points(); + const auto dets = pe.determinants(); + + const auto ofs = e.cell_model_dof_offset(iT); + const auto cbs = re.num_basis_functions(); + + assert(pqps.size() == dets.size()); + const auto bar = pe.barycenter(); + auto eps = mpl.epsilon( e.material_tag(), bar ); + auto mu = mpl.mu( e.material_tag(), bar ); + + field_values mat(eps, eps, eps, mu, mu, mu); + + for (size_t iQp = 0; iQp < pqps.size(); iQp++) + { + const auto& pqp = pqps[iQp]; + const vecxd phi = re.basis_functions(iQp); + field_values Fh = eval_field(state.emf_curr, ofs, cbs, phi); + energy += 0.5*mat*Fh*Fh*pqp.weight(); + } + } + } + +#ifdef USE_MPI + MPI_Allreduce(MPI_IN_PLACE, &energy, 6, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +#endif /* USE_MPI */ + return energy; +} + +#ifdef ENABLE_GPU_SOLVER +static void +validate(const model&, maxwell::solver_state_gpu&, + maxwell::parameter_loader&, std::ofstream&) +{} +#endif /* ENABLE_GPU_SOLVER */ + +} // namespace maxwell \ No newline at end of file diff --git a/src/maxwell/maxwell_solver.cpp b/src/maxwell/maxwell_solver.cpp index b6575125392d33bea1544401355639d4a07768da..179afbcb2d57edc34abeb1336b0eb06e23b92d42 100644 --- a/src/maxwell/maxwell_solver.cpp +++ b/src/maxwell/maxwell_solver.cpp @@ -19,41 +19,12 @@ #include "libgmshdg/param_loader.h" #include "maxwell/maxwell_interface.h" #include "maxwell/maxwell_common.h" +#include "maxwell/maxwell_postpro.h" #include "timecounter.h" #include "sgr.hpp" using namespace sgr; -#if 0 -static void -make_geometry(int order, double mesh_h) -{ - gm::add("difftest"); - /* - std::vector<std::pair<int,int>> objects; - - objects.push_back( - std::make_pair(3, gmo::addBox(0.0, 0.0, 0.0, 1.0, 1.0, 0.05) ) - ); - objects.push_back( - std::make_pair(3, gmo::addBox(0.0, 0.0, 0.05, 1.0, 1.0, 0.05) ) - ); - - std::vector<std::pair<int, int>> tools; - gmsh::vectorpair odt; - std::vector<gmsh::vectorpair> odtm; - gmo::fragment(objects, tools, odt, odtm); - */ - gmo::addBox(0.0, 0.0, 0.0, 1.0, 1.0, 0.1); - - gmo::synchronize(); - - gvp_t vp; - gm::getEntities(vp); - gmm::setSize(vp, mesh_h); -} -#endif - template<typename State> void initialize_solver(const model& mod, State& state, const maxwell::parameter_loader& mpl) { @@ -196,265 +167,10 @@ reinit_materials(const model& mod, maxwell::solver_state& state, maxwell::parame } #endif /* ENABLE_EXP_GEOMETRIC_DIODE */ -struct maxwell_6ple { - double Ex; - double Ey; - double Ez; - double Hx; - double Hy; - double Hz; - - maxwell_6ple() - : Ex(0.0), Ey(0.0), Ez(0.0), - Hx(0.0), Hy(0.0), Hz(0.0) - {} - - maxwell_6ple(const vec3d& E, const vec3d& H) - : Ex( E(0) ), Ey( E(1) ), Ez( E(2) ), - Hx( H(0) ), Hy( H(1) ), Hz( H(2) ) - {} - - maxwell_6ple(double pEx, double pEy, double pEz, double pHx, double pHy, double pHz) - : Ex(pEx), Ey(pEy), Ez(pEz), Hx(pHx), Hy(pHy), Hz(pHz) - {} - - maxwell_6ple& operator+=(const maxwell_6ple& other) - { - Ex += other.Ex; - Ey += other.Ey; - Ez += other.Ez; - Hx += other.Hx; - Hy += other.Hy; - Hz += other.Hz; - return *this; - } - - maxwell_6ple operator+(const maxwell_6ple& other) const - { - maxwell_6ple ret = *this; - ret += other; - return ret; - } - - maxwell_6ple& operator-=(const maxwell_6ple& other) - { - Ex -= other.Ex; - Ey -= other.Ey; - Ez -= other.Ez; - Hx -= other.Hx; - Hy -= other.Hy; - Hz -= other.Hz; - return *this; - } - - maxwell_6ple operator-(const maxwell_6ple& other) const - { - maxwell_6ple ret = *this; - ret -= other; - return ret; - } - - maxwell_6ple& operator*=(const maxwell_6ple& other) - { - Ex *= other.Ex; - Ey *= other.Ey; - Ez *= other.Ez; - Hx *= other.Hx; - Hy *= other.Hy; - Hz *= other.Hz; - return *this; - } - - maxwell_6ple operator*(const maxwell_6ple& other) const - { - maxwell_6ple ret = *this; - ret *= other; - return ret; - } - - maxwell_6ple& operator*=(double other) - { - Ex *= other; - Ey *= other; - Ez *= other; - Hx *= other; - Hy *= other; - Hz *= other; - return *this; - } - - maxwell_6ple operator*(double other) const - { - maxwell_6ple ret = *this; - ret *= other; - return ret; - } - - maxwell_6ple& operator/=(const maxwell_6ple& other) - { - Ex /= other.Ex; - Ey /= other.Ey; - Ez /= other.Ez; - Hx /= other.Hx; - Hy /= other.Hy; - Hz /= other.Hz; - return *this; - } - - maxwell_6ple operator/(const maxwell_6ple& other) const - { - maxwell_6ple ret = *this; - ret /= other; - return ret; - } -}; - -static -maxwell_6ple operator*(double d, const maxwell_6ple& m) -{ - return m*d; -} - -static std::ostream& -operator<<(std::ostream& os, const maxwell_6ple& m) -{ - os << m.Ex << " " << m.Ey << " " << m.Ez << " "; - os << m.Hx << " " << m.Hy << " " << m.Hz; - return os; -} - -static maxwell_6ple -sqrt(const maxwell_6ple& m) -{ - maxwell_6ple ret; - ret.Ex = std::sqrt(m.Ex); - ret.Ey = std::sqrt(m.Ey); - ret.Ez = std::sqrt(m.Ez); - ret.Hx = std::sqrt(m.Hx); - ret.Hy = std::sqrt(m.Hy); - ret.Hz = std::sqrt(m.Hz); - return ret; -} - -static double -hsum(const maxwell_6ple& m) -{ - return m.Ex + m.Ey + m.Ez + m.Hx + m.Hy + m.Hz; -} - -static maxwell_6ple -eval_field(const maxwell::field& f, size_t ofs, size_t cbs, - const vecxd& phi) -{ - assert(ofs+cbs <= f.num_dofs); - maxwell_6ple ret; - ret.Ex = f.Ex.segment(ofs, cbs).dot(phi); - ret.Ey = f.Ey.segment(ofs, cbs).dot(phi); - ret.Ez = f.Ez.segment(ofs, cbs).dot(phi); - ret.Hx = f.Hx.segment(ofs, cbs).dot(phi); - ret.Hy = f.Hy.segment(ofs, cbs).dot(phi); - ret.Hz = f.Hz.segment(ofs, cbs).dot(phi); - return ret; -} - -static maxwell_6ple -compute_error(const model& mod, maxwell::solver_state& state, - maxwell::parameter_loader& mpl) -{ - maxwell_6ple err; - - if (not mpl.has_analytical_solution()) - throw std::invalid_argument("analytical solution not defined in the Lua configuration"); - - for (auto& e : mod) - { - for (size_t iT = 0; iT < e.num_cells(); iT++) - { - const auto& pe = e.cell(iT); - const auto& re = e.cell_refelem(pe); - - const auto pqps = pe.integration_points(); - const auto dets = pe.determinants(); - - const auto ofs = e.cell_model_dof_offset(iT); - const auto cbs = re.num_basis_functions(); - - assert(pqps.size() == dets.size()); - const auto bar = pe.barycenter(); - auto eps = mpl.epsilon( e.material_tag(), bar ); - auto mu = mpl.mu( e.material_tag(), bar ); - - for (size_t iQp = 0; iQp < pqps.size(); iQp++) - { - const auto& pqp = pqps[iQp]; - const vecxd phi = re.basis_functions(iQp); - - maxwell_6ple Fh = eval_field(state.emf_curr, ofs, cbs, phi); - - auto [E, H] = mpl.eval_analytical_solution(e.material_tag(), - pqp.point(), state.curr_time); - maxwell_6ple F(E,H); - maxwell_6ple Fdiff = F - Fh; - err += Fdiff*Fdiff*pqp.weight(); - } - } - } - -#ifdef USE_MPI - MPI_Allreduce(MPI_IN_PLACE, &err, 6, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -#endif /* USE_MPI */ - return sqrt(err); -} - -static maxwell_6ple -compute_energy(const model& mod, const maxwell::solver_state& state, - const maxwell::parameter_loader& mpl) -{ - maxwell_6ple energy; - - for (auto& e : mod) - { - for (size_t iT = 0; iT < e.num_cells(); iT++) - { - const auto& pe = e.cell(iT); - const auto& re = e.cell_refelem(pe); - - const auto pqps = pe.integration_points(); - const auto dets = pe.determinants(); - - const auto ofs = e.cell_model_dof_offset(iT); - const auto cbs = re.num_basis_functions(); - - assert(pqps.size() == dets.size()); - const auto bar = pe.barycenter(); - auto eps = mpl.epsilon( e.material_tag(), bar ); - auto mu = mpl.mu( e.material_tag(), bar ); - - maxwell_6ple mat(eps, eps, eps, mu, mu, mu); - - for (size_t iQp = 0; iQp < pqps.size(); iQp++) - { - const auto& pqp = pqps[iQp]; - const vecxd phi = re.basis_functions(iQp); - maxwell_6ple Fh = eval_field(state.emf_curr, ofs, cbs, phi); - energy += 0.5*mat*Fh*Fh*pqp.weight(); - } - } - } - -#ifdef USE_MPI - MPI_Allreduce(MPI_IN_PLACE, &energy, 6, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -#endif /* USE_MPI */ - return energy; -} - -#ifdef ENABLE_GPU_SOLVER -static void -validate(const model&, maxwell::solver_state_gpu&, - maxwell::parameter_loader&, std::ofstream&) -{} -#endif /* ENABLE_GPU_SOLVER */ +/****************************************************************************/ +/* Solver driver + */ template<typename State> void solver_mainloop(const model& mod, State& state, maxwell::parameter_loader& mpl) { @@ -533,19 +249,25 @@ void solver_mainloop(const model& mod, State& state, maxwell::parameter_loader& std::cout << showcursor << std::endl; } +/****************************************************************************/ +/* Register Lua usertypes valid for both CPU and GPU + */ static void register_lua_usertypes(maxwell::parameter_loader& mpl) { + using namespace maxwell; + sol::state& lua = mpl.lua_state(); - sol::usertype<maxwell_6ple> maxwell_6ple_ut = lua.new_usertype<maxwell_6ple>("maxwell_6ple", - sol::constructors<maxwell_6ple()>() - ); - maxwell_6ple_ut["Ex"] = &maxwell_6ple::Ex; - maxwell_6ple_ut["Ey"] = &maxwell_6ple::Ey; - maxwell_6ple_ut["Ez"] = &maxwell_6ple::Ez; - maxwell_6ple_ut["Hx"] = &maxwell_6ple::Hx; - maxwell_6ple_ut["Hy"] = &maxwell_6ple::Hy; - maxwell_6ple_ut["Hz"] = &maxwell_6ple::Hz; + sol::usertype<field_values> field_values_ut = + lua.new_usertype<field_values>("field_values", + sol::constructors<field_values()>() + ); + field_values_ut["Ex"] = &field_values::Ex; + field_values_ut["Ey"] = &field_values::Ey; + field_values_ut["Ez"] = &field_values::Ez; + field_values_ut["Hx"] = &field_values::Hx; + field_values_ut["Hy"] = &field_values::Hy; + field_values_ut["Hz"] = &field_values::Hz; #ifdef ENABLE_EXP_GEOMETRIC_DIODE sol::usertype<point_3d> point_3d_ut = lua.new_usertype<point_3d>("point", @@ -559,6 +281,9 @@ register_lua_usertypes(maxwell::parameter_loader& mpl) #endif /* ENABLE_EXP_GEOMETRIC_DIODE */ } +/****************************************************************************/ +/* Register Lua usertypes valid only for CPU + */ static void register_lua_usertypes_bystate(maxwell::parameter_loader& mpl, model& mod, maxwell::solver_state& state) @@ -583,6 +308,9 @@ register_lua_usertypes_bystate(maxwell::parameter_loader& mpl, #endif /*ENABLE_EXP_GEOMETRIC_DIODE */ } +/****************************************************************************/ +/* Register Lua usertypes valid only for GPU + */ #ifdef ENABLE_GPU_SOLVER static void register_lua_usertypes_bystate(maxwell::parameter_loader& mpl, @@ -590,6 +318,9 @@ register_lua_usertypes_bystate(maxwell::parameter_loader& mpl, {} #endif +/****************************************************************************/ +/* Main + */ int main(int argc, char *argv[]) { #ifdef USE_MPI