Line data Source code
1 : //* This file is part of SALAMANDER: Software for Advanced Large-scale Analysis of MAgnetic confinement for Numerical Design, Engineering & Research, 2 : //* A multiphysics application for modeling plasma facing components 3 : //* https://github.com/idaholab/salamander 4 : //* https://mooseframework.inl.gov/salamander 5 : //* 6 : //* SALAMANDER is powered by the MOOSE Framework 7 : //* https://www.mooseframework.inl.gov 8 : //* 9 : //* Licensed under LGPL 2.1, please see LICENSE for details 10 : //* https://www.gnu.org/licenses/lgpl-2.1.html 11 : //* 12 : //* Copyright 2025, Battelle Energy Alliance, LLC 13 : //* ALL RIGHTS RESERVED 14 : //* 15 : 16 : #include "PerElementParticleInitializer.h" 17 : #include "MooseRandom.h" 18 : #include "ElementSampler.h" 19 : 20 : registerMooseObject("SalamanderApp", PerElementParticleInitializer); 21 : 22 : InputParameters 23 553 : PerElementParticleInitializer::validParams() 24 : { 25 553 : auto params = ParticleInitializerBase::validParams(); 26 553 : params.addClassDescription( 27 : "Particle initializer that uniformly distributes a specified number of particles per " 28 : "element and calculates the corresponding particle weight based on the requested number " 29 : "density, particles per element, and the elements \"volume\"."); 30 1106 : params.addRangeCheckedParam<unsigned int>( 31 : "particles_per_element", 32 : "particles_per_element != 0", 33 : "The number of computational particles that should be placed in each element"); 34 : 35 1106 : params.addRangeCheckedParam<Real>("number_density", 36 : "number_density > 0.0", 37 : "The number density of particles you want to represent"); 38 553 : return params; 39 0 : } 40 : 41 276 : PerElementParticleInitializer::PerElementParticleInitializer(const InputParameters & parameters) 42 : : ParticleInitializerBase(parameters), 43 275 : _number_density(getParam<Real>("number_density")), 44 826 : _particles_per_element(getParam<unsigned int>("particles_per_element")) 45 : { 46 275 : } 47 : 48 : std::vector<InitialParticleData> 49 91 : PerElementParticleInitializer::getParticleData() const 50 : { 51 : 52 : // counting the number of elements this process is responsible for 53 : // this will allow us to allocated data structures of the appropriate length 54 91 : const auto & elem_range = *_fe_problem.mesh().getActiveLocalElementRange(); 55 : const auto num_local_elements = std::distance(elem_range.begin(), elem_range.end()); 56 : // if there are no elements for this processor: do nothing 57 91 : if (num_local_elements == 0) 58 0 : return {}; 59 : 60 : std::vector<InitialParticleData> data = 61 91 : std::vector<InitialParticleData>(num_local_elements * _particles_per_element); 62 : 63 : // random number generator to be used for sampling the elements 64 : MooseRandom generator; 65 91 : SALAMANDER::ElementSampler sampler = SALAMANDER::ElementSampler(_fe_problem, _seed, generator); 66 : // This will store the uniformly distributed points within the reference elements 67 : uint elem_count = 0; 68 4203 : for (const auto elem : *_fe_problem.mesh().getActiveLocalElementRange()) 69 : { 70 : 71 : // now that all of the particle locations have been placed we need to 72 : // set up the data they will need to be made into actual rays 73 4113 : const auto & physical_points = sampler.sampleElement(elem, _particles_per_element); 74 4112 : Real weight = _number_density * elem->volume() / (_particles_per_element); 75 45232 : for (const auto i : make_range(_particles_per_element)) 76 : { 77 41120 : uint particle_index = elem_count * _particles_per_element + i; 78 41120 : data[particle_index].elem = elem; 79 41120 : data[particle_index].weight = weight; 80 41120 : data[particle_index].species = _species; 81 41120 : data[particle_index].mass = _mass; 82 41120 : data[particle_index].charge = _charge; 83 41120 : data[particle_index].position = physical_points[i]; 84 41120 : data[particle_index].velocity = Point(); 85 164480 : for (const auto i : make_range(uint(3))) 86 123360 : data[particle_index].velocity(i) = _velocity_distributions[i]->quantile(generator.rand()); 87 : } 88 4112 : elem_count++; 89 : } 90 : return data; 91 180 : }