1- #include " emengine .h"
1+ #include " fdtd_engine .h"
22
33template <std::floating_point T>
44FDTDGeometry<T>::FDTDGeometry(const Config<T> &config)
@@ -7,45 +7,44 @@ FDTDGeometry<T>::FDTDGeometry(const Config<T> &config)
77 mu(mu_r * VAC_PERMEABILITY<T>), sigma(config.sigma) {
88
99 SPDLOG_TRACE (" enter FDTDGeometry<T>::FDTDGeometry" );
10- SPDLOG_DEBUG (" FDTD bounding box (m): {:.3e} x {:.3e} x {:.3e}" , len.x , len.y ,
10+ SPDLOG_DEBUG (" bounding box (m): {:.3e} x {:.3e} x {:.3e}" , len.x , len.y ,
1111 len.z );
1212
1313 // (m) maximum spatial step based on maximum frequency
1414 const T ds_min_wavelength =
1515 VAC_SPEED_OF_LIGHT<T> /
1616 (sqrt (ep_r * mu_r) * static_cast <T>(config.num_vox_min_wavelength ) *
1717 config.max_frequency );
18- SPDLOG_DEBUG (
19- " FDTD maximum spatial step based on maximum frequency (m): {:.3e}" ,
20- ds_min_wavelength);
18+ SPDLOG_DEBUG (" maximum spatial step based on maximum frequency (m): {:.3e}" ,
19+ ds_min_wavelength);
2120
2221 // (m) maximum spatial step based on minimum feature size
2322 const T ds_min_feature_size = std::min ({len.x , len.y , len.z }) /
2423 static_cast <T>(config.num_vox_min_feature );
25- SPDLOG_DEBUG (" FDTD maximum spatial step based on feature size (m): {:.3e}" ,
24+ SPDLOG_DEBUG (" maximum spatial step based on feature size (m): {:.3e}" ,
2625 ds_min_feature_size);
2726
2827 // (m) maximum required spatial step
2928 const T ds = std::min ({ds_min_wavelength, ds_min_feature_size});
30- SPDLOG_DEBUG (" FDTD maximum spatial step (m): {:.3e}" , ds);
29+ SPDLOG_DEBUG (" maximum spatial step (m): {:.3e}" , ds);
3130
3231 // number of voxels in each direction snapped to ds
3332 nv = {static_cast <size_t >(ceil (static_cast <double >(len.x ) / ds)),
3433 static_cast <size_t >(ceil (static_cast <double >(len.y ) / ds)),
3534 static_cast <size_t >(ceil (static_cast <double >(len.z ) / ds))};
36- SPDLOG_DEBUG (" FDTD voxels per field : {} x {} x {}" , nv.x , nv.y , nv.z );
37- SPDLOG_DEBUG (" FDTD voxels to update each step: {}" , 6 * nv.x );
35+ SPDLOG_DEBUG (" field voxel dimensions : {} x {} x {}" , nv.x , nv.y , nv.z );
36+ SPDLOG_DEBUG (" voxels to update each step: {}" , 6 * nv.x );
3837
3938 // (m) final spatial steps
4039 d = {len.x / static_cast <T>(nv.x ), len.y / static_cast <T>(nv.y ),
4140 len.z / static_cast <T>(nv.z )};
42- SPDLOG_DEBUG (" FDTD voxel size (m): {:.3e} x {:.3e} x {:.3e}" , d.x , d.y , d.z );
41+ SPDLOG_DEBUG (" voxel size (m): {:.3e} x {:.3e} x {:.3e}" , d.x , d.y , d.z );
4342
4443 // (m^-1) inverse spatial steps
4544 d_inv = {static_cast <T>(1.0 ) / d.x , static_cast <T>(1.0 ) / d.y ,
4645 static_cast <T>(1.0 ) / d.z };
47- SPDLOG_DEBUG (" FDTD inverse voxel size (m) , {:.3e} x {:.3e} x {:.3e}" ,
48- d_inv.x , d_inv. y , d_inv.z );
46+ SPDLOG_DEBUG (" inverse voxel size (m) , {:.3e} x {:.3e} x {:.3e}" , d_inv. x ,
47+ d_inv.y , d_inv.z );
4948
5049 SPDLOG_TRACE (" exit FDTDGeometry<T>::FDTDGeometry" );
5150}
@@ -77,7 +76,7 @@ std::expected<FDTDEngine<T>, std::string>
7776FDTDEngine<T>::create(const Config<T> &config) {
7877 SPDLOG_TRACE (" enter FDTDEngine<T>::create" );
7978 try {
80- // todo why not const like FDTD geometry ?
79+ // todo why not const like FDTDGeometry ?
8180 FDTDEngine engine (config);
8281 SPDLOG_TRACE (" exit FDTDEngine<T>::create with success" );
8382 return engine;
@@ -88,83 +87,16 @@ FDTDEngine<T>::create(const Config<T> &config) {
8887}
8988
9089template <std::floating_point T>
91- std::expected<void , std::string> FDTDEngine<T>::advance_to(const T end_t ) {
92- SPDLOG_TRACE (" enter FDTDEngine<T>::advance_to" );
93- SPDLOG_DEBUG (" FDTD current time is {:.3e} (s)" , time);
94- SPDLOG_DEBUG (" FDTD advance time to {:.3e} (s)" , end_t );
95- if (end_t > time) {
96- // (s) time difference between current state and end time
97- const T adv_t = end_t - time;
98-
99- if (const auto adv_by_result = advance_by (adv_t );
100- !adv_by_result.has_value ()) {
101- SPDLOG_CRITICAL (" FDTD advance time by advance_by returned with error: {}" ,
102- adv_by_result.error ());
103- return std::unexpected (adv_by_result.error ());
104- }
105-
106- } else {
107- SPDLOG_WARN (
108- " end time of {:.3e} (s) is not greater than current time of {:.3e} (s)" ,
109- end_t , time);
110- }
111-
112- SPDLOG_TRACE (" exit FDTDEngine<T>::advance_to" );
113- return {};
114- }
115-
116- template <std::floating_point T>
117- std::expected<void , std::string> FDTDEngine<T>::advance_by(const T adv_t ) {
118- SPDLOG_TRACE (" enter FDTDEngine<T>::advance_by" );
119- SPDLOG_DEBUG (" FDTD advance time by {:.3e} (s)" , adv_t );
120-
121- // (s) initial time
122- // NOTE only used if SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE
123- [[maybe_unused]] const auto init_time = time;
124-
125- // number of steps required by CFL condition
126- const size_t steps = calc_cfl_steps (adv_t );
127-
128- // (s) time step
129- const T dt = adv_t / static_cast <T>(steps);
130- SPDLOG_DEBUG (" FDTD timestep: {:.3e} (s)" , dt);
131-
132- // preprocess loop constants
133- const T ea = 1.0 / (geom.ep / dt + geom.sigma / 2.0 );
134- const T eb = geom.ep / dt - geom.sigma / 2.0 ;
135- const T hxa = dt * geom.d_inv .x / geom.mu ;
136- const T hya = dt * geom.d_inv .y / geom.mu ;
137- const T hza = dt * geom.d_inv .z / geom.mu ;
138-
139- // loop start time
140- [[maybe_unused]] const spdlog::stopwatch watch;
141-
142- // main time loop
143- SPDLOG_DEBUG (" FDTD enter main time loop" );
144- try {
145- for (uint64_t i = 0 ; i < steps; ++i) {
90+ uint64_t FDTDEngine<T>::calc_num_steps(const T adv_t ) const {
91+ SPDLOG_TRACE (" enter FDTDEngine<T>::calc_num_steps" );
14692
147- // advance by one step
148- step (dt, ea, eb, hxa, hya, hza);
93+ // find maximum number of timesteps required for any solver
94+ const uint64_t max_num_steps = calc_cfl_steps (adv_t );
95+ SPDLOG_DEBUG (" maximum number of steps required by any solver: {}" ,
96+ max_num_steps);
14997
150- SPDLOG_TRACE (" step: {}/{} elapsed time: {:.5e}/{:.5e} (s)" , i + 1 , steps,
151- time, init_time + adv_t );
152- }
153- } catch (const std::runtime_error &err) {
154- SPDLOG_CRITICAL (" FDTD main time loop returned with error: {}" , err.what ());
155- return std::unexpected (err.what ());
156- }
157- SPDLOG_DEBUG (" FDTD exit main time loop with success" );
158-
159- // basic loop performance diagnostics
160- [[maybe_unused]] const auto loop_time = watch.elapsed ().count ();
161- [[maybe_unused]] const auto num_cells = 6 * e.x .size () * steps;
162- SPDLOG_INFO (" loop runtime: {:.3e} (s)" , loop_time);
163- SPDLOG_INFO (" voxel compute rate {:.3e}" ,
164- static_cast <double >(num_cells) / loop_time);
165-
166- SPDLOG_TRACE (" exit FDTDEngine<T>::advance_by" );
167- return {};
98+ SPDLOG_TRACE (" exit FDTDEngine<T>::calc_num_steps" );
99+ return max_num_steps;
168100}
169101
170102template <std::floating_point T>
@@ -175,49 +107,95 @@ uint64_t FDTDEngine<T>::calc_cfl_steps(const T time_span) const {
175107 1.0 / (VAC_SPEED_OF_LIGHT<T> / sqrt (geom.ep_r * geom.mu_r ) *
176108 sqrt (pow (geom.d_inv .x , 2 ) + pow (geom.d_inv .y , 2 ) +
177109 pow (geom.d_inv .z , 2 )));
178- SPDLOG_DEBUG (
179- " FDTD maximum possible timesteps to satisfy CFL condition: {:.3e} (s)" ,
180- maximum_dt);
110+ SPDLOG_DEBUG (" maximum possible timestep to satisfy CFL condition (s): {:.3e}" ,
111+ maximum_dt);
181112
182113 const T num_steps = static_cast <uint64_t >(ceil (time_span / maximum_dt));
183- SPDLOG_DEBUG (" FDTD steps required to satisfy CFL condition: {}" , num_steps);
114+ SPDLOG_DEBUG (" steps required to satisfy CFL condition: {}" , num_steps);
184115
185116 SPDLOG_TRACE (" exit FDTDEngine<T>::calc_cfl_steps" );
186117 return num_steps;
187118}
188119
189- template <std::floating_point T>
190- void FDTDEngine<T>::step(const T dt, const T ea, const T eb, const T hxa,
191- const T hya, const T hza) {
120+ template <std::floating_point T> void FDTDEngine<T>::step(const T dt) {
121+ SPDLOG_TRACE (" enter FDTDEngine<T>::step" );
122+
123+ // TODO it would be nice to not need to recalculate these every time step is
124+ // TODO called, the performance penalty of this has yet to be assed however
125+
126+ // electric field a loop constant
127+ const T ea = 1.0 / (geom.ep / dt + geom.sigma / 2.0 );
128+ SPDLOG_TRACE (" ea loop constant: {:.3e}" , ea);
129+
130+ // electric field b loop constant
131+ const T eb = geom.ep / dt - geom.sigma / 2.0 ;
132+ SPDLOG_TRACE (" eb loop constant: {:.3e}" , eb);
133+
134+ // magnetic field a loop constant for x-component
135+ const T hxa = dt * geom.d_inv .x / geom.mu ;
136+ SPDLOG_TRACE (" hxa loop constant: {:.3e}" , hxa);
137+
138+ // magnetic field a loop constant for y-component
139+ const T hya = dt * geom.d_inv .y / geom.mu ;
140+ SPDLOG_TRACE (" hya loop constant: {:.3e}" , hya);
141+
142+ // magnetic field a loop constant for z-component
143+ const T hza = dt * geom.d_inv .z / geom.mu ;
144+ SPDLOG_TRACE (" hza loop constant: {:.3e}" , hza);
145+
192146 // half timestep update before updating magnetic fields
193147 time += ONE_OVER_TWO<T> * dt;
148+ SPDLOG_TRACE (" advance half time step to (s): {:.5e}" , time);
194149
195150 // update magnetic fields
196151 update_h (hxa, hya, hza);
197152
198153 // half timestep update before updating electric fields
199154 time += ONE_OVER_TWO<T> * dt;
155+ SPDLOG_TRACE (" advance half time step to (s): {:.5e}" , time);
200156
201157 // update electric fields
202158 update_e (ea, eb);
159+
160+ SPDLOG_TRACE (" exit FDTDEngine<T>::step" );
161+ }
162+
163+ template <std::floating_point T>
164+ uint64_t FDTDEngine<T>::get_field_num_vox() const {
165+ SPDLOG_TRACE (" enter FDTDEngine<T>::get_field_num_vox" );
166+
167+ const auto num_vox = e.x .size ();
168+
169+ SPDLOG_TRACE (" exit FDTDEngine<T>::get_field_num_vox" );
170+ return num_vox;
203171}
204172
205173template <std::floating_point T>
206174void FDTDEngine<T>::update_e(const T ea, const T eb) {
175+ SPDLOG_TRACE (" enter FDTDEngine<T>::update_e" );
176+
207177 update_ex (ea, eb);
208178 update_ey (ea, eb);
209179 update_ez (ea, eb);
180+
181+ SPDLOG_TRACE (" exit FDTDEngine<T>::update_e" );
210182}
211183
212184template <std::floating_point T>
213185void FDTDEngine<T>::update_h(const T hxa, const T hya, const T hza) {
186+ SPDLOG_TRACE (" enter FDTDEngine<T>::update_h" );
187+
214188 update_hx (hya, hza);
215189 update_hy (hxa, hza);
216190 update_hz (hya, hza);
191+
192+ SPDLOG_TRACE (" exit FDTDEngine<T>::update_h" );
217193}
218194
219195template <std::floating_point T>
220196void FDTDEngine<T>::update_ex(const T ea, const T eb) {
197+ SPDLOG_TRACE (" enter FDTDEngine<T>::update_ex" );
198+
221199 // assumes PEC outer boundary
222200 for (size_t i = 1 ; i < e.x .extent (0 ) - 1 ; ++i) {
223201 for (size_t j = 1 ; j < e.x .extent (1 ) - 1 ; ++j) {
@@ -228,10 +206,14 @@ void FDTDEngine<T>::update_ex(const T ea, const T eb) {
228206 }
229207 }
230208 }
209+
210+ SPDLOG_TRACE (" exit FDTDEngine<T>::update_ex" );
231211}
232212
233213template <std::floating_point T>
234214void FDTDEngine<T>::update_ey(const T ea, const T eb) {
215+ SPDLOG_TRACE (" enter FDTDEngine<T>::update_ey" );
216+
235217 // assumes PEC outer boundary
236218 for (size_t i = 1 ; i < e.y .extent (0 ) - 1 ; ++i) {
237219 for (size_t j = 1 ; j < e.y .extent (1 ) - 1 ; ++j) {
@@ -242,10 +224,14 @@ void FDTDEngine<T>::update_ey(const T ea, const T eb) {
242224 }
243225 }
244226 }
227+
228+ SPDLOG_TRACE (" exit FDTDEngine<T>::update_ey" );
245229}
246230
247231template <std::floating_point T>
248232void FDTDEngine<T>::update_ez(const T ea, const T eb) {
233+ SPDLOG_TRACE (" enter FDTDEngine<T>::update_ez" );
234+
249235 // assumes PEC outer boundary
250236 for (size_t i = 1 ; i < e.z .extent (0 ) - 1 ; ++i) {
251237 for (size_t j = 1 ; j < e.z .extent (1 ) - 1 ; ++j) {
@@ -256,10 +242,14 @@ void FDTDEngine<T>::update_ez(const T ea, const T eb) {
256242 }
257243 }
258244 }
245+
246+ SPDLOG_TRACE (" exit FDTDEngine<T>::update_ez" );
259247}
260248
261249template <std::floating_point T>
262250void FDTDEngine<T>::update_hx(const T hya, const T hza) {
251+ SPDLOG_TRACE (" enter FDTDEngine<T>::update_hx" );
252+
263253 // todo correctly implement for PEC boundary
264254 for (size_t i = 1 ; i < h.x .extent (0 ) - 1 ; ++i) {
265255 for (size_t j = 1 ; j < h.x .extent (1 ) - 1 ; ++j) {
@@ -269,10 +259,14 @@ void FDTDEngine<T>::update_hx(const T hya, const T hza) {
269259 }
270260 }
271261 }
262+
263+ SPDLOG_TRACE (" exit FDTDEngine<T>::update_hx" );
272264}
273265
274266template <std::floating_point T>
275267void FDTDEngine<T>::update_hy(const T hxa, const T hza) {
268+ SPDLOG_TRACE (" enter FDTDEngine<T>::update_hy" );
269+
276270 // todo correctly implement for PEC boundary
277271 for (size_t i = 1 ; i < h.y .extent (0 ) - 1 ; ++i) {
278272 for (size_t j = 1 ; j < h.y .extent (1 ) - 1 ; ++j) {
@@ -282,10 +276,14 @@ void FDTDEngine<T>::update_hy(const T hxa, const T hza) {
282276 }
283277 }
284278 }
279+
280+ SPDLOG_TRACE (" exit FDTDEngine<T>::update_hy" );
285281}
286282
287283template <std::floating_point T>
288284void FDTDEngine<T>::update_hz(const T hxa, const T hya) {
285+ SPDLOG_TRACE (" enter FDTDEngine<T>::update_hz" );
286+
289287 // todo correctly implement for PEC boundary
290288 for (size_t i = 1 ; i < h.z .extent (0 ) - 1 ; ++i) {
291289 for (size_t j = 1 ; j < h.z .extent (1 ) - 1 ; ++j) {
@@ -295,6 +293,8 @@ void FDTDEngine<T>::update_hz(const T hxa, const T hya) {
295293 }
296294 }
297295 }
296+
297+ SPDLOG_TRACE (" exit FDTDEngine<T>::update_hz" );
298298}
299299
300300// explicit template instantiation
0 commit comments