laplace2d.cc 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra/examples - Solve Poisson equation in a rectangle, with linear elements.
  3. // (c) Daniel Llorens - 2017
  4. // This library is free software; you can redistribute it and/or modify it under
  5. // the terms of the GNU Lesser General Public License as published by the Free
  6. // Software Foundation; either version 3 of the License, or (at your option) any
  7. // later version.
  8. // Adapted from lsolver/laplace2d.cc by Christian Badura, 1998/05.
  9. // FIXME mult() benchmarks well against the Cish original, but cghs dominates
  10. // the computation and we do much worse against BLAS.
  11. // FIXME ASCII plot like the APL examples do.
  12. #include "ra/ra.hh"
  13. #include "ra/test.hh"
  14. #include "examples/cghs.hh"
  15. #include "ra/test.hh"
  16. #include <numbers>
  17. using std::cout, std::endl;
  18. using ra::sqrm, ra::TestRecorder, ra::Benchmark;
  19. constexpr auto PI = std::numbers::pi_v<double>;
  20. Benchmark::clock::duration tmul(0);
  21. struct StiffMat { double h; };
  22. template <class V, class W>
  23. void mult(StiffMat const & A, V const & v, W & w)
  24. {
  25. auto t0 = Benchmark::clock::now();
  26. auto i = ra::iota(v.len(0)-2, 1);
  27. auto j = ra::iota(v.len(1)-2, 1);
  28. w(i, j) = 4*v(i, j) -v(i-1, j) -v(i, j-1) -v(i+1, j) -v(i, j+1);
  29. tmul += (Benchmark::clock::now()-t0);
  30. }
  31. struct MassMat { double h; };
  32. template <class V, class W>
  33. void mult(MassMat const & M, V const & v, W & w)
  34. {
  35. auto t0 = Benchmark::clock::now();
  36. auto i = ra::iota(v.len(0)-2, 1);
  37. auto j = ra::iota(v.len(1)-2, 1);
  38. w(i, j) = sqrm(M.h) * (v(i, j)/2. + (v(i-1, j) + v(i, j-1) + v(i+1, j) + v(i, j+1) + v(i+1, j+1) + v(i-1, j-1))/12.);
  39. tmul += Benchmark::clock::now()-t0;
  40. }
  41. // problem: -laplace u=f, with solution g
  42. inline double f(double x, double y)
  43. {
  44. return 8.*PI*PI*sin(2.*PI*x)*sin(2.*PI*y);
  45. }
  46. inline double g(double x, double y)
  47. {
  48. return sin(2.*PI*x)*sin(2.*PI*y);
  49. }
  50. int main(int argc, char *argv[])
  51. {
  52. TestRecorder tr(std::cout);
  53. auto t0 = Benchmark::clock::now();
  54. int N = 50;
  55. double EPS = 1e-5;
  56. double h = 1./N;
  57. ra::Big<double, 2> v({N+1, N+1}, 0.), u({N+1, N+1}, 0.), w({N+1, N+1}, 0.), b({N+1, N+1}, 0.);
  58. auto i = ra::iota(N-1, 1);
  59. auto j = ra::iota(N-1, 1);
  60. auto ih = ra::iota(N-1, h, h);
  61. auto jh = ra::iota(N-1, h, h);
  62. v(i, j) = from(g, ih, jh);
  63. w(i, j) = from(f, ih, jh);
  64. StiffMat sm { h };
  65. MassMat mm { h };
  66. mult(mm, w, b);
  67. ra::Big<double, 3> work({3, N+1, N+1}, ra::none);
  68. int its = cghs(sm, b, u, work, EPS);
  69. double max = amax(abs(u-v));
  70. auto ttot = Benchmark::clock::now()-t0;
  71. cout << "total time " << Benchmark::toseconds(ttot)/1e-3 << " " << "ms" << endl;
  72. cout << "mul time " << Benchmark::toseconds(ttot)/1e-3 << " " << "ms" << endl;
  73. tr.info("max ", max).test_le(max, 0.00463);
  74. tr.info("its ", its).test_le(its, 67);
  75. return tr.summary();
  76. }