File indexing completed on 2026-05-09 08:40:06
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/Config.hh"
0010
0011 #include "corecel/Assert.hh"
0012 #include "corecel/Macros.hh"
0013 #include "corecel/Types.hh"
0014 #include "celeritas/Quantities.hh"
0015 #include "celeritas/Types.hh"
0016 #include "celeritas/em/xs/EPlusGGMacroXsCalculator.hh"
0017 #include "celeritas/em/xs/LivermorePEMicroXsCalculator.hh"
0018 #include "celeritas/grid/GridIdFinder.hh"
0019 #include "celeritas/grid/XsCalculator.hh"
0020 #include "celeritas/mat/MaterialView.hh"
0021 #include "celeritas/neutron/xs/NeutronElasticMicroXsCalculator.hh"
0022 #include "celeritas/random/TabulatedElementSelector.hh"
0023
0024 #include "MacroXsCalculator.hh"
0025 #include "ParticleTrackView.hh"
0026 #include "PhysicsData.hh"
0027
0028 namespace celeritas
0029 {
0030
0031
0032
0033
0034
0035
0036
0037 class PhysicsTrackView
0038 {
0039 public:
0040
0041
0042 using Initializer_t = PhysicsTrackInitializer;
0043 using PhysicsParamsRef = NativeCRef<PhysicsParamsData>;
0044 using PhysicsStateRef = NativeRef<PhysicsStateData>;
0045 using Energy = units::MevEnergy;
0046 using ModelFinder = GridIdFinder<Energy, ParticleModelId>;
0047 using UniformTableId = OpaqueId<UniformTable>;
0048
0049
0050 public:
0051
0052 inline CELER_FUNCTION PhysicsTrackView(PhysicsParamsRef const& params,
0053 PhysicsStateRef const& states,
0054 ParticleTrackView const& particle,
0055 PhysMatId material,
0056 TrackSlotId tid);
0057
0058
0059 inline CELER_FUNCTION PhysicsTrackView& operator=(Initializer_t const&);
0060
0061
0062 inline CELER_FUNCTION void interaction_mfp(real_type);
0063
0064
0065 inline CELER_FUNCTION void reset_interaction_mfp();
0066
0067
0068 inline CELER_FUNCTION void dedx_range(real_type);
0069
0070
0071 inline CELER_FUNCTION void msc_range(MscRange const&);
0072
0073
0074
0075
0076 CELER_FORCEINLINE_FUNCTION bool has_interaction_mfp() const;
0077
0078
0079 CELER_FORCEINLINE_FUNCTION real_type interaction_mfp() const;
0080
0081
0082 CELER_FORCEINLINE_FUNCTION real_type dedx_range() const;
0083
0084
0085 CELER_FORCEINLINE_FUNCTION MscRange const& msc_range() const;
0086
0087
0088 CELER_FORCEINLINE_FUNCTION PhysMatId material_id() const;
0089
0090
0091
0092
0093 inline CELER_FUNCTION ParticleProcessId::size_type
0094 num_particle_processes() const;
0095
0096
0097 inline CELER_FUNCTION ProcessId process(ParticleProcessId) const;
0098
0099
0100 inline CELER_FUNCTION XsGridId macro_xs_grid(ParticleProcessId) const;
0101
0102
0103 inline CELER_FUNCTION UniformGridId energy_loss_grid() const;
0104
0105
0106 inline CELER_FUNCTION UniformGridId range_grid() const;
0107
0108
0109 inline CELER_FUNCTION UniformGridId inverse_range_grid() const;
0110
0111
0112 inline CELER_FUNCTION IntegralXsProcess const&
0113 integral_xs_process(ParticleProcessId ppid) const;
0114
0115
0116 inline CELER_FUNCTION real_type calc_xs(ParticleProcessId ppid,
0117 MaterialView const& material,
0118 Energy energy) const;
0119
0120
0121 inline CELER_FUNCTION real_type calc_max_xs(IntegralXsProcess const& process,
0122 ParticleProcessId ppid,
0123 MaterialView const& material,
0124 Energy energy) const;
0125
0126
0127 inline CELER_FUNCTION
0128 ModelFinder make_model_finder(ParticleProcessId) const;
0129
0130
0131 inline CELER_FUNCTION UniformTableId cdf_table(ParticleModelId) const;
0132
0133
0134 inline CELER_FUNCTION
0135 TabulatedElementSelector make_element_selector(UniformTableId,
0136 Energy) const;
0137
0138
0139 inline CELER_FUNCTION ParticleProcessId at_rest_process() const;
0140
0141
0142
0143
0144 inline CELER_FUNCTION ModelId action_to_model(ActionId) const;
0145
0146
0147 inline CELER_FUNCTION ActionId model_to_action(ModelId) const;
0148
0149
0150 inline CELER_FUNCTION ModelId model_id(ParticleModelId) const;
0151
0152
0153 inline CELER_FUNCTION real_type range_to_step(real_type range) const;
0154
0155
0156 CELER_FORCEINLINE_FUNCTION PhysicsParamsScalars const& scalars() const;
0157
0158
0159 CELER_FORCEINLINE_FUNCTION ParticleScalars const& particle_scalars() const;
0160
0161
0162 inline CELER_FUNCTION size_type num_particles() const;
0163
0164
0165 template<class T>
0166 inline CELER_FUNCTION T make_calculator(UniformGridId) const;
0167
0168
0169
0170
0171 inline CELER_FUNCTION ModelId hardwired_model(ParticleProcessId ppid,
0172 Energy energy) const;
0173
0174 private:
0175 PhysicsParamsRef const& params_;
0176 PhysicsStateRef const& states_;
0177 ParticleId const particle_;
0178 PhysMatId const material_;
0179 TrackSlotId const track_slot_;
0180 bool is_heavy_;
0181
0182
0183
0184 CELER_FORCEINLINE_FUNCTION PhysicsTrackState& state();
0185 CELER_FORCEINLINE_FUNCTION PhysicsTrackState const& state() const;
0186 CELER_FORCEINLINE_FUNCTION ProcessGroup const& process_group() const;
0187 inline CELER_FUNCTION UniformGridId uniform_grid(UniformTable const&) const;
0188 };
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198 CELER_FUNCTION
0199 PhysicsTrackView::PhysicsTrackView(PhysicsParamsRef const& params,
0200 PhysicsStateRef const& states,
0201 ParticleTrackView const& particle,
0202 PhysMatId mid,
0203 TrackSlotId tid)
0204 : params_(params)
0205 , states_(states)
0206 , particle_(particle.particle_id())
0207 , material_(mid)
0208 , track_slot_(tid)
0209 , is_heavy_(particle.is_heavy())
0210 {
0211 CELER_EXPECT(track_slot_);
0212 }
0213
0214
0215
0216
0217
0218 CELER_FUNCTION PhysicsTrackView&
0219 PhysicsTrackView::operator=(Initializer_t const&)
0220 {
0221 this->state().interaction_mfp = 0;
0222 this->state().msc_range = {};
0223 return *this;
0224 }
0225
0226
0227
0228
0229
0230
0231
0232 CELER_FUNCTION void PhysicsTrackView::interaction_mfp(real_type mfp)
0233 {
0234 CELER_EXPECT(mfp > 0);
0235 this->state().interaction_mfp = mfp;
0236 }
0237
0238
0239
0240
0241
0242
0243
0244 CELER_FUNCTION void PhysicsTrackView::reset_interaction_mfp()
0245 {
0246 this->state().interaction_mfp = 0;
0247 }
0248
0249
0250
0251
0252
0253
0254
0255 CELER_FUNCTION void PhysicsTrackView::dedx_range(real_type range)
0256 {
0257 CELER_EXPECT(range > 0);
0258 this->state().dedx_range = range;
0259 }
0260
0261
0262
0263
0264
0265
0266
0267 CELER_FUNCTION void PhysicsTrackView::msc_range(MscRange const& msc_range)
0268 {
0269 this->state().msc_range = msc_range;
0270 }
0271
0272
0273
0274
0275
0276 CELER_FUNCTION PhysMatId PhysicsTrackView::material_id() const
0277 {
0278 return material_;
0279 }
0280
0281
0282
0283
0284
0285 CELER_FUNCTION bool PhysicsTrackView::has_interaction_mfp() const
0286 {
0287 return this->state().interaction_mfp > 0;
0288 }
0289
0290
0291
0292
0293
0294 CELER_FUNCTION real_type PhysicsTrackView::interaction_mfp() const
0295 {
0296 real_type mfp = this->state().interaction_mfp;
0297 CELER_ENSURE(mfp >= 0);
0298 return mfp;
0299 }
0300
0301
0302
0303
0304
0305 CELER_FUNCTION real_type PhysicsTrackView::dedx_range() const
0306 {
0307 real_type range = this->state().dedx_range;
0308 CELER_ENSURE(range > 0);
0309 return range;
0310 }
0311
0312
0313
0314
0315
0316 CELER_FUNCTION MscRange const& PhysicsTrackView::msc_range() const
0317 {
0318 return this->state().msc_range;
0319 }
0320
0321
0322
0323
0324
0325 CELER_FUNCTION ParticleProcessId::size_type
0326 PhysicsTrackView::num_particle_processes() const
0327 {
0328 return this->process_group().size();
0329 }
0330
0331
0332
0333
0334
0335 CELER_FUNCTION ProcessId PhysicsTrackView::process(ParticleProcessId ppid) const
0336 {
0337 CELER_EXPECT(ppid < this->num_particle_processes());
0338 return params_.process_ids[this->process_group().processes[ppid.get()]];
0339 }
0340
0341
0342
0343
0344
0345 CELER_FUNCTION XsGridId
0346 PhysicsTrackView::macro_xs_grid(ParticleProcessId ppid) const
0347 {
0348 CELER_EXPECT(ppid < this->num_particle_processes());
0349 auto table_id = this->process_group().macro_xs[ppid.get()];
0350 CELER_ASSERT(table_id);
0351 auto const& table = params_.xs_tables[table_id];
0352 if (!table)
0353 {
0354
0355 return {};
0356 }
0357 CELER_ASSERT(material_ < table.grids.size());
0358 auto grid_id = table.grids[material_.get()];
0359 if (!grid_id)
0360 {
0361
0362 return {};
0363 }
0364 return params_.xs_grid_ids[grid_id];
0365 }
0366
0367
0368
0369
0370
0371 CELER_FUNCTION UniformGridId PhysicsTrackView::energy_loss_grid() const
0372 {
0373 return this->uniform_grid(this->process_group().energy_loss);
0374 }
0375
0376
0377
0378
0379
0380 CELER_FUNCTION UniformGridId PhysicsTrackView::range_grid() const
0381 {
0382 return this->uniform_grid(this->process_group().range);
0383 }
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397 CELER_FUNCTION UniformGridId PhysicsTrackView::inverse_range_grid() const
0398 {
0399 if (auto const& grid
0400 = this->uniform_grid(this->process_group().inverse_range))
0401 {
0402 return grid;
0403 }
0404 return this->range_grid();
0405 }
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433 CELER_FUNCTION auto
0434 PhysicsTrackView::integral_xs_process(ParticleProcessId ppid) const
0435 -> IntegralXsProcess const&
0436 {
0437 CELER_EXPECT(ppid < this->num_particle_processes());
0438 return params_.integral_xs[this->process_group().integral_xs[ppid.get()]];
0439 }
0440
0441
0442
0443
0444
0445 CELER_FUNCTION real_type PhysicsTrackView::calc_xs(ParticleProcessId ppid,
0446 MaterialView const& material,
0447 Energy energy) const
0448 {
0449 real_type result = 0;
0450
0451 if (auto model_id = this->hardwired_model(ppid, energy))
0452 {
0453
0454
0455 if (model_id == params_.hardwired.ids.livermore_pe)
0456 {
0457 result = MacroXsCalculator<LivermorePEMicroXsCalculator>(
0458 params_.hardwired.livermore_pe, material)(energy);
0459 }
0460 else if (model_id == params_.hardwired.ids.eplusgg)
0461 {
0462 result = EPlusGGMacroXsCalculator(params_.hardwired.eplusgg,
0463 material)(energy);
0464 }
0465 else if (model_id == params_.hardwired.ids.chips)
0466 {
0467 result = MacroXsCalculator<NeutronElasticMicroXsCalculator>(
0468 params_.hardwired.chips, material)(energy);
0469 }
0470 }
0471 else if (auto grid_id = this->macro_xs_grid(ppid))
0472 {
0473
0474 CELER_ASSERT(grid_id < params_.xs_grids.size());
0475 result = XsCalculator(params_.xs_grids[grid_id], params_.reals)(energy);
0476 }
0477
0478 CELER_ENSURE(result >= 0);
0479 return result;
0480 }
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498 CELER_FUNCTION real_type
0499 PhysicsTrackView::calc_max_xs(IntegralXsProcess const& process,
0500 ParticleProcessId ppid,
0501 MaterialView const& material,
0502 Energy energy) const
0503 {
0504 CELER_EXPECT(process);
0505 CELER_EXPECT(material_ < process.energy_max_xs.size());
0506
0507 real_type energy_max_xs
0508 = params_.reals[process.energy_max_xs[material_.get()]];
0509 real_type energy_xi = energy.value() * params_.scalars.min_eprime_over_e;
0510 if (energy_max_xs >= energy_xi && energy_max_xs < energy.value())
0511 {
0512 return this->calc_xs(ppid, material, Energy{energy_max_xs});
0513 }
0514 return max(this->calc_xs(ppid, material, energy),
0515 this->calc_xs(ppid, material, Energy{energy_xi}));
0516 }
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526 CELER_FUNCTION ModelId PhysicsTrackView::hardwired_model(ParticleProcessId ppid,
0527 Energy energy) const
0528 {
0529 ProcessId process = this->process(ppid);
0530 if ((process == params_.hardwired.ids.photoelectric
0531 && energy < LivermoreElement::tabulated_threshold())
0532 || (process == params_.hardwired.ids.annihilation)
0533 || (process == params_.hardwired.ids.neutron_elastic))
0534 {
0535 auto find_model = this->make_model_finder(ppid);
0536 return this->model_id(find_model(energy));
0537 }
0538
0539 return {};
0540 }
0541
0542
0543
0544
0545
0546 CELER_FUNCTION auto
0547 PhysicsTrackView::make_model_finder(ParticleProcessId ppid) const
0548 -> ModelFinder
0549 {
0550 CELER_EXPECT(ppid < this->num_particle_processes());
0551 ModelGroup const& md
0552 = params_.model_groups[this->process_group().models[ppid.get()]];
0553 return ModelFinder(params_.reals[md.energy], params_.pmodel_ids[md.model]);
0554 }
0555
0556
0557
0558
0559
0560
0561
0562
0563 CELER_FUNCTION
0564 auto PhysicsTrackView::cdf_table(ParticleModelId pmid) const -> UniformTableId
0565 {
0566 CELER_EXPECT(pmid < params_.model_cdf.size());
0567
0568
0569 ModelCdfTable const& model_cdf = params_.model_cdf[pmid];
0570 if (!model_cdf)
0571 {
0572
0573 return {};
0574 }
0575
0576
0577 CELER_ASSERT(material_ < model_cdf.tables.size());
0578 auto table_id = model_cdf.tables[material_.get()];
0579 CELER_ASSERT(table_id < params_.uniform_tables.size());
0580 if (!params_.uniform_tables[table_id])
0581 {
0582
0583 return {};
0584 }
0585 return table_id;
0586 }
0587
0588
0589
0590
0591
0592 CELER_FUNCTION
0593 TabulatedElementSelector
0594 PhysicsTrackView::make_element_selector(UniformTableId table_id,
0595 Energy energy) const
0596 {
0597 CELER_EXPECT(table_id < params_.uniform_tables.size());
0598 auto const& table = params_.uniform_tables[table_id];
0599 return TabulatedElementSelector{table,
0600 params_.uniform_grids,
0601 params_.uniform_grid_ids,
0602 params_.reals,
0603 energy};
0604 }
0605
0606
0607
0608
0609
0610
0611
0612
0613 CELER_FUNCTION ParticleProcessId PhysicsTrackView::at_rest_process() const
0614 {
0615 return this->process_group().at_rest;
0616 }
0617
0618
0619
0620
0621
0622 CELER_FUNCTION ModelId PhysicsTrackView::action_to_model(ActionId action) const
0623 {
0624 if (!action)
0625 return ModelId{};
0626
0627
0628 ModelId::size_type result = action.unchecked_get()
0629 - params_.scalars.model_to_action;
0630 if (result >= params_.scalars.num_models)
0631 return ModelId{};
0632
0633 return ModelId{result};
0634 }
0635
0636
0637
0638
0639
0640 CELER_FUNCTION ActionId PhysicsTrackView::model_to_action(ModelId model) const
0641 {
0642 CELER_ASSERT(model < params_.scalars.num_models);
0643 return ActionId{model.unchecked_get() + params_.scalars.model_to_action};
0644 }
0645
0646
0647
0648
0649
0650 CELER_FUNCTION ModelId PhysicsTrackView::model_id(ParticleModelId pmid) const
0651 {
0652 CELER_EXPECT(pmid < params_.model_ids.size());
0653 return params_.model_ids[pmid];
0654 }
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669 CELER_FUNCTION real_type PhysicsTrackView::range_to_step(real_type range) const
0670 {
0671 CELER_ASSERT(range >= 0);
0672 auto const& scalars = this->particle_scalars();
0673 real_type const rho = scalars.min_range;
0674 if (range < rho * (1 + celeritas::sqrt_tol()))
0675 {
0676
0677
0678
0679 return range;
0680 }
0681
0682 real_type const alpha = scalars.max_step_over_range;
0683 real_type step = alpha * range + rho * (1 - alpha) * (2 - rho / range);
0684 CELER_ENSURE(step > 0 && step <= range);
0685 return step;
0686 }
0687
0688
0689
0690
0691
0692 CELER_FORCEINLINE_FUNCTION PhysicsParamsScalars const&
0693 PhysicsTrackView::scalars() const
0694 {
0695 return params_.scalars;
0696 }
0697
0698
0699
0700
0701
0702
0703
0704
0705 CELER_FORCEINLINE_FUNCTION ParticleScalars const&
0706 PhysicsTrackView::particle_scalars() const
0707 {
0708 if (is_heavy_)
0709 {
0710 return params_.scalars.heavy;
0711 }
0712 return params_.scalars.light;
0713 }
0714
0715
0716
0717
0718
0719 CELER_FUNCTION size_type PhysicsTrackView::num_particles() const
0720 {
0721 return params_.process_groups.size();
0722 }
0723
0724
0725
0726
0727
0728
0729
0730
0731 template<class T>
0732 CELER_FUNCTION T PhysicsTrackView::make_calculator(UniformGridId id) const
0733 {
0734 CELER_EXPECT(id < params_.uniform_grids.size());
0735 return T{params_.uniform_grids[id], params_.reals};
0736 }
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751 CELER_FUNCTION UniformGridId
0752 PhysicsTrackView::uniform_grid(UniformTable const& table) const
0753 {
0754 if (!table)
0755 {
0756
0757 return {};
0758 }
0759 CELER_ASSERT(material_ < table.grids.size());
0760 auto grid_id = table.grids[material_.get()];
0761 if (!grid_id)
0762 {
0763
0764 return {};
0765 }
0766 return params_.uniform_grid_ids[grid_id];
0767 }
0768
0769
0770 CELER_FUNCTION PhysicsTrackState& PhysicsTrackView::state()
0771 {
0772 return states_.state[track_slot_];
0773 }
0774
0775
0776 CELER_FUNCTION PhysicsTrackState const& PhysicsTrackView::state() const
0777 {
0778 return states_.state[track_slot_];
0779 }
0780
0781
0782 CELER_FUNCTION ProcessGroup const& PhysicsTrackView::process_group() const
0783 {
0784 CELER_EXPECT(particle_ < params_.process_groups.size());
0785 return params_.process_groups[particle_];
0786 }
0787
0788
0789 }