@@ -946,17 +946,16 @@ void FlatSourceDomain::output_to_vtk() const
946946}
947947
948948void FlatSourceDomain::apply_external_source_to_source_region (
949- Discrete* discrete, double strength_factor, int64_t sr )
949+ Discrete* discrete, double strength_factor, SourceRegionHandle& srh )
950950{
951- source_regions_ .external_source_present (sr ) = 1 ;
951+ srh .external_source_present () = 1 ;
952952
953953 const auto & discrete_energies = discrete->x ();
954954 const auto & discrete_probs = discrete->prob ();
955955
956956 for (int i = 0 ; i < discrete_energies.size (); i++) {
957957 int g = data::mg.get_group_index (discrete_energies[i]);
958- source_regions_.external_source (sr, g) +=
959- discrete_probs[i] * strength_factor;
958+ srh.external_source (g) += discrete_probs[i] * strength_factor;
960959 }
961960}
962961
@@ -980,8 +979,9 @@ void FlatSourceDomain::apply_external_source_to_cell_instances(int32_t i_cell,
980979 if (target_material_id == C_NONE ||
981980 cell_material_id == target_material_id) {
982981 int64_t source_region = source_region_offsets_[i_cell] + j;
983- apply_external_source_to_source_region (
984- discrete, strength_factor, source_region);
982+ SourceRegionHandle srh =
983+ source_regions_.get_source_region_handle (source_region);
984+ apply_external_source_to_source_region (discrete, strength_factor, srh);
985985 }
986986 }
987987}
@@ -1023,34 +1023,88 @@ void FlatSourceDomain::convert_external_sources()
10231023{
10241024 // Loop over external sources
10251025 for (int es = 0 ; es < model::external_sources.size (); es++) {
1026+
1027+ // Extract source information
10261028 Source* s = model::external_sources[es].get ();
10271029 IndependentSource* is = dynamic_cast <IndependentSource*>(s);
10281030 Discrete* energy = dynamic_cast <Discrete*>(is->energy ());
10291031 const std::unordered_set<int32_t >& domain_ids = is->domain_ids ();
1030-
10311032 double strength_factor = is->strength ();
10321033
1033- if (is->domain_type () == Source::DomainType::MATERIAL) {
1034- for (int32_t material_id : domain_ids) {
1035- for (int i_cell = 0 ; i_cell < model::cells.size (); i_cell++) {
1036- apply_external_source_to_cell_and_children (
1037- i_cell, energy, strength_factor, material_id);
1038- }
1034+ // If there is no domain constraint specified, then this must be a point
1035+ // source. In this case, we need to find the source region that contains the
1036+ // point source and apply or relate it to the external source.
1037+ if (is->domain_ids ().size () == 0 ) {
1038+
1039+ // Extract the point source coordinate and find the base source region at
1040+ // that point
1041+ auto sp = dynamic_cast <SpatialPoint*>(is->space ());
1042+ GeometryState gs;
1043+ gs.r () = sp->r ();
1044+ gs.r_last () = sp->r ();
1045+ gs.u () = {1.0 , 0.0 , 0.0 };
1046+ bool found = exhaustive_find_cell (gs);
1047+ if (!found) {
1048+ fatal_error (fmt::format (" Could not find cell containing external "
1049+ " point source at {}" ,
1050+ sp->r ()));
10391051 }
1040- } else if (is->domain_type () == Source::DomainType::CELL) {
1041- for (int32_t cell_id : domain_ids) {
1042- int32_t i_cell = model::cell_map[cell_id];
1043- apply_external_source_to_cell_and_children (
1044- i_cell, energy, strength_factor, C_NONE);
1052+ int i_cell = gs.lowest_coord ().cell ;
1053+ int64_t sr = source_region_offsets_[i_cell] + gs.cell_instance ();
1054+
1055+ if (RandomRay::mesh_subdivision_enabled_) {
1056+ // If mesh subdivision is enabled, we need to determine which subdivided
1057+ // mesh bin the point source coordinate is in as well
1058+ int mesh_idx = source_regions_.mesh (sr);
1059+ int mesh_bin;
1060+ if (mesh_idx == C_NONE) {
1061+ mesh_bin = 0 ;
1062+ } else {
1063+ mesh_bin = model::meshes[mesh_idx]->get_bin (gs.r ());
1064+ }
1065+ // With the source region and mesh bin known, we can use the
1066+ // accompanying SourceRegionKey as a key into a map that stores the
1067+ // corresponding external source index for the point source. Notably, we
1068+ // do not actually apply the external source to any source regions here,
1069+ // as if mesh subdivision is enabled, they haven't actually been
1070+ // discovered & initilized yet. When discovered, they will read from the
1071+ // point_source_map to determine if there are any point source terms
1072+ // that should be applied.
1073+ SourceRegionKey key {sr, mesh_bin};
1074+ point_source_map_[key] = es;
1075+ } else {
1076+ // If we are not using mesh subdivision, we can apply the external
1077+ // source directly to the source region as we do for volumetric domain
1078+ // constraint sources.
1079+ SourceRegionHandle srh = source_regions_.get_source_region_handle (sr);
1080+ apply_external_source_to_source_region (energy, strength_factor, srh);
10451081 }
1046- } else if (is->domain_type () == Source::DomainType::UNIVERSE) {
1047- for (int32_t universe_id : domain_ids) {
1048- int32_t i_universe = model::universe_map[universe_id];
1049- Universe& universe = *model::universes[i_universe];
1050- for (int32_t i_cell : universe.cells_ ) {
1082+
1083+ } else {
1084+ // If not a point source, then use the volumetric domain constraints to
1085+ // determine which source regions to apply the external source to.
1086+ if (is->domain_type () == Source::DomainType::MATERIAL) {
1087+ for (int32_t material_id : domain_ids) {
1088+ for (int i_cell = 0 ; i_cell < model::cells.size (); i_cell++) {
1089+ apply_external_source_to_cell_and_children (
1090+ i_cell, energy, strength_factor, material_id);
1091+ }
1092+ }
1093+ } else if (is->domain_type () == Source::DomainType::CELL) {
1094+ for (int32_t cell_id : domain_ids) {
1095+ int32_t i_cell = model::cell_map[cell_id];
10511096 apply_external_source_to_cell_and_children (
10521097 i_cell, energy, strength_factor, C_NONE);
10531098 }
1099+ } else if (is->domain_type () == Source::DomainType::UNIVERSE) {
1100+ for (int32_t universe_id : domain_ids) {
1101+ int32_t i_universe = model::universe_map[universe_id];
1102+ Universe& universe = *model::universes[i_universe];
1103+ for (int32_t i_cell : universe.cells_ ) {
1104+ apply_external_source_to_cell_and_children (
1105+ i_cell, energy, strength_factor, C_NONE);
1106+ }
1107+ }
10541108 }
10551109 }
10561110 } // End loop over external sources
@@ -1399,6 +1453,25 @@ SourceRegionHandle FlatSourceDomain::get_subdivided_source_region_handle(
13991453 sr_key, {base_source_regions_.get_source_region_handle (sr), sr});
14001454 discovered_source_regions_.unlock (sr_key);
14011455 SourceRegionHandle handle {*sr_ptr};
1456+
1457+ // Check if the new source region contains a point source and apply it if so
1458+ auto it2 = point_source_map_.find (sr_key);
1459+ if (it2 != point_source_map_.end ()) {
1460+ int es = it2->second ;
1461+ auto s = model::external_sources[es].get ();
1462+ auto is = dynamic_cast <IndependentSource*>(s);
1463+ auto energy = dynamic_cast <Discrete*>(is->energy ());
1464+ double strength_factor = is->strength ();
1465+ apply_external_source_to_source_region (energy, strength_factor, handle);
1466+ int material = handle.material ();
1467+ if (material != MATERIAL_VOID) {
1468+ for (int g = 0 ; g < negroups_; g++) {
1469+ double sigma_t = sigma_t_[material * negroups_ + g];
1470+ handle.external_source (g) /= sigma_t ;
1471+ }
1472+ }
1473+ }
1474+
14021475 return handle;
14031476}
14041477
0 commit comments