Skip to content

Commit 91691c8

Browse files
committed
Calc. Sens. Coeff. in one run
1 parent cdceace commit 91691c8

5 files changed

Lines changed: 225 additions & 84 deletions

File tree

include/openmc/particle_data.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ class ParticleData : public GeometryState {
714714
{
715715
flux_derivs_.resize(newSize, 0.0);
716716
}
717-
717+
718718
// Resize and initialize sensitivity vectors
719719
void resize_init_cumulative_sensitivities(int newSize)
720720
{

include/openmc/tallies/sensitivity.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@ struct TallySensitivity {
6969

7070
SensitivityVariable variable; //!< Independent variable (like xs)
7171
int id; //!< User-defined identifier
72-
int sens_nuclide; //!< Nuclide this material is applied to
73-
int sens_element; //!< Element this material is applied to
72+
int sens_nuclide; //!< Nuclide the sensitivity is calculated for
73+
int sens_element; //!< Element the sensitivity is calculated for
7474
int sens_reaction; //!< Need something to specify reaction, use ReactionType?
75+
int sens_material; //!< Material the sensitivity is calculated in
76+
int sens_cell; //!< Cell the sensitivity is calculated in
7577
std::vector<double> energy_bins_; //!< Energy bins on which to discretize the cross section
7678
int n_bins_; //!< something to indicate the size of the vector
7779

@@ -110,7 +112,7 @@ void score_collision_sensitivity(Particle& p);
110112
//! \param distance The distance in [cm] traveled by the particle
111113
void score_track_sensitivity(Particle& p, double distance);
112114

113-
// void score_source_sensitivity(Particle& p);
115+
void score_source_sensitivity(Particle& p);
114116

115117
} // namespace openmc
116118

src/particle.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ bool Particle::create_secondary(
9696
}
9797
bank.time = time();
9898
bank_second_E() += bank.E;
99+
// if (!model::active_tallies.empty()) score_source_sensitivity(*this);
99100
return true;
100101
}
101102

@@ -403,6 +404,7 @@ void Particle::event_collide()
403404
if (!model::active_tallies.empty()) {
404405
score_collision_derivative(*this);
405406
score_collision_sensitivity(*this); // Score cumulative sensitivity for sensitivity tallies.
407+
// score_source_sensitivity(*this);
406408
}
407409

408410
#ifdef DAGMC

src/tallies/sensitivity.cpp

Lines changed: 145 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,11 @@ SensitivityTally::set_filters(span<Filter*> filters)
205205

206206
// Copy in the given filter indices.
207207
auto n = filters.size();
208-
if (n != 1) {
209-
throw std::runtime_error{fmt::format("Cannot use more than one filter for sensitivity")};
210-
}
208+
if (settings::run_mode == RunMode::EIGENVALUE) {
209+
if (n != 1) {
210+
throw std::runtime_error{fmt::format("Cannot use more than one filter for eigenvalue sensitivity")};
211+
}
212+
}
211213
reserveFilters(n);
212214

213215
for (int i = 0; i < n; ++i) {
@@ -217,9 +219,11 @@ SensitivityTally::set_filters(span<Filter*> filters)
217219
// filters_.push_back(model::filter_map.at(f->id()));
218220

219221
// Keep track of indices for special filters.
220-
if (!dynamic_cast<const ImportanceFilter*>(f)) {
221-
throw std::runtime_error{fmt::format("Must use an importance filter for sensitivity")};
222-
}
222+
if (settings::run_mode == RunMode::EIGENVALUE) {
223+
if (!dynamic_cast<const ImportanceFilter*>(f)) {
224+
throw std::runtime_error{fmt::format("Must use an importance filter for eigenvalue sensitivity")};
225+
}
226+
}
223227
}
224228

225229
// Set the strides. Filters are traversed in reverse so that the last filter
@@ -363,6 +367,9 @@ TallySensitivity::TallySensitivity(pugi::xml_node node)
363367
fatal_error(fmt::format("Unrecognized variable \"{}\" on derivative {}",
364368
variable_str, id));
365369
}
370+
371+
// sens_material = std::stoi(get_node_value(node, "material"));
372+
// sens_cell = std::stoi(get_node_value(node, "cell"));
366373

367374
}
368375

@@ -470,13 +477,15 @@ double get_nuclide_xs_sens(const Particle& p, int i_nuclide, int score_bin)
470477
void
471478
score_track_sensitivity(Particle& p, double distance)
472479
{
473-
// A void material cannot be perturbed so it will not affect flux sensitivities.
480+
// A void material cannot be perturbed so it will not affect sensitivities.
474481
if (p.material() == MATERIAL_VOID) return;
475482
const Material& material {*model::materials[p.material()]};
476483

477484
for (auto idx = 0; idx < model::tally_sens.size(); idx++) {
478485
const auto& sens = model::tally_sens[idx];
479486
auto& cumulative_sensitivities = p.cumulative_sensitivities(idx);
487+
// if (sens.sens_material != material.id_) // this particle location must be inside detector region? confirm
488+
// continue;
480489

481490
double atom_density = 0.;
482491
if (sens.sens_nuclide >= 0) {
@@ -597,7 +606,7 @@ score_track_sensitivity(Particle& p, double distance)
597606

598607
void score_collision_sensitivity(Particle& p)
599608
{
600-
// A void material cannot be perturbed so it will not affect flux derivatives.
609+
// A void material cannot be perturbed so it will not affect sensitivities.
601610
if (p.material() == MATERIAL_VOID) return;
602611

603612
// only scattering events effect the cumulative tallies
@@ -608,6 +617,8 @@ void score_collision_sensitivity(Particle& p)
608617
for (auto idx = 0; idx < model::tally_sens.size(); idx++) {
609618
const auto& sens = model::tally_sens[idx];
610619
auto& cumulative_sensitivities = p.cumulative_sensitivities(idx);
620+
621+
// if (sens.sens_material != material.id_) continue;
611622

612623
if (p.event_nuclide() != sens.sens_nuclide) continue;
613624
// Find the index in this material for the diff_nuclide.
@@ -757,4 +768,130 @@ void score_collision_sensitivity(Particle& p)
757768
}
758769
}
759770

771+
// should this routine only be called if the particle being transported is a secondary particle?
772+
// do we need to note which event produced the secondary particle?
773+
void score_source_sensitivity(Particle& p)
774+
{
775+
// A void material cannot be perturbed so it will not affect sensitivities.
776+
if (p.material() == MATERIAL_VOID) return;
777+
778+
// only scattering events affect source sensitivity
779+
if (p.event() != TallyEvent::SCATTER) return;
780+
781+
const Material& material {*model::materials[p.material()]};
782+
783+
for (auto idx = 0; idx < model::tally_sens.size(); idx++) {
784+
const auto& sens = model::tally_sens[idx];
785+
auto& cumulative_sensitivities = p.cumulative_sensitivities(idx);
786+
787+
if (p.event_nuclide() != sens.sens_nuclide) continue;
788+
// Find the index in this material for the diff_nuclide.
789+
int i;
790+
for (i = 0; i < material.nuclide_.size(); ++i)
791+
if (material.nuclide_[i] == sens.sens_nuclide) break;
792+
// Make sure we found the nuclide.
793+
if (material.nuclide_[i] != sens.sens_nuclide) {
794+
fatal_error(fmt::format(
795+
"Could not find nuclide {} in material {} for tally sensitivity {}",
796+
data::nuclides[sens.sens_nuclide]->name_, material.id_, sens.id));
797+
}
798+
799+
switch (sens.variable) {
800+
801+
case SensitivityVariable::CROSS_SECTION:
802+
{
803+
804+
// Get the energy of the secondary particle.
805+
double E = p.E();
806+
807+
// only scattering events that produce secondary particles
808+
double score;
809+
switch (sens.sens_reaction) {
810+
case N_ND:
811+
if (p.event_mt() != sens.sens_reaction) continue;
812+
score = 1.0;
813+
break;
814+
case N_NP:
815+
if (p.event_mt() != sens.sens_reaction) continue;
816+
score = 1.0;
817+
break;
818+
case N_NA:
819+
if (p.event_mt() != sens.sens_reaction) continue;
820+
score = 1.0;
821+
break;
822+
case N_2N:
823+
if (p.event_mt() != sens.sens_reaction) continue;
824+
score = 1.0;
825+
break;
826+
case ELASTIC:
827+
case N_T:
828+
case N_XT:
829+
case N_GAMMA:
830+
case N_P:
831+
case N_A:
832+
case N_D:
833+
score = 0.0;
834+
break;
835+
case N_LEVEL:
836+
case N_N1:
837+
case N_N40:
838+
case N_NC:
839+
case 52:
840+
case 53:
841+
case 54:
842+
case 55:
843+
case 56:
844+
case 57:
845+
case 58:
846+
case 59:
847+
case 60:
848+
case 61:
849+
case 62:
850+
case 63:
851+
case 64:
852+
case 65:
853+
case 66:
854+
case 67:
855+
case 68:
856+
case 69:
857+
case 70:
858+
case 71:
859+
case 72:
860+
case 73:
861+
case 74:
862+
case 75:
863+
case 76:
864+
case 77:
865+
case 78:
866+
case 79:
867+
case 80:
868+
case 81:
869+
case 82:
870+
case 83:
871+
case 84:
872+
case 85:
873+
case 86:
874+
case 87:
875+
case 88:
876+
case 89:
877+
if (p.event_mt() != N_LEVEL || p.event_mt() != N_N1 || p.event_mt() != N_N40
878+
|| p.event_mt() != N_NC || (p.event_mt() < N_N1 && p.event_mt() > N_NC)) continue;
879+
score = 1.0;
880+
break;
881+
default:
882+
score = 0.0;
883+
break;
884+
}
885+
886+
// Bin the energy.
887+
if (E >= sens.energy_bins_.front() && E <= sens.energy_bins_.back()) {
888+
auto bin = lower_bound_index(sens.energy_bins_.begin(), sens.energy_bins_.end(), E);
889+
cumulative_sensitivities[bin] += score;
890+
}
891+
}
892+
break;
893+
}
894+
}
895+
}
896+
760897
}// namespace openmc

0 commit comments

Comments
 (0)