@@ -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)
470477void
471478score_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
598607void 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