Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
MCGIDI_sampling.cc
Go to the documentation of this file.
1/*
2# <<BEGIN-copyright>>
3# Copyright 2019, Lawrence Livermore National Security, LLC.
4# This file is part of the gidiplus package (https://github.com/LLNL/gidiplus).
5# gidiplus is licensed under the MIT license (see https://opensource.org/licenses/MIT).
6# SPDX-License-Identifier: MIT
7# <<END-copyright>>
8*/
9
10#include "MCGIDI.hpp"
11
12#ifndef MCGIDI_CrossSectionLinearSubSearch
13 #ifndef MCGIDI_CrossSectionBinarySubSearch
14 #define MCGIDI_CrossSectionBinarySubSearch
15 #endif
16#endif
17
18namespace MCGIDI {
19
20namespace Sampling {
21
22/* *********************************************************************************************************//**
23 * This function returns the index in *a_energies* where *a_energy* lies between the returned index and the next index.
24 * The returned index must lie between a_hashIndices[a_hashIndex] and a_hashIndices[a_hashIndex+1].
25 * If *a_energy* is below the domain of *a_energies*, 0 is returned. If *a_energy* is above the domain of *a_energies*,
26 * the size of *a_energies* minus 2 is returned.
27 * The argument *a_energyFraction* the weight for the energy at the returned index with the next index getting weighting 1 minus
28 * *a_energyFraction*.
29 *
30 * @param a_hashIndex [in] The index in *a_hashIndices* where the index in *a_energy* must be bound by it and the next index in *a_hashIndex*.
31 * @param a_hashIndices [in] The list of hash indices.
32 * @param a_energies [in] The list of energies.
33 * @param a_energy [in] The energy whose index is requested.
34 * @param a_energyFraction [in] This represents the weighting to apply to the two bounding energies.
35 *
36 * @return The index bounding *a_energy* in the member *a_energies*.
37 ***********************************************************************************************************/
38
39LUPI_HOST_DEVICE std::size_t evaluationForHashIndex( std::size_t a_hashIndex, Vector<std::size_t> const &a_hashIndices, double a_energy,
40 Vector<double> const &a_energies, double *a_energyFraction ) {
41
42 *a_energyFraction = 1.0;
43
44 if( a_energy <= a_energies[0] ) return( 0 );
45 if( a_energy >= a_energies.back( ) ) {
46 *a_energyFraction = 0.0;
47 return( ( a_energies.size( ) - 2 ) );
48 }
49
50 std::size_t index1 = a_hashIndices[a_hashIndex];
51
52#ifdef MCGIDI_CrossSectionLinearSubSearch
53 while( a_energies[index1] > a_energy ) --index1; // Make sure the calls gave the correct *a_hashIndex*.
54 while( a_energies[index1] < a_energy ) ++index1;
55 --index1;
56#endif
57
58#ifdef MCGIDI_CrossSectionBinarySubSearch
59 std::size_t index2 = a_hashIndices[a_hashIndex];
60 std::size_t index3 = a_energies.size( ) - 1;
61 if( ( a_hashIndex + 1 ) < a_hashIndices.size( ) ) index3 = a_hashIndices[a_hashIndex+1] + 1;
62 if( index3 == a_energies.size( ) ) --index3;
63 if( index2 != index3 ) index2 = static_cast<std::size_t>( binarySearchVectorBounded( a_energy, a_energies, index2, index3, false ) );
64#endif
65
66#ifdef MCGIDI_CrossSectionBinarySubSearch
67 #ifdef MCGIDI_CrossSectionLinearSubSearch
68 if( index1 != index2 ) {
69 std::cerr << "Help " << index1 << " " << index2 << std::endl;
70 }
71 #endif
72 index1 = index2;
73#endif
74
75 *a_energyFraction = ( a_energies[index1+1] - a_energy ) / ( a_energies[index1+1] - a_energies[index1] );
76
77 return( index1 );
78}
79
80namespace Upscatter {
81
82/*! \class ModelDBRC_data
83 * This class is used to store the cross section for the elastic scattering upscatter model B with Doppler Broadening
84 * Rejection Correction (DBRC) with enum MCGIDI::Sampling::Upscatter::DBRC.
85 */
86
87/* *********************************************************************************************************//**
88 *
89 ***********************************************************************************************************/
90
99
100/* *********************************************************************************************************//**
101 *
102 ***********************************************************************************************************/
103
104LUPI_HOST ModelDBRC_data::ModelDBRC_data( double a_neutronMass, double a_targetMass, Vector<double> const &a_energies, Vector<double> const &a_crossSections,
105 DomainHash const &a_domainHash ) :
106 m_neutronMass( a_neutronMass ),
107 m_targetMass( a_targetMass ),
108 m_energies( a_energies ),
109 m_crossSections( a_crossSections ),
110 m_hashIndices( a_domainHash.map( a_energies ) ),
111 m_domainHash( 4000, 1e-8, 10 ) {
112
113}
114
115/* *********************************************************************************************************//**
116 ***********************************************************************************************************/
117
121
122/* *********************************************************************************************************//**
123 * This method returns the cross section evaluate at the projectile speed *a_speed*.
124 *
125 * @param a_temperature [in] The temperature of the target.
126 *
127 * @return The thermal speed of the target.
128 ***********************************************************************************************************/
129
131
132 double energyFraction;
133 std::size_t hashIndex = m_domainHash.index( a_energy );
134 std::size_t index = evaluationForHashIndex( hashIndex, m_hashIndices, a_energy, m_energies, &energyFraction );
135
136 return( energyFraction * m_crossSections[index] + ( 1.0 - energyFraction ) * m_crossSections[index+1] );
137}
138
139/* *********************************************************************************************************//**
140 * This method returns the thermal speed of the target with temperature *a_temperature*.
141 *
142 * @param a_temperature [in] The temperature of the target.
143 *
144 * @return The thermal speed of the target.
145 ***********************************************************************************************************/
146
148
149 return( sqrt( 2.0 * a_temperature / m_targetMass ) );
150}
151
152/* *********************************************************************************************************//**
153 * This method sets *a_crossSectionMin* and *a_crossSectionMax* to the minimum and maximum cross section values
154 * for the cross section in the window (*a_speed* - 4 * *a_targetThermalSpeed*) < speed < (*a_speed* + 4 * *a_targetThermalSpeed*).
155 * If (a_speed - 4 * a_targetThermalSpeed) is less than the lowest speed in the data, then it is replaced with the
156 * lowest speed.
157 *
158 * @param a_energy [in] The energy of the projectile (i.e., incident neutron).
159 * @param a_targetThermalSpeed [in] The thermal speed of the target.
160 *
161 * @return The maximum cross section in the search window.
162 ***********************************************************************************************************/
163
164LUPI_HOST_DEVICE double ModelDBRC_data::crossSectionMax( double a_energy, double a_targetThermalSpeed ) {
165
166 double crossSectionMax2 = 0.0;
167 double energyFraction;
168 double a_speed = MCGIDI_particleBeta( m_neutronMass, a_energy );
169
170 double speedMin = a_speed - 4 * a_targetThermalSpeed;
171 if( speedMin < 0.0 ) speedMin = 0.0;
172 double energyMin = 0.5 * m_neutronMass * speedMin * speedMin;
173 std::size_t hashIndex = m_domainHash.index( energyMin );
174 std::size_t indexMin = evaluationForHashIndex( hashIndex, m_hashIndices, energyMin, m_energies, &energyFraction );
175
176 double speedMax = a_speed + 4 * a_targetThermalSpeed;
177 double energyMax = 0.5 * m_neutronMass * speedMax * speedMax;
178 hashIndex = m_domainHash.index( energyMax );
179 std::size_t indexMax = evaluationForHashIndex( hashIndex, m_hashIndices, energyMax, m_energies, &energyFraction );
180 if( indexMax < m_energies.size( ) ) ++indexMax;
181
182 for( std::size_t index = indexMin; index < indexMax; ++index ) {
183 if( crossSectionMax2 < m_crossSections[index] ) crossSectionMax2 = m_crossSections[index];
184 }
185
186 return( crossSectionMax2 );
187}
188
189/* *********************************************************************************************************//**
190 * This method serializes *this* for broadcasting as needed for MPI and GPUs. The method can count the number of required
191 * bytes, pack *this* or unpack *this* depending on *a_mode*.
192 *
193 * @param a_buffer [in] The buffer to read or write data to depending on *a_mode*.
194 * @param a_mode [in] Specifies the action of this method.
195 ***********************************************************************************************************/
196
198
199 DATA_MEMBER_DOUBLE( m_neutronMass, a_buffer, a_mode );
200 DATA_MEMBER_DOUBLE( m_targetMass, a_buffer, a_mode );
201 DATA_MEMBER_VECTOR_DOUBLE( m_energies, a_buffer, a_mode );
202 DATA_MEMBER_VECTOR_DOUBLE( m_crossSections, a_buffer, a_mode );
203 DATA_MEMBER_VECTOR_SIZE_T( m_hashIndices, a_buffer, a_mode );
204 m_domainHash.serialize( a_buffer, a_mode );
205}
206
207/* *********************************************************************************************************//**
208 * This method serializes data for a *ModelDBRC_data* instance.
209 *
210 * @param a_modelDBRC_data [in/out] A pointer to the **ModelDBRC_data** instance to serialize.
211 * @param a_buffer [in] The buffer to read or write data to depending on *a_mode*.
212 * @param a_mode [in] Specifies the action of this method.
213 *
214 * @returns A pointer the serialized **ModelDBRC_data** instance.
215 ***********************************************************************************************************/
216
218
219 bool haveDBRC = a_modelDBRC_data != nullptr;
220 DATA_MEMBER_CAST( haveDBRC, a_buffer, a_mode, bool );
221
222 if( haveDBRC ) {
223 if( a_mode == LUPI::DataBuffer::Mode::Unpack ) {
224 if (a_buffer.m_placement != nullptr) {
225 a_modelDBRC_data = new(a_buffer.m_placement) ModelDBRC_data;
226 a_buffer.incrementPlacement( sizeof( ModelDBRC_data ) ); }
227 else {
228 a_modelDBRC_data = new ModelDBRC_data;
229 }
230 }
231
232 if( a_mode == LUPI::DataBuffer::Mode::Memory ) {
233 a_buffer.incrementPlacement( sizeof( ModelDBRC_data ) );
234 }
235
236 a_modelDBRC_data->serialize( a_buffer, a_mode );
237 }
238
239 return( a_modelDBRC_data );
240}
241
242}
243
244/*
245=========================================================
246*/
247LUPI_HOST_DEVICE ClientRandomNumberGenerator::ClientRandomNumberGenerator( double (*a_generator)( void * ), void *a_state ) :
248 m_generator( a_generator ),
249 m_state( a_state ) {
250}
251
252/*
253=========================================================
254*/
255LUPI_HOST_DEVICE ClientCodeRNGData::ClientCodeRNGData( double (*a_generator)( void * ), void *a_state ) :
256 ClientRandomNumberGenerator( a_generator, a_state ) {
257}
258
259/*
260=========================================================
261*/
262LUPI_HOST_DEVICE Input::Input( bool a_wantVelocity, Upscatter::Model a_upscatterModel ) :
263 m_wantVelocity( a_wantVelocity ),
264 m_upscatterModel( a_upscatterModel ) {
265
266}
267
268/* *********************************************************************************************************//**
269 * This method sets the *m_temperature* and *m_modelTemperature* members to *a_temperature*, the *m_energy* and *m_modelEnergy* members
270 * to *a_energy*, and the *m_dataInTargetFrame* member to **false**. Ergo, this method resets members in the no upscatter mode.
271 *
272 * @param a_temperature [in] The temperature of the material.
273 * @param a_energy [in] The energy of the projectile.
274 ***********************************************************************************************************/
275
276LUPI_HOST_DEVICE void Input::setTemperatureAndEnergy( double a_temperature, double a_energy ) {
277
278 m_dataInTargetFrame = false;
279
280 m_temperature = a_temperature;
281 m_modelTemperature = a_temperature;
282
283 m_energy = a_energy;
284 m_modelEnergy = a_energy;
285}
286
287} // End of namespace Sampling.
288
289} // End of namespace MCGIDI.
#define DATA_MEMBER_CAST(member, buf, mode, someType)
#define DATA_MEMBER_VECTOR_DOUBLE(member, buf, mode)
#define DATA_MEMBER_VECTOR_SIZE_T(member, buf, mode)
#define DATA_MEMBER_DOUBLE(member, buf, mode)
#define LUPI_HOST_DEVICE
#define LUPI_HOST
#define MCGIDI_particleBeta(a_mass_unitOfEnergy, a_kineticEnergy)
Definition MCGIDI.hpp:71
LUPI_HOST_DEVICE void incrementPlacement(std::size_t a_delta)
LUPI_HOST_DEVICE ClientCodeRNGData(double(*a_generator)(void *), void *a_state)
LUPI_HOST_DEVICE ClientRandomNumberGenerator(double(*a_generator)(void *), void *a_state)
LUPI_HOST_DEVICE void setTemperatureAndEnergy(double a_temperature, double a_energy)
LUPI_HOST_DEVICE Input(bool a_wantVelocity, Upscatter::Model a_upscatterModel)
Upscatter::Model m_upscatterModel
LUPI_HOST_DEVICE double crossSectionMax(double a_energy, double a_targetThermalSpeed)
LUPI_HOST_DEVICE void serialize(LUPI::DataBuffer &a_buffer, LUPI::DataBuffer::Mode a_mode)
LUPI_HOST_DEVICE double targetThermalSpeed(double a_temperature)
LUPI_HOST_DEVICE double evaluate(double a_energy)
LUPI_HOST_DEVICE std::size_t size() const
LUPI_HOST_DEVICE T & back()
LUPI_HOST_DEVICE ModelDBRC_data * serializeModelDBRC_data(LUPI::DataBuffer &a_buffer, LUPI::DataBuffer::Mode a_mode, ModelDBRC_data *a_modelDBRC_data)
LUPI_HOST_DEVICE std::size_t evaluationForHashIndex(std::size_t a_hashIndex, Vector< std::size_t > const &a_hashIndices, double a_energy, Vector< double > const &a_energies, double *a_energyFraction)
Simple C++ string class, useful as replacement for std::string if this cannot be used,...
Definition MCGIDI.hpp:43
LUPI_HOST_DEVICE int binarySearchVectorBounded(double a_x, Vector< double > const &a_Xs, std::size_t a_lower, std::size_t a_upper, bool a_boundIndex)
Definition MCGIDI.hpp:347