|
37 | 37 | /// - *anum* : Atomic number of the nucleus
|
38 | 38 | /// - *znum* : Number of protons in the nucleus
|
39 | 39 | /// - *abundance* : Mass percentage of the nucleus in the target material.
|
| 40 | +/// - *abundanceInMol* : Mol (or volume) percentage of the nucleus in the |
| 41 | +/// target material. |
40 | 42 | /// - *wimpDensity* : WIMP density in the DM halo in GeV/cm3
|
41 | 43 | /// - *labVelocity* : WIMP velocity in the lab (Earth) frame reference
|
42 | 44 | /// in km/s
|
|
68 | 70 | /// <parameter name="useQuenchingFactor" value="true"/>
|
69 | 71 | /// </TRestWimpSensitivity>
|
70 | 72 | /// \endcode
|
| 73 | +/// Other ways to define the target material is through the use of |
| 74 | +/// compounds. Also, the abundances can be given in mol (or volume) using |
| 75 | +/// the parameter *abundanceInMol* instead of *abundance*. Examples for an |
| 76 | +/// Ar+Isobutane mixture at 99% in volume can be found inside the files |
| 77 | +/// 'REST_PATH/source/libraries/wimp/examples/WIMP_compound_1.rml' and |
| 78 | +/// 'REST_PATH/source/libraries/wimp/examples/WIMP_compound_2.rml'. |
71 | 79 | ///
|
72 | 80 | /// Besides target material elements, the other parameters are optional,
|
73 | 81 | /// and if not provided they will take their default values.
|
@@ -161,23 +169,123 @@ void TRestWimpSensitivity::InitFromConfigFile() {
|
161 | 169 | ///
|
162 | 170 | void TRestWimpSensitivity::ReadNuclei() {
|
163 | 171 | fNuclei.clear();
|
| 172 | + bool anyAbundanceGivenInMol = false; |
164 | 173 |
|
| 174 | + // Read nuclei (standalone given) elements |
165 | 175 | TiXmlElement* ElementDef = GetElement("addElement");
|
166 | 176 | while (ElementDef) {
|
167 | 177 | TRestWimpNucleus nucleus;
|
168 | 178 | nucleus.fNucleusName = GetFieldValue("nucleusName", ElementDef);
|
169 | 179 | nucleus.fAnum = StringToDouble(GetFieldValue("anum", ElementDef));
|
170 | 180 | nucleus.fZnum = StringToInteger(GetFieldValue("znum", ElementDef));
|
171 |
| - nucleus.fAbundance = StringToDouble(GetFieldValue("abundance", ElementDef)); |
| 181 | + |
| 182 | + std::string el = |
| 183 | + !ElementDef->Attribute("abundance") ? "Not defined" : ElementDef->Attribute("abundance"); |
| 184 | + if (!(el.empty() || el == "Not defined")) nucleus.fAbundance = StringToDouble(el); |
| 185 | + |
| 186 | + el = !ElementDef->Attribute("abundanceInMol") ? "Not defined" |
| 187 | + : ElementDef->Attribute("abundanceInMol"); |
| 188 | + if (!(el.empty() || el == "Not defined")) { |
| 189 | + nucleus.fAbundanceMol = StringToDouble(el); |
| 190 | + anyAbundanceGivenInMol = true; |
| 191 | + } |
| 192 | + |
| 193 | + if (nucleus.fAbundance == 0 || nucleus.fAbundanceMol == 0) { |
| 194 | + if (nucleus.fAbundance == 0) |
| 195 | + nucleus.fAbundance = nucleus.fAbundanceMol * nucleus.fAnum; |
| 196 | + else if (nucleus.fAbundanceMol == 0) |
| 197 | + nucleus.fAbundanceMol = nucleus.fAbundance / nucleus.fAnum; |
| 198 | + else |
| 199 | + RESTError << "abundance or abundanceInMol not defined for nucleus " << nucleus.fNucleusName |
| 200 | + << RESTendl; |
| 201 | + } |
172 | 202 | fNuclei.emplace_back(nucleus);
|
173 | 203 | ElementDef = GetNextElement(ElementDef);
|
174 | 204 | }
|
| 205 | + |
| 206 | + // Read nuclei (compound form given) elements |
| 207 | + TiXmlElement* CompoundDef = GetElement("addCompound"); |
| 208 | + while (CompoundDef) { |
| 209 | + bool compoundAbundanceGivenInMol = false; |
| 210 | + std::string compoundName = GetFieldValue("compoundName", CompoundDef); |
| 211 | + double compoundAbundance = 0, compoundAbundanceInMol = 0; |
| 212 | + double totalMolMass = 0; |
| 213 | + |
| 214 | + std::string el = |
| 215 | + !CompoundDef->Attribute("abundance") ? "Not defined" : CompoundDef->Attribute("abundance"); |
| 216 | + if (!(el.empty() || el == "Not defined")) compoundAbundance = StringToDouble(el); |
| 217 | + |
| 218 | + el = !CompoundDef->Attribute("abundanceInMol") ? "Not defined" |
| 219 | + : CompoundDef->Attribute("abundanceInMol"); |
| 220 | + if (!(el.empty() || el == "Not defined")) { |
| 221 | + compoundAbundanceInMol = StringToDouble(el); |
| 222 | + compoundAbundanceGivenInMol = true; |
| 223 | + anyAbundanceGivenInMol = true; |
| 224 | + } |
| 225 | + |
| 226 | + if (compoundAbundance == 0 && compoundAbundanceInMol == 0) { |
| 227 | + RESTWarning << "abundance or abundanceInMol not defined for compound " << compoundName |
| 228 | + << ". Setting its abundanceInMol to 1 " << RESTendl; |
| 229 | + compoundAbundanceInMol = 1; |
| 230 | + } |
| 231 | + |
| 232 | + // Read nuclei (inside compound) elements |
| 233 | + TiXmlElement* ElementDef = GetElement("addElement", CompoundDef); |
| 234 | + int i = 0; |
| 235 | + while (ElementDef) { |
| 236 | + i++; |
| 237 | + TRestWimpNucleus nucleus; |
| 238 | + nucleus.fNucleusName = GetFieldValue("nucleusName", ElementDef); |
| 239 | + nucleus.fAnum = StringToDouble(GetFieldValue("anum", ElementDef)); |
| 240 | + nucleus.fZnum = StringToInteger(GetFieldValue("znum", ElementDef)); |
| 241 | + totalMolMass += nucleus.fAnum * nucleus.GetStechiometricFactorFromCompound(compoundName); |
| 242 | + |
| 243 | + fNuclei.emplace_back(nucleus); |
| 244 | + ElementDef = GetNextElement(ElementDef); |
| 245 | + } |
| 246 | + if (compoundAbundanceGivenInMol) |
| 247 | + compoundAbundance = compoundAbundanceInMol * totalMolMass; |
| 248 | + else |
| 249 | + compoundAbundanceInMol = compoundAbundance / totalMolMass; |
| 250 | + // Set the compound abundance to all nuclei elements inside the compound |
| 251 | + for (auto it = fNuclei.end() - i; it != fNuclei.end(); it++) { |
| 252 | + auto& nucleus = *it; |
| 253 | + int stechiometricFactor = nucleus.GetStechiometricFactorFromCompound(compoundName); |
| 254 | + nucleus.fAbundanceMol = compoundAbundanceInMol * stechiometricFactor; |
| 255 | + nucleus.fAbundance = nucleus.fAbundanceMol * nucleus.fAnum; |
| 256 | + } |
| 257 | + |
| 258 | + CompoundDef = GetNextElement(CompoundDef); |
| 259 | + } |
| 260 | + |
| 261 | + // Merge the repeated nuclei (same name, anum and znum) by summing their abundances |
| 262 | + std::map<std::tuple<TString, Double_t, Int_t>, TRestWimpNucleus> uniqueNucleiMap; |
| 263 | + for (const auto& nucleus : fNuclei) { |
| 264 | + auto key = std::make_tuple(nucleus.fNucleusName, nucleus.fAnum, nucleus.fZnum); |
| 265 | + if (uniqueNucleiMap.find(key) != uniqueNucleiMap.end()) { |
| 266 | + uniqueNucleiMap[key].fAbundance += nucleus.fAbundance; |
| 267 | + uniqueNucleiMap[key].fAbundanceMol += nucleus.fAbundanceMol; |
| 268 | + } else |
| 269 | + uniqueNucleiMap[key] = nucleus; |
| 270 | + } |
| 271 | + fNuclei.clear(); |
| 272 | + for (const auto& entry : uniqueNucleiMap) fNuclei.push_back(entry.second); |
| 273 | + |
| 274 | + // normalize fAbundance (in mass only) if anyAbundanceGivenInMol |
| 275 | + if (anyAbundanceGivenInMol) { |
| 276 | + double sumMass = 0; |
| 277 | + for (auto& nucl : fNuclei) sumMass += nucl.fAbundance; |
| 278 | + for (auto& nucl : fNuclei) nucl.fAbundance /= sumMass; |
| 279 | + } |
| 280 | + |
| 281 | + for (auto& nucl : fNuclei) nucl.PrintNucleus(); |
175 | 282 | }
|
176 | 283 |
|
177 | 284 | ///////////////////////////////////////////////
|
178 | 285 | /// \brief Get recoil spectra for a given WIMP
|
179 | 286 | /// mass and cross section
|
180 |
| -/// Better performance version |
| 287 | +/// Better performance version (velocity integral |
| 288 | +/// is done only once for all recoil energies). |
181 | 289 | ///
|
182 | 290 | std::map<std::string, TH1D*> TRestWimpSensitivity::GetRecoilSpectra(const double wimpMass,
|
183 | 291 | const double crossSection) {
|
|
0 commit comments