LCOV - code coverage report
Current view: top level - src/tensor_computes - LBMFixedFirstOrderBC.C (source / functions) Hit Total Coverage
Test: idaholab/swift: #92 (25e020) with base b3cd84 Lines: 0 173 0.0 %
Date: 2025-09-10 17:10:32 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /**********************************************************************/
       2             : /*                    DO NOT MODIFY THIS HEADER                       */
       3             : /*             Swift, a Fourier spectral solver for MOOSE             */
       4             : /*                                                                    */
       5             : /*            Copyright 2024 Battelle Energy Alliance, LLC            */
       6             : /*                        ALL RIGHTS RESERVED                         */
       7             : /**********************************************************************/
       8             : 
       9             : #include "LBMFixedFirstOrderBC.h"
      10             : #include "LatticeBoltzmannProblem.h"
      11             : #include "LatticeBoltzmannStencilBase.h"
      12             : 
      13             : #include <cstdlib>
      14             : 
      15             : using namespace torch::indexing;
      16             : 
      17             : registerMooseObject("SwiftApp", LBMFixedFirstOrderBC);
      18             : 
      19             : InputParameters
      20           0 : LBMFixedFirstOrderBC::validParams()
      21             : {
      22           0 :   InputParameters params = LBMBoundaryCondition::validParams();
      23           0 :   params.addClassDescription("LBMFixedFirstOrderBC object");
      24           0 :   params.addRequiredParam<TensorInputBufferName>("f", "Input buffer distribution function");
      25           0 :   params.addRequiredParam<std::string>("value", "Fixed input velocity");
      26           0 :   params.addParam<bool>("perturb", false, "Whether to perturb first order moment at the boundary");
      27           0 :   return params;
      28           0 : }
      29             : 
      30           0 : LBMFixedFirstOrderBC::LBMFixedFirstOrderBC(const InputParameters & parameters)
      31             :   : LBMBoundaryCondition(parameters),
      32           0 :     _f(getInputBufferByName(getParam<TensorInputBufferName>("f"))),
      33           0 :     _grid_size(_lb_problem.getGridSize()),
      34           0 :     _value(_lb_problem.getConstant<Real>(getParam<std::string>("value"))),
      35           0 :     _perturb(getParam<bool>("perturb"))
      36             : {
      37           0 : }
      38             : 
      39             : void
      40           0 : LBMFixedFirstOrderBC::frontBoundary()
      41             : {
      42           0 :   if (_domain.getDim() == 2)
      43           0 :     mooseError("There is no front boundary in 2 dimensions.");
      44             :   else
      45           0 :     mooseError("Front boundary is not implemented, but it can be replaced by any other boundary by "
      46             :                "rotating the domain.");
      47             : }
      48             : 
      49             : void
      50           0 : LBMFixedFirstOrderBC::backBoundary()
      51             : {
      52           0 :   if (_domain.getDim() == 2)
      53           0 :     mooseError("There is no back boundary in 2 dimensions.");
      54             :   else
      55           0 :     mooseError("Back boundary is not implemented, but it can be replaced by any other boundary by "
      56             :                "rotating the domain.");
      57             : }
      58             : 
      59             : void
      60           0 : LBMFixedFirstOrderBC::leftBoundaryD2Q9()
      61             : {
      62             :   Real deltaU = 0.0;
      63           0 :   torch::Tensor u_x_perturbed = torch::zeros({_grid_size[1], 1}, MooseTensor::floatTensorOptions());
      64             : 
      65           0 :   if (_perturb)
      66             :   {
      67           0 :     deltaU = 1.0e-6 * _value;
      68             :     Real phi = 0.0; // static_cast<Real>(rand()) / static_cast<float>(RAND_MAX) * 2.0 * M_PI;
      69             :     torch::Tensor y_coords =
      70           0 :         torch::arange(0, _grid_size[1], MooseTensor::floatTensorOptions()).unsqueeze(1);
      71           0 :     u_x_perturbed = _value + deltaU * torch::sin(y_coords / _grid_size[1] * 2.0 * M_PI + phi);
      72             :   }
      73             :   else
      74           0 :     u_x_perturbed.fill_(_value);
      75             : 
      76             :   torch::Tensor density =
      77           0 :       1.0 / (1.0 - u_x_perturbed) *
      78           0 :       (_f.index({0, Slice(), Slice(), 0}) + _f.index({0, Slice(), Slice(), 2}) +
      79           0 :        _f.index({0, Slice(), Slice(), 4}) +
      80           0 :        2.0 * (_f.index({0, Slice(), Slice(), 3}) + _f.index({0, Slice(), Slice(), 6}) +
      81           0 :               _f.index({0, Slice(), Slice(), 7})));
      82             : 
      83             :   // axis aligned direction
      84           0 :   const auto & opposite_dir = _stencil._op[_stencil._left[0]];
      85           0 :   _u.index_put_({0, Slice(), Slice(), _stencil._left[0]},
      86           0 :                 _f.index({0, Slice(), Slice(), opposite_dir}) +
      87           0 :                     2.0 / 3.0 * density * u_x_perturbed);
      88             : 
      89             :   // other directions
      90           0 :   for (unsigned int i = 1; i < _stencil._left.size(0); i++)
      91             :   {
      92           0 :     const auto & opposite_dir = _stencil._op[_stencil._left[i]];
      93           0 :     _u.index_put_(
      94           0 :         {0, Slice(), Slice(), _stencil._left[i]},
      95           0 :         _f.index({0, Slice(), Slice(), opposite_dir}) -
      96           0 :             0.5 * _stencil._ey[_stencil._left[i]] *
      97           0 :                 (_f.index({0, Slice(), Slice(), 2}) - _f.index({0, Slice(), Slice(), 4})) +
      98           0 :             1.0 / 6.0 * density * u_x_perturbed);
      99             :   }
     100           0 : }
     101             : 
     102             : void
     103           0 : LBMFixedFirstOrderBC::leftBoundary()
     104             : {
     105           0 :   if (_stencil._q == 9)
     106           0 :     leftBoundaryD2Q9(); // higher order specialization for D2Q9
     107             :   else
     108             :   {
     109           0 :     torch::Tensor density = 1.0 / (1.0 - _value) *
     110           0 :                             (torch::sum(_f.index({0, Slice(), Slice(), -_stencil._neutral_x}), -1) +
     111           0 :                              2 * torch::sum(_f.index({0, Slice(), Slice(), _stencil._right}), -1));
     112             : 
     113           0 :     _u.index_put_({0, Slice(), Slice(), _stencil._left[0]},
     114           0 :                   _f.index({0, Slice(), Slice(), _stencil._right[0]}) +
     115           0 :                       2.0 * _stencil._weights[_stencil._left[0]] / _lb_problem._cs2 * _value *
     116             :                           density);
     117             : 
     118           0 :     for (unsigned int i = 1; i < _stencil._left.size(0); i++)
     119             :     {
     120           0 :       _u.index_put_({0, Slice(), Slice(), _stencil._left[i]},
     121           0 :                     _f.index({0, Slice(), Slice(), _stencil._right[i]}) +
     122           0 :                         2.0 * _stencil._weights[_stencil._left[i]] / _lb_problem._cs2 * _value *
     123             :                             density);
     124             :     }
     125             :   }
     126           0 : }
     127             : 
     128             : void
     129           0 : LBMFixedFirstOrderBC::rightBoundaryD2Q9()
     130             : {
     131           0 :   torch::Tensor density = 1.0 / (1.0 + _value) *
     132           0 :                           (_f.index({_grid_size[0] - 1, Slice(), Slice(), 0}) +
     133           0 :                            _f.index({_grid_size[0] - 1, Slice(), Slice(), 2}) +
     134           0 :                            _f.index({_grid_size[0] - 1, Slice(), Slice(), 4}) +
     135           0 :                            2 * (_f.index({_grid_size[0] - 1, Slice(), Slice(), 1}) +
     136           0 :                                 _f.index({_grid_size[0] - 1, Slice(), Slice(), 5}) +
     137           0 :                                 _f.index({_grid_size[0] - 1, Slice(), Slice(), 8})));
     138             : 
     139             :   // axis aligned direction
     140           0 :   const auto & opposite_dir = _stencil._op[_stencil._left[0]];
     141           0 :   _u.index_put_({_grid_size[0] - 1, Slice(), Slice(), opposite_dir},
     142           0 :                 _f.index({_grid_size[0] - 1, Slice(), Slice(), _stencil._left[0]}) -
     143           0 :                     2.0 / 3.0 * density * _value);
     144             : 
     145             :   // other directions
     146           0 :   for (unsigned int i = 1; i < _stencil._left.size(0); i++)
     147             :   {
     148           0 :     const auto & opposite_dir = _stencil._op[_stencil._left[i]];
     149           0 :     _u.index_put_({_grid_size[0] - 1, Slice(), Slice(), opposite_dir},
     150           0 :                   _f.index({_grid_size[0] - 1, Slice(), Slice(), _stencil._left[i]}) +
     151           0 :                       0.5 * _stencil._ey[opposite_dir] *
     152           0 :                           (_f.index({_grid_size[0] - 1, Slice(), Slice(), 4}) -
     153           0 :                            _f.index({_grid_size[0] - 1, Slice(), Slice(), 2})) -
     154           0 :                       1.0 / 6.0 * density * _value);
     155             :   }
     156           0 : }
     157             : 
     158             : void
     159           0 : LBMFixedFirstOrderBC::rightBoundary()
     160             : {
     161           0 :   if (_stencil._q == 9)
     162           0 :     rightBoundaryD2Q9(); // higher order specialization for D2Q9
     163             :   else
     164             :   {
     165             :     torch::Tensor density =
     166           0 :         1.0 / (1.0 + _value) *
     167           0 :         (torch::sum(_f.index({_grid_size[0] - 1, Slice(), Slice(), -_stencil._neutral_x}), -1) +
     168           0 :          2 * torch::sum(_f.index({_grid_size[0] - 1, Slice(), Slice(), _stencil._left}), -1));
     169             : 
     170           0 :     _u.index_put_({_grid_size[0] - 1, Slice(), Slice(), _stencil._right[0]},
     171           0 :                   _f.index({_grid_size[0] - 1, Slice(), Slice(), _stencil._left[0]}) -
     172           0 :                       2.0 * _stencil._weights[_stencil._right[0]] / _lb_problem._cs2 * _value *
     173             :                           density);
     174             : 
     175           0 :     for (unsigned int i = 1; i < _stencil._right.size(0); i++)
     176             :     {
     177           0 :       _u.index_put_({_grid_size[0] - 1, Slice(), Slice(), _stencil._right[i]},
     178           0 :                     _f.index({_grid_size[0] - 1, Slice(), Slice(), _stencil._left[i]}) -
     179           0 :                         2.0 * _stencil._weights[_stencil._right[i]] / _lb_problem._cs2 * _value *
     180             :                             density);
     181             :     }
     182             :   }
     183           0 : }
     184             : 
     185             : void
     186           0 : LBMFixedFirstOrderBC::bottomBoundaryD2Q9()
     187             : {
     188             :   torch::Tensor density =
     189           0 :       1.0 / (1.0 - _value) *
     190           0 :       (_f.index({Slice(), 0, Slice(), 0}) + _f.index({Slice(), 0, Slice(), 1}) +
     191           0 :        _f.index({Slice(), 0, Slice(), 3}) +
     192           0 :        2 * (_f.index({Slice(), 0, Slice(), 4}) + _f.index({Slice(), 0, Slice(), 7}) +
     193           0 :             _f.index({Slice(), 0, Slice(), 8})));
     194             : 
     195             :   // axis aligned direction
     196           0 :   const auto & opposite_dir = _stencil._op[_stencil._bottom[0]];
     197           0 :   _u.index_put_({Slice(), 0, Slice(), _stencil._bottom[0]},
     198           0 :                 _f.index({Slice(), 0, Slice(), opposite_dir}) + 2.0 / 3.0 * density * _value);
     199             : 
     200             :   // other directions
     201           0 :   for (unsigned int i = 1; i < _stencil._bottom.size(0); i++)
     202             :   {
     203           0 :     const auto & opposite_dir = _stencil._op[_stencil._bottom[i]];
     204           0 :     _u.index_put_(
     205           0 :         {Slice(), 0, Slice(), _stencil._bottom[i]},
     206           0 :         _f.index({Slice(), 0, Slice(), opposite_dir}) -
     207           0 :             0.5 * _stencil._ex[_stencil._bottom[i]] *
     208           0 :                 (_f.index({Slice(), 0, Slice(), 1}) - _f.index({Slice(), 0, Slice(), 3})) +
     209           0 :             1.0 / 6.0 * density * _value);
     210             :   }
     211           0 : }
     212             : 
     213             : void
     214           0 : LBMFixedFirstOrderBC::bottomBoundary()
     215             : {
     216           0 :   if (_stencil._q == 9)
     217           0 :     bottomBoundaryD2Q9();
     218             :   else
     219           0 :     mooseError("Bottom boundary is not implemented, but it can be replaced by another boundary by "
     220             :                "rotating the domain.");
     221           0 : }
     222             : 
     223             : void
     224           0 : LBMFixedFirstOrderBC::topBoundaryD2Q9()
     225             : {
     226           0 :   torch::Tensor density = 1.0 / (1.0 + _value) *
     227           0 :                           (_f.index({Slice(), _grid_size[1] - 1, Slice(), 0}) +
     228           0 :                            _f.index({Slice(), _grid_size[1] - 1, Slice(), 1}) +
     229           0 :                            _f.index({Slice(), _grid_size[1] - 1, Slice(), 3}) +
     230           0 :                            2 * (_f.index({Slice(), _grid_size[1] - 1, Slice(), 2}) +
     231           0 :                                 _f.index({Slice(), _grid_size[1] - 1, Slice(), 5}) +
     232           0 :                                 _f.index({Slice(), _grid_size[1] - 1, Slice(), 6})));
     233             : 
     234             :   // axis aligned direction
     235           0 :   const auto & opposite_dir = _stencil._op[_stencil._bottom[0]];
     236           0 :   _u.index_put_({Slice(), _grid_size[1] - 1, Slice(), opposite_dir},
     237           0 :                 _f.index({Slice(), _grid_size[1] - 1, Slice(), _stencil._bottom[0]}) -
     238           0 :                     2.0 / 3.0 * density * _value);
     239             : 
     240             :   // other directions
     241           0 :   for (unsigned int i = 1; i < _stencil._bottom.size(0); i++)
     242             :   {
     243           0 :     const auto & opposite_dir = _stencil._op[_stencil._bottom[i]];
     244           0 :     _u.index_put_({Slice(), _grid_size[1] - 1, Slice(), opposite_dir},
     245           0 :                   _f.index({Slice(), _grid_size[1] - 1, Slice(), _stencil._bottom[i]}) +
     246           0 :                       0.5 * _stencil._ex[opposite_dir] *
     247           0 :                           (_f.index({Slice(), _grid_size[1] - 1, Slice(), 3}) -
     248           0 :                            _f.index({Slice(), _grid_size[1] - 1, Slice(), 1})) -
     249           0 :                       1.0 / 6.0 * density * _value);
     250             :   }
     251           0 : }
     252             : 
     253             : void
     254           0 : LBMFixedFirstOrderBC::topBoundary()
     255             : {
     256           0 :   if (_stencil._q == 9)
     257           0 :     topBoundaryD2Q9();
     258             :   else
     259           0 :     mooseError("Top boundary is not implemented, but it can be replaced by another boundary by "
     260             :                "rotating the domain.");
     261           0 : }
     262             : 
     263             : void
     264           0 : LBMFixedFirstOrderBC::computeBuffer()
     265             : {
     266           0 :   _u = _u.clone();
     267           0 :   switch (_boundary)
     268             :   {
     269           0 :     case Boundary::top:
     270           0 :       topBoundary();
     271           0 :       break;
     272           0 :     case Boundary::bottom:
     273           0 :       bottomBoundary();
     274           0 :       break;
     275           0 :     case Boundary::left:
     276           0 :       leftBoundary();
     277           0 :       break;
     278           0 :     case Boundary::right:
     279           0 :       rightBoundary();
     280           0 :       break;
     281           0 :     case Boundary::front:
     282           0 :       frontBoundary();
     283           0 :       break;
     284           0 :     case Boundary::back:
     285           0 :       backBoundary();
     286           0 :       break;
     287           0 :     case Boundary::wall:
     288           0 :       wallBoundary();
     289           0 :       break;
     290           0 :     default:
     291           0 :       mooseError("Undefined boundary names");
     292             :   }
     293           0 :   _lb_problem.maskedFillSolids(_u, 0);
     294           0 : }

Generated by: LCOV version 1.14