Graph Framework
Loading...
Searching...
No Matches
particle_in_cell.hpp
Go to the documentation of this file.
1//------------------------------------------------------------------------------
6//------------------------------------------------------------------------------
7
8#ifndef particle_in_cell_h
9#define particle_in_cell_h
10
11#include <numbers>
12#include <bit>
13
14#include "piecewise.hpp"
15#include "workflow.hpp"
16#include "random.hpp"
17#include "logical.hpp"
18
19namespace graph {
20//------------------------------------------------------------------------------
24//------------------------------------------------------------------------------
25 template<std::floating_point T>
26 class apply_u_node final : public no_derivative<T, false,
27 n_branch_node<7, T, false>,
28 7> {
29 private:
30//------------------------------------------------------------------------------
35//------------------------------------------------------------------------------
36 static std::string to_string(std::array<shared_leaf<T>, 7> branches) {
37 std::string s = "apply_u";
38 for (auto &b : branches) {
39 s += jit::format_to_string(reinterpret_cast<size_t> (b.get()));
40 }
41 return s;
42 }
43
44//------------------------------------------------------------------------------
54//------------------------------------------------------------------------------
55 static void func(backend::buffer<T> &x,
56 const backend::buffer<T> &i,
60 const backend::buffer<T> &A,
61 const backend::buffer<T> &B) {
62 const size_t size = x.size();
63 assert(size == i.size() &&
64 size == rand.size() &&
65 size == mof.size() &&
66 size == tbnu_e_dt.size() &&
67 size == A.size() &&
68 size == B.size() &&
69 "Expected all arguments to have the same length.");
70
71 for (size_t j = 0; j < size; j++) {
72 const T mof_j = mof[j];
73 const T a_j = A[j];
74 const T b_j = B[j];
75 T temp_x = x[j];
76 const T tbnu_e_dt_j = tbnu_e_dt[j];
77 if constexpr (std::same_as<T, float>) {
78 uint32_t rand_j = std::bit_cast<uint32_t> (rand[j]);
79 for (uint8_t k = 0, ke = i[j]; k < ke; k++, rand_j >>= 1) {
80 const T E0 = mof_j*temp_x;
81 const int8_t rm = 4*(rand_j & 1) - 2;
82 const T C = rm*std::sqrt(tbnu_e_dt_j*E0);
83 temp_x = (E0*a_j + b_j + C)/mof_j;
84 }
85 } else {
86 uint64_t rand_j = std::bit_cast<uint64_t> (rand[j]);
87 for (uint8_t k = 0, ke = i[j]; k < ke; k++, rand_j >>= 1) {
88 const T E0 = mof_j*temp_x;
89 const int8_t rm = 4*(rand_j & 1) - 2;
90 const T C = rm*std::sqrt(tbnu_e_dt_j*E0);
91 temp_x = (E0*a_j + b_j + C)/mof_j;
92 }
93 }
94 x[j] = temp_x;
95 }
96 }
97
98 public:
99//------------------------------------------------------------------------------
109//------------------------------------------------------------------------------
118 n_branch_node<7, T, false>, 7> ({x, i, rand, mof, tbnu_e_dt, A, B},
119 apply_u_node::to_string({x, i, rand, mof, tbnu_e_dt, A, B})) {}
120
121//------------------------------------------------------------------------------
125//------------------------------------------------------------------------------
127 backend::buffer<T> x = this->branches[0]->evaluate();
128 const backend::buffer<T> i = this->branches[1]->evaluate();
129 const backend::buffer<T> rand = this->branches[2]->evaluate();
130 const backend::buffer<T> mof = this->branches[3]->evaluate();
131 const backend::buffer<T> tbnu_e_dt = this->branches[4]->evaluate();
132 const backend::buffer<T> A = this->branches[5]->evaluate();
133 const backend::buffer<T> B = this->branches[6]->evaluate();
134
135 apply_u_node::func(x, i, rand, mof, tbnu_e_dt, A, B);
136 return x;
137 }
138
139//------------------------------------------------------------------------------
143//------------------------------------------------------------------------------
145 return this->shared_from_this();
146 }
147
148//------------------------------------------------------------------------------
159//------------------------------------------------------------------------------
160 virtual void compile_preamble(std::ostringstream &stream,
161 jit::register_map &registers,
166 jit::preamble_map &pre_funcs,
167 int &avail_const_mem) {
168 if (!pre_funcs.contains("apply_u")) {
169 pre_funcs.insert("apply_u");
170
171 jit::add_type<T> (stream);
172 stream << " apply_u(const ";
173 jit::add_type<T> (stream);
174 stream << " x, const uint8_t i, uint32_t rand, const ";
175 jit::add_type<T> (stream);
176 stream << " mof, const ";
177 jit::add_type<T> (stream);
178 stream << " tbnu_e_dt, const ";
179 jit::add_type<T> (stream);
180 stream << " A, const ";
181 jit::add_type<T> (stream);
182 stream << " B) {" << std::endl
183 << " ";
184 jit::add_type<T> (stream);
185 stream << " temp_x = x;" << std::endl
186 << " for (uint8_t j = 0; j < i; j++, rand >>= 1) {" << std::endl
187 << " const ";
188 jit::add_type<T> (stream);
189 stream << " E0 = mof*temp_x;" << std::endl
190 << " const uint8_t rm = 4*(rand & 1) - 2;" << std::endl
191 << " const ";
192 jit::add_type<T> (stream);
193 stream << " C = rm*sqrt(tbnu_e_dt*E0);" << std::endl
194 << " temp_x = (E0*A + B + C)/mof;" << std::endl
195 << " }" << std::endl
196 << " return temp_x;" << std::endl
197 << "}" << std::endl;
198 }
199
200 if (!visited.contains(this)) {
201 for (auto &b : this->branches) {
202 b->compile_preamble(stream, registers,
203 visited, usage,
205 pre_funcs, avail_const_mem);
206 }
207
208 visited.insert(this);
209#ifdef SHOW_USE_COUNT
210 usage[this] = 1;
211 } else {
212 ++usage[this];
213#endif
214 }
215 }
216
217//------------------------------------------------------------------------------
225//------------------------------------------------------------------------------
226 virtual shared_leaf<T> compile(std::ostringstream &stream,
227 jit::register_map &registers,
229 const jit::register_usage &usage) {
230 if (registers.find(this) == registers.end()) {
231 auto x = this->branches[0]->compile(stream, registers, thread_mem, usage);
232 auto i = this->branches[1]->compile(stream, registers, thread_mem, usage);
233 auto rand = this->branches[2]->compile(stream, registers, thread_mem, usage);
234 auto mof = this->branches[3]->compile(stream, registers, thread_mem, usage);
235 auto tbnu_e_dt = this->branches[4]->compile(stream, registers, thread_mem, usage);
236 auto A = this->branches[5]->compile(stream, registers, thread_mem, usage);
237 auto B = this->branches[6]->compile(stream, registers, thread_mem, usage);
238
239 registers[this] = jit::to_string('r', this);
240 stream << " const ";
241 jit::add_type<T> (stream);
242 stream << " " << registers[this] << " = apply_u("
243 << registers[x.get()] << ", "
244 << registers[i.get()] << ", ";
245 stream << registers[rand.get()] << ", "
246 << registers[mof.get()] << ", "
247 << registers[tbnu_e_dt.get()] << ", "
248 << registers[A.get()] << ", "
249 << registers[B.get()] << ")";
250 this->endline(stream, usage);
251 }
252
253 return this->shared_from_this();
254 }
255
256//------------------------------------------------------------------------------
261//------------------------------------------------------------------------------
262 virtual bool is_match(shared_leaf<T> x) {
263 if (this == x.get()) {
264 return true;
265 }
266
267 auto x_cast = apply_u_cast(x);
268 bool temp;
269 if (x_cast.get()) {
270 temp = this->branches[0]->is_match(x_cast->get_arg(0));
271 for (size_t i = 1; i < 7 && temp; i++) {
272 temp = temp && this->branches[i]->is_match(x_cast->get_arg(i));
273 }
274 }
275
276 return temp;
277 }
278
279//------------------------------------------------------------------------------
281//------------------------------------------------------------------------------
282 virtual void to_latex() const {
283 std::cout << "\\apply_u{\\left(";
284 this->branches[0]->to_latex();
285 for (uint8_t i = 1; i < 7; i++) {
286 std::cout << ", ";
287 this->branches[i]->to_latex();
288 }
289 std::cout << "\\right)}";
290 }
291
292//------------------------------------------------------------------------------
296//------------------------------------------------------------------------------
298 if (this->has_pseudo()) {
299 return apply_u(this->branches[0]->remove_pseudo(),
300 this->branches[1]->remove_pseudo(),
301 this->branches[2]->remove_pseudo(),
302 this->branches[3]->remove_pseudo(),
303 this->branches[4]->remove_pseudo(),
304 this->branches[5]->remove_pseudo(),
305 this->branches[6]->remove_pseudo());
306 }
307 return this->shared_from_this();
308 }
309
310//------------------------------------------------------------------------------
316//------------------------------------------------------------------------------
317 virtual shared_leaf<T> to_vizgraph(std::stringstream &stream,
318 jit::register_map &registers) {
319 if (registers.find(this) == registers.end()) {
320 const std::string name = jit::to_string('r', this);
321 registers[this] = name;
322 stream << " " << name
323 << " [label = \"apply_u\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
324
325 for (auto &b : this->branches) {
326 auto temp = b->to_vizgraph(stream, registers);
327 stream << " " << name << " -- " << registers[temp.get()] << ";" << std::endl;
328 }
329 }
330
331 return this->shared_from_this();
332 }
333 };
334
335//------------------------------------------------------------------------------
348//------------------------------------------------------------------------------
349 template<std::floating_point T>
357 auto temp = std::make_shared<apply_u_node<T>> (x, i, rand, mof,
358 tbnu_e_dt, A, B)->reduce();
359// Test for hash collisions.
360 for (size_t i = temp->get_hash();
362 if (leaf_node<T>::caches.nodes.find(i) ==
363 leaf_node<T>::caches.nodes.end()) {
364 leaf_node<T>::caches.nodes[i] = temp;
365 return temp;
366 } else if (temp->is_match(leaf_node<T>::caches.nodes[i])) {
367 return leaf_node<T>::caches.nodes[i];
368 }
369 }
370#if defined(__clang__) || defined(__GNUC__)
372#else
373 assert(false && "Should never reach.");
374#endif
375 }
376
378 template<std::floating_point T>
379 using shared_apply_u = std::shared_ptr<apply_u_node<T>>;
380
381//------------------------------------------------------------------------------
388//------------------------------------------------------------------------------
389 template<std::floating_point T>
391 return std::dynamic_pointer_cast<apply_u_node<T>> (x);
392 }
393
394//------------------------------------------------------------------------------
398//------------------------------------------------------------------------------
399 template<std::floating_point T>
400 class apply_xi_node final : public no_derivative<T, false,
401 n_branch_node<4, T, false>,
402 4> {
403 private:
404//------------------------------------------------------------------------------
409//------------------------------------------------------------------------------
410 static std::string to_string(std::array<shared_leaf<T>, 4> branches) {
411 std::string s = "apply_xi";
412 for (auto &b : branches) {
413 s += jit::format_to_string(reinterpret_cast<size_t> (b.get()));
414 }
415 return s;
416 }
417
418//------------------------------------------------------------------------------
425//------------------------------------------------------------------------------
426 static void func(backend::buffer<T> &x,
427 const backend::buffer<T> &i,
430 const size_t size = x.size();
431 assert(size == i.size() &&
432 size == rand.size() &&
433 size == nu_D_dt.size() &&
434 "Expected all arguments to have the same length.");
435
436 for (size_t j = 0; j < size; j++) {
437 const T nu_D_dt_j = nu_D_dt[j];
438 T temp_x = x[j];
439 if constexpr (std::same_as<T, float>) {
440 uint32_t rand_j = std::bit_cast<uint32_t> (rand[j]);
441 for (uint8_t k = 0, ke = i[j]; k < ke; k++, rand_j >>= 1) {
442 const T A = -temp_x*nu_D_dt_j;
443 const int8_t rm = 2*(rand_j & 1) - 1;
444 const T C = rm*std::sqrt((1 - temp_x*temp_x)*nu_D_dt_j);
445 temp_x += A + C;
446 }
447 } else {
448 uint64_t rand_j = std::bit_cast<uint64_t> (rand[j]);
449 for (uint8_t k = 0, ke = i[j]; k < ke; k++, rand_j >>= 1) {
450 const T A = -temp_x*nu_D_dt_j;
451 const int8_t rm = 2*(rand_j & 1) - 1;
452 const T C = rm*std::sqrt((1 - temp_x*temp_x)*nu_D_dt_j);
453 temp_x += A + C;
454 }
455 }
456 x[j] = temp_x;
457 }
458 }
459
460 public:
461//------------------------------------------------------------------------------
468//------------------------------------------------------------------------------
474 n_branch_node<4, T, false>, 4> ({x, i, rand, nu_D_dt},
475 apply_xi_node::to_string({x, i, rand, nu_D_dt})) {}
476
477//------------------------------------------------------------------------------
481//------------------------------------------------------------------------------
483 backend::buffer<T> x = this->branches[0]->evaluate();
484 const backend::buffer<T> i = this->branches[1]->evaluate();
485 const backend::buffer<T> rand = this->branches[2]->evaluate();
486 const backend::buffer<T> nu_D_dt = this->branches[3]->evaluate();
487
488 apply_xi_node::func(x, i, rand, nu_D_dt);
489 return x;
490 }
491
492//------------------------------------------------------------------------------
496//------------------------------------------------------------------------------
498 return this->shared_from_this();
499 }
500
501//------------------------------------------------------------------------------
512//------------------------------------------------------------------------------
513 virtual void compile_preamble(std::ostringstream &stream,
514 jit::register_map &registers,
519 jit::preamble_map &pre_funcs,
520 int &avail_const_mem) {
521 if (!pre_funcs.contains("apply_xi")) {
522 pre_funcs.insert("apply_xi");
523
524 jit::add_type<T> (stream);
525 stream << " apply_xi(const ";
526 jit::add_type<T> (stream);
527 stream << " x, const uint8_t i, uint32_t rand, const ";
528 jit::add_type<T> (stream);
529 stream << " nu_D_dt) {" << std::endl
530 << " ";
531 jit::add_type<T> (stream);
532 stream << " temp_x = x;" << std::endl
533 << " for (uint8_t j = 0; j < i; j++, rand >>= 1) {" << std::endl
534 << " const ";
535 jit::add_type<T> (stream);
536 stream << " A = -temp_x*nu_D_dt;" << std::endl
537 << " const uint8_t rm = 2*(rand & 1) - 1;" << std::endl
538 << " const ";
539 jit::add_type<T> (stream);
540 stream << " C = rm*sqrt((1 - temp_x*temp_x)*nu_D_dt);" << std::endl
541 << " temp_x += A + C;" << std::endl
542 << " }" << std::endl
543 << " return temp_x;" << std::endl
544 << "}" << std::endl;
545 }
546
547 if (!visited.contains(this)) {
548 for (auto &b : this->branches) {
549 b->compile_preamble(stream, registers,
550 visited, usage,
552 pre_funcs, avail_const_mem);
553 }
554
555 visited.insert(this);
556#ifdef SHOW_USE_COUNT
557 usage[this] = 1;
558 } else {
559 ++usage[this];
560#endif
561 }
562 }
563
564//------------------------------------------------------------------------------
572//------------------------------------------------------------------------------
573 virtual shared_leaf<T> compile(std::ostringstream &stream,
574 jit::register_map &registers,
576 const jit::register_usage &usage) {
577 if (registers.find(this) == registers.end()) {
578 auto x = this->branches[0]->compile(stream, registers, thread_mem, usage);
579 auto i = this->branches[1]->compile(stream, registers, thread_mem, usage);
580 auto rand = this->branches[2]->compile(stream, registers, thread_mem, usage);
581 auto nu_D_dt = this->branches[3]->compile(stream, registers, thread_mem, usage);
582
583 registers[this] = jit::to_string('r', this);
584 stream << " const ";
585 jit::add_type<T> (stream);
586 stream << " " << registers[this] << " = apply_xi("
587 << registers[x.get()] << ", "
588 << registers[i.get()] << ", ";
589 stream << registers[rand.get()] << ", "
590 << registers[nu_D_dt.get()] << ")";
591 this->endline(stream, usage);
592 }
593
594 return this->shared_from_this();
595 }
596
597//------------------------------------------------------------------------------
602//------------------------------------------------------------------------------
603 virtual bool is_match(shared_leaf<T> x) {
604 if (this == x.get()) {
605 return true;
606 }
607
608 auto x_cast = apply_xi_cast(x);
609 bool temp;
610 if (x_cast.get()) {
611 temp = this->branches[0]->is_match(x_cast->get_arg(0));
612 for (size_t i = 1; i < 4 && temp; i++) {
613 temp = temp && this->branches[i]->is_match(x_cast->get_arg(i));
614 }
615 }
616
617 return temp;
618 }
619
620//------------------------------------------------------------------------------
622//------------------------------------------------------------------------------
623 virtual void to_latex() const {
624 std::cout << "\\apply_xi{\\left(";
625 this->branches[0]->to_latex();
626 for (uint8_t i = 1; i < 4; i++) {
627 std::cout << ", ";
628 this->branches[i]->to_latex();
629 }
630 std::cout << "\\right)}";
631 }
632
633//------------------------------------------------------------------------------
637//------------------------------------------------------------------------------
639 if (this->has_pseudo()) {
640 return apply_xi(this->branches[0]->remove_pseudo(),
641 this->branches[1]->remove_pseudo(),
642 this->branches[2]->remove_pseudo(),
643 this->branches[3]->remove_pseudo());
644 }
645 return this->shared_from_this();
646 }
647
648//------------------------------------------------------------------------------
654//------------------------------------------------------------------------------
655 virtual shared_leaf<T> to_vizgraph(std::stringstream &stream,
656 jit::register_map &registers) {
657 if (registers.find(this) == registers.end()) {
658 const std::string name = jit::to_string('r', this);
659 registers[this] = name;
660 stream << " " << name
661 << " [label = \"apply_xi\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
662
663 for (auto &b : this->branches) {
664 auto temp = b->to_vizgraph(stream, registers);
665 stream << " " << name << " -- " << registers[temp.get()] << ";" << std::endl;
666 }
667 }
668
669 return this->shared_from_this();
670 }
671 };
672
673//------------------------------------------------------------------------------
683//------------------------------------------------------------------------------
684 template<std::floating_point T>
689 auto temp = std::make_shared<apply_xi_node<T>> (x, i, rand,
690 nu_D_dt)->reduce();
691// Test for hash collisions.
692 for (size_t i = temp->get_hash();
694 if (leaf_node<T>::caches.nodes.find(i) ==
695 leaf_node<T>::caches.nodes.end()) {
696 leaf_node<T>::caches.nodes[i] = temp;
697 return temp;
698 } else if (temp->is_match(leaf_node<T>::caches.nodes[i])) {
699 return leaf_node<T>::caches.nodes[i];
700 }
701 }
702#if defined(__clang__) || defined(__GNUC__)
704#else
705 assert(false && "Should never reach.");
706#endif
707 }
708
710 template<std::floating_point T>
711 using shared_apply_xi = std::shared_ptr<apply_xi_node<T>>;
712
713//------------------------------------------------------------------------------
720//------------------------------------------------------------------------------
721 template<std::floating_point T>
723 return std::dynamic_pointer_cast<apply_xi_node<T>> (x);
724 }
725}
726
727namespace pic {
728// FIXME: This should be in a separate file of physics constants.
730 template<std::floating_point T>
731 constexpr T c = static_cast<T> (299792458.0);
733 template<std::floating_point T>
734 constexpr T epsilon0 = static_cast<T> (8.8541878188E-12);
736 template<std::floating_point T>
737 constexpr T q = static_cast<T> (1.602176634E-19);
739 template<std::floating_point T>
740 constexpr T m_hydrogen = static_cast<T> (1.67362192595E-27);
742 template<std::floating_point T>
743 constexpr T m_atomic = static_cast<T> (1.66053906892E-27);
745 template<std::floating_point T>
746 constexpr T m_electron = static_cast<T> (9.1093837139E-31);
748 template<std::floating_point T>
749 constexpr T kb = static_cast<T> (1.380649E-23);
750
751//------------------------------------------------------------------------------
755//------------------------------------------------------------------------------
756 template<std::floating_point T>
758 private:
759//------------------------------------------------------------------------------
764//------------------------------------------------------------------------------
765 T make_m(const std::vector<T> &ion_masses) {
766 T total_m = static_cast<T> (0);
767 for (const T &mass : ion_masses) {
768 total_m += mass;
769 }
770 return total_m/ion_masses.size();
771 }
772
773//------------------------------------------------------------------------------
778//------------------------------------------------------------------------------
779 T make_q(const std::vector<uint8_t> &ion_zs) {
780 T total_q = static_cast<T> (0);
781 for (const uint8_t &z : ion_zs) {
782 total_q += z*pic::q<T>;
783 }
784 return total_q/ion_zs.size();
785 }
786
787 public:
789 const T m;
791 const T q;
793 const T ne;
795 const T wpe;
797 const T t;
799 const T l;
801 const T v;
803 const T te;
805 const T efield;
807 const T bfield;
808
809//------------------------------------------------------------------------------
815//------------------------------------------------------------------------------
816 characteristics(const std::vector<T> &ion_masses,
817 const std::vector<uint8_t> &ion_zs,
818 const T ne) :
819 m(make_m(ion_masses)), q(make_q(ion_zs)), ne(ne),
820 wpe(std::sqrt(ne*q*q/(m*epsilon0<T>))),
821 t(1/wpe), l(c<T>/wpe), v(c<T>), te(m*v*v/kb<T>), efield(m*c<T>/(q*t)),
822 bfield(efield/c<T>) {}
823
824//------------------------------------------------------------------------------
828//------------------------------------------------------------------------------
829 T get_volume() const {
830 return l*l*l;
831 }
832 };
833
834//------------------------------------------------------------------------------
836//------------------------------------------------------------------------------
837 template<std::floating_point T>
839 public:
841 const T b0;
843 const T a0;
845 const size_t filter_iterations;
847 const T smoothing;
849 const T dt;
851 const T t_para;
853 const T t_perp;
854
855//------------------------------------------------------------------------------
865//------------------------------------------------------------------------------
866 parameters(const T b0, const T r1, const T r2,
867 const size_t filter_iterations,
868 const T smoothing, const T dt,
869 const T t_para, const T t_perp,
870 const characteristics<T> &norms) :
871 b0(b0/norms.bfield),
872 a0(std::numbers::pi_v<T>*(r2*r2 - r1*r1)/(norms.l*norms.l)),
874 dt(dt/norms.t), t_para(t_para), t_perp(t_perp) {}
875 };
876
877//------------------------------------------------------------------------------
883//------------------------------------------------------------------------------
884 template<std::floating_point T>
885 class ion {
886 public:
888 const uint8_t z;
890 const T charge;
892 const T mass;
900 std::array<graph::shared_leaf<T>, 3> weights;
902 const T num_real;
903
904//------------------------------------------------------------------------------
912//------------------------------------------------------------------------------
913 ion(const T mass,
914 const uint8_t z,
915 const size_t num_ions,
916 const T num_real,
917 const characteristics<T> &norms) :
918 z(z), charge(z*pic::q<T>/norms.q),
920 x(graph::variable<T> (num_ions, "x")),
921 v_para(graph::variable<T> (num_ions, "v_{||}")),
922 v_perp(graph::variable<T> (num_ions, "v_{\\perp}")),
923 weights({
924 graph::variable<T> (num_ions, "w_{0}"),
925 graph::variable<T> (num_ions, "w_{1}"),
926 graph::variable<T> (num_ions, "w_{2}")
927 }) {}
928
929//------------------------------------------------------------------------------
933//------------------------------------------------------------------------------
937
938//------------------------------------------------------------------------------
942//------------------------------------------------------------------------------
943 size_t size() const {
944 return get_x()->size();
945 }
946
947//------------------------------------------------------------------------------
951//------------------------------------------------------------------------------
952 T *x_data() const {
953 return get_x()->data();
954 }
955
956//------------------------------------------------------------------------------
960//------------------------------------------------------------------------------
964
965//------------------------------------------------------------------------------
969//------------------------------------------------------------------------------
970 T *v_para_data() const {
971 return get_v_para()->data();
972 }
973
974//------------------------------------------------------------------------------
978//------------------------------------------------------------------------------
982
983//------------------------------------------------------------------------------
987//------------------------------------------------------------------------------
988 T *v_perp_data() const {
989 return graph::variable_cast(v_perp)->data();
990 }
991
992//------------------------------------------------------------------------------
996//------------------------------------------------------------------------------
997 T super_to_real() const {
998 return num_real/size();
999 }
1000
1001//------------------------------------------------------------------------------
1009//------------------------------------------------------------------------------
1011 output::data_set<T> &data,
1013 const std::string tag) {
1014 data.create_variable(file, "x_" + tag, x, work.get_context());
1015 data.create_variable(file, "vpara_" + tag, v_para,
1016 work.get_context());
1017 data.create_variable(file, "vperp_" + tag, v_perp,
1018 work.get_context());
1019 }
1020
1021//------------------------------------------------------------------------------
1026//------------------------------------------------------------------------------
1028 return func(x);
1029 }
1030 };
1031
1032//------------------------------------------------------------------------------
1036//------------------------------------------------------------------------------
1037 template<std::floating_point T>
1038 class mesh {
1039 private:
1040//------------------------------------------------------------------------------
1049//------------------------------------------------------------------------------
1050 template<size_t I=0>
1052 const T scale,
1053 const size_t iterations=0) const {
1054 auto low = iterations ? build_y_index<I> (x - dx, scale, iterations - 1) :
1055 graph::index_1D(y[I], x, dx, xmin + dx);
1056 auto center = graph::index_1D(y[I], x, dx, xmin);
1057 auto high = iterations ? build_y_index<I> (x + dx, scale, iterations - 1) :
1058 graph::index_1D(y[I], x, dx, xmin - dx);
1059
1060 const T center_w = static_cast<T> (0.5);
1061 const T side_w = static_cast<T> (0.25);
1062
1063 auto b = center_w*center + side_w*low + side_w*high;
1064 return (1 - scale)*center + scale*b;
1065 }
1066
1067 public:
1069 const T xmin;
1071 const T xmax;
1073 const T dx;
1075 std::array<graph::shared_leaf<T>, 4> y;
1085
1086//------------------------------------------------------------------------------
1093//------------------------------------------------------------------------------
1094 mesh(const T x_min,
1095 const T x_max,
1096 const size_t num,
1097 const characteristics<T> &norms) :
1098 y({
1099 graph::variable<T> (num, "y^{0}_{m}"),
1100 graph::variable<T> (num, "y^{1}_{m}"),
1101 graph::variable<T> (num, "y^{2}_{m}"),
1102 graph::variable<T> (num, "y^{3}_{m}")
1103 }), xmin(x_min/norms.l), xmax(x_max/norms.l),
1104 dx((xmax - xmin)/(num - 1)) {}
1105
1106//------------------------------------------------------------------------------
1111//------------------------------------------------------------------------------
1115
1116//------------------------------------------------------------------------------
1121//------------------------------------------------------------------------------
1125
1126//------------------------------------------------------------------------------
1135//------------------------------------------------------------------------------
1136 template<size_t I=0, offset O=center>
1138 const parameters<T> &params) const {
1139 if constexpr (O == low) {
1140 return build_y_index<I> (x - dx, params.smoothing,
1141 params.filter_iterations - 1);
1142 } else if constexpr (O == center) {
1143 return build_y_index<I> (x, params.smoothing,
1144 params.filter_iterations - 1);
1145 } else {
1146 return build_y_index<I> (x + dx, params.smoothing,
1147 params.filter_iterations - 1);
1148 }
1149 }
1150
1151//------------------------------------------------------------------------------
1160//------------------------------------------------------------------------------
1161 template<size_t I=0, offset O=center>
1163 const parameters<T> &params) const {
1164 const T two = 2;
1165 if constexpr (O == low) {
1166 auto low = build_y_index<I> (x - two*dx, params.smoothing,
1167 params.filter_iterations);
1168 auto high = build_y_index<I> (x, params.smoothing,
1169 params.filter_iterations);
1170 return (high - low)/two;
1171 } else if constexpr (O == center) {
1172 auto low = build_y_index<I> (x - dx, params.smoothing,
1173 params.filter_iterations);
1174 auto high = build_y_index<I> (x + dx, params.smoothing,
1175 params.filter_iterations);
1176 return (high - low)/two;
1177 } else {
1178 auto low = build_y_index<I> (x, params.smoothing,
1179 params.filter_iterations);
1180 auto high = build_y_index<I> (x + two*dx, params.smoothing,
1181 params.filter_iterations);
1182 return (high - low)/two;
1183 }
1184 }
1185
1186//------------------------------------------------------------------------------
1191//------------------------------------------------------------------------------
1192 std::array<graph::shared_leaf<T>, 3> build_mesh_solve(const ion<T> &ion) const {
1193 auto weights = build_weights(ion.x);
1194 auto sum_low = graph::atomic_accumulate_1D(y[0], ion.x - dx,
1195 dx, xmin, weights[0]);
1196 auto sum = graph::atomic_accumulate_1D(y[0], ion.x,
1197 dx, xmin, weights[1]);
1198 auto sum_high = graph::atomic_accumulate_1D(y[0], ion.x + dx,
1199 dx, xmin, weights[2]);
1200 return {sum_low, sum, sum_high};
1201 }
1202
1203//------------------------------------------------------------------------------
1207//------------------------------------------------------------------------------
1208 size_t size() const {
1209 return graph::variable_cast(y[0])->size();
1210 }
1211
1212//------------------------------------------------------------------------------
1218//------------------------------------------------------------------------------
1219 template<size_t I=0>
1220 T *data() const {
1221 return graph::variable_cast(y[I])->data();
1222 }
1223
1224//------------------------------------------------------------------------------
1231//------------------------------------------------------------------------------
1234 workflow::manager<T> &work) {
1235 data.create_variable(file, "y_0", y[0], work.get_context());
1236 data.create_variable(file, "y_1", y[1], work.get_context());
1237 data.create_variable(file, "y_2", y[2], work.get_context());
1238 data.create_variable(file, "y_3", y[3], work.get_context());
1239 }
1240
1241//------------------------------------------------------------------------------
1246//------------------------------------------------------------------------------
1247 std::array<graph::shared_leaf<T>, 3> build_weights(graph::shared_leaf<T> x) const {
1248 auto x_off = build_x_index(x) - x;
1249 auto xnorm1 = static_cast<T> (1.5) + (x_off - dx)/dx;
1250 auto xnorm2 = x_off/dx;
1251 auto xnorm3 = static_cast<T> (1.5) - (x_off + dx)/dx;
1252
1253 auto w0 = static_cast<T> (0.5)*xnorm1*xnorm1;
1254 auto w1 = static_cast<T> (0.75) - xnorm2*xnorm2;
1255 auto w2 = static_cast<T> (0.5)*xnorm3*xnorm3;
1256
1257 return {w0, w1, w2};
1258 }
1259
1260//------------------------------------------------------------------------------
1265//------------------------------------------------------------------------------
1267 auto weights = build_weights(x);
1268
1269 auto ymesh0 = graph::index_1D(y[0], x - dx, dx, xmin);
1270 auto ymesh1 = graph::index_1D(y[0], x, dx, xmin);
1271 auto ymesh2 = graph::index_1D(y[0], x + dx, dx, xmin);
1272
1273 return weights[0]*ymesh0 + weights[1]*ymesh1 + weights[2]*ymesh2;
1274 }
1275 };
1276
1277//------------------------------------------------------------------------------
1285//------------------------------------------------------------------------------
1286 template<std::floating_point T>
1287 std::array<graph::shared_leaf<T>, 3> cartesian_to_sphereical(graph::shared_leaf<T> x,
1289 auto w = graph::hypot(x, y);
1290 return {
1291 w, x/w,
1292 graph::none<T> ()*graph::copysign(static_cast<T> (1), y)
1293 };
1294 }
1295
1296//------------------------------------------------------------------------------
1305//------------------------------------------------------------------------------
1306 template<std::floating_point T>
1307 std::array<graph::shared_leaf<T>, 2> sphereical_to_cartesian(graph::shared_leaf<T> w,
1309 graph::shared_leaf<T> sinphi) {
1310 return {
1311 w*xi,
1312 graph::none<T> ()*w*graph::sqrt(static_cast<T> (1) - xi*xi)*sinphi
1313 };
1314 }
1315
1316//------------------------------------------------------------------------------
1318//------------------------------------------------------------------------------
1319 enum model {
1323 chen
1325
1326//------------------------------------------------------------------------------
1339//------------------------------------------------------------------------------
1340 template<std::floating_point T, model M>
1342 const T mass_a,
1343 const T mass_b,
1346 graph::shared_leaf<T> erfp_xab) {
1347 auto mass_ratio = static_cast<T> (2)*mass_a/mass_b*gb;
1348 auto nu = nuab0/xab;
1349 if constexpr (M == model::hinton) {
1350 return nu*(mass_ratio - erfp_xab/xab);
1351 } else {
1352 return nu*mass_ratio;
1353 }
1354 }
1355
1356//------------------------------------------------------------------------------
1370//------------------------------------------------------------------------------
1371 template<std::floating_point T, model M>
1372 std::array<graph::shared_leaf<T>, 2> build_ion_ion_collision(const ion<T> &ion_a,
1373 const ion<T> &ion_b,
1374 const mesh<T> &mesh,
1375 const characteristics<T> &norms,
1376 const parameters<T> &params,
1377 graph::shared_leaf<T> total_density,
1378 graph::shared_leaf<T> total_flux,
1379 const graph::shared_random_state<T> state) {
1380 const T dt = params.dt*norms.t;
1381
1382 const T mass_b = ion_b.mass*norms.m;
1383 const uint8_t zb2 = ion_b.z*ion_b.z;
1384
1385 auto nb = build_density(ion_a.x, ion_b, mesh, norms, params)/norms.get_volume();
1386 auto tpara = ion_a.build_profile([](graph::shared_leaf<T> x) -> graph::shared_leaf<T> {
1387 return graph::one<T> ();
1388 });
1389 auto tperp = ion_a.build_profile([](graph::shared_leaf<T> x) -> graph::shared_leaf<T> {
1390 return graph::one<T> ();
1391 });
1392 auto tb = static_cast<T> (0.5)*(tpara + tperp)*norms.te*kb<T>/q<T>;
1394 return graph::one<T> ();
1395 })*norms.v/norms.get_volume();
1396 auto uxb = nv/nb;
1397
1398 total_density = total_density + nb;
1399 total_flux = total_flux + nv;
1400
1401 return build_common_collision<T, M> (ion_a, norms, uxb, tb, nb, mass_b,
1402 zb2, dt, state);
1403 }
1404
1405//------------------------------------------------------------------------------
1418//------------------------------------------------------------------------------
1419 template<std::floating_point T, model M>
1420 std::array<graph::shared_leaf<T>, 2> build_ion_electron_collision(const ion<T> &ion_a,
1421 const mesh<T> &mesh,
1422 const characteristics<T> &norms,
1423 const parameters<T> &params,
1424 graph::shared_leaf<T> total_density,
1425 graph::shared_leaf<T> total_flux,
1426 const graph::shared_random_state<T> state) {
1427 const T dt = params.dt*norms.t;
1428
1429 const T mass_b = m_electron<T>;
1430 const uint8_t zb2 = 1;
1431
1432 auto nb = total_density;
1434 return graph::one<T> ();
1435 })*norms.te;
1436
1437 auto uxb = total_flux/total_density;
1438
1439 return build_common_collision<T, M> (ion_a, norms, uxb, tb, nb, mass_b,
1440 zb2, dt, state);
1441 }
1442
1443//------------------------------------------------------------------------------
1458//------------------------------------------------------------------------------
1459 template<std::floating_point T, model M>
1460 std::array<graph::shared_leaf<T>, 2> build_common_collision(const ion<T> &ion_a,
1461 const characteristics<T> &norms,
1465 const T mass_b,
1466 const uint8_t zb2,
1467 const T dt,
1468 const graph::shared_random_state<T> state) {
1469 const T mass_a = ion_a.mass*norms.m;
1470 const uint8_t za2 = ion_a.z*ion_a.z;
1471
1472// Convert to b frame.
1473 auto wxa = ion_a.v_para*norms.v - uxb;
1474 auto wya = ion_a.v_perp*norms.v;
1475
1476// Convert to sphereical.
1477 auto sphere = cartesian_to_sphereical(wxa, wya);
1478
1479// Apply Monte-Carlo collision operator.
1480 auto wtb = graph::sqrt(static_cast<T> (2)*q<T>*tb/mass_b);
1481 auto xab = sphere[0]/wtb;
1482
1483 auto erf_xab = graph::erf(xab);
1484 auto erfp_xab = erf_xab->df(xab);
1485 auto erfpp_xab = erfp_xab->df(xab);
1486
1487 auto gb = (erf_xab - xab*erfp_xab)/(static_cast<T> (2)*xab*xab);
1488 auto logA = static_cast<T> (30) - static_cast<T> (0.5)*graph::log(nb/(tb*graph::sqrt(tb)));
1489 auto nuab0 = nb*q<T>*q<T>*q<T>*q<T>*static_cast<T> (za2*zb2)*logA
1490 / (static_cast<T> (2)*std::numbers::pi_v<T>*mass_a*mass_a*epsilon0<T>*epsilon0<T>*wtb*wtb*wtb);
1491
1492// Velocity Scattering operator.
1493 auto nu_e_dt = build_colision_rate<T, M> (xab, mass_a, mass_b, gb, nuab0, erfp_xab)*dt;
1494 auto steps = graph::min(nu_e_dt*2.5, static_cast<T> (32));
1495
1496 nu_e_dt = nu_e_dt*steps;
1497
1498 auto E_nuE_d_nu_E_dE = static_cast<T> (0.5)*((static_cast<T> (3.0)*(xab*erfp_xab - erf_xab) - xab*xab*erfpp_xab)/(erf_xab - xab*erfp_xab));
1499
1500 const T mof = mass_a/(static_cast<T> (2)*q<T>);
1501 auto A = static_cast<T> (1) - static_cast<T> (2)*nu_e_dt;
1502 auto tbnu_e_df = tb*nu_e_dt;
1503 auto B = static_cast<T> (2)*tbnu_e_df*(static_cast<T> (1.5) + E_nuE_d_nu_E_dE);
1504
1505 auto rand1 = graph::random<T> (state);
1506 auto u_op = graph::apply_u(sphere[0]*sphere[0], steps, rand1,
1507 graph::constant(mof), tbnu_e_df, A, B);
1508 sphere[0] = graph::sqrt(u_op);
1509
1510 auto nu_D_dt = nuab0*(erf_xab - gb)/(xab*xab*xab)*dt;
1511 steps = graph::min(nu_D_dt, static_cast<T> (32));
1512 nu_D_dt = nu_D_dt/steps;
1513
1514 auto rand2 = graph::random<T> (state);
1515 sphere[1] = graph::apply_xi(sphere[1], steps, rand2, nu_D_dt);
1516
1517 sphere[1] = graph::if_(sphere[1]*sphere[1] > static_cast<T> (1),
1518 graph::copysign(static_cast<T> (1), sphere[1]) -
1519 sphere[1] % graph::copysign(static_cast<T> (1), sphere[1]),
1520 sphere[1]);
1521
1522 auto cart = sphereical_to_cartesian(sphere[0], sphere[1], sphere[2]);
1523 return {(cart[0] + uxb)/norms.v, cart[1]/norms.v};
1524 }
1525
1526//------------------------------------------------------------------------------
1537//------------------------------------------------------------------------------
1538 template<std::floating_point T>
1539 std::array<graph::shared_leaf<T>,3> build_initialization(const pic::ion<T> &ion,
1540 const mesh<T> &mesh,
1541 const characteristics<T> &norms,
1542 const parameters<T> &params,
1543 const graph::shared_random_state<T> state) {
1544// The mesh is already normalized so position_dist will be a normalized quantity.
1545 auto position_dist = graph::uniform_random<T> (mesh.xmin, mesh.xmax,
1546 state);
1547 auto phi_dist = graph::uniform_random<T> (static_cast<T> (0),
1548 static_cast<T> (2)*std::numbers::pi_v<T>,
1549 state);
1550 auto r_dist = graph::uniform_random<T> (std::numeric_limits<T>::min(),
1551 static_cast<T> (1),
1552 state);
1553
1554 const T vtpara = std::sqrt(2*params.t_para*q<T>/ion.mass);
1555 auto vpara = vtpara*graph::sqrt(-graph::log(r_dist))
1556 * graph::sin(phi_dist);
1557
1558 phi_dist = graph::uniform_random<T> (static_cast<T> (0),
1559 static_cast<T> (2)*std::numbers::pi_v<T>,
1560 state);
1561 r_dist = graph::uniform_random<T> (std::numeric_limits<T>::min(),
1562 static_cast<T> (1),
1563 state);
1564
1565 const T vtperp = std::sqrt(2*params.t_perp*q<T>/ion.mass);
1566 auto vperp1 = vtperp*graph::sqrt(-graph::log(r_dist))
1567 * graph::cos(phi_dist);
1568 auto vperp2 = vtperp*graph::sqrt(-graph::log(r_dist))
1569 * graph::sin(phi_dist);
1570 auto vperp = graph::sqrt(vperp1*vperp1 + vperp2*vperp2);
1571
1572 return {position_dist, vpara/norms.v, vperp/norms.v};
1573 }
1574
1575//------------------------------------------------------------------------------
1589//------------------------------------------------------------------------------
1590 template<std::floating_point T>
1591 std::array<graph::shared_leaf<T>, 3> build_reinjection(const ion<T> &ion,
1592 const mesh<T> &mesh,
1593 const characteristics<T> &norms,
1594 const parameters<T> &params,
1595 const graph::shared_random_state<T> state) {
1596 auto resampled = build_initialization(ion, mesh, norms, params, state);
1597 auto is_outside = ion.x <= mesh.xmin || ion.x >= mesh.xmax;
1598
1599 auto reinject_x = graph::if_(is_outside ||
1600 graph::isnan(ion.x) ||
1601 graph::isinf(ion.x), resampled[0], ion.x);
1602 auto reinject_vpara = graph::if_(is_outside ||
1603 graph::isnan(ion.x) ||
1604 graph::isinf(ion.x), resampled[1], ion.v_para);
1605 auto reinject_vperp = graph::if_(is_outside ||
1606 graph::isnan(ion.x) ||
1607 graph::isinf(ion.x), resampled[2], ion.v_perp);
1608 return {reinject_x, reinject_vpara, reinject_vperp};
1609 }
1610
1611//------------------------------------------------------------------------------
1620//------------------------------------------------------------------------------
1621 template<std::floating_point T>
1623 const characteristics<T> &norms,
1624 const parameters<T> &params) {
1625 return (x*x*(norms.l*norms.l) + static_cast<T> (0.5))*params.b0;
1626 }
1627
1628//------------------------------------------------------------------------------
1641//------------------------------------------------------------------------------
1642 template<std::floating_point T, size_t I=0,
1645 const ion<T> &ion,
1646 const mesh<T> &mesh,
1647 const characteristics<T> &norms,
1648 const parameters<T> &params) {
1649 auto y = mesh.template build_y_index<I, O> (x, params);
1650
1651// Compression factor.
1652 auto cf = build_magnetic_field(x, norms, params)/params.b0;
1653// Scale factor.
1654 const T sf = ion.super_to_real()/(params.a0*mesh.dx);
1655
1656 return static_cast<T> (ion.z)*y*cf*sf;
1657 }
1658
1659//------------------------------------------------------------------------------
1672//------------------------------------------------------------------------------
1673 template<std::floating_point T, size_t I=0,
1676 const ion<T> &ion,
1677 const mesh<T> &mesh,
1678 const characteristics<T> &norms,
1679 const parameters<T> &params) {
1680 auto y = mesh.template build_dydx_index<I, O> (x, params);
1681
1682// Compression factor.
1683 auto cf = build_magnetic_field(x, norms, params)/params.b0;
1684// Scale factor.
1685 const T sf = ion.super_to_real()/(params.a0*mesh.dx);
1686
1687 return static_cast<T> (ion.z)*y*cf*sf;
1688 }
1689
1690//------------------------------------------------------------------------------
1698//------------------------------------------------------------------------------
1699 template<std::floating_point T>
1701 const characteristics<T> &norms) {
1702 return graph::constant<T> (static_cast<T> (2.5)*q<T>/(norms.te*kb<T>));
1703 }
1704
1705//------------------------------------------------------------------------------
1716//------------------------------------------------------------------------------
1717 template<std::floating_point T, mesh<T>::offset O=mesh<T>::center>
1719 const ion<T> &ion,
1720 const mesh<T> &mesh,
1721 const characteristics<T> &norms,
1722 const parameters<T> &params) {
1723 auto n0 = build_density<T, 0, O> (x, ion, mesh, norms, params);
1724 auto n1 = build_density<T, 1, O> (x, ion, mesh, norms, params);
1725 auto n2 = build_density<T, 2, O> (x, ion, mesh, norms, params);
1726 auto n3 = build_density<T, 3, O> (x, ion, mesh, norms, params);
1727
1728 auto dn0dx = build_density_gradient<T, 0, O> (x, ion, mesh, norms, params);
1729 auto dn1dx = build_density_gradient<T, 1, O> (x, ion, mesh, norms, params);
1730 auto dn2dx = build_density_gradient<T, 2, O> (x, ion, mesh, norms, params);
1731 auto dn3dx = build_density_gradient<T, 3, O> (x, ion, mesh, norms, params);
1732
1733 auto n = (n0 + n1 + n2 + n3)/static_cast<T> (4);
1734 auto dndx = (dn0dx + dn1dx + dn2dx + dn3dx)/static_cast<T> (4);
1735
1736 auto te = build_electron_temperature(x, norms);
1737 const T scale = norms.q/q<T>;
1738 auto pressure = te*n*scale;
1739
1740 return graph::none<T> ()/n*(dndx*te*scale + pressure->df(x));
1741 }
1742
1743//------------------------------------------------------------------------------
1754//------------------------------------------------------------------------------
1755 template<std::floating_point T>
1757 const ion<T> &ion,
1758 const mesh<T> &mesh,
1759 const characteristics<T> &norms,
1760 const parameters<T> &params) {
1761 auto weights = mesh.build_weights(x);
1762
1763 auto ymesh0 = build_electric_efield<T, ::pic::mesh<T>::low> (x, ion, mesh, norms, params);
1764 auto ymesh1 = build_electric_efield<T, ::pic::mesh<T>::center> (x, ion, mesh, norms, params);
1765 auto ymesh2 = build_electric_efield<T, ::pic::mesh<T>::high> (x, ion, mesh, norms, params);
1766
1767 return weights[0]*ymesh0 + weights[1]*ymesh1 + weights[2]*ymesh2;
1768 }
1769
1770//------------------------------------------------------------------------------
1781//------------------------------------------------------------------------------
1782 template<std::floating_point T>
1783 std::array<graph::shared_leaf<T>, 3> build_F_expressions(const std::array<graph::shared_leaf<T>, 3> z,
1784 const ion<T> &ion,
1785 const mesh<T> &mesh,
1786 const characteristics<T> &norms,
1787 const parameters<T> &params) {
1788 auto bfield = build_magnetic_field<T> (z[0], norms, params);
1789 auto efield = build_interpolate_efield<T> (z[0], ion, mesh, norms, params);
1790 auto temp = 0.5*z[2]*z[1]*bfield->df(z[0])/bfield;
1791 return {
1792 z[1]*params.dt,
1793 temp*params.dt,
1794 (ion.charge/ion.mass*norms.m*efield - temp)*params.dt
1795 };
1796 }
1797
1798//------------------------------------------------------------------------------
1808//------------------------------------------------------------------------------
1809 template<std::floating_point T>
1810 std::array<graph::shared_leaf<T>, 3> build_rk4_step(const ion<T> &ion,
1811 const mesh<T> &mesh,
1812 const characteristics<T> &norms,
1813 const parameters<T> &params) {
1814// Step 1
1815 std::array<graph::shared_leaf<T>, 3> Z1{ion.x, ion.v_para, ion.v_perp};
1816 std::array<graph::shared_leaf<T>, 3> dZ1(build_F_expressions<T> (Z1, ion, mesh, norms, params));
1817
1818// Step 2
1819 std::array<graph::shared_leaf<T>, 3> Z2{
1820 Z1[0] + dZ1[0]/static_cast<T> (2),
1821 Z1[1] + dZ1[1]/static_cast<T> (2),
1822 Z1[2] + dZ1[2]/static_cast<T> (2)
1823 };
1824 std::array<graph::shared_leaf<T>, 3> dZ2(build_F_expressions<T> (Z2, ion, mesh, norms, params));
1825
1826// Step 3
1827 std::array<graph::shared_leaf<T>, 3> Z3{
1828 Z1[0] + dZ2[0]/static_cast<T> (2),
1829 Z1[1] + dZ2[1]/static_cast<T> (2),
1830 Z1[2] + dZ2[2]/static_cast<T> (2)
1831 };
1832 std::array<graph::shared_leaf<T>, 3> dZ3(build_F_expressions<T> (Z3, ion, mesh, norms, params));
1833
1834// Step 4
1835 std::array<graph::shared_leaf<T>, 3> Z4{
1836 Z1[0] + dZ3[0],
1837 Z1[1] + dZ3[1],
1838 Z1[2] + dZ3[2]
1839 };
1840 std::array<graph::shared_leaf<T>, 3> dZ4(build_F_expressions<T> (Z4, ion, mesh, norms, params));
1841
1842// Rk4 Solution
1843 return {
1844 Z1[0] + (dZ1[0] + static_cast<T> (2)*(dZ2[0] + dZ3[0]) + dZ4[0])/static_cast<T> (6),
1845 Z1[1] + (dZ1[1] + static_cast<T> (2)*(dZ2[1] + dZ3[1]) + dZ4[1])/static_cast<T> (6),
1846 Z1[2] + (dZ1[2] + static_cast<T> (2)*(dZ2[2] + dZ3[2]) + dZ4[2])/static_cast<T> (6)
1847 };
1848 }
1849}
1850
1851#endif /* particle_in_cell_h */
Class representing a generic buffer.
Definition backend.hpp:29
U Collision node.
Definition particle_in_cell.hpp:28
virtual shared_leaf< T > remove_pseudo()
Remove pseudo variable nodes.
Definition particle_in_cell.hpp:297
virtual shared_leaf< T > compile(std::ostringstream &stream, jit::register_map &registers, const jit::register_map &thread_mem, const jit::register_usage &usage)
Compile the node.
Definition particle_in_cell.hpp:226
virtual shared_leaf< T > reduce()
Reduce the apply_u(x, i, rand, mof, tbnu_e_dt, A, B).
Definition particle_in_cell.hpp:144
virtual backend::buffer< T > evaluate()
Evaluate the results of the applying the u operator.
Definition particle_in_cell.hpp:126
virtual shared_leaf< T > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition particle_in_cell.hpp:317
apply_u_node(shared_leaf< T > x, shared_leaf< T > i, shared_leaf< T > rand, shared_leaf< T > mof, shared_leaf< T > tbnu_e_dt, shared_leaf< T > A, shared_leaf< T > B)
Construct an apply_u_node.
Definition particle_in_cell.hpp:110
virtual void to_latex() const
Convert the node to latex.
Definition particle_in_cell.hpp:282
virtual bool is_match(shared_leaf< T > x)
Query if the nodes match.
Definition particle_in_cell.hpp:262
virtual void compile_preamble(std::ostringstream &stream, jit::register_map &registers, jit::visiter_map &visited, jit::register_usage &usage, jit::texture1d_list &textures1d, jit::texture2d_list &textures2d, jit::preamble_map &pre_funcs, int &avail_const_mem)
Compile preamble.
Definition particle_in_cell.hpp:160
Xi Collision node.
Definition particle_in_cell.hpp:402
virtual void to_latex() const
Convert the node to latex.
Definition particle_in_cell.hpp:623
virtual shared_leaf< T > reduce()
Reduce the apply_zi(x, i, rand, nu_D_dt).
Definition particle_in_cell.hpp:497
virtual shared_leaf< T > remove_pseudo()
Remove pseudo variable nodes.
Definition particle_in_cell.hpp:638
apply_xi_node(shared_leaf< T > x, shared_leaf< T > i, shared_leaf< T > rand, shared_leaf< T > nu_D_dt)
Construct an apply_xi_node.
Definition particle_in_cell.hpp:469
virtual void compile_preamble(std::ostringstream &stream, jit::register_map &registers, jit::visiter_map &visited, jit::register_usage &usage, jit::texture1d_list &textures1d, jit::texture2d_list &textures2d, jit::preamble_map &pre_funcs, int &avail_const_mem)
Compile preamble.
Definition particle_in_cell.hpp:513
virtual bool is_match(shared_leaf< T > x)
Query if the nodes match.
Definition particle_in_cell.hpp:603
virtual shared_leaf< T > compile(std::ostringstream &stream, jit::register_map &registers, const jit::register_map &thread_mem, const jit::register_usage &usage)
Compile the node.
Definition particle_in_cell.hpp:573
virtual backend::buffer< T > evaluate()
Evaluate the results of the applying the xi operator.
Definition particle_in_cell.hpp:482
virtual shared_leaf< T > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition particle_in_cell.hpp:655
Class representing a node leaf.
Definition node.hpp:371
virtual void endline(std::ostringstream &stream, const jit::register_usage &usage, const char end=';') const
End a line in the kernel source.
Definition node.hpp:653
virtual bool has_pseudo() const
Query if the node contains pseudo variables.
Definition node.hpp:633
Class representing a N branch node.
Definition node.hpp:1571
std::array< shared_leaf< T, SAFE_MATH >, N > branches
Branches of the tree.
Definition node.hpp:1574
Nodes without derivatives.
Definition node.hpp:1713
Class representing a netcdf dataset.
Definition output.hpp:166
void create_variable(const result_file &result, const std::string &name, graph::shared_leaf< T, SAFE_MATH > &node, jit::context< T, SAFE_MATH > &context)
Create a variable.
Definition output.hpp:260
Class representing a netcdf based output file.
Definition output.hpp:32
Characteristic factors.
Definition particle_in_cell.hpp:757
const T bfield
Magnetic field;.
Definition particle_in_cell.hpp:807
const T m
Mass.
Definition particle_in_cell.hpp:789
const T ne
Electron density.
Definition particle_in_cell.hpp:793
const T v
Velocity.
Definition particle_in_cell.hpp:801
const T wpe
Plasma Frequency.
Definition particle_in_cell.hpp:795
const T l
Length.
Definition particle_in_cell.hpp:799
T get_volume() const
Get the characteristic volume.
Definition particle_in_cell.hpp:829
const T te
Electron temperature;.
Definition particle_in_cell.hpp:803
const T efield
Electric field;.
Definition particle_in_cell.hpp:805
const T t
Time.
Definition particle_in_cell.hpp:797
const T q
Charge.
Definition particle_in_cell.hpp:791
characteristics(const std::vector< T > &ion_masses, const std::vector< uint8_t > &ion_zs, const T ne)
Construct the characteristics.
Definition particle_in_cell.hpp:816
ion class.
Definition particle_in_cell.hpp:885
graph::shared_variable< T > get_v_para() const
Get x case as variable.
Definition particle_in_cell.hpp:961
const uint8_t z
Atomic number.
Definition particle_in_cell.hpp:888
graph::shared_leaf< T > v_perp
Normalized Perpendicular velocity.
Definition particle_in_cell.hpp:898
graph::shared_leaf< T > build_profile(std::function< graph::shared_leaf< T >(graph::shared_leaf< T >)> func) const
Build a profile.
Definition particle_in_cell.hpp:1027
graph::shared_variable< T > get_x() const
Get x case as variable.
Definition particle_in_cell.hpp:934
graph::shared_leaf< T > x
Normalized Position.
Definition particle_in_cell.hpp:894
T * v_para_data() const
Get the data for the parallel velocity.
Definition particle_in_cell.hpp:970
size_t size() const
Get the number of computational ions.
Definition particle_in_cell.hpp:943
T * v_perp_data() const
Get the data for the perpendicular velocity.
Definition particle_in_cell.hpp:988
void define_variables(const output::result_file &file, output::data_set< T > &data, workflow::manager< T > &work, const std::string tag)
Define variables.
Definition particle_in_cell.hpp:1010
const T mass
Particle mass.
Definition particle_in_cell.hpp:892
const T num_real
Number of real particles.
Definition particle_in_cell.hpp:902
graph::shared_variable< T > get_v_perp() const
Get x case as variable.
Definition particle_in_cell.hpp:979
T * x_data() const
Get the data for x.
Definition particle_in_cell.hpp:952
T super_to_real() const
Conversion factor from super particles to real particles.
Definition particle_in_cell.hpp:997
ion(const T mass, const uint8_t z, const size_t num_ions, const T num_real, const characteristics< T > &norms)
Construct an ion object.
Definition particle_in_cell.hpp:913
graph::shared_leaf< T > v_para
Normalized Parallel velocity.
Definition particle_in_cell.hpp:896
const T charge
Charge.
Definition particle_in_cell.hpp:890
std::array< graph::shared_leaf< T >, 3 > weights
Mesh Weights.
Definition particle_in_cell.hpp:900
Mesh class.
Definition particle_in_cell.hpp:1038
graph::shared_leaf< T > build_i_index(graph::shared_leaf< T > x) const
Build i index.
Definition particle_in_cell.hpp:1122
graph::shared_leaf< T > build_y_index(graph::shared_leaf< T > x, const parameters< T > &params) const
Build y index.
Definition particle_in_cell.hpp:1137
offset
Mesh point.
Definition particle_in_cell.hpp:1077
@ high
Higher index.
Definition particle_in_cell.hpp:1083
@ center
Center index.
Definition particle_in_cell.hpp:1081
@ low
Lower index.
Definition particle_in_cell.hpp:1079
graph::shared_leaf< T > build_x_index(graph::shared_leaf< T > x) const
Build x index.
Definition particle_in_cell.hpp:1112
std::array< graph::shared_leaf< T >, 3 > build_mesh_solve(const ion< T > &ion) const
Build mesh accumulation.
Definition particle_in_cell.hpp:1192
const T xmax
Max x.
Definition particle_in_cell.hpp:1071
T * data() const
Get the number of computational ions.
Definition particle_in_cell.hpp:1220
graph::shared_leaf< T > build_dydx_index(graph::shared_leaf< T > x, const parameters< T > &params) const
Build dy/dx index.
Definition particle_in_cell.hpp:1162
void define_variables(const output::result_file &file, output::data_set< T > &data, workflow::manager< T > &work)
Define variables.
Definition particle_in_cell.hpp:1232
std::array< graph::shared_leaf< T >, 4 > y
Mesh y values.
Definition particle_in_cell.hpp:1075
graph::shared_leaf< T > build_interpolation(graph::shared_leaf< T > x) const
Build interpolation expression.
Definition particle_in_cell.hpp:1266
mesh(const T x_min, const T x_max, const size_t num, const characteristics< T > &norms)
Construct a mesh object.
Definition particle_in_cell.hpp:1094
std::array< graph::shared_leaf< T >, 3 > build_weights(graph::shared_leaf< T > x) const
Build interpolation weights.
Definition particle_in_cell.hpp:1247
const T dx
Dx.
Definition particle_in_cell.hpp:1073
const T xmin
Min x.
Definition particle_in_cell.hpp:1069
size_t size() const
Get the number of computational ions.
Definition particle_in_cell.hpp:1208
Parameter Class.
Definition particle_in_cell.hpp:838
const T a0
Geometry.
Definition particle_in_cell.hpp:843
parameters(const T b0, const T r1, const T r2, const size_t filter_iterations, const T smoothing, const T dt, const T t_para, const T t_perp, const characteristics< T > &norms)
Construct a parameters object.
Definition particle_in_cell.hpp:866
const T b0
Initial magnetic field.
Definition particle_in_cell.hpp:841
const T t_para
Parallel temperature.
Definition particle_in_cell.hpp:851
const T dt
Time step.
Definition particle_in_cell.hpp:849
const size_t filter_iterations
Filter Iterations.
Definition particle_in_cell.hpp:845
const T t_perp
Perpendicular temperature.
Definition particle_in_cell.hpp:853
const T smoothing
Smoothing parameters.
Definition particle_in_cell.hpp:847
Class representing a workflow manager.
Definition workflow.hpp:400
jit::context< T, SAFE_MATH > & get_context()
Get the jit context.
Definition workflow.hpp:722
subroutine assert(test, message)
Assert check.
Definition f_binding_test.f90:38
Nodes for boolean logic.
Name space for graph nodes.
Definition arithmetic.hpp:13
shared_leaf< T > apply_u(shared_leaf< T > x, shared_leaf< T > i, shared_leaf< T > rand, shared_leaf< T > mof, shared_leaf< T > tbnu_e_dt, shared_leaf< T > A, shared_leaf< T > B)
Build apply_u node.
Definition particle_in_cell.hpp:350
shared_leaf< T, SAFE_MATH > log(shared_leaf< T, SAFE_MATH > x)
Define log convenience function.
Definition math.hpp:797
shared_leaf< T, SAFE_MATH > isnan(shared_leaf< T, SAFE_MATH > arg)
Build isnan node from the argument leaves.
Definition logical.hpp:326
constexpr shared_leaf< T, SAFE_MATH > zero()
Forward declare for zero.
Definition node.hpp:1154
shared_leaf< T > apply_xi(shared_leaf< T > x, shared_leaf< T > i, shared_leaf< T > rand, shared_leaf< T > nu_D_dt)
Build apply_xi node.
Definition particle_in_cell.hpp:685
std::shared_ptr< variable_node< T, SAFE_MATH > > shared_variable
Convenience type alias for shared variable nodes.
Definition node.hpp:2146
std::shared_ptr< apply_xi_node< T > > shared_apply_xi
Convenience type alias for shared sqrt nodes.
Definition particle_in_cell.hpp:711
shared_leaf< T, SAFE_MATH > atomic_accumulate_1D(shared_leaf< T, SAFE_MATH > v, shared_leaf< T, SAFE_MATH > i, shared_leaf< T, SAFE_MATH > x)
Define atomic_accumulate_1D convenience function.
Definition piecewise.hpp:2362
shared_apply_xi< T > apply_xi_cast(shared_leaf< T > x)
Cast to a apply_u node.
Definition particle_in_cell.hpp:722
shared_leaf< T, SAFE_MATH > index_1D(shared_leaf< T, SAFE_MATH > v, shared_leaf< T, SAFE_MATH > x)
Define index_1D convenience function.
Definition piecewise.hpp:1712
shared_leaf< T, SAFE_MATH > erf(shared_leaf< T, SAFE_MATH > x)
Define erf convenience function.
Definition math.hpp:1649
shared_leaf< T, SAFE_MATH > copysign(shared_leaf< T, SAFE_MATH > l, shared_leaf< T, SAFE_MATH > r)
Build copysign node.
Definition math.hpp:2532
shared_apply_u< T > apply_u_cast(shared_leaf< T > x)
Cast to a apply_u node.
Definition particle_in_cell.hpp:390
std::shared_ptr< random_state_node< T, SAFE_MATH > > shared_random_state
Convenience type alias for shared sqrt nodes.
Definition random.hpp:269
shared_variable< T, SAFE_MATH > variable_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a variable node.
Definition node.hpp:2169
constexpr T i
Convenience type for imaginary constant.
Definition node.hpp:1186
shared_leaf< T, SAFE_MATH > if_(shared_leaf< T, SAFE_MATH > c, shared_leaf< T, SAFE_MATH > t, shared_leaf< T, SAFE_MATH > f)
Build an if node from a condition and two leaves.
Definition logical.hpp:2963
shared_leaf< T, SAFE_MATH > constant(const backend::buffer< T > &d)
Construct a constant.
Definition node.hpp:1111
shared_leaf< T, SAFE_MATH > sin(shared_leaf< T, SAFE_MATH > x)
Define sine convenience function.
Definition trigonometry.hpp:225
shared_leaf< T, SAFE_MATH > sqrt(shared_leaf< T, SAFE_MATH > x)
Define sqrt convenience function.
Definition math.hpp:297
shared_leaf< T, SAFE_MATH > min(shared_leaf< T, SAFE_MATH > l, shared_leaf< T, SAFE_MATH > r)
Build a max node from a condition and two leaves.
Definition logical.hpp:3266
std::shared_ptr< leaf_node< T, SAFE_MATH > > shared_leaf
Convenience type alias for shared leaf nodes.
Definition node.hpp:691
shared_leaf< T, SAFE_MATH > isinf(shared_leaf< T, SAFE_MATH > arg)
Build not node from the argument leaves.
Definition logical.hpp:157
shared_leaf< T, SAFE_MATH > cos(shared_leaf< T, SAFE_MATH > x)
Define cosine convenience function.
Definition trigonometry.hpp:479
shared_leaf< T, SAFE_MATH > hypot(shared_leaf< T, SAFE_MATH > l, shared_leaf< T, SAFE_MATH > r)
Build hypot node.
Definition math.hpp:2222
shared_leaf< T, SAFE_MATH > argument(shared_leaf< T, SAFE_MATH > x, const T scale, const T offset, const size_t length)
Define argument convenience function.
Definition piecewise.hpp:308
std::shared_ptr< apply_u_node< T > > shared_apply_u
Convenience type alias for shared sqrt nodes.
Definition particle_in_cell.hpp:379
std::unordered_set< void * > visiter_map
Type alias for listing visited nodes.
Definition register.hpp:263
std::string format_to_string(const T value)
Convert a value to a string while avoiding locale.
Definition register.hpp:213
std::unordered_map< void *, size_t > register_usage
Type alias for counting register usage.
Definition register.hpp:261
std::unordered_set< std::string > preamble_map
Type alias for preamble defined functions.
Definition register.hpp:269
std::unordered_map< void *, std::string > register_map
Type alias for mapping node pointers to register names.
Definition register.hpp:259
std::unordered_map< void *, std::array< size_t, 2 > > texture2d_list
Type alias for indexing 2D textures.
Definition register.hpp:267
std::unordered_map< void *, size_t > texture1d_list
Type alias for indexing 1D textures.
Definition register.hpp:265
std::string to_string(const char prefix, const NODE *pointer)
Convert a graph::leaf_node pointer to a string.
Definition register.hpp:247
graph::shared_leaf< T > build_interpolate_efield(graph::shared_leaf< T > x, const ion< T > &ion, const mesh< T > &mesh, const characteristics< T > &norms, const parameters< T > &params)
Build interpolation expression.
Definition particle_in_cell.hpp:1756
constexpr T kb
Boltzman constant.
Definition particle_in_cell.hpp:749
graph::shared_leaf< T > build_magnetic_field(graph::shared_leaf< T > x, const characteristics< T > &norms, const parameters< T > &params)
Build a magnetic field.
Definition particle_in_cell.hpp:1622
std::array< graph::shared_leaf< T >, 2 > build_ion_electron_collision(const ion< T > &ion_a, const mesh< T > &mesh, const characteristics< T > &norms, const parameters< T > &params, graph::shared_leaf< T > total_density, graph::shared_leaf< T > total_flux, const graph::shared_random_state< T > state)
Build ion electron collision.
Definition particle_in_cell.hpp:1420
std::array< graph::shared_leaf< T >, 2 > build_common_collision(const ion< T > &ion_a, const characteristics< T > &norms, graph::shared_leaf< T > uxb, graph::shared_leaf< T > tb, graph::shared_leaf< T > nb, const T mass_b, const uint8_t zb2, const T dt, const graph::shared_random_state< T > state)
Build common collisions graphs for all species.
Definition particle_in_cell.hpp:1460
constexpr T epsilon0
Vacuum permitivity F/m.
Definition particle_in_cell.hpp:734
std::array< graph::shared_leaf< T >, 3 > build_F_expressions(const std::array< graph::shared_leaf< T >, 3 > z, const ion< T > &ion, const mesh< T > &mesh, const characteristics< T > &norms, const parameters< T > &params)
Build F expressions.
Definition particle_in_cell.hpp:1783
graph::shared_leaf< T > build_colision_rate(graph::shared_leaf< T > xab, const T mass_a, const T mass_b, graph::shared_leaf< T > gb, graph::shared_leaf< T > nuab0, graph::shared_leaf< T > erfp_xab)
Calculate ν_{E}.
Definition particle_in_cell.hpp:1341
std::array< graph::shared_leaf< T >, 3 > cartesian_to_sphereical(graph::shared_leaf< T > x, graph::shared_leaf< T > y)
Convert from cartesian to sphereical coordinates.
Definition particle_in_cell.hpp:1287
constexpr T q
Fundamental charge coulombs.
Definition particle_in_cell.hpp:737
graph::shared_leaf< T > build_density(graph::shared_leaf< T > x, const ion< T > &ion, const mesh< T > &mesh, const characteristics< T > &norms, const parameters< T > &params)
Build expressions for the density.
Definition particle_in_cell.hpp:1644
graph::shared_leaf< T > build_electron_temperature(graph::shared_leaf< T > x, const characteristics< T > &norms)
Build Expressions for Electron temperature.
Definition particle_in_cell.hpp:1700
std::array< graph::shared_leaf< T >, 3 > build_rk4_step(const ion< T > &ion, const mesh< T > &mesh, const characteristics< T > &norms, const parameters< T > &params)
Build Runga Kutta step update.
Definition particle_in_cell.hpp:1810
std::array< graph::shared_leaf< T >, 2 > sphereical_to_cartesian(graph::shared_leaf< T > w, graph::shared_leaf< T > xi, graph::shared_leaf< T > sinphi)
Convert from sphereical to cartesian coordinates.
Definition particle_in_cell.hpp:1307
constexpr T m_atomic
Atomic mass.
Definition particle_in_cell.hpp:743
std::array< graph::shared_leaf< T >, 2 > build_ion_ion_collision(const ion< T > &ion_a, const ion< T > &ion_b, const mesh< T > &mesh, const characteristics< T > &norms, const parameters< T > &params, graph::shared_leaf< T > total_density, graph::shared_leaf< T > total_flux, const graph::shared_random_state< T > state)
Build ion ion collision.
Definition particle_in_cell.hpp:1372
model
Model for coulomb scattering operators.
Definition particle_in_cell.hpp:1319
@ hinton
From Hinton 1983 EQ 92 and T.S. Chen 1988 EQ 50.
Definition particle_in_cell.hpp:1321
@ chen
From T.S. Chen 1988 Report EQ 57 commonly used for NBI.
Definition particle_in_cell.hpp:1323
std::array< graph::shared_leaf< T >, 3 > build_initialization(const pic::ion< T > &ion, const mesh< T > &mesh, const characteristics< T > &norms, const parameters< T > &params, const graph::shared_random_state< T > state)
Build initialization.
Definition particle_in_cell.hpp:1539
std::array< graph::shared_leaf< T >, 3 > build_reinjection(const ion< T > &ion, const mesh< T > &mesh, const characteristics< T > &norms, const parameters< T > &params, const graph::shared_random_state< T > state)
Build reinjected expressions.
Definition particle_in_cell.hpp:1591
graph::shared_leaf< T > build_electric_efield(graph::shared_leaf< T > x, const ion< T > &ion, const mesh< T > &mesh, const characteristics< T > &norms, const parameters< T > &params)
Build expressions for the electric field.
Definition particle_in_cell.hpp:1718
constexpr T c
Speed of light m/s.
Definition particle_in_cell.hpp:731
constexpr T m_hydrogen
Hydrogen mass kg.
Definition particle_in_cell.hpp:740
constexpr T m_electron
Electron mass kg.
Definition particle_in_cell.hpp:746
graph::shared_leaf< T > build_density_gradient(graph::shared_leaf< T > x, const ion< T > &ion, const mesh< T > &mesh, const characteristics< T > &norms, const parameters< T > &params)
Build expressions for the density gradient.
Definition particle_in_cell.hpp:1675
Piecewise nodes.
Random constants and distributions.
Classes to manage workflows,.