16 #include <boost/format.hpp>
29 #define BCVLOG(level) CVLOG(level, "Boris") << this->log_indent->indent(level)
51 template<
typename precision>
54 os <<
"pos: [" << x <<
" " << y <<
" " << z <<
"]\tvel: [" << y <<
" " << v <<
" " << w <<
"]";
58 template<
typename precision>
61 pfasst::config::options::add_option<size_t>(
"Boris-SDC",
"num_particles",
"number of particles in the cloud");
62 pfasst::config::options::add_option<precision>(
"Boris-SDC",
"epsilon",
"Boris' epsilon");
63 pfasst::config::options::add_option<precision>(
"Boris-SDC",
"omega_e",
"E-field constant");
64 pfasst::config::options::add_option<precision>(
"Boris-SDC",
"omega_b",
"B-field constant");
67 template<
typename precision>
76 LogIndent::LogIndent()
78 this->vlog_levels.fill(0);
80 LogIndent::~LogIndent()
83 void LogIndent::increment(
const size_t vlevel)
85 this->vlog_levels.at(vlevel - 1)++;
87 void LogIndent::decrement(
const size_t vlevel)
89 this->vlog_levels.at(vlevel - 1)--;
91 const string LogIndent::indent(
const size_t vlevel)
const
94 for(
size_t vl = 0; vl < vlevel; ++vl) {
95 count += this->vlog_levels.at(vl);
97 return string(count * 2,
' ');
101 template<
typename scalar,
typename time>
105 BCVLOG(7) <<
"building rhs for node " << m <<
" of "
106 << ((previous) ?
"previous" :
"current") <<
" sweep";
107 this->log_indent->increment(7);
109 BCVLOG(7) <<
"e-forces: " << rhs;
112 rhs +=
cross_prod(this->saved_particles[m]->velocities(), this->saved_b_vecs[m]);
114 rhs +=
cross_prod(this->particles[m]->velocities(), this->b_vecs[m]);
117 BCVLOG(7) <<
"=> rhs: " << rhs;
118 this->log_indent->decrement(7);
122 template<
typename scalar,
typename time>
125 BCVLOG(8) <<
"computing max residual";
126 this->log_indent->increment(8);
128 this->residual(this->get_controller()->get_step_size(), this->residuals);
130 scalar max_residual = scalar(0.0);
132 for (
size_t m = 1; m < this->residuals.size(); ++m) {
133 auto residual_m = dynamic_pointer_cast<
encap_type>(this->residuals[m]);
135 max_residual =
std::max(max_residual, residual_m->norm0());
138 BCVLOG(8) <<
"=> max residual: " << max_residual;
142 template<
typename scalar,
typename time>
145 const scalar energy,
const scalar drift,
const scalar residual)
147 BCVLOG(9) <<
"writing center particle to file";
148 this->data_stream_fmt % (iter+1) % sweep % -1
149 % center[0] % center[1] % center[2]
152 % energy % drift % residual;
153 this->data_stream << this->data_stream_fmt << endl;
156 template<
typename scalar,
typename time>
158 const shared_ptr<encap_type>& cloud,
159 const scalar energy,
const scalar drift,
160 const scalar residual,
161 const bool with_center)
163 this->log_indent->increment(9);
164 for (
size_t p = 0; p < cloud->size(); ++p) {
165 BCVLOG(9) <<
"writing cloud particle " << p <<
" to file";
167 this->data_stream_fmt % (iter+1) % sweep % p
168 % cloud->positions()[p * cloud->dim()] % cloud->positions()[p * cloud->dim() + 1] % cloud->positions()[p * cloud->dim() + 2]
169 % cloud->velocities()[p * cloud->dim()] % cloud->velocities()[p * cloud->dim() + 1] % cloud->velocities()[p * cloud->dim() + 2]
170 % energy % drift % residual;
171 this->data_stream << this->data_stream_fmt << endl;
174 this->write_center_to_file(iter, sweep, cloud->center_of_mass(), energy, drift, residual);
176 this->log_indent->decrement(9);
179 template<
typename scalar,
typename time>
182 BCVLOG(4) <<
"updating position (" << m <<
"->" << m+1 <<
") with dt=" << dt <<
", ds=" << ds;
183 this->log_indent->increment(4);
184 this->particles[m+1]->positions() = this->particles[m]->positions();
185 BCVLOG(4) <<
"old: " << this->particles[m+1]->positions();
186 this->log_indent->increment(5);
188 this->particles[m+1]->positions() += this->start_particles->velocities() * ds;
189 BCVLOG(5) <<
"+= " << this->start_particles->velocities() <<
" * " << ds;
191 for (
size_t l = 0; l <= m; l++) {
192 auto rhs_this = this->build_rhs(l);
193 auto rhs_prev = this->build_rhs(l,
true);
194 this->particles[m+1]->positions() += rhs_this * dt * dt * this->sx_mat(m+1, l);
195 BCVLOG(5) <<
"+= " << rhs_this <<
" * " << dt * dt <<
" * " << this->sx_mat(m+1, l);
196 this->particles[m+1]->positions() -= rhs_prev * dt * dt * this->sx_mat(m+1, l);
197 BCVLOG(5) <<
"-= " << rhs_prev <<
" * " << dt * dt <<
" * " << this->sx_mat(m+1, l);
200 this->particles[m+1]->positions() += this->ss_integrals[m+1];
201 BCVLOG(5) <<
"+= " << this->ss_integrals[m+1];
202 this->log_indent->decrement(5);
203 this->log_indent->decrement(4);
206 template<
typename scalar,
typename time>
209 BCVLOG(4) <<
"updating velocity (" << m <<
"->" << m+1 <<
") with ds=" << ds;
210 this->log_indent->increment(4);
211 velocity_type c_k_term = cloud_component_factory<scalar>(this->particles[0]->size(), this->particles[0]->dim());
214 BCVLOG(5) <<
"c_k: " << c_k_term;
215 this->log_indent->increment(5);
217 auto t1 = this->build_rhs(m+1,
true);
218 c_k_term -= t1 * 0.5 * ds;
219 BCVLOG(5) <<
"-= 0.5 * " << t1 <<
" * " << ds <<
" => " << c_k_term;
221 auto t2 = this->build_rhs(m,
true);
222 c_k_term -= t2 * 0.5 * ds;
223 BCVLOG(5) <<
"-= 0.5 * " << t2 <<
" * " << ds <<
" => " << c_k_term;
225 c_k_term += this->s_integrals[m+1];
226 BCVLOG(5) <<
"+= " << this->s_integrals[m+1];
227 this->log_indent->decrement(5);
228 BCVLOG(4) <<
"=> c_k: " << c_k_term;
231 this->boris_solve(nodes[m], nodes[m+1], ds, m, c_k_term);
232 this->log_indent->decrement(4);
236 template<
typename scalar,
typename time>
238 const string& data_file)
239 : impl_solver(impl_solver)
241 , exact_updated(false)
244 , data_stream(data_file, ios_base::out | ios_base::trunc)
247 CLOG(INFO,
"Boris") <<
"writing particle data to: " << data_file;
249 this->
DATA_STREAM_FORMAT_STR =
"%d,%d,%d,%.16f,%.16f,%.16f,%.16f,%.16f,%.16f,%.16f,%.16f,%.16f";
256 template<
typename scalar,
typename time>
259 CLOG(INFO,
"Boris") <<
"number force computations: " << this->f_evals;
263 template<
typename scalar,
typename time>
266 this->particles[m]->copy(u0);
269 template<
typename scalar,
typename time>
272 this->start_particles->operator=(*(u0.get()));
275 template<
typename scalar,
typename time>
278 return this->particles[m];
281 template<
typename scalar,
typename time>
284 return this->start_particles;
287 template<
typename scalar,
typename time>
288 shared_ptr<typename BorisSweeper<scalar, time>::acceleration_type>
291 return this->tau_q_corrections[m];
294 template<
typename scalar,
typename time>
295 shared_ptr<typename BorisSweeper<scalar, time>::acceleration_type>
298 return this->tau_qq_corrections[m];
301 template<
typename scalar,
typename time>
304 return this->saved_particles[m];
307 template<
typename scalar,
typename time>
310 BCVLOG(1) <<
"computing and setting initial energy";
311 this->log_indent->increment(1);
313 auto p0 = this->start_particles;
314 BCVLOG(2) <<
"initial particles: " << p0;
315 this->initial_energy = this->impl_solver->energy(p0, this->get_controller()->get_time());
316 CLOG(INFO,
"Boris") <<
"initial total energy of system: " << this->initial_energy;
318 this->write_particle_cloud_to_file(0, 0, p0, this->initial_energy, 0, 0);
319 this->log_indent->decrement(1);
322 template<
typename scalar,
typename time>
325 shared_ptr<encap_type> q_cast = dynamic_pointer_cast<
encap_type>(q);
327 this->exact(q_cast, t);
330 template<
typename scalar,
typename time>
333 this->exact(*(q.get()), t);
336 template<
typename scalar,
typename time>
339 BCVLOG(8) <<
"computing exact solution at t=" <<
t;
340 this->log_indent->increment(8);
342 if (!this->exact_updated) {
343 typedef complex<scalar> C;
345 auto initial = this->particles[0];
346 scalar x0 = initial->positions()[0],
347 y0 = initial->positions()[1],
348 z0 = initial->positions()[2],
349 u0 = initial->velocities()[0],
350 v0 = initial->velocities()[1],
351 w0 = initial->velocities()[2],
352 omega_e = this->impl_solver->omega_e(),
353 omega_b = this->impl_solver->omega_b(),
354 epsilon = this->impl_solver->epsilon();
355 time
dt = this->get_controller()->get_step_size();
357 C omega_tilde = sqrt(-2.0 * epsilon) * omega_e;
358 q.
positions()[2] = (z0 * cos(omega_tilde * (scalar)(dt))
359 + w0 / omega_tilde * sin(omega_tilde * (scalar)(dt))).real();
361 C sqrt_in_omega = sqrt(pow(omega_b, 2) + 4.0 * epsilon * pow(omega_e, 2));
362 C omega_minus = 0.5 * (omega_b - sqrt_in_omega);
363 C omega_plus = 0.5 * (omega_b + sqrt_in_omega);
365 C r_minus = (omega_plus * x0 + v0) / (omega_plus - omega_minus);
366 C r_plus = x0 - r_minus;
368 C i_minus = (omega_plus * y0 - u0) / (omega_plus - omega_minus);
369 C i_plus = y0 - i_minus;
371 C x_y_move = (r_plus + i * i_plus) * exp(- i * omega_plus * (scalar)(
dt))
372 + (r_minus + i * i_minus) * exp(- i * omega_minus * (scalar)(
dt));
376 q.
velocities()[2] = (- z0 * omega_tilde * sin(omega_tilde * (scalar)(dt)) + w0 * cos(omega_tilde * (scalar)(dt))).real();
377 C u_v_move = (- i * omega_plus * (r_plus + i * i_plus)) * exp(-i * omega_plus * (scalar)(dt))
378 - (i * omega_minus * (r_minus + i * i_minus)) * exp(-i * omega_minus * (scalar)(dt));
382 this->exact_cache = make_shared<encap_type>(q);
383 this->exact_updated =
true;
385 BCVLOG(8) <<
"exact solution has been computed previously.";
386 q = *(this->exact_cache.get());
388 BCVLOG(8) <<
"exact solution at t=" << t <<
": " << q;
389 this->log_indent->decrement(8);
392 template<
typename scalar,
typename time>
395 auto end = this->end_particles;
397 scalar e_end = this->impl_solver->energy(end, t);
398 e_tuple.
e_drift = abs(this->initial_energy - e_end);
399 e_tuple.
res = this->compute_residual_max();
401 size_t n = this->get_controller()->get_step();
402 size_t k = this->get_controller()->get_iteration();
405 CLOG(INFO,
"Boris") << boost::format(this->FORMAT_STR) % (n+1) % k % (this->coarse ?
"coarse" :
"fine") % e_tuple.
res % e_tuple.
e_drift % e_end;
406 BCVLOG(9) <<
"particle at t_end: " << end;
409 if (this->particles[0]->size() == 1) {
413 e_tuple.
p_err.x = ex->positions()[0] - end->positions()[0];
414 e_tuple.
p_err.y = ex->positions()[1] - end->positions()[1];
415 e_tuple.
p_err.z = ex->positions()[2] - end->positions()[2];
416 e_tuple.
p_err.u = ex->velocities()[0] - end->velocities()[0];
417 e_tuple.
p_err.v = ex->velocities()[1] - end->velocities()[1];
418 e_tuple.
p_err.w = ex->velocities()[2] - end->velocities()[2];
420 BCVLOG(9) <<
"absolute error at end point: " << e_tuple.
p_err;
424 this->write_particle_cloud_to_file(n, k, end, e_end, e_tuple.
e_drift, e_tuple.
res);
427 template<
typename scalar,
typename time>
433 template<
typename scalar,
typename time>
437 BCVLOG(1) <<
"setting up Boris Sweeper for " << ((coarse) ?
"coarse" :
"fine") <<
" level";
438 this->log_indent->increment(1);
439 this->coarse = coarse;
440 auto const nodes = this->get_nodes();
441 assert(nodes.size() >= 1);
442 const size_t nnodes = nodes.size();
443 const size_t num_s_integrals = this->quadrature->left_is_node() ? nnodes : nnodes - 1;
444 BCVLOG(2) <<
"there will be " << num_s_integrals <<
" integrals for " << nnodes <<
" nodes";
447 this->delta_nodes = vector<time>(nnodes, time(0.0));
448 for (
size_t m = 1; m < nnodes; m++) {
449 this->delta_nodes[m] = nodes[m] - nodes[m - 1];
455 this->energy_evals.resize(nnodes);
456 for (
size_t m = 0; m < nnodes; ++m) {
457 this->particles.push_back(dynamic_pointer_cast<encap_type>(this->get_factory()->create(
pfasst::encap::solution)));
458 this->residuals.push_back(dynamic_pointer_cast<encap_type>(this->get_factory()->create(
pfasst::encap::solution)));
459 this->saved_particles.push_back(dynamic_pointer_cast<encap_type>(this->get_factory()->create(
pfasst::encap::solution)));
460 this->forces.push_back(cloud_component_factory<scalar>(this->particles[m]->size(), this->particles[m]->dim()));
461 this->saved_forces.push_back(cloud_component_factory<scalar>(this->particles[m]->size(), this->particles[m]->dim()));
462 this->b_vecs.push_back(cloud_component_factory<scalar>(this->particles[m]->size(), this->particles[m]->dim()));
463 this->saved_b_vecs.push_back(cloud_component_factory<scalar>(this->particles[m]->size(), this->particles[m]->dim()));
465 this->tau_q_corrections.push_back(make_shared<acceleration_type>(cloud_component_factory<scalar>(this->particles[m]->size(), this->particles[m]->dim())));
466 this->tau_qq_corrections.push_back(make_shared<acceleration_type>(cloud_component_factory<scalar>(this->particles[m]->size(), this->particles[m]->dim())));
470 for (
size_t m = 0; m < num_s_integrals; ++m) {
471 this->s_integrals.push_back(cloud_component_factory<scalar>(this->particles[m]->size(), this->particles[m]->dim()));
472 this->ss_integrals.push_back(cloud_component_factory<scalar>(this->particles[m]->size(), this->particles[m]->dim()));
475 this->q_mat = this->get_quadrature()->get_q_mat();
476 this->qq_mat = this->q_mat * this->q_mat;
478 this->s_mat.fill(time(0.0));
480 this->qt_mat.fill(time(0.0));
482 this->qx_mat.fill(time(0.0));
484 this->ss_mat.fill(time(0.0));
486 this->sx_mat.fill(time(0.0));
488 this->st_mat.fill(time(0.0));
495 qe_mat.fill(time(0.0));
497 qi_mat.fill(time(0.0));
498 for (
size_t i = 0; i < nnodes; ++i) {
499 for (
size_t j = 0; j < nnodes; ++j) {
500 if (j < i) { qe_mat(i, j) = delta_nodes[j + 1]; }
501 if (j > 0 && j <= i) { qi_mat(i, j) = delta_nodes[j]; }
506 this->qt_mat = 0.5 * (qe_mat + qi_mat);
510 this->qx_mat = qe_mat * qt_mat;
513 for (
size_t i = 1; i < nnodes; i++) {
514 for (
size_t j = 0; j < nnodes; j++) {
517 this->qx_mat(i, j) += 0.5 * qe_mat(i, j) * qe_mat(i, j);
520 this->s_mat.row(i) = this->q_mat.row(i) - this->q_mat.row(i - 1);
521 this->ss_mat.row(i) = this->qq_mat.row(i) - this->qq_mat.row(i - 1);
522 this->sx_mat.row(i) = this->qx_mat.row(i) - this->qx_mat.row(i - 1);
523 this->st_mat.row(i) = this->qt_mat.row(i) - this->qt_mat.row(i - 1);
526 size_t nsteps = this->get_controller()->get_end_time() / this->get_controller()->get_step_size();
527 size_t digit_step = to_string(nsteps + 1).length();
528 size_t digit_iter = to_string(this->get_controller()->get_max_iterations() - 1).length();
529 this->FORMAT_STR =
"step: %|" + to_string(digit_step) +
"| iter: %|" + to_string(digit_iter) +
"| (%-6s)"
530 +
" residual: %10.4e energy drift: %10.4e total energy: %10.2f";
533 this->log_indent->decrement(1);
536 template<
typename scalar,
typename time>
542 template<
typename scalar,
typename time>
544 vector<shared_ptr<acceleration_type>> dst_qq)
const
546 BCVLOG(6) <<
"integrating over dt=" <<
dt;
547 this->log_indent->increment(6);
548 const size_t nnodes = this->get_nodes().size();
550 vector<acceleration_type> rhs(nnodes);
551 for (
size_t m = 0; m < nnodes; ++m) {
552 rhs[m] = this->build_rhs(m);
555 for (
size_t m = 0; m < nnodes; ++m) {
558 for (
size_t n = 0; n < nnodes; ++n) {
560 *(dst_qq[m].get()) += rhs[n] * dt * dt * this->qq_mat(m, n)
561 + this->start_particles->velocities() * dt * this->q_mat(m, n);
563 *(dst_q[m].get()) += rhs[n] * dt * this->q_mat(m, n);
565 BCVLOG(6) <<
"integral(QQ)[" << m <<
"]: " << *(dst_qq[m].get());
566 BCVLOG(6) <<
"integral(Q)[" << m <<
"]: " << *(dst_q[m].get());
568 this->log_indent->decrement(6);
571 template<
typename scalar,
typename time>
574 BCVLOG(8) <<
"computing residual";
575 const auto nodes = this->get_nodes();
576 const size_t nnodes = nodes.size();
577 assert(dst.size() == nnodes);
579 vector<shared_ptr<encap_type>> dst_cast(nnodes);
580 vector<shared_ptr<acceleration_type>> q_int(nnodes), qq_int(nnodes);
581 for (
size_t m = 0; m < nnodes; ++m) {
582 dst_cast[m] = dynamic_pointer_cast<
encap_type>(dst[m]);
585 qq_int[m] = make_shared<acceleration_type>(this->start_particles->size() * this->start_particles->dim());
586 q_int[m] = make_shared<acceleration_type>(this->start_particles->size() * this->start_particles->dim());
590 this->integrate(dt, q_int, qq_int);
592 for (
size_t m = 1; m < nnodes; ++m) {
593 BCVLOG(8) <<
"for node " << m;
594 zero(dst_cast[m]->positions());
595 zero(dst_cast[m]->velocities());
597 dst_cast[m]->positions() = *(qq_int[m].get());
598 dst_cast[m]->velocities() = *(q_int[m].get());
601 dst_cast[m]->positions() += this->start_particles->positions() - this->particles[m]->positions();
602 dst_cast[m]->velocities() += this->start_particles->velocities() - this->particles[m]->velocities();
605 if (this->tau_q_corrections.size() > 0 && this->tau_qq_corrections.size()) {
606 dst_cast[m]->positions() += *(this->tau_qq_corrections[m].get());
607 dst_cast[m]->velocities() += *(this->tau_q_corrections[m].get());
611 this->log_indent->decrement(8);
614 template<
typename scalar,
typename time>
617 BCVLOG(2) <<
"advancing to next step";
618 this->log_indent->increment(2);
619 this->start_particles->copy(this->end_particles);
620 this->energy_evals.front() = this->energy_evals.back();
621 this->forces.front() = this->forces.back();
622 this->b_vecs.front() = this->b_vecs.back();
623 this->exact_updated =
false;
624 BCVLOG(9) <<
"new starting values:";
625 BCVLOG(9) <<
" => start_particles: " << this->start_particles;
626 BCVLOG(9) <<
" => energies: " << this->energy_evals.front();
627 BCVLOG(9) <<
" => forces: " << this->forces.front();
628 BCVLOG(9) <<
" => b_vecs: " << this->b_vecs.front();
629 this->log_indent->decrement(2);
632 template<
typename scalar,
typename time>
635 time
t = this->get_controller()->get_time() + this->get_controller()->get_step_size() * this->delta_nodes[m];
636 BCVLOG(2) <<
"computing forces at node " << m <<
" (t=" << t <<
")";
637 this->log_indent->increment(2);
639 #ifndef BORIS_SAME_LEVELS
641 BCVLOG(2) <<
"only external electric field (because on coarse level)";
643 this->forces[m] = this->impl_solver->external_e_field_evaluate(this->particles[m], t);
645 BCVLOG(2) <<
"internal and external electric field (because not on coarse level)";
646 this->forces[m] = this->impl_solver->e_field_evaluate(this->particles[m], t);
649 BCVLOG(2) <<
"internal and external electric field";
650 this->forces[m] = this->impl_solver->e_field_evaluate(this->particles[m], t);
652 this->b_vecs[m] = this->impl_solver->b_field_vecs(this->particles[m], t);
654 BCVLOG(9) <<
"for particles:" << this->particles[m];
655 BCVLOG(9) <<
" => e_forces:" << this->forces[m];
656 BCVLOG(9) <<
" => b_vecs: " << this->b_vecs[m];
657 this->log_indent->decrement(2);
661 template<
typename scalar,
typename time>
664 BCVLOG(1) <<
"predicting with initial particle cloud: " << *(this->start_particles.get());
665 this->log_indent->increment(1);
667 this->particles[0]->copy(this->start_particles);
670 for (
size_t m = 0; m < this->particles.size(); ++m) {
675 this->end_particles->copy(this->particles.back());
678 this->log_indent->decrement(1);
681 template<
typename scalar,
typename time>
684 const auto nodes = this->get_nodes();
685 const size_t nnodes = nodes.size();
687 time
t = this->get_controller()->get_time();
688 time
dt = this->get_controller()->get_step_size();
689 BCVLOG(1) <<
"sweeping for t=" << t <<
" and dt=" <<
dt;
690 this->log_indent->increment(1);
691 BCVLOG(2) <<
"with nodes: " << nodes;
692 BCVLOG(2) <<
"initial: " << *(this->start_particles.get());
693 BCVLOG(2) <<
"previous particles:";
694 for (
size_t m = 0; m < nnodes; ++m) {
695 BCVLOG(2) <<
" [" << m <<
"]: " << *(this->saved_particles[m].get());
697 BCVLOG(2) <<
"current particles:";
698 for (
size_t m = 0; m < nnodes; ++m) {
699 BCVLOG(2) <<
" [" << m <<
"]: " << *(this->particles[m].get());
702 this->impl_solver->energy(this->particles.front(),
t);
705 BCVLOG(1) <<
"computing integrals";
706 if (this->get_quadrature()->left_is_node()) {
708 for (
size_t m = 1; m < nnodes; m++) {
709 zero(this->s_integrals[m]);
710 zero(this->ss_integrals[m]);
711 for (
size_t l = 0; l < nnodes; l++) {
712 auto rhs = this->build_rhs(l);
713 this->s_integrals[m] += rhs * dt * this->s_mat(m, l);
714 this->ss_integrals[m] += rhs * dt * dt * this->ss_mat(m, l);
717 if (this->tau_q_corrections.size() > 0 && this->tau_qq_corrections.size()) {
718 BCVLOG(2) <<
"adding FAS correction to integrals";
719 this->log_indent->increment(2);
720 for (
size_t m = 0; m < nnodes; ++m) {
721 BCVLOG(2) <<
"+= tau_q[" << m <<
"] (<" << this->tau_q_corrections[m] <<
">" << *(this->tau_q_corrections[m].get()) <<
")";
722 BCVLOG(2) <<
"+= tau_qq[" << m <<
"] (<" << this->tau_qq_corrections[m] <<
">" << *(this->tau_qq_corrections[m].get()) <<
")";
723 this->s_integrals[m] += *(this->tau_q_corrections[m].get());
724 this->ss_integrals[m] += *(this->tau_qq_corrections[m].get());
726 BCVLOG(2) <<
"-= tau_q[" << m-1 <<
"] (<" << this->tau_q_corrections[m-1] <<
">" << *(this->tau_q_corrections[m-1].get()) <<
")";
727 BCVLOG(2) <<
"-= tau_qq[" << m-1 <<
"] (<" << this->tau_qq_corrections[m-1] <<
">" << *(this->tau_qq_corrections[m-1].get()) <<
")";
728 this->s_integrals[m] -= *(this->tau_q_corrections[m-1].get());
729 this->ss_integrals[m] -= *(this->tau_qq_corrections[m-1].get());
732 this->log_indent->decrement(2);
737 BCVLOG(2) <<
"s_int: " << this->s_integrals;
738 BCVLOG(2) <<
"ss_int: " << this->ss_integrals;
742 for (
size_t m = 0; m < nnodes - 1; m++) {
743 time ds = dt * this->delta_nodes[m+1];
744 BCVLOG(1) <<
"node " << m <<
" (ds=" << ds <<
")";
745 this->log_indent->increment(1);
746 BCVLOG(2) <<
"old m+1 particle: " << this->particles[m+1];
751 this->update_position(m, dt, ds);
752 BCVLOG(1) <<
"new positions: " << this->particles[m+1]->positions();
755 #ifndef BORIS_SAME_LEVELS
757 BCVLOG(2) <<
"only external electric field (because on coarse level)";
759 this->forces[m+1] = this->impl_solver->external_e_field_evaluate(this->particles[m+1], t + nodes[m]);
761 BCVLOG(2) <<
"internal and external electric field (because not on coarse level)";
762 this->forces[m+1] = this->impl_solver->e_field_evaluate(this->particles[m+1], t + nodes[m]);
765 BCVLOG(2) <<
"internal and external electric field";
766 this->forces[m+1] = this->impl_solver->e_field_evaluate(this->particles[m+1], t + nodes[m]);
770 this->update_velocity(m, ds, nodes);
771 BCVLOG(1) <<
"new velocities: " << this->particles[m+1]->velocities();
773 this->log_indent->decrement(1);
776 if (this->get_quadrature()->right_is_node()) {
777 this->end_particles->copy(this->particles.back());
783 this->log_indent->decrement(1);
786 template<
typename scalar,
typename time>
789 BCVLOG(2) <<
"saving current state" << ((initial_only) ?
" (only initial)" :
"");
790 this->log_indent->increment(2);
792 this->saved_particles[0] = make_shared<encap_type>(*(this->particles[0].get()));
793 this->saved_forces[0] = this->forces[0];
794 this->saved_b_vecs[0] = this->b_vecs[0];
796 for (
size_t m = 0; m < this->saved_particles.size(); m++) {
797 BCVLOG(9) <<
"node " << m;
798 BCVLOG(9) <<
" particle: " << this->particles[m];
799 this->saved_particles[m] = make_shared<encap_type>(*(this->particles[m].get()));
800 BCVLOG(9) <<
" previous_particle: " << this->saved_particles[m];
802 BCVLOG(9) <<
"forces: " << this->forces;
803 this->saved_forces = this->forces;
804 BCVLOG(9) <<
"saved_forces: " << this->saved_forces;
805 BCVLOG(9) <<
"b_vecs: " << this->b_vecs;
806 this->saved_b_vecs = this->b_vecs;
807 BCVLOG(9) <<
"saved_b_vecs: " << this->saved_b_vecs;
809 this->log_indent->decrement(2);
812 template<
typename scalar,
typename time>
815 for (
size_t m = 1; m < this->particles.size(); ++m) {
816 this->set_state(const_pointer_cast<const encap_type>(this->particles[0]), m);
820 template<
typename scalar,
typename time>
823 time
t = this->get_controller()->get_time();
824 time
dt = this->get_controller()->get_step_size();
825 this->echo_error(t + dt);
828 template<
typename scalar,
typename time>
831 time
t = this->get_controller()->get_time();
832 time
dt = this->get_controller()->get_step_size();
833 this->echo_error(t + dt);
836 template<
typename scalar,
typename time>
840 template<
typename scalar,
typename time>
843 this->start_particles->post(comm, tag);
846 template<
typename scalar,
typename time>
849 this->end_particles->send(comm, tag, blocking);
852 template<
typename scalar,
typename time>
855 this->start_particles->recv(comm, tag, blocking);
856 if (this->quadrature->left_is_node()) {
857 this->particles[0]->copy(this->start_particles);
861 template<
typename scalar,
typename time>
864 if (comm->
rank() == comm->
size() - 1) {
865 this->start_particles->copy(this->end_particles);
867 this->start_particles->broadcast(comm);
870 template<
typename scalar,
typename time>
874 BCVLOG(3) <<
"solving with Boris' method";
875 this->log_indent->increment(3);
876 const size_t npart = this->start_particles->size();
880 BCVLOG(5) <<
"c_k_term/2: " << c_k_term_half;
881 vector<scalar> beta =
cmp_wise_div(this->particles[m]->charges(), this->particles[m]->masses()) / scalar(2.0) * ds;
882 BCVLOG(5) <<
"beta: " << beta;
883 acceleration_type e_forces_mean = (this->forces[m] + this->forces[m+1]) / scalar(2.0);
884 BCVLOG(5) <<
"e_mean: " << e_forces_mean <<
" (<=" << this->forces[m] <<
" +" << this->forces[m+1] <<
" / 2)";
890 v_minus += e_forces_mean * beta + c_k_term_half;
891 BCVLOG(3) <<
"v-: " << v_minus;
894 vector<scalar> b_field_vector = this->impl_solver->get_b_field_vector();
897 BCVLOG(3) <<
"v': " << v_prime;
904 velocity_type boris_s = (boris_t * scalar(2.0)) / (boris_t_sqr + scalar(1.0));
906 BCVLOG(3) <<
"v+: " << v_plus;
910 this->particles[m+1]->velocities() = v_plus + e_forces_mean * beta + c_k_term_half;
911 this->log_indent->decrement(3);
virtual void setup(bool coarse=false) override
Setup (allocate etc) the sweeper.
static void zero(vector< precision > &data)
virtual void post_predict() override
Hook automatically run after each completed predict.
virtual void set_state(shared_ptr< const encap_type > u0, size_t m)
virtual shared_ptr< acceleration_type > get_tau_qq_as_force(size_t m) const
virtual void broadcast(ICommunicator *comm) override
virtual void residual(time dt, vector< shared_ptr< Encapsulation< time >>> dst) const override
Compute residual at each SDC node (including FAS corrections).
map< error_index, ErrorTuple< scalar >> error_map
virtual void save(bool initial_only=false) override
Save states (and/or function values) at all nodes.
pair< size_t, size_t > error_index
Not implemented yet exception.
virtual void set_initial_energy()
virtual void boris_solve(const time tm, const time t_next, const time ds, const size_t m, const velocity_type &c_k_term)
static vector< precision > kronecker(const vector< precision > &first, const vector< precision > &second)
void cross_prod(const double first[DIM], const double second[DIM], double cross_prod[DIM])
virtual void advance() override
Advance from one time step to the next.
virtual void evaluate(size_t m)
virtual void spread() override
Initialize solution values at all time nodes with meaningful values.
ParticleCloudComponent< precision > & positions()
static void add_custom_logger(const string &id)
Provides convenient way of adding additional named loggers.
virtual void post_sweep() override
Hook automatically run after each completed sweep.
virtual void post(ICommunicator *comm, int tag) override
ParticleCloudComponent< precision > & velocities()
vector< precision > ParticleComponent
virtual void exact(shared_ptr< Encapsulation< time >> q, time t)
virtual error_map< scalar > get_errors() const
virtual void setup(bool coarse) override
Setup (allocate etc) the sweeper.
virtual shared_ptr< Encapsulation< time > > get_state(size_t m) const override
Retrieve solution values of current iteration at time node index m.
virtual shared_ptr< Encapsulation< time > > get_saved_state(size_t m) const override
Retrieve solution values of previous iteration at time node index m.
static vector< precision > norm_sq_npart(const vector< precision > &data, const size_t npart)
static vector< precision > cross_prod(const vector< precision > &first, const vector< precision > &second)
virtual shared_ptr< Encapsulation< time > > get_start_state() const
virtual shared_ptr< acceleration_type > get_tau_q_as_force(size_t m) const
static vector< precision > cmp_wise_div(const vector< precision > &first, const vector< precision > &second)
ParticleCloudComponent< scalar > velocity_type
static precision max(const vector< precision > &data)
Data/solution encapsulation.
virtual void recv(ICommunicator *comm, int tag, bool blocking) override
string DATA_STREAM_FORMAT_STR
ParticleCloudComponent< scalar > acceleration_type
virtual void send(ICommunicator *comm, int tag, bool blocking) override
ParticleError< scalar > p_err
virtual void post_step() override
Hook automatically run after each completed time step.
#define UNUSED(expr)
Denoting unused function parameters for omitting compiler warnings.
virtual void predict(bool initial) override
Perform a predictor sweep.
virtual void echo_error(const time t, bool predict=false)
Abstract interface for communicators.
Eigen::Matrix< coeff, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > Matrix
virtual void sweep() override
Perform one SDC sweep/iteration.
virtual void set_start_state(shared_ptr< const encap_type > u0)
boost::format data_stream_fmt
virtual void integrate(time dt, vector< shared_ptr< Encapsulation< time >>> dst) const override
Integrates values of right hand side at all time nodes \( t \in [0,M-1] \) simultaneously.