Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
CETmaterial.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // CETmaterial.cxx, (c) ATLAS Detector software
8 
9 #include <fstream>
10 
11 // Tracking
12 #include "TrkExAlgs/CETmaterial.h"
21 
22 //================ Constructor =================================================
23 
24 Trk::CETmaterial::CETmaterial(const std::string& name, ISvcLocator* pSvcLocator)
25  :
26  AthAlgorithm(name,pSvcLocator),
27  m_chronoStatSvc( "ChronoStatSvc", name )
28 { }
29 
30 //================ Destructor =================================================
31 
33 {
34  delete m_err;
35 }
36 
37 
38 //================ Initialization =================================================
39 
41 {
42  // Code entered here will be executed once at program start.
43 
44  ATH_MSG_INFO( "initialize()" );
45 
46  // Get Extrapolator from ToolService
47  if (m_extrapolator.retrieve().isFailure()) {
48  ATH_MSG_FATAL( "Could not retrieve Tool " << m_extrapolator << ". Exiting." );
49  return StatusCode::FAILURE;
50  }
51  if (m_extraprec.retrieve().isFailure()) {
52  ATH_MSG_FATAL( "Could not retrieve Tool " << m_extraprec << ". Exiting." );
53  return StatusCode::FAILURE;
54  }
55 
56  ATH_MSG_INFO( "initialize() successful" );
57  return StatusCode::SUCCESS;
58 }
59 
60 //================ Finalization =================================================
61 
63 {
64  // Code entered here will be executed once at the end of the program run.
65 
66  if (m_chronoStatSvc) m_chronoStatSvc->chronoPrint("MS::scan");
67 
68  return StatusCode::SUCCESS;
69 }
70 
71 //================ Execution ====================================================
72 
74 {
75  ATH_MSG_INFO( "execute()" );
76  const EventContext& ctx = Gaudi::Hive::currentContext();
77  // retrieve outer boundary cylinder surface
78  if (!m_outerBoundary) {
79  m_trackingGeometry = m_extrapolator->trackingGeometry();
80  m_outerBoundary = &(m_trackingGeometry->highestTrackingVolume()->boundarySurfaces()[2]->surfaceRepresentation());
81  if (!m_outerBoundary) {
82  ATH_MSG_FATAL( "Could not retrieve cylinder boundary from " << m_extrapolator << ". Exiting." );
83  return StatusCode::FAILURE;
84  }
85  ATH_MSG_INFO( "boundary retrieved " );
86  }
87 
88  if (m_chronoStatSvc) m_chronoStatSvc->chronoStart("MS::scan");
89 
90  // scan
91  std::vector<const TrackStateOnSurface*> material;
92  std::vector<const TrackStateOnSurface*> matPrec;
93  double phi = -M_PI;
94  for ( unsigned int it = 0; it < m_numScan+1; it++) {
95  // the initial perigee
96  double z0 = m_minZ0 + (m_maxZ0-m_minZ0)/m_numScan *it;
97  phi += 1*Gaudi::Units::deg; if (phi>M_PI) phi -=2*M_PI;
98 
99  double theta = m_minTheta + (m_maxTheta-m_minTheta)/m_numScan*it;
100  double p = m_minP + (m_maxP-m_minP)/m_numScan *it;
101  Trk::PerigeeSurface surface( Amg::Vector3D(0.,0.,0.));
102  Trk::Perigee initialPerigee(0., z0, phi, theta, m_charge/p, surface);
103 
104  const Trk::TrackParameters* seed = initialPerigee.clone();
105  const Trk::PerigeeSurface& pSf = initialPerigee.associatedSurface();
106  material.clear(); matPrec.clear();
107  const Trk::TrackParameters* currPar = seed;
108  const Trk::TrackParameters* precPar = seed;
109  if (m_domsentry) {
110  if (!m_msentry) {
111  m_msentry = m_trackingGeometry->trackingVolume("Calo::Containers::Calorimeter");
112  }
113  if (m_msentry) {
114  const Trk::TrackParameters* msEntry =
115  m_extrapolator->extrapolateToVolume(
116  ctx,
117  *currPar,
118  *m_msentry,
120  static_cast<Trk::ParticleHypothesis>(m_particleType.value())).release();
121  if (msEntry) {
122  printMat(
123  theta,
124  phi,
125  currPar->momentum().mag() - msEntry->momentum().mag(),
126  Amg::error(msEntry->covariance()->inverse().eval(), Trk::theta),
127  Amg::error(msEntry->covariance()->inverse().eval(), Trk::phi));
128 
129  const std::vector<const Trk::TrackStateOnSurface*>* mmsentry = m_extrapolator->extrapolateM(ctx,
130  *currPar,
131  msEntry->associatedSurface(),
133  false,
134  static_cast<Trk::ParticleHypothesis>(m_particleType.value()));
135  if (mmsentry ) {
136  for (const auto& entry : *mmsentry) {
137  if (entry) {
138  ATH_MSG_DEBUG("position:eloss:"
139  << entry->trackParameters()->position() << ":"
140  << entry->trackParameters()->momentum().mag() - currPar->momentum().mag());
141  }
142  }
143 
144  currPar = (mmsentry->back()) ? mmsentry->back()->trackParameters() : msEntry;
145 
146  const std::vector<const Trk::TrackStateOnSurface*>* peri = m_extrapolator->extrapolateM(ctx,
147  *currPar,
148  pSf,
150  false,
151  static_cast<Trk::ParticleHypothesis>(m_particleType.value()));
152  ATH_MSG_INFO ( "material scan:backward:" );
153  if (peri){
154  ATH_MSG_DEBUG ("trPar vector size:" << peri->size() );
155  } else {
156  ATH_MSG_ERROR ("Perigee pointer is null in CETmaterial.cxx");
157  delete msEntry;
158  return StatusCode::FAILURE;
159  }
160  for (const auto& entry : *peri) {
161  if (entry && entry->trackParameters()) {
162  ATH_MSG_DEBUG("position:eloss:"
163  << entry->trackParameters()->position() << ":"
164  << entry->trackParameters()->momentum().mag() - msEntry->momentum().mag());
165  }
166  }
167 
168  if (peri->back() && peri->back()->trackParameters()) {
169  ATH_MSG_INFO( "extrapolation to perigee:input: "
170  << initialPerigee.parameters()[0] << ","
171  << initialPerigee.parameters()[1] << ","
172  << initialPerigee.parameters()[2] << ","
173  << initialPerigee.parameters()[3] << ","
174  << initialPerigee.momentum().mag() );
175  ATH_MSG_INFO( "extrapolation to perigee:output: "
176  << peri->back()->trackParameters()->parameters()[0] << ","
177  << peri->back()->trackParameters()->parameters()[1] << ","
178  << peri->back()->trackParameters()->parameters()[2] << ","
179  << peri->back()->trackParameters()->parameters()[3] << ","
180  << peri->back()->trackParameters()->momentum().mag() );
181  } else {
182  ATH_MSG_ERROR( "extrapolation to perigee failed for input parameters: " << msEntry->parameters() );
183  }
184  delete peri;
185  delete msEntry;
186  } else {
187  ATH_MSG_ERROR( "extrapolation to MSentry failed for input parameters: " << currPar->parameters() );
188  printMat(theta,phi,0.);
189  }
190  }
191  }
192  delete currPar;
193  continue;
194  }
195  if (m_checkStepWise) {
196  double matApp = 0.;
197  while (currPar) {
198  std::pair<std::unique_ptr<Trk::TrackParameters>,const Trk::Layer*> next = m_extrapolator->extrapolateToNextActiveLayerM(
199  ctx,
200  *currPar,
202  true,
203  material,
204  static_cast<Trk::ParticleHypothesis>(m_particleType.value()));
205 
206 
207  const Trk::TrackParameters* nextPar = next.first.release();
208  const Trk::Layer* lay = next.second;
209  currPar = nextPar;
210 
211  if (m_doprecision && precPar && currPar ) {
212  // try to extrapolate to the same surface
213  const std::vector<const Trk::TrackStateOnSurface*>* nextPrec = m_extraprec->extrapolateM(
214  ctx,
215  *precPar,currPar->associatedSurface(),
217  false,
218  static_cast<Trk::ParticleHypothesis>(m_particleType.value()));
219  delete precPar;
220  // collect material
221  if (nextPrec) {
222  for (const auto *i : *nextPrec) {
223  const Trk::MaterialEffectsBase* mEff = i->materialEffectsOnTrack();
224  const Trk::TrackParameters* trPar = i->trackParameters();
225  if (mEff && trPar) {
226  matApp += mEff->thicknessInX0();
227  }
228  }
229  }
230  // stop of extrapolation failed
231  if (!lay || !nextPrec || nextPrec->empty() || !nextPrec->back() ) break;
232  precPar = nextPrec->back()->trackParameters();
233  double mat=0.;
234  if (!material.empty()) for (auto & i : material) {
235  if (i->materialEffectsOnTrack()) mat += i->materialEffectsOnTrack()->thicknessInX0();
236  }
237  if ( precPar ) printMatComp(theta,phi,currPar,lay->enclosingDetachedTrackingVolume()->name(),mat,matApp,currPar->parameters()[0]-precPar->parameters()[0],
238  currPar->parameters()[1]-precPar->parameters()[1]);
239  else if (currPar) {
240  //precPar is nullptr here
241  ATH_MSG_INFO( "expected layer not reached:" << currPar->position() );
242  }
243  }
244  if (nextPar && m_printActive) {
245  int id = 0;
246  if (lay) id = lay->layerType();
247  double matc=0.;
248  if (!material.empty()) for (auto & i : material) {
249  if (i->materialEffectsOnTrack()) matc += i->materialEffectsOnTrack()->thicknessInX0();
250  }
251  else ATH_MSG_INFO( "mat & error:" << theta << "," << phi << "," << matc << ","
252  << Amg::error(nextPar->covariance()->inverse().eval(),Trk::theta) << ","
253  << Amg::error(nextPar->covariance()->inverse().eval(),Trk::phi) );
254 
255  printMatPrec(theta,phi,nextPar,nextPar,matc,id,"unknown");
256  }
257  if (!lay) break;
258  }
259  if (m_printMaterial) {
260  double mat=0.;
261  if (!material.empty()) for (auto & i : material) {
262  if (i->materialEffectsOnTrack()) {
263  mat += i->materialEffectsOnTrack()->thicknessInX0();
264  }
265  }
266  printMat(theta,phi,mat);
267  }
268  } else {
269  const std::vector<const Trk::TrackStateOnSurface*>* destParameters = m_extrapolator->extrapolateM(
270  ctx,
271  *currPar,
272  *m_outerBoundary,
274  false,
275  static_cast<Trk::ParticleHypothesis>(m_particleType.value()));
276 
277  if (m_printMaterial) {
278  double mat=0.;
279  if (destParameters) for (const auto *destParameter : *destParameters) {
280  const Trk::MaterialEffectsBase* mEff = destParameter->materialEffectsOnTrack();
281  const Trk::TrackParameters* trPar = destParameter->trackParameters();
282  if (trPar) {
283  //const Trk::MeasuredTrackParameters* mdest = dynamic_cast<const Trk::MeasuredTrackParameters*> (trPar);
284  //if (mdest) ATH_MSG_INFO( "radiation thickness and errors(theta,phi):" << theta << "," << phi << "," << mat << "," <<
285  // mdest->localErrorMatrix().error(Trk::theta) << "," << mdest->localErrorMatrix().error(Trk::phi) );
286  }
287  if (mEff && trPar) {
288  mat += mEff->thicknessInX0();
289  // find volume
290  std::vector<const Trk::DetachedTrackingVolume*> detVols = m_extrapolator->trackingGeometry()->lowestDetachedTrackingVolumes(trPar->position());
291  if (!detVols.empty()) printMatScan(theta,phi,trPar->position().perp(),trPar->position().z(),mEff->thicknessInX0(),(detVols)[0]->name());
292  else printMatScan(theta,phi,trPar->position().perp(),trPar->position().z(),mEff->thicknessInX0(),m_extrapolator->trackingGeometry()->lowestStaticTrackingVolume(trPar->position())->volumeName());
293  }
294  }
295  if (destParameters) {
296  //const Trk::MeasuredTrackParameters* mdest = dynamic_cast<const Trk::MeasuredTrackParameters*> ((*destParameters).back()->trackParameters());
297  //if (mdest) ATH_MSG_INFO( "radiation thickness and errors(theta,phi):" << theta << "," << phi << "," << mat << "," <<
298  //mdest->localErrorMatrix().error(Trk::theta) << "," << mdest->localErrorMatrix().error(Trk::phi) );
299  }
300  printMat(theta,phi,mat);
301  }
302 
303  if (!destParameters || destParameters->empty() ) {
304  ATH_MSG_ERROR( "extrapolation to outer boundary failed for input parameters: " << initialPerigee.parameters() );
305  } else if (destParameters->back()->trackParameters()) {
306  // forward extrapolation ok
307  if (m_backward) {
308  material.clear();
309  const std::vector<const Trk::TrackStateOnSurface*>* peri = m_extrapolator->extrapolateM(
310  ctx, *(destParameters->back()->trackParameters()),
311  pSf,
313  false,
314  static_cast<Trk::ParticleHypothesis>(m_particleType.value()));
315 
316  if (peri) {
317  ATH_MSG_INFO( "trPar vector size:" << peri->size() );
318  for (unsigned int i=0; i< peri->size(); i++)
319  ATH_MSG_INFO( "position:" << i << "," << (*peri)[i]->trackParameters()->position() );
320  ATH_MSG_INFO( "extrapolation to perigee:input: " << initialPerigee.parameters() );
321  ATH_MSG_INFO( "extrapolation to perigee:output: " << peri->back()->trackParameters()->parameters() );
322  } else {
323  ATH_MSG_ERROR( "extrapolation to perigee failed for input parameters: " << destParameters->back()->trackParameters()->parameters() );
324  }
325  delete peri;
326  }
327  }
328 
329  delete destParameters;
330  }
331  }
332 
333  if (m_chronoStatSvc) m_chronoStatSvc->chronoStop("MS::scan");
334 
335  return StatusCode::SUCCESS;
336 }
337 
338 //============================================================================================
339 
340 void Trk::CETmaterial::printMat(double theta, double phi, double mat, double dtheta, double dphi) const {
341 
342  std::ofstream myfilemat;
343  myfilemat.open (m_matTotFile,std::ios::app);
344  myfilemat<<theta<<" "<<phi<<" "<<mat<<" "<<dtheta<<" "<<dphi<<std::endl;
345 }
346 
347 
348 void Trk::CETmaterial::printMatScan(double theta, double phi, double r, double z, double mat, const std::string& name) const {
349 
350  std::ofstream myfilemat;
351  myfilemat.open(m_matScanFile,std::ios::app);
352  myfilemat << theta << " " << phi << " " << r << " " << z << " " << mat << " " << name << std::endl;
353 }
354 
355 void Trk::CETmaterial::printMatPrec(double theta, double phi, const Trk::TrackParameters* nextPar, const Trk::TrackParameters* mdest, double mat, int id, const std::string& name) {
356 
357  if (name.empty()) {}; // dummy to get rid of warning message (unused variable name)
358  std::ofstream myfilemat;
359  myfilemat.open(m_matActiveFile,std::ios::app);
360 
361  if (!m_th && !m_ph) {
362  m_th = theta;
363  m_ph = phi;
364  m_id = id;
365  m_matSaved = mat;
366  delete m_next; m_next=nextPar->clone();
367  delete m_err;
368  m_err=nullptr;
369  if (mdest) {
370  m_err=new Amg::MatrixX;
371  *m_err = mdest->covariance()->inverse().eval();
372  }
373  return;
374  }
375 
376  if ( theta!=m_th || phi!=m_ph ) {
377 
378  if (m_err && m_id>0) {
379  myfilemat << m_th << " " << m_ph << " " << 1 << " " << m_id << " " << m_matSaved << std::endl;
380  myfilemat << m_next->parameters()[Trk::locX] << " " << m_next->parameters()[Trk::locY] << " " << m_next->parameters()[Trk::phi]
381  << " " << m_next->parameters()[Trk::theta] << " " << m_next->parameters()[Trk::qOverP] << std::endl;
382  myfilemat << Amg::error(*m_err,Trk::locX) << " " << Amg::error(*m_err,Trk::locY)
383  << " " << Amg::error(*m_err,Trk::phi) << " " << Amg::error(*m_err,Trk::theta)
384  << " " << Amg::error(*m_err,Trk::qOverP) << std::endl;
385  } else {
386  myfilemat << m_th << " " << m_ph << " " << 0 << " " << m_id << std::endl;
387  myfilemat << m_next->parameters()[Trk::locX] << " " << m_next->parameters()[Trk::locY] << " " << m_next->parameters()[Trk::phi]
388  << " " << m_next->parameters()[Trk::theta] << " " << m_next->parameters()[Trk::qOverP] << std::endl;
389  }
390  m_th = theta;
391  m_ph = phi;
392  m_id = id;
393  m_matSaved = mat;
394  delete m_next; m_next=nextPar->clone();
395  delete m_err;
396  m_err=nullptr;
397 
398  if (mdest) {
399  m_err=new Amg::MatrixX;
400  *m_err = mdest->covariance()->inverse().eval();
401  }
402  return;
403  }
404 
405  // update data
406  if (id>1) {
407  m_th = theta;
408  m_ph = phi;
409  m_id = id;
410  m_matSaved = mat;
411  delete m_next; m_next=nextPar->clone();
412  delete m_err;
413  m_err=nullptr;
414  if (mdest) {
415  m_err=new Amg::MatrixX;
416  *m_err = mdest->covariance()->inverse().eval();
417  }
418  }
419  }
420 
421 void Trk::CETmaterial::printMatComp(double theta, double phi, const Trk::TrackParameters* currPar, const std::string& name, double mat, double matApp,double dx, double dy) const
422 {
423  std::ofstream myfilemat;
424  myfilemat.open(m_matCompFile,std::ios::app);
425  myfilemat << theta << " " << phi << " " << currPar->position().perp() << " " << currPar->position().z() << " " << name.substr(0,2)
426  << " " << mat << " " << matApp << " " << dx << " " << dy << std::endl;
427 }
Trk::CETmaterial::CETmaterial
CETmaterial(const std::string &name, ISvcLocator *pSvcLocator)
Standard Athena-Algorithm Constructor.
Definition: CETmaterial.cxx:24
beamspotman.r
def r
Definition: beamspotman.py:676
Trk::CETmaterial::finalize
StatusCode finalize()
standard Athena-Algorithm method
Definition: CETmaterial.cxx:62
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
Trk::CETmaterial::~CETmaterial
~CETmaterial()
Default Destructor.
Definition: CETmaterial.cxx:32
Amg::MatrixX
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Definition: EventPrimitives.h:27
Trk::z
@ z
global position (cartesian)
Definition: ParamDefs.h:57
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
PerigeeSurface.h
Trk::locX
@ locX
Definition: ParamDefs.h:37
Trk::locY
@ locY
local cartesian
Definition: ParamDefs.h:38
Trk::CETmaterial::printMatComp
void printMatComp(double theta, double phi, const Trk::TrackParameters *currPar, const std::string &name, double mat, double matApp, double dx, double dy) const
Definition: CETmaterial.cxx:421
Trk::PerigeeSurface
Definition: PerigeeSurface.h:43
Trk::next
@ next
Definition: BinningData.h:33
Trk::ParametersBase::position
const Amg::Vector3D & position() const
Access method for the position.
Trk::oppositeMomentum
@ oppositeMomentum
Definition: PropDirection.h:21
Trk::ParametersBase::associatedSurface
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
Trk::ParametersT
Dummy class used to allow special convertors to be called for surfaces owned by a detector element.
Definition: EMErrorDetail.h:25
mat
GeoMaterial * mat
Definition: LArDetectorConstructionTBEC.cxx:55
EventPrimitivesHelpers.h
skel.it
it
Definition: skel.GENtoEVGEN.py:407
M_PI
#define M_PI
Definition: ActiveFraction.h:11
deg
#define deg
Definition: SbPolyhedron.cxx:17
Trk::z0
@ z0
Definition: ParamDefs.h:64
Trk::Layer::enclosingDetachedTrackingVolume
const DetachedTrackingVolume * enclosingDetachedTrackingVolume() const
get the confining DetachedTrackingVolume
Trk::MaterialEffectsBase::thicknessInX0
double thicknessInX0() const
returns the actually traversed material .
Trk::alongMomentum
@ alongMomentum
Definition: PropDirection.h:20
Trk::MaterialEffectsBase
base class to integrate material effects on Trk::Track in a flexible way.
Definition: MaterialEffectsBase.h:35
Trk::CETmaterial::printMatPrec
void printMatPrec(double theta, double phi, const Trk::TrackParameters *, const Trk::TrackParameters *, double mat, int id, const std::string &name)
Definition: CETmaterial.cxx:355
Trk::Layer::layerType
int layerType() const
get the Layer coding
Trk::ParticleHypothesis
ParticleHypothesis
Definition: ParticleHypothesis.h:25
Trk::ParametersT::associatedSurface
virtual const S & associatedSurface() const override final
Access to the Surface method.
CylinderVolumeBounds.h
Trk::CETmaterial::printMat
void printMat(double th, double ph, double mat, double dtheta=0., double dphi=0.) const
Definition: CETmaterial.cxx:340
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
lumiFormat.i
int i
Definition: lumiFormat.py:85
Trk::theta
@ theta
Definition: ParamDefs.h:66
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Trk::CETmaterial::execute
StatusCode execute()
standard Athena-Algorithm method
Definition: CETmaterial.cxx:73
CylinderSurface.h
Trk::CETmaterial::printMatScan
void printMatScan(double theta, double phi, double r, double z, double mat, const std::string &name) const
Definition: CETmaterial.cxx:348
Trk::ParametersBase
Definition: ParametersBase.h:55
ParticleHypothesis.h
AthAlgorithm
Definition: AthAlgorithm.h:47
GetAllXsec.entry
list entry
Definition: GetAllXsec.py:132
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:239
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
Amg::error
double error(const Amg::MatrixX &mat, int index)
return diagonal error of the matrix caller should ensure the matrix is symmetric and the index is in ...
Definition: EventPrimitivesHelpers.h:40
Trk::DetachedTrackingVolume::name
const std::string & name() const
returns the Name
Definition: DetachedTrackingVolume.h:134
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
makeTRTBarrelCans.dy
tuple dy
Definition: makeTRTBarrelCans.py:21
Trk::ParametersBase::momentum
const Amg::Vector3D & momentum() const
Access method for the momentum.
makeTRTBarrelCans.dx
tuple dx
Definition: makeTRTBarrelCans.py:20
Trk::qOverP
@ qOverP
perigee
Definition: ParamDefs.h:67
CETmaterial.h
DiscSurface.h
TrackingGeometry.h
Trk::phi
@ phi
Definition: ParamDefs.h:75
Trk::CETmaterial::initialize
StatusCode initialize()
standard Athena-Algorithm method
Definition: CETmaterial.cxx:40
Trk::ParametersT::clone
virtual ParametersT< DIM, T, S > * clone() const override final
Virtual clone.
TrackStateOnSurface.h
Trk::ParametersBase::clone
virtual ParametersBase< DIM, T > * clone() const override=0
clone method for polymorphic deep copy
Trk::Layer
Definition: Layer.h:73