G4OCCT 0.1.0
Geant4 interface to Open CASCADE Technology (OCCT) geometry definitions
Loading...
Searching...
No Matches
G4OCCTMaterialMapReader.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: LGPL-2.1-or-later
2// Copyright (C) 2026 G4OCCT Contributors
3
6
8
9// Xerces — provided transitively by Geant4::G4gdml.
10// G4GDMLRead.hh already includes the Xerces DOM headers; we repeat them here
11// for clarity and to document the direct dependency.
12#include <xercesc/dom/DOM.hpp>
13#include <xercesc/parsers/XercesDOMParser.hpp>
14#include <xercesc/util/PlatformUtils.hpp>
15
16// Geant4
17#include <G4Exception.hh>
18#include <G4Material.hh>
19#include <G4NistManager.hh>
20
22 // Xerces initialization is ref-counted; safe to call multiple times.
23 xercesc::XMLPlatformUtils::Initialize();
24
25 G4OCCTMaterialMap result;
26
27 {
28 // Limit parser scope so it is destroyed before Terminate().
29 xercesc::XercesDOMParser parser;
30 parser.setDoNamespaces(false);
31 parser.setDoSchema(false);
32 parser.setCreateEntityReferenceNodes(false);
33
34 try {
35 parser.parse(path.c_str());
36 } catch (const xercesc::XMLException& e) {
37 xercesc::XMLPlatformUtils::Terminate();
38 G4Exception("G4OCCTMaterialMapReader::ReadFile", "G4OCCT_MatReader001", FatalException,
39 ("XML error parsing '" + path + "': " + Transcode(e.getMessage())).c_str());
40 return result;
41 } catch (const xercesc::DOMException& e) {
42 xercesc::XMLPlatformUtils::Terminate();
43 G4Exception("G4OCCTMaterialMapReader::ReadFile", "G4OCCT_MatReader002", FatalException,
44 ("DOM error parsing '" + path + "': " + Transcode(e.getMessage())).c_str());
45 return result;
46 }
47
48 const xercesc::DOMDocument* const doc = parser.getDocument();
49 if (!doc) {
50 xercesc::XMLPlatformUtils::Terminate();
51 G4Exception("G4OCCTMaterialMapReader::ReadFile", "G4OCCT_MatReader003", FatalException,
52 ("Cannot open document: " + path).c_str());
53 return result;
54 }
55
56 const xercesc::DOMElement* const root = doc->getDocumentElement();
57 if (!root) {
58 xercesc::XMLPlatformUtils::Terminate();
59 G4Exception("G4OCCTMaterialMapReader::ReadFile", "G4OCCT_MatReader004", FatalException,
60 ("Empty document: " + path).c_str());
61 return result;
62 }
63
64 const G4String rootTag = Transcode(root->getTagName());
65 if (rootTag != "materials") {
66 xercesc::XMLPlatformUtils::Terminate();
67 G4Exception(
68 "G4OCCTMaterialMapReader::ReadFile", "G4OCCT_MatReader005", FatalException,
69 ("Root element must be <materials>, got <" + rootTag + "> in '" + path + "'").c_str());
70 return result;
71 }
72
73 // ── Pass 1: isotopes and elements ──────────────────────────────────────
74 // Must precede materials so that <fraction ref="Si"/> can resolve "Si".
75 for (xercesc::DOMNode* node = root->getFirstChild(); node != nullptr;
76 node = node->getNextSibling()) {
77 if (node->getNodeType() != xercesc::DOMNode::ELEMENT_NODE) {
78 continue;
79 }
80 const auto* child = dynamic_cast<const xercesc::DOMElement*>(node);
81 if (!child) {
82 continue;
83 }
84 const G4String tag = Transcode(child->getTagName());
85 if (tag == "isotope") {
86 IsotopeRead(child);
87 } else if (tag == "element") {
88 ElementRead(child);
89 }
90 }
91
92 // ── Pass 2: materials ──────────────────────────────────────────────────
93 for (xercesc::DOMNode* node = root->getFirstChild(); node != nullptr;
94 node = node->getNextSibling()) {
95 if (node->getNodeType() != xercesc::DOMNode::ELEMENT_NODE) {
96 continue;
97 }
98 const auto* child = dynamic_cast<const xercesc::DOMElement*>(node);
99 if (!child) {
100 continue;
101 }
102 if (Transcode(child->getTagName()) != "material") {
103 continue;
104 }
105
106 // Extract our custom attributes and the GDML 'name' attribute.
107 G4String stepName;
108 G4String geant4Name;
109 G4String gdmlName;
110 const xercesc::DOMNamedNodeMap* attrs = child->getAttributes();
111 for (XMLSize_t i = 0; i < attrs->getLength(); ++i) {
112 const auto* attr = dynamic_cast<const xercesc::DOMAttr*>(attrs->item(i));
113 if (!attr) {
114 continue;
115 }
116 const G4String aName = Transcode(attr->getName());
117 const G4String aValue = Transcode(attr->getValue());
118 if (aName == "stepName") {
119 stepName = aValue;
120 } else if (aName == "geant4Name") {
121 geant4Name = aValue;
122 } else if (aName == "name") {
123 gdmlName = aValue;
124 }
125 }
126
127 if (stepName.empty()) {
128 G4Exception("G4OCCTMaterialMapReader::ReadFile", "G4OCCT_MatReader006", FatalException,
129 ("<material> element in '" + path +
130 "' is missing the required 'stepName' "
131 "attribute.")
132 .c_str());
133 continue;
134 }
135
136 G4Material* mat = nullptr;
137
138 if (!geant4Name.empty()) {
139 // ── Type 1: NIST alias ────────────────────────────────────────────
140 mat = G4NistManager::Instance()->FindOrBuildMaterial(geant4Name);
141 if (!mat) {
142 G4Exception("G4OCCTMaterialMapReader::ReadFile", "G4OCCT_MatReader007", FatalException,
143 ("NIST material '" + geant4Name + "' not found (stepName='" + stepName +
144 "'). "
145 "Check the spelling against the Geant4 NIST material database.")
146 .c_str());
147 continue;
148 }
149 } else {
150 // ── Type 2: Inline GDML material definition ───────────────────────
151 if (gdmlName.empty()) {
152 G4Exception("G4OCCTMaterialMapReader::ReadFile", "G4OCCT_MatReader008", FatalException,
153 ("Inline <material stepName=\"" + stepName + "\"> in '" + path +
154 "' requires a 'name' attribute (used as the GDML material registry key).")
155 .c_str());
156 continue;
157 }
158 // Reuse the material if it was already registered in the global
159 // G4 material table (e.g. by a preceding G4GDMLParser::Read call
160 // on the reference geometry). Creating a duplicate G4Material
161 // with the same name is a fatal error in Geant4.
162 //
163 // G4GDMLParser::Read() appends "0x<ptr>" suffixes (GenerateName)
164 // and then strips them back to plain names via StripNames(). Check
165 // both the generated name (pre-strip) and the plain name (post-strip)
166 // so that inline materials already registered under either convention
167 // are reused without re-creation.
168 mat = G4Material::GetMaterial(GenerateName(gdmlName), /*warning=*/false);
169 if (mat == nullptr) {
170 mat = G4Material::GetMaterial(gdmlName, /*warning=*/false);
171 }
172 if (mat == nullptr) {
173 // Material not yet registered — delegate full GDML parsing to
174 // the inherited method, which creates the G4Material.
175 MaterialRead(child);
176 mat = GetMaterial(GenerateName(gdmlName));
177 if (mat == nullptr) {
178 mat = G4Material::GetMaterial(gdmlName, /*warning=*/false);
179 }
180 }
181 if (!mat) {
182 G4Exception("G4OCCTMaterialMapReader::ReadFile", "G4OCCT_MatReader009", FatalException,
183 ("Failed to create inline material '" + gdmlName + "' (stepName='" +
184 stepName + "') in '" + path +
185 "'. Check that density and composition are valid.")
186 .c_str());
187 continue;
188 }
189 }
190
191 result.Add(stepName, mat);
192 }
193 } // xercesc::XercesDOMParser destroyed here
194
195 xercesc::XMLPlatformUtils::Terminate();
196 return result;
197}
Declaration of G4OCCTMaterialMapReader.
G4OCCTMaterialMap ReadFile(const G4String &path)
Maps STEP material names to Geant4 G4Material objects.
void Add(const G4String &stepName, G4Material *material)