@@ -946,17 +946,16 @@ void FlatSourceDomain::output_to_vtk() const
946
946
}
947
947
948
948
void FlatSourceDomain::apply_external_source_to_source_region (
949
- Discrete* discrete, double strength_factor, int64_t sr )
949
+ Discrete* discrete, double strength_factor, SourceRegionHandle& srh )
950
950
{
951
- source_regions_ .external_source_present (sr ) = 1 ;
951
+ srh .external_source_present () = 1 ;
952
952
953
953
const auto & discrete_energies = discrete->x ();
954
954
const auto & discrete_probs = discrete->prob ();
955
955
956
956
for (int i = 0 ; i < discrete_energies.size (); i++) {
957
957
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;
960
959
}
961
960
}
962
961
@@ -980,8 +979,9 @@ void FlatSourceDomain::apply_external_source_to_cell_instances(int32_t i_cell,
980
979
if (target_material_id == C_NONE ||
981
980
cell_material_id == target_material_id) {
982
981
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);
985
985
}
986
986
}
987
987
}
@@ -1023,34 +1023,88 @@ void FlatSourceDomain::convert_external_sources()
1023
1023
{
1024
1024
// Loop over external sources
1025
1025
for (int es = 0 ; es < model::external_sources.size (); es++) {
1026
+
1027
+ // Extract source information
1026
1028
Source* s = model::external_sources[es].get ();
1027
1029
IndependentSource* is = dynamic_cast <IndependentSource*>(s);
1028
1030
Discrete* energy = dynamic_cast <Discrete*>(is->energy ());
1029
1031
const std::unordered_set<int32_t >& domain_ids = is->domain_ids ();
1030
-
1031
1032
double strength_factor = is->strength ();
1032
1033
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 ()));
1039
1051
}
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);
1045
1081
}
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];
1051
1096
apply_external_source_to_cell_and_children (
1052
1097
i_cell, energy, strength_factor, C_NONE);
1053
1098
}
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
+ }
1054
1108
}
1055
1109
}
1056
1110
} // End loop over external sources
@@ -1399,6 +1453,25 @@ SourceRegionHandle FlatSourceDomain::get_subdivided_source_region_handle(
1399
1453
sr_key, {base_source_regions_.get_source_region_handle (sr), sr});
1400
1454
discovered_source_regions_.unlock (sr_key);
1401
1455
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
+
1402
1475
return handle;
1403
1476
}
1404
1477
0 commit comments