3737
3838namespace openmc {
3939
40+ std::atomic<int64_t > source_n_accept {0 };
41+ std::atomic<int64_t > source_n_reject {0 };
42+
4043namespace {
4144
4245void validate_particle_type (ParticleType type, const std::string& context)
@@ -191,9 +194,8 @@ void check_rejection_fraction(int64_t n_reject, int64_t n_accept)
191194SourceSite Source::sample_with_constraints (uint64_t * seed) const
192195{
193196 bool accepted = false ;
194- static int64_t n_reject = 0 ;
195- static int64_t n_accept = 0 ;
196- SourceSite site;
197+ int64_t n_local_reject = 0 ;
198+ SourceSite site {};
197199
198200 while (!accepted) {
199201 // Sample a source site without considering constraints yet
@@ -207,9 +209,13 @@ SourceSite Source::sample_with_constraints(uint64_t* seed) const
207209 satisfies_energy_constraints (site.E ) &&
208210 satisfies_time_constraints (site.time );
209211 if (!accepted) {
210- // Increment number of rejections and check against minimum fraction
211- ++n_reject;
212- check_rejection_fraction (n_reject, n_accept);
212+ ++n_local_reject;
213+
214+ // Check per-particle rejection limit
215+ if (n_local_reject >= MAX_SOURCE_REJECTIONS_PER_SAMPLE) {
216+ fatal_error (" Exceeded maximum number of source rejections per "
217+ " sample. Please check your source definition." );
218+ }
213219
214220 // For the "kill" strategy, accept particle but set weight to 0 so that
215221 // it is terminated immediately
@@ -221,8 +227,13 @@ SourceSite Source::sample_with_constraints(uint64_t* seed) const
221227 }
222228 }
223229
224- // Increment number of accepted samples
225- ++n_accept;
230+ // Flush local rejection count, update accept counter, and check overall
231+ // rejection fraction
232+ if (n_local_reject > 0 ) {
233+ source_n_reject += n_local_reject;
234+ }
235+ ++source_n_accept;
236+ check_rejection_fraction (source_n_reject, source_n_accept);
226237
227238 return site;
228239}
@@ -361,15 +372,14 @@ IndependentSource::IndependentSource(pugi::xml_node node) : Source(node)
361372
362373SourceSite IndependentSource::sample (uint64_t * seed) const
363374{
364- SourceSite site;
375+ SourceSite site {} ;
365376 site.particle = particle_;
366377 double r_wgt = 1.0 ;
367378 double E_wgt = 1.0 ;
368379
369380 // Repeat sampling source location until a good site has been accepted
370381 bool accepted = false ;
371- static int64_t n_reject = 0 ;
372- static int64_t n_accept = 0 ;
382+ int64_t n_local_reject = 0 ;
373383
374384 while (!accepted) {
375385
@@ -383,8 +393,11 @@ SourceSite IndependentSource::sample(uint64_t* seed) const
383393
384394 // Check for rejection
385395 if (!accepted) {
386- ++n_reject;
387- check_rejection_fraction (n_reject, n_accept);
396+ ++n_local_reject;
397+ if (n_local_reject >= MAX_SOURCE_REJECTIONS_PER_SAMPLE) {
398+ fatal_error (" Exceeded maximum number of source rejections per "
399+ " sample. Please check your source definition." );
400+ }
388401 }
389402 }
390403
@@ -419,8 +432,11 @@ SourceSite IndependentSource::sample(uint64_t* seed) const
419432 (satisfies_energy_constraints (site.E )))
420433 break ;
421434
422- n_reject++;
423- check_rejection_fraction (n_reject, n_accept);
435+ ++n_local_reject;
436+ if (n_local_reject >= MAX_SOURCE_REJECTIONS_PER_SAMPLE) {
437+ fatal_error (" Exceeded maximum number of source rejections per "
438+ " sample. Please check your source definition." );
439+ }
424440 }
425441
426442 // Sample particle creation time
@@ -430,8 +446,10 @@ SourceSite IndependentSource::sample(uint64_t* seed) const
430446 site.wgt *= (E_wgt * time_wgt);
431447 }
432448
433- // Increment number of accepted samples
434- ++n_accept;
449+ // Flush local rejection count into global counter
450+ if (n_local_reject > 0 ) {
451+ source_n_reject += n_local_reject;
452+ }
435453
436454 return site;
437455}
@@ -692,6 +710,13 @@ SourceSite sample_external_source(uint64_t* seed)
692710void free_memory_source ()
693711{
694712 model::external_sources.clear ();
713+ reset_source_rejection_counters ();
714+ }
715+
716+ void reset_source_rejection_counters ()
717+ {
718+ source_n_accept = 0 ;
719+ source_n_reject = 0 ;
695720}
696721
697722// ==============================================================================
@@ -712,8 +737,15 @@ extern "C" int openmc_sample_external_source(
712737 }
713738
714739 auto sites_array = static_cast <SourceSite*>(sites);
740+
741+ // Derive independent per-particle seeds from the base seed so that
742+ // each iteration has its own RNG state for thread-safe parallel sampling.
743+ uint64_t base_seed = *seed;
744+
745+ #pragma omp parallel for schedule(static)
715746 for (size_t i = 0 ; i < n; ++i) {
716- sites_array[i] = sample_external_source (seed);
747+ uint64_t particle_seed = init_seed (base_seed + i, STREAM_SOURCE);
748+ sites_array[i] = sample_external_source (&particle_seed);
717749 }
718750 return 0 ;
719751}
0 commit comments