LCOV - code coverage report
Current view: top level - src/userobjects - BoundingBoxParticleInitializer.C (source / functions) Hit Total Coverage
Test: idaholab/salamander: d3fcc7 Lines: 69 70 98.6 %
Date: 2025-08-11 14:54:34 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of SALAMANDER: Software for Advanced Large-scale Analysis of MAgnetic
       2             : //* confinement for Numerical Design, Engineering & Research,
       3             : //* A multiphysics application for modeling plasma facing components
       4             : //* https://github.com/idaholab/salamander
       5             : //* https://mooseframework.inl.gov/salamander
       6             : //*
       7             : //* SALAMANDER is powered by the MOOSE Framework
       8             : //* https://www.mooseframework.inl.gov
       9             : //*
      10             : //* Licensed under LGPL 2.1, please see LICENSE for details
      11             : //* https://www.gnu.org/licenses/lgpl-2.1.html
      12             : //*
      13             : //* Copyright 2025, Battelle Energy Alliance, LLC
      14             : //* ALL RIGHTS RESERVED
      15             : //*
      16             : 
      17             : #include "BoundingBoxParticleInitializer.h"
      18             : #include "MooseRandom.h"
      19             : #include "ElementSampler.h"
      20             : #include "VelocityInitializerBase.h"
      21             : 
      22             : registerMooseObject("SalamanderApp", BoundingBoxParticleInitializer);
      23             : 
      24             : InputParameters
      25         275 : BoundingBoxParticleInitializer::validParams()
      26             : {
      27         275 :   auto params = PerElementParticleInitializer::validParams();
      28         275 :   params.addClassDescription(
      29             :       "This initializer performs the same task as [PerElementParticleInitializer.md], however, "
      30             :       "only particles that exist within the bounding box are created.");
      31         550 :   params.addRequiredParam<Point>("bottom_left", "The bottom left corner of the bounding box");
      32         550 :   params.addRequiredParam<Point>("top_right", "The top right corner of the bounding box");
      33             : 
      34         275 :   return params;
      35           0 : }
      36             : 
      37         139 : BoundingBoxParticleInitializer::BoundingBoxParticleInitializer(const InputParameters & parameters)
      38             :   : PerElementParticleInitializer(parameters),
      39         139 :     _bottom_left(getParam<Point>("bottom_left")),
      40         278 :     _top_right(getParam<Point>("top_right")),
      41        1112 :     _planes({{-1, 0, 0, _bottom_left(0)},
      42         139 :              {1, 0, 0, -_top_right(0)},
      43         139 :              {0, -1, 0, _bottom_left(1)},
      44         139 :              {0, 1, 0, -_top_right(1)},
      45         139 :              {0, 0, -1, _bottom_left(2)},
      46         139 :              {0, 0, 1, -_top_right(2)}})
      47             : {
      48         464 :   for (const auto i : make_range(_mesh_dimension))
      49         326 :     if (_top_right(i) <= _bottom_left(i))
      50           1 :       paramError("top_right",
      51           2 :                  "Component " + std::to_string(uint(i)) + " of 'top_right' is <= component " +
      52           1 :                      std::to_string(uint(i)) + " of 'bottom_left'");
      53             : 
      54         138 :   if (_mesh_dimension != Moose::dim)
      55         196 :     mooseWarning(std::to_string(uint(Moose::dim)) +
      56             :                  " components are required for libMesh::Point input.\n"
      57          66 :                  "However, your simulation is only " +
      58         130 :                  std::to_string(uint(_mesh_dimension)) +
      59             :                  " dimensional.\n"
      60          66 :                  "The extra component" +
      61         153 :                  std::string(_mesh_dimension == uint(2) ? "s" : "") +
      62             :                  " of the libMesh::Point input will be ignored.\n");
      63         414 : }
      64             : 
      65             : std::vector<InitialParticleData>
      66          91 : BoundingBoxParticleInitializer::getParticleData() const
      67             : {
      68             : 
      69             :   // first collect the elements that we will place particles in
      70             :   std::vector<const Elem *> valid_elems;
      71             : 
      72       28072 :   for (const auto elem : *_fe_problem.mesh().getActiveLocalElementRange())
      73             :   {
      74             :     unsigned int intersection_count = 0;
      75             :     unsigned int nodes_within = 0;
      76             :     bool elem_added = false;
      77             :     // if one of the nodes is in our box or on the edge
      78             :     // of the box then we need to add this to the elements we want
      79             :     // to place particles in
      80      140091 :     for (const auto & node : elem->node_ref_range())
      81             :     {
      82             :       unsigned int dim_valid = 0;
      83             :       // first we can check to see if one node is within the bounding box
      84             :       // this is sufficient for 1D
      85      452706 :       for (const auto i : make_range(_mesh_dimension))
      86             :       {
      87      337571 :         if (node(i) >= _bottom_left(i) && node(i) <= _top_right(i))
      88      119577 :           dim_valid++;
      89             :       }
      90             : 
      91      115135 :       if (dim_valid == _mesh_dimension)
      92             :       {
      93        3025 :         valid_elems.push_back(elem);
      94             :         elem_added = true;
      95             :         break;
      96             :       }
      97             : 
      98             :       // if we are in a higher dimension then we need to check for
      99             :       // elements which intersect the bounding box but do not have
     100             :       // any nodes within the bounding box
     101      112110 :       if (_mesh_dimension > 1)
     102             :       {
     103             :         // checking to see which side of each plane each node is on
     104      769466 :         for (const auto i : make_range(2 * _mesh_dimension))
     105             :         {
     106             :           Real plane_value = 0;
     107     2600688 :           for (const auto j : make_range(_mesh_dimension))
     108     1943228 :             plane_value += node(j) * _planes[i][j];
     109             : 
     110      657460 :           plane_value += _planes[i][3];
     111             : 
     112      657460 :           if (plane_value >= 0)
     113      217890 :             nodes_within++;
     114             :         }
     115      112006 :         if (nodes_within > 1)
     116      103546 :           intersection_count++;
     117             :       }
     118             :     }
     119        3025 :     if (elem_added)
     120        3025 :       continue;
     121             :     // if more than two planes are intersecting the
     122             :     // element then we need to put some particles within it as well
     123       24956 :     if (intersection_count > 1)
     124       24908 :       valid_elems.push_back(elem);
     125             :   }
     126             : 
     127             :   // if there are no elements for this processor: do nothing
     128          91 :   if (valid_elems.size() == 0)
     129           6 :     return {};
     130             : 
     131             :   std::vector<InitialParticleData> data;
     132             :   MooseRandom generator;
     133             :   // this objects allows us to uniformly sample space in elements
     134          85 :   SALAMANDER::ElementSampler sampler = SALAMANDER::ElementSampler(_fe_problem, _seed, generator);
     135       28017 :   for (const auto elem : valid_elems)
     136             :   {
     137             :     // first sample points in the element like we would if this were a uniform initialization
     138             :     // across the whole domain
     139       27933 :     const auto & physical_points = sampler.sampleElement(elem, _particles_per_element);
     140       27932 :     const auto & velocities = _velocity_initializer.getParticleVelocities(_particles_per_element);
     141       27932 :     Real weight = _number_density * elem->volume() / (_particles_per_element);
     142      586572 :     for (const auto i : make_range(_particles_per_element))
     143             :     {
     144             :       // we need to check to make sure that every point we have
     145             :       // created is actually in the bounding box as well
     146             :       unsigned int dim_valid = 0;
     147     2185280 :       for (const auto j : make_range(_mesh_dimension))
     148             :       {
     149     1626640 :         if (physical_points[i](j) >= _bottom_left(j) && physical_points[i](j) <= _top_right(j))
     150      583548 :           dim_valid++;
     151             :       }
     152             :       // if the point is in the box then we can add a particle for this point
     153      558640 :       if (dim_valid == _mesh_dimension)
     154             :       {
     155       22558 :         auto & particle = data.emplace_back();
     156       22558 :         particle.elem = elem;
     157       22558 :         particle.weight = weight;
     158       22558 :         particle.species = _species;
     159       22558 :         particle.mass = _mass;
     160       22558 :         particle.charge = _charge;
     161       22558 :         particle.position = physical_points[i];
     162       22558 :         particle.velocity = velocities[i];
     163             :       }
     164             :     }
     165             :   }
     166             :   return data;
     167         168 : }

Generated by: LCOV version 1.14