laplace2d.cc 2.8 KB

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