CbmRoot
Loading...
Searching...
No Matches
CaInitManager.cxx
Go to the documentation of this file.
1/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Sergey Gorbunov, Sergei Zharko [committer] */
4
9
10#include "CaInitManager.h"
11
12#include "CaConfigReader.h"
13#include "KfSetupBuilder.h"
14
15#include <boost/archive/binary_iarchive.hpp>
16#include <boost/archive/binary_oarchive.hpp>
17#include <boost/archive/text_iarchive.hpp>
18
19#include <algorithm>
20#include <fstream>
21#include <sstream>
22
23namespace cbm::algo::ca
24{
25 // --------------------------------------------------------------------------------------------------------------------
26 //
27 void InitManager::AddStation(const StationInitializer& inStation) { fvStationInfo.push_back(inStation); }
28
29 // --------------------------------------------------------------------------------------------------------------------
30 //
32 {
33 const auto& stations = par.GetStations();
34 for (int iSt = 0; iSt < par.GetNstationsActive(); ++iSt) {
35 auto stationIn = Station<double>(stations[iSt]);
36 // Get detector ID of the station
37 auto [detId, locId] = par.GetStationIndexLocal(par.GetActiveToGeoMap()[iSt]);
38 auto stationInfo = ca::StationInitializer(detId, locId);
39 stationInfo.SetStationType(stationIn.type);
40 stationInfo.SetZmin(0.); // NOTE: Deprecated (not used)
41 stationInfo.SetZmax(0.); // NOTE: Deprecated (not used)
42 stationInfo.SetZref(stationIn.fZ);
43 stationInfo.SetXmax(stationIn.Xmax);
44 stationInfo.SetYmax(stationIn.Ymax);
45 stationInfo.SetFieldStatus(stationIn.fieldStatus);
46 stationInfo.SetTimeInfo(stationIn.timeInfo);
47 stationInfo.SetTrackingStatus(true);
48 this->AddStation(stationInfo);
49 }
50 }
51
52 // --------------------------------------------------------------------------------------------------------------------
53 //
55 {
58 fbConfigIsRead = false;
60 }
61
62 // --------------------------------------------------------------------------------------------------------------------
63 //
65 {
66 // Clear stations set and a thickness map
67 fvStationInfo.clear();
69
70 // Set number of stations do default values
71 this->ClearStationLayout();
72
73 // Clear field info
74 fParameters.fVertexFieldRegion = kf::FieldRegion<fvec>();
75 fParameters.fVertexFieldValue = kf::FieldValue<fvec>();
77
78 // Clear target position
79 fParameters.fTargetPos.fill(Undef<float>);
80 fTargetZ = 0.;
82
83 // Clear field function
84 fFieldFunction = FieldFunction_t([](const double(&)[3], double(&)[3]) {});
86
87 // Clear other flags
88 fParameters.fRandomSeed = 1;
89 fParameters.fGhostSuppression = 0;
92
93 fParameters.fMisalignmentX.fill(0.);
94 fParameters.fMisalignmentY.fill(0.);
95 fParameters.fMisalignmentT.fill(0.);
96
97 fParameters.fDevIsIgnoreHitSearchAreas = false;
98 fParameters.fDevIsUseOfOriginalField = false;
99 fParameters.fDevIsMatchDoubletsViaMc = false;
100 fParameters.fDevIsMatchTripletsViaMc = false;
101 fParameters.fDevIsExtendTracksViaMc = false;
102 fParameters.fDevIsSuppressOverlapHitsViaMc = false;
103 fParameters.fDevIsParSearchWUsed = false;
104
105 fbGeometryConfigLock = false;
106 }
107
108 // --------------------------------------------------------------------------------------------------------------------
109 //
117
118 // --------------------------------------------------------------------------------------------------------------------
119 // NOTE: this function should be called once in the SendParameters
121 {
122 // Read configuration files
123 this->ReadInputConfigs();
124 if (!fbConfigIsRead) { // Check config reading status
125 return false;
126 }
127
128 if (!fParameters.fDevIsParSearchWUsed) {
130 }
131
132 // Apply magnetic field to the station info objects
133 std::for_each(fvStationInfo.begin(), fvStationInfo.end(), [&](auto& st) { st.SetFieldFunction(fFieldFunction); });
134
135 // Check initialization
136 this->CheckInit();
137
139 LOG(error) << "ca::InitManager: Attempt to form parameters container before all necessary fields were initialized"
141 return false;
142 }
143
144 { // Form array of stations
145 auto destIt = fParameters.fStations.begin();
146 for (const auto& station : fvStationInfo) {
147 if (!station.GetTrackingStatus()) {
148 continue;
149 }
150 *destIt = station.GetStation();
151 ++destIt;
152 }
153 }
154
155 // Check the consistency of the parameters object. If object inconsistent, it throws std::logic_error
156 try {
157 fParameters.CheckConsistency();
158 }
159 catch (const std::logic_error& err) {
160 LOG(error) << "ca::InitManager: parameters container consistency check failed. Reason: " << err.what();
161 return false;
162 }
163
164 return true;
165 }
166
167 // --------------------------------------------------------------------------------------------------------------------
168 //
170 {
172 std::stringstream msg;
173 msg << "ca::InitManager: number of active stations cannot be accessed until the station layout is initialized";
174 throw std::runtime_error(msg.str());
175 }
176 return fParameters.GetNstationsActive();
177 }
178
179 // --------------------------------------------------------------------------------------------------------------------
180 //
182 {
184 std::stringstream msg;
185 msg << "ca::InitManager: number of active stations cannot be accessed until the station layout is initialized";
186 throw std::runtime_error(msg.str());
187 }
188 return fParameters.GetNstationsActive(detectorID);
189 }
190
191 // --------------------------------------------------------------------------------------------------------------------
192 //
194 {
196 std::stringstream msg;
197 msg << "ca::InitManager: number of geometry stations cannot be accessed until the station layout is initialized";
198 throw std::runtime_error(msg.str());
199 }
200 return fParameters.GetNstationsGeometry();
201 }
202
203 // --------------------------------------------------------------------------------------------------------------------
204 //
206 {
208 std::stringstream msg;
209 msg << "ca::InitManager: number of geometry stations cannot be accessed until the station layout is initialized";
210 throw std::runtime_error(msg.str());
211 }
212 return fParameters.GetNstationsGeometry(detectorID);
213 }
214
215 // --------------------------------------------------------------------------------------------------------------------
216 //
217 std::vector<StationInitializer>& InitManager::GetStationInfo()
218 {
220 std::stringstream msg;
221 msg << "ca::InitManager: station info container cannot be accessed until the station layout is initialized";
222 throw std::runtime_error(msg.str());
223 }
224 return fvStationInfo;
225 }
226
227
228 // --------------------------------------------------------------------------------------------------------------------
229 //
231 {
232 LOG(info) << "ca::InitManager::InitStationLayout(): ....";
233 this->ClearStationLayout();
234 std::sort(fvStationInfo.begin(), fvStationInfo.end());
235
236 for (const auto& aStation : fvStationInfo) {
237 ++fParameters.fvFirstGeoId[static_cast<int>(aStation.GetDetectorID()) + 1];
238 }
239 for (int iDet = 1; iDet < static_cast<int>(fParameters.fvFirstGeoId.size()) - 1; ++iDet) {
240 fParameters.fvFirstGeoId[iDet + 1] += fParameters.fvFirstGeoId[iDet];
241 }
242
243 fParameters.fNstationsActiveTotal = 0;
244 for (int iStGeo = 0; iStGeo < static_cast<int>(fvStationInfo.size()); ++iStGeo) {
245 const auto& aStation = fvStationInfo[iStGeo];
246 int iDet = static_cast<int>(aStation.GetDetectorID());
247 int iStLocal = aStation.GetStationID();
248 // Fill local -> geo map
249 fParameters.fvGeoToLocalIdMap[iStGeo] = std::make_pair(aStation.GetDetectorID(), iStLocal);
250 // Fill geo -> local map
251 fParameters.fvLocalToGeoIdMap[fParameters.fvFirstGeoId[iDet] + iStLocal] = iStGeo;
252 // Fill geo <-> active map
253 int iStActive = aStation.GetTrackingStatus() ? fParameters.fNstationsActiveTotal++ : -1;
254 fParameters.fvGeoToActiveMap[iStGeo] = iStActive;
255 if (iStActive > -1) {
256 fParameters.fvActiveToGeoMap[iStActive] = iStGeo;
257 }
258 }
260
261 for (auto& aStation : fvStationInfo) {
262 aStation.SetGeoLayerID(fParameters.GetStationIndexGeometry(aStation.GetStationID(), aStation.GetDetectorID()));
263 }
264 }
265
266 // --------------------------------------------------------------------------------------------------------------------
267 //
269 {
271 LOG(warn) << "ca::InitManager::InitTargetField: attempt to reinitialize the field value and field region "
272 << "near target. Ignore";
273 return;
274 }
275
276 // Check for field function
278 std::stringstream msg;
279 msg << "Attempt to initialize the field value and field region near target before initializing field function";
280 throw std::runtime_error(msg.str());
281 }
282 // Check for target defined
284 std::stringstream msg;
285 msg << "Attempt to initialize the field value and field region near target before the target position"
286 << "initialization";
287 throw std::runtime_error(msg.str());
288 }
289 constexpr int nDimensions{3};
290 constexpr int nPointsNodal{3};
291
292 std::array<double, nPointsNodal> inputNodalZ{fTargetZ, fTargetZ + zStep, fTargetZ + 2. * zStep};
293 std::array<kf::FieldValue<fvec>, nPointsNodal> B{};
294 std::array<fvec, nPointsNodal> z{};
295 // loop over nodal points
296 for (int idx = 0; idx < nPointsNodal; ++idx) {
297 double point[nDimensions]{0., 0., inputNodalZ[idx]};
298 double field[nDimensions]{};
299 fFieldFunction(point, field);
300 z[idx] = inputNodalZ[idx];
301 B[idx].Set(field[0], field[1], field[2]);
302 } // loop over nodal points: end
303 fParameters.fVertexFieldRegion.Set(B[0], z[0], B[1], z[1], B[2], z[2]);
304 fParameters.fVertexFieldValue = B[0];
305
307 }
308
309 // --------------------------------------------------------------------------------------------------------------------
310 //
312 {
313 // TODO: probably some checks must be inserted here (S.Zharko)
315 std::stringstream msg;
316 msg << "Attempt to push back a CA track finder iteration before the number of iterations was defined";
317 throw std::runtime_error(msg.str());
318 }
319 fParameters.fCAIterations.push_back(iteration);
320 }
321
322 // -------------------------------------------------------------------------------------------------------------------
323 //
325 {
326 if (!fbConfigIsRead) {
327 LOG(info) << "ca::InitManager: reading parameter configuration ...";
328 try {
329 auto configReader = ConfigReader(this, 4);
330 configReader.SetMainConfigPath(fsConfigInputMain);
331 configReader.SetUserConfigPath(fsConfigInputUser);
332 configReader.SetGeometryLock(fbGeometryConfigLock);
333 configReader.Read();
334 fbConfigIsRead = true;
335 LOG(info) << "ca::InitManager: reading parameter configuration ... \033[1;32mdone\033[0m";
336 }
337 catch (const std::runtime_error& err) {
338 LOG(error) << "ca::InitManager: reading parameter configuration ... \033[1;31mfail\033[0m. Reason: "
339 << err.what();
340 }
341 }
342 }
343
344 // -------------------------------------------------------------------------------------------------------------------
345 //
346 void InitManager::ReadGeometrySetup(const std::string& fileName)
347 {
348 // Open input binary file
350 }
351
352 // -------------------------------------------------------------------------------------------------------------------
353 //
354 void InitManager::ReadParametersObject(const std::string& fileName)
355 {
356 using namespace constants;
357 // clrs::CL - end colored log
358 // clrs::GNb - bold green log
359 // clrs::RDb - bold red log
360
361 // Open input binary file
362 std::ifstream ifs(fileName, std::ios::binary);
363 if (!ifs) {
364 std::stringstream msg;
365 msg << "ca::InitManager: parameters data file \"" << clrs::GNb << fileName << clrs::CL << "\" was not found";
366 throw std::runtime_error(msg.str());
367 }
368
369 // Get L1InputData object
370 try {
371 boost::archive::binary_iarchive ia(ifs);
372 ia >> fParameters;
374 }
375 catch (const std::exception&) {
376 std::stringstream msg;
377 msg << "ca::InitManager: parameters file \"" << clrs::GNb << fileName << clrs::CL
378 << "\" has incorrect data format or was corrupted";
379 throw std::runtime_error(msg.str());
380 }
381
385 }
386
387 // -------------------------------------------------------------------------------------------------------------------
388 //
389 void InitManager::ReadSearchWindows(const std::string& fileName)
390 {
391 // Open input binary file
392 std::ifstream ifs(fileName);
393 if (!ifs) {
394 std::stringstream msg;
395 msg << "ca::InitManager: search window file \"" << fileName << "\" was not found";
396 throw std::runtime_error(msg.str());
397 }
398
399 try {
400 boost::archive::text_iarchive ia(ifs);
401 int nPars = -1;
402 int nWindows = -1;
403 ia >> nPars;
404 assert(nPars == 1); // Currently only the constant windows are available
405 ia >> nWindows;
406 std::stringstream errMsg;
407 for (int iW = 0; iW < nWindows; ++iW) {
408 SearchWindow swBuffer;
409 ia >> swBuffer;
410 int iStationID = swBuffer.GetStationID();
411 int iTrackGrID = swBuffer.GetTrackGroupID();
412 if (iStationID < 0 || iStationID > constants::size::MaxNstations) {
413 errMsg << "\t- wrong station id for entry " << iW << ": " << iStationID << " (should be between 0 and "
415 }
416 if (iTrackGrID < 0 || iTrackGrID > constants::size::MaxNtrackGroups) {
417 errMsg << "\t- wrong track group id for entry " << iW << ": " << iTrackGrID << " (should be between 0 and "
419 }
420 fParameters.fSearchWindows[iTrackGrID * constants::size::MaxNstations + iStationID] = swBuffer;
421 }
422 if (errMsg.str().size()) {
423 std::stringstream msg;
424 msg << "ca::InitManager: some errors occurred while reading search windows: " << errMsg.str();
425 throw std::runtime_error(msg.str());
426 }
427 }
428 catch (const std::exception& err) {
429 std::stringstream msg;
430 msg << "search windows file \"" << fileName << "\" has incorrect data format or was corrupted. ";
431 msg << "Exception catched: " << err.what();
432 throw std::runtime_error(msg.str());
433 }
434
436 }
437
438 // --------------------------------------------------------------------------------------------------------------------
439 //
441 {
442 fCAIterationsNumberCrosscheck = nIterations;
443 auto& iterationsContainer = fParameters.fCAIterations;
444
445 // NOTE: should be called to prevent multiple copies of objects between the memory reallocations
446 iterationsContainer.reserve(nIterations);
448 }
449
450 // --------------------------------------------------------------------------------------------------------------------
451 //
453 {
455 fFieldFunction = fieldFunction;
457 }
458 else {
459 LOG(warn) << "ca::InitManager::SetFieldFunction: attempt to reinitialize the field function. Ignored";
460 }
461 }
462
463 // --------------------------------------------------------------------------------------------------------------------
464 //
465 void InitManager::SetGhostSuppression(int ghostSuppression)
466 {
468 LOG(warn)
469 << "ca::InitManager::SetGhostSuppression: attempt of reinitializating the ghost suppresion flag. Ignore";
470 return;
471 }
472 fParameters.fGhostSuppression = ghostSuppression;
474 }
475
476 // --------------------------------------------------------------------------------------------------------------------
477 //
478 void InitManager::SetRandomSeed(unsigned int seed)
479 {
481 LOG(warn) << "ca::InitManager::SetRandomSeed: attempt of reinitializating the random seed. Ignore";
482 return;
483 }
484 fParameters.fRandomSeed = seed;
486 }
487
488 // --------------------------------------------------------------------------------------------------------------------
489 //
490 void InitManager::SetTargetPosition(double x, double y, double z)
491 {
493 LOG(warn) << "ca::InitManager::SetTargetPosition: attempt to reinitialize the target position. Ignore";
494 return;
495 }
496
498 fParameters.fTargetPos[0] = x;
499 fParameters.fTargetPos[1] = y;
500 fParameters.fTargetPos[2] = z;
502 fTargetZ = z;
504 }
505
506 // --------------------------------------------------------------------------------------------------------------------
507 //
509
510 // --------------------------------------------------------------------------------------------------------------------
511 //
512 void InitManager::WriteParametersObject(const std::string& fileName) const
513 {
516 // Open output binary file
517 std::ofstream ofs(fileName, std::ios::binary);
518 if (!ofs) {
519 std::stringstream msg;
520 msg << "ca::InitManager: failed opening file \"" << GNb << fileName << CL << "\" to write parameters object";
521 throw std::runtime_error(msg.str());
522 }
523
524 LOG(info) << "ca::InitManager: writing CA parameters object to file \"" << GNb << fileName << '\"' << CL;
525
526 // Serialize L1Parameters object and write
527 boost::archive::binary_oarchive oa(ofs);
528 oa << fParameters;
529 }
530
531 // --------------------------------------------------------------------------------------------------------------------
532 //
534 {
535 bool ifInitPassed = true;
537 int nIterationsActual = fParameters.fCAIterations.size();
538 int nIterationsExpected = fCAIterationsNumberCrosscheck;
539 if (nIterationsActual != nIterationsExpected) {
540 LOG(warn) << "ca::InitManager::CheckCAIterations: incorrect number of iterations registered: "
541 << nIterationsActual << " of " << nIterationsExpected << " expected";
542 ifInitPassed = false;
543 }
544 }
546 }
547
548 // --------------------------------------------------------------------------------------------------------------------
549 // TODO: REWRITE! and add const qualifier (S.Zharko)
551 {
552 bool ifInitPassed = true;
554 // (1) Check the stations themselves
555 bool bStationsFinalized = std::all_of(fvStationInfo.begin(), fvStationInfo.end(),
556 [](const auto& st) { return st.GetInitController().IsFinalized(); });
557 if (!bStationsFinalized) {
558 std::stringstream msg;
559 msg << "ca::InitManager: At least one of the StationInitializer objects is not finalized";
560 }
561
562 // (2) Check for maximum allowed number of stations
563 if (fParameters.GetNstationsGeometry() > constants::size::MaxNstations) {
564 std::stringstream msg;
565 msg << "Actual total number of registered stations in geometry (" << fParameters.GetNstationsGeometry()
566 << ") is larger then possible (" << constants::size::MaxNstations
567 << "). Please, select another set of active tracking detectors or recompile the code with enlarged"
568 << " constants::size::MaxNstations value";
569 throw std::runtime_error(msg.str());
570 }
571 }
573 }
574
575 // -------------------------------------------------------------------------------------------------------------------
576 //
578 {
579 fParameters.fvFirstGeoId.fill(0);
580 fParameters.fvLocalToGeoIdMap.fill(0);
581 fParameters.fvGeoToLocalIdMap.fill(std::make_pair(static_cast<EDetectorID>(0), -1));
582 fParameters.fvGeoToActiveMap.fill(-1); // Note: by default all the stations are inactive
583 fParameters.fvActiveToGeoMap.fill(0);
584 fParameters.fNstationsActiveTotal = -1;
586 }
587} // namespace cbm::algo::ca
Configuration parameter file reader for the CA tracking algorithm (header)
Input data management class for the CA tracking algorithm (header)
A base KF-Setup initialization class (source)
A reader for the CA parameters from the YAML configuration files.
std::vector< StationInitializer > & GetStationInfo()
Gets a reference to the stations array.
void SetTargetPosition(double x, double y, double z)
Sets target position.
void ClearStationLayout()
Returns station layout into undefined condition.
void SetFieldFunction(const FieldFunction_t &fieldFcn)
Sets a magnetic field function, which will be applied for all the stations.
InitController_t fInitController
Initialization flags.
void ReadSearchWindows(const std::string &fileName)
Reads search windows from file.
void InitTargetField(double zStep)
Calculates kf::FieldValue and L1FieldReference values for a selected step in z-axis from the target p...
Parameters< fvec > fParameters
CA parameters object.
int fCAIterationsNumberCrosscheck
Number of iterations to be passed (must be used for cross-checks)
bool fbConfigIsRead
Flag, if configuration file was read.
void SetCAIterationsNumberCrosscheck(int nIterations)
Sets a number of CA track finder iterations to provide initialization cross-check.
void ReadGeometrySetup(const std::string &fileName)
Reads geometry setup from file.
int GetNstationsGeometry() const
Gets total number of stations, provided by setup geometry.
void ClearCAIterations()
Clears vector of CA track finder iterations.
void InitStationLayout()
Initializes station layout.
Parameters< fvec > && TakeParameters()
Takes parameters object from the init-manager instance.
bool fbGeometryConfigLock
Lock geometry initialization.
void SetGeometrySetup(const cbm::algo::kf::Setup< DataT > &setup)
Sets setup.
void ReadParametersObject(const std::string &fileName)
Reads parameters object from boost-serialized binary file.
void AddStations(const Parameters< fvec > &par)
Adds tracking stations from the parameters file.
std::function< void(const double(&xyz)[3], double(&B)[3])> FieldFunction_t
void SetGhostSuppression(int ghostSuppression)
Sets the flag to enable/disable the ghost suppression routine.
void CheckCAIterationsInit()
Checker for Iteration container initialization (sets EInitKey::kCAIterations)
void ClearSetupInfo()
Clears vector of base setup.
void WriteParametersObject(const std::string &fileName) const
Writes parameters object from boost-serialized binary file.
double fTargetZ
Target position z component in double precision.
void SetRandomSeed(unsigned int seed)
Sets pseudo-random numbers generator seed.
std::string fsConfigInputMain
name for the input configuration file
void ReadInputConfigs()
Reads main and user parameters configs.
FieldFunction_t fFieldFunction
A function which returns magnetic field vector B in a radius-vector xyz.
int GetNstationsActive() const
Gets total number of active stations.
void PushBackCAIteration(const Iteration &iteration)
Pushes an CA track finder iteration into a sequence of iteration using reference.
std::vector< StationInitializer > fvStationInfo
Vector of StationInitializer objects (active + inactive)
void AddStation(const StationInitializer &station)
Adds a tracking station to the geometry.
void CheckInit()
Provides final checks of the parameters object.
@ kSearchWindows
6) If the hit search windows were initialized
@ kFieldFunction
0) If magnetic field getter function is set
@ kTargetPos
1) If target position was defined
@ kCAIterationsNumberCrosscheck
4) If the number of CA track finder is initialized
@ kStationLayoutInitialized
9) If stations layout is initialized
@ kRandomSeed
8) If the random seed is provided
@ kStationsInfo
3) If all the planned stations were added to the manager
@ kPrimaryVertexField
2) If magnetic field value and region defined at primary vertex
@ kCAIterations
5) If the CA track finder iterations were initialized
bool FormParametersContainer()
Forms parameters container.
void CheckStationsInfoInit()
Checker for StationInitializer set initialization (sets EInitKey::kStationsInfo)
std::string fsConfigInputUser
name for the input configuration file
A set of parameters for the CA Track finder iteration.
bool GetFlag(InitKeyEnum bitKey) const
void SetFlag(InitKeyEnum bitKey, bool newStatus=true)
bool IsFinalized() const
Checks, if the object is finalized, i.e. all its fields were set up.
std::string ToString(int indentLevel=0) const
A container for all external parameters of the CA tracking algorithm.
int GetNstationsActive() const
Gets total number of active stations.
const StationArray_t< int > & GetActiveToGeoMap() const
Provides access to the map of active to geo station indices (const)
const StationsContainer_t< DataT > & GetStations() const
Provides access to L1Stations container (const)
std::pair< EDetectorID, int > GetStationIndexLocal(int geoIndex) const
Gets local index of station.
Class L1SearchWindow defines a parameterisation of hits search window for CA tracking algorithm TODO:...
int GetStationID() const
Gets station id.
int GetTrackGroupID() const
Gets track group id.
A base class which provides interface to L1Algo station geometry.
Magnetic field region, corresponding to a hit triplet.
Magnetic flux density vector.
static Setup< T > Load(const std::string &fileName)
Loads a serialized setup from a file.
constexpr char GNb[]
bold green
Definition CaDefs.h:155
constexpr char CL[]
clear
Definition CaDefs.h:132
constexpr int MaxNstations
Max number of stations, 2^6 = 64.
Definition CaDefs.h:44
constexpr int MaxNtrackGroups
Definition CaDefs.h:51
TODO: SZh 8.11.2022: add selection of parameterisation.
Definition CaBranch.h:14
EDetectorID
Enumeration for the tracking detector subsystems in CBM-CA.
Definition CbmDefs.h:176