OTSClassifyEng.cpp 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469
  1. #pragma once
  2. #include "stdafx.h"
  3. #include "OTSClassifyEng.h"
  4. #include "OTSHelper.h"
  5. namespace OTSClassifyEngine
  6. {
  7. using namespace OTSClassifyEngine;
  8. const double MIN_ELEMENT_SUM = 0.02;
  9. const long INC_DEFAULTSIZE = 100;
  10. const long INC_ELEMENTSIZE_MIN = 0;
  11. const CString STR_CONNECT = _T("-");
  12. const CString STR_FE = _T("Fe");
  13. const CString STR_C = _T("C");
  14. const CString STR_SI = _T("Si");
  15. const CString STR_O = _T("O");
  16. const CString STR_SUL = _T("S");
  17. const CString STR_N = _T("N");
  18. const CString STR_CR = _T("Cr");
  19. const double SIC_MOLAR_CUTOFF = 85.0;
  20. const double FEO_MOLAR_CUTOFF = 85.0;
  21. // key element
  22. const long INC_KEY_ELEMENT_MAX = 4;
  23. const double INC_KEY_ELEMENT_CUT_OFF = 0.02; // weight%
  24. const double INC_KEY_ELEMENT_TOTAL_100 = 5.0; // total molar value
  25. const CString INC_KEY_ELEMENT_NAMES[INC_KEY_ELEMENT_MAX] =
  26. {
  27. _T("S"),_T("N"),_T("O"),_T("C")
  28. };
  29. // sub element
  30. const long INC_SUB_ELEMENT_MAX = 12;
  31. const double INC_SUB_ELEMENT_CUT_OFF = 0.02; // weight%
  32. const double INC_SUB_ELEMENT_TOTAL_100 = 5.0; // molar value
  33. const CString INC_SUB_ELEMENT_NAMES[INC_SUB_ELEMENT_MAX] =
  34. {
  35. _T("Mg"),_T("Al"),_T("Si"),_T("Ca"),_T("Ti"),_T("V"),_T("Mn"),_T("Zr"),_T("Nb"),_T("Mo"),_T("Ce"),_T("La")
  36. };
  37. // element 100 % molar value mapping cut off
  38. const double ELEMENT_MAPPING_100MOLAR = 2.0;
  39. // sulfur classification
  40. const double MIN_SUL_MOLAR = ELEMENT_MAPPING_100MOLAR;
  41. const double MIN_SUL_SUB_MOLAR = ELEMENT_MAPPING_100MOLAR;
  42. const long INC_SUL_SUB_ELEMENT_MAX = 5;
  43. const CString INC_SUL_SUB_ELEMENT_NAMES[INC_SUL_SUB_ELEMENT_MAX] =
  44. {
  45. _T("Mn"),_T("Ca"),_T("Mg"),_T("Ce"),_T("La")
  46. };
  47. const CString INC_SULFILSES_NAMES[INC_SUL_SUB_ELEMENT_MAX] =
  48. {
  49. _T("MnS"),_T("CaS"),_T("MgS"),_T("Ce(La)2S3"),_T("Ce(La)2S3")
  50. };
  51. const double INC_SULFILSES_MAPPING_RATIO[INC_SUL_SUB_ELEMENT_MAX] =
  52. {
  53. 1.0, 1.0, 1.0, 1.5, 1.5
  54. };
  55. const double SULFIDE_MOLAR_CUTOFF = 5.0;
  56. const CString SULFIDE_STR = _T("Sulfide");
  57. // O classification
  58. const long INC_OXIDE_SUB_ELEMENT_MAX = 9;
  59. const CString INC_OXIDE_SUB_ELEMENT_NAMES[INC_OXIDE_SUB_ELEMENT_MAX] =
  60. {
  61. _T("Al"),_T("Mg"),_T("Si"),_T("Mn"),_T("Ca"),_T("Ce"),_T("Cr"),_T("Ti"),_T("La")
  62. };
  63. const CString INC_OXIDE_NAMES[INC_OXIDE_SUB_ELEMENT_MAX] =
  64. {
  65. _T("Al2O3"),_T("MgO"),_T("SiO2"),_T("MnO"),_T("CaO"),_T("CeO"),_T("Oxide"),_T("Oxide"),_T("REOxide")
  66. };
  67. const double SIMPLE_OXIDE_MOLAR_CUTOFF = 90.0;
  68. const long REOXIDE_KEY_ELEMENT_MAX = 2;
  69. const CString REOXIDE_KEY_ELEMENT_NAMES[REOXIDE_KEY_ELEMENT_MAX] =
  70. {
  71. _T("Ce"),_T("La")
  72. };
  73. const CString REOXIDE_STR = _T("REOxide");
  74. const long REALOXIDE_SUB_ELEMENT_MAX = 2;
  75. const CString REALOXIDE_SUB_ELEMENT_NAMES[REALOXIDE_SUB_ELEMENT_MAX] =
  76. {
  77. _T("Si"),_T("Al")
  78. };
  79. const double REALOXIDE_ELEMELTS_MOLAR_CUTOFF = 90.0;
  80. const CString REALOXIDE_STR = _T("REAlOxide");
  81. const long SPINEL_KEY_ELEMENT_MAX = 2;
  82. const double REALOXIDE_ELEMENT_MOLAR_LOW_CUTOFF = 20;
  83. const CString SPINEL_KEY_ELEMENT_NAMES[SPINEL_KEY_ELEMENT_MAX] =
  84. {
  85. _T("Mg"),_T("Al")
  86. };
  87. const double SPINEL_KEY_ELEMENT_MOLAR_TOTAL = 90.0;
  88. const double SPINEL_ELEMENT_RATIO_MIN = 1.6;
  89. const double SPINEL_ELEMENT_RATIO_MAX = 2.4;
  90. const CString SPINEL_STR = _T("Spinel");
  91. const CString SILICATE_KEY_ELEMENT_NAME = _T("Si");
  92. const double SILICATE_KEY_ELEMENT_MOLAR_TOTAL_MIN = 10.0;
  93. const double SILICATE_KEY_ELEMENT_MOLAR_TOTAL_MAX = 90.0;
  94. const CString SILICATE_STR = _T("Silicate");
  95. const long ALUMINATE_KEY_ELEMENT_MAX = 2;
  96. const CString ALUMINATE_KEY_ELEMENT_NAME[ALUMINATE_KEY_ELEMENT_MAX] =
  97. {
  98. _T("Al"),_T("Ca")
  99. };
  100. const double ALUMINAT_KEY_ELEMENT_MOLAR_TOTAL_MIN = 10.0;
  101. const double ALUMINAT_KEY_ELEMENT_MOLAR_TOTAL_MAX = 90.0;
  102. const CString ALUMINATE12CaO_7Al2O3_STR = _T("12CaO-7Al2O3");
  103. const CString ALUMINATE3CaO_Al2O3_STR = _T("3CaO-Al2O3");
  104. const CString ALUMINATE_STR = _T("Aluminate");
  105. const CString Ca_ALUMINATE_STR = _T("Ca-Aluminate");
  106. const CString STR_OXIDE = _T("O");
  107. const double MIN_OXIDE_MOLAR = 5.0;
  108. const double MIN_OXIDE_SUB_MOLAR_TOTAL = 5.0;
  109. const double MIN_OXIDE_SUB_MOLAR_CUTOFF = ELEMENT_MAPPING_100MOLAR;
  110. const CString OXIDE_STR = _T("Oxide");
  111. // nitrogen classification
  112. const long INC_NITR_SUB_ELEMENT_MAX = 8;
  113. const CString INC_NITR_SUB_ELEMENT_NAMES[INC_NITR_SUB_ELEMENT_MAX] =
  114. {
  115. _T("Ti"),_T("V"),_T("Nb"),_T("Al"),_T("Zr"),_T("Cr"),_T("La"),_T("Ce")
  116. };
  117. const CString INC_NITR_NAMES[INC_NITR_SUB_ELEMENT_MAX] =
  118. {
  119. _T("TiN"),_T("VN"),_T("NbN"),_T("AlN"),_T("Nitride"),_T("Nitride"),_T("Nitride"),_T("Nitride")
  120. };
  121. const double INC_NITR_MAPPING_RATIO[INC_NITR_SUB_ELEMENT_MAX] =
  122. {
  123. 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0
  124. };
  125. const CString STR_NITR = _T("N");
  126. const CString STR_Nb = _T("Nb");
  127. const double MIN_NITR_MOLAR = ELEMENT_MAPPING_100MOLAR;
  128. const double MIN_NITR_SUB_MOLAR = ELEMENT_MAPPING_100MOLAR;
  129. const double NITRIDE_MOLAR_CUTOFF = 5.0;
  130. const CString NITRIDE_STR = _T("Nitride");
  131. #pragma region ÐÂÌí¼ÓµÄ̼ÄÚÈÝ
  132. // carbon classification
  133. const long INC_CAR_SUB_ELEMENT_MAX = 1;
  134. const CString INC_CAR_SUB_ELEMENT_NAMES[INC_CAR_SUB_ELEMENT_MAX] =
  135. {
  136. _T("Nb")
  137. };
  138. const CString INC_CAR_NAMES[INC_CAR_SUB_ELEMENT_MAX] =
  139. {
  140. _T("NbC")
  141. };
  142. const double INC_CAR_MAPPING_RATIO[INC_CAR_SUB_ELEMENT_MAX] =
  143. {
  144. 1.0
  145. };
  146. const CString STR_CAR = _T("C");
  147. const double MIN_CAR_MOLAR = ELEMENT_MAPPING_100MOLAR;
  148. const double MIN_CAR_SUB_MOLAR = ELEMENT_MAPPING_100MOLAR;
  149. const double CARBON_MOLAR_CUTOFF = 5.0;
  150. const CString CARBON_STR = _T("Carbon");
  151. #pragma endregion
  152. COTSClassifyEng::COTSClassifyEng(CInclutionSTDDataPtr a_pPartSTDData) // constructor
  153. {
  154. ASSERT(a_pPartSTDData);
  155. // get all sulfides STD items
  156. pPartSTDData = a_pPartSTDData;
  157. if (!GetClassifySTDItem(a_pPartSTDData, INC_CLASSIFY_TYPE::SUL, listSulfideSTD))
  158. {
  159. // something is wrong
  160. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::SulClassify: failed to call GetClassifySTDItem method."));
  161. }
  162. // get all oxides STD items
  163. if (!GetClassifySTDItem(a_pPartSTDData, INC_CLASSIFY_TYPE::OXIDE, listOxideSTD))
  164. {
  165. // something wrong
  166. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::OxideClassify: failed to call GetClassifySTDItem method."));
  167. }
  168. // get all nitride STD items
  169. if (!GetClassifySTDItem(a_pPartSTDData, INC_CLASSIFY_TYPE::NITR, listNitrideSTD))
  170. {
  171. // something wrong
  172. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NitrideClassify: failed to call GetClassifySTDItem method."));
  173. }
  174. // get all nitride STD items
  175. if (!GetClassifySTDItem(a_pPartSTDData, INC_CLASSIFY_TYPE::CARBON, listCarbonSTD))
  176. {
  177. // something wrong
  178. LogErrorTrace(__FILE__, __LINE__, _T("CClassifyEng::NitrideClassify: failed to call GetClassifySTDItem method."));
  179. }
  180. }
  181. COTSClassifyEng::~COTSClassifyEng() // detractor
  182. {
  183. }
  184. //Dispose ClassifyXray
  185. BOOL COTSClassifyEng::ClassifyXray( STEEL_TECHNOLOGY steelTech, CElementChemistriesList& a_listElementChemistries, int& a_nIncId, int& a_GrpId)
  186. {
  187. // the element chemistries list is an inclusion
  188. CElementChemistriesList listElChemsIncNoFe;
  189. double dMolarSumNoFe = 0.0f;
  190. OTS_PARTICLE_TYPE incId;
  191. NOT_INCLUTION_ID notAIncId;// is not an inc but we can identify
  192. if (!FilterInvalidIncXRay(a_listElementChemistries, listElChemsIncNoFe,dMolarSumNoFe, incId, notAIncId))
  193. {
  194. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::failed to call IsAnValidIncXRay"));
  195. return FALSE;
  196. }
  197. if (incId == OTS_PARTCLE_TYPE::ISNOT_INCLUTION)// this is not an inclution particle,but we can identify.
  198. {
  199. a_nIncId =(int) notAIncId;
  200. a_GrpId = (int)OTS_PARTCLE_TYPE::ISNOT_INCLUTION;
  201. return TRUE;
  202. }
  203. if (incId == OTS_PARTCLE_TYPE::INVALID)// this is not an valid inclution particle.
  204. {
  205. a_nIncId = (int)OTS_PARTCLE_TYPE::INVALID;
  206. a_GrpId = (int)OTS_PARTCLE_TYPE::INVALID;
  207. return TRUE;
  208. }
  209. // system STD classification
  210. int nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  211. if (!SystemClassify( steelTech, listElChemsIncNoFe, dMolarSumNoFe, nIncId))
  212. {
  213. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::ClassifyXray: failed to call SystemClassify method."));
  214. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  215. return FALSE;
  216. }
  217. // identified?
  218. if (nIncId > (int)OTS_PARTICLE_TYPE::IDENTIFIED)
  219. {// identified, return TRUE
  220. a_nIncId = nIncId;
  221. IDENTIFIED_INC_GRP_ID grpid;
  222. GroupClassify(a_listElementChemistries,nIncId, grpid);
  223. a_GrpId = (int)grpid;
  224. return TRUE;
  225. }
  226. // identified?
  227. if (nIncId > (int)OTS_PARTICLE_TYPE::IDENTIFIED)
  228. {
  229. // identified, return TRUE
  230. a_nIncId = nIncId;
  231. IDENTIFIED_INC_GRP_ID grpid;
  232. GroupClassify(a_listElementChemistries,nIncId, grpid);
  233. a_GrpId = (int)grpid;
  234. return TRUE;
  235. }
  236. // can't identify this inclusion
  237. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  238. IDENTIFIED_INC_GRP_ID grpid;
  239. GroupClassify(a_listElementChemistries,nIncId, grpid);
  240. a_GrpId = (int)grpid;
  241. return TRUE;
  242. }
  243. // public
  244. // check if the x-ray is an inc x-ray,
  245. BOOL COTSClassifyEng::FilterInvalidIncXRay(CElementChemistriesList a_listElementChemistries,
  246. CElementChemistriesList& a_listElChemsIncNoFe,
  247. double& a_dMolarSumNoFe,
  248. OTS_PARTICLE_TYPE& a_nIncId,
  249. NOT_INCLUTION_ID& notIncId)
  250. {
  251. // go through all elementS
  252. a_listElChemsIncNoFe.clear();
  253. a_dMolarSumNoFe = 0;
  254. double dSumKeyElements = 0;
  255. double dSumSubElements = 0;
  256. double dCarbonMolar = 0;
  257. double dOMolar = 0;
  258. double dSiMolar = 0;
  259. double dFeMolar = 0;
  260. for (auto pElChem : a_listElementChemistries)
  261. {
  262. // create a new element chemistry
  263. CElementChemistryPtr pElChemNew = CElementChemistryPtr(new CElementChemistry(*pElChem.get()));
  264. // key element? S,O,N
  265. if (IsKeyElement(pElChem))
  266. {
  267. // this is a key element
  268. // get molar percentage of this element
  269. double dMolarPercentage = pElChem->GetMolarPercentage();
  270. // cal molar percentage sum (both lists)
  271. a_dMolarSumNoFe += dMolarPercentage;
  272. // cal key element molar percentage sum
  273. dSumKeyElements += dMolarPercentage;
  274. // add the element into the two lists
  275. a_listElChemsIncNoFe.push_back(pElChemNew);
  276. if (pElChem->GetName().CompareNoCase(STR_O) == 0)
  277. {
  278. dOMolar = pElChem->GetMolarPercentage();
  279. }
  280. else if (pElChem->GetName().CompareNoCase(STR_C) == 0)
  281. {
  282. dCarbonMolar = pElChem->GetMolarPercentage();
  283. }
  284. }
  285. // sub element?, include Fe
  286. else if (IsSubElement(pElChem))
  287. {
  288. // this is a sub element
  289. // get molar percentage of this element
  290. double dMolarPercentage = pElChem->GetMolarPercentage();
  291. // cal molar percentage sum list (no Fe)
  292. a_dMolarSumNoFe += pElChem->GetMolarPercentage();
  293. // cal key element molar percentage sum
  294. dSumSubElements += dMolarPercentage;
  295. // add the element into the list (no Fe)
  296. a_listElChemsIncNoFe.push_back(pElChemNew);
  297. // Si
  298. if (pElChem->GetName().CompareNoCase(STR_SI) == 0)
  299. {
  300. dSiMolar = pElChem->GetMolarPercentage();
  301. }
  302. }
  303. else if (pElChem->GetName().CompareNoCase(STR_FE) == 0)
  304. {
  305. dFeMolar = pElChem->GetMolarPercentage();
  306. }
  307. }
  308. // not a inc if this is a SiC
  309. //=========================================
  310. // any carbon?
  311. if (dCarbonMolar > MIN_DOUBLE_VALUE)
  312. {
  313. // calculate molar % of C + Si
  314. double dMolarC_Si = Cal100NorValue(dCarbonMolar + dSiMolar, a_dMolarSumNoFe + dCarbonMolar);
  315. if (dMolarC_Si > SIC_MOLAR_CUTOFF)
  316. {
  317. // this is a SiC, not a inclusion, return FALSE
  318. a_nIncId =OTS_PARTCLE_TYPE::ISNOT_INCLUTION;
  319. notIncId = NOT_INCLUTION_ID::SiC;
  320. return TRUE;
  321. }
  322. }
  323. //=========================================
  324. //FeO
  325. if (dOMolar > MIN_DOUBLE_VALUE)
  326. {
  327. // calculate molar % of Fe + O
  328. double dMolarFe_O = Cal100NorValue(dOMolar + dFeMolar, a_dMolarSumNoFe + dCarbonMolar);
  329. if (dMolarFe_O > FEO_MOLAR_CUTOFF)
  330. {
  331. if (a_listElementChemistries.size() == 2)//there is only Fe and O
  332. {
  333. if (std::find_if(a_listElementChemistries.begin(), a_listElementChemistries.end(), [](CElementChemistryPtr i) {return ((i->GetName().CompareNoCase(STR_CR) != 0) && (i->GetName().CompareNoCase(STR_O) != 0)); }) != a_listElementChemistries.end())
  334. {
  335. //this is a FeO, not a inclusion, return FALSE
  336. a_nIncId = OTS_PARTCLE_TYPE::ISNOT_INCLUTION;
  337. notIncId = NOT_INCLUTION_ID::FeO;
  338. return TRUE;
  339. }
  340. }
  341. }
  342. }
  343. // both key molar percentage sum and sub molar percentage sum have to be over certain values
  344. double dSumKeyElementsMolar = Cal100NorValue(dSumKeyElements, a_dMolarSumNoFe);
  345. double dSumSubElementsMolar = Cal100NorValue(dSumSubElements, a_dMolarSumNoFe);
  346. if (a_dMolarSumNoFe < MIN_ELEMENT_SUM)
  347. {
  348. a_nIncId = OTS_PARTICLE_TYPE::INVALID;
  349. return TRUE;
  350. }
  351. if (dSumKeyElementsMolar > INC_KEY_ELEMENT_TOTAL_100 && dSumSubElementsMolar > INC_SUB_ELEMENT_TOTAL_100)
  352. {
  353. a_nIncId = OTS_PARTCLE_TYPE::NOT_IDENTIFIED;
  354. return TRUE;
  355. }
  356. else
  357. {
  358. a_nIncId = OTS_PARTICLE_TYPE::INVALID;
  359. return TRUE;
  360. }
  361. }
  362. // system classification
  363. BOOL COTSClassifyEng::SystemClassify(
  364. STEEL_TECHNOLOGY steelTech,
  365. CElementChemistriesList& a_listElChemsIncNoFe,
  366. double a_dMolarSumNoFe,
  367. int& a_nIncId)
  368. {
  369. // try sulfide classification
  370. int nIncId = (int)OTS_PARTICLE_TYPE::INVALID;
  371. if (!SulClassify(steelTech, a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId))
  372. {
  373. // something wrong
  374. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::ClassifyXray: failed to call SulClassify method."));
  375. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  376. return FALSE;
  377. }
  378. // inclusion identified?
  379. if (nIncId != (int)OTS_PARTICLE_TYPE::INVALID)
  380. {
  381. // yes, this is a sulfide
  382. a_nIncId = nIncId;
  383. return TRUE;
  384. }
  385. // nitride classification
  386. if (!NitrideClassify(a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId))
  387. {
  388. // something wrong
  389. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::ClassifyXray: failed to call NitrideClassify method."));
  390. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  391. return FALSE;
  392. }
  393. // inclusion identified?
  394. if (nIncId != (int)OTS_PARTICLE_TYPE::INVALID)
  395. {
  396. // yes, this is a nitride
  397. a_nIncId = nIncId;
  398. return TRUE;
  399. }
  400. // oxide classification
  401. if (!OxideClassify(a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId))
  402. {
  403. // something wrong
  404. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::ClassifyXray: failed to call OxideClassify method."));
  405. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  406. return FALSE;
  407. }
  408. // inclusion identified?
  409. if (nIncId != (int)OTS_PARTICLE_TYPE::INVALID)
  410. {
  411. // yes, this is a oxide
  412. a_nIncId = nIncId;
  413. return TRUE;
  414. }
  415. // CarbonClassify classification
  416. if (!CarbonClassify(a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId))
  417. {
  418. // something wrong
  419. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::ClassifyXray: failed to call CarbonClassify method."));
  420. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  421. return FALSE;
  422. }
  423. // inclusion identified?
  424. if (nIncId != (int)OTS_PARTICLE_TYPE::INVALID)
  425. {
  426. // yes, this is a oxide
  427. a_nIncId = nIncId;
  428. return TRUE;
  429. }
  430. // can't identify this inclusion
  431. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  432. return TRUE;
  433. }
  434. BOOL COTSClassifyEng::GroupClassify(CElementChemistriesList& a_listElChemsIncNoFe,int incId, IDENTIFIED_INC_GRP_ID& a_GrpId)
  435. {
  436. double dOWeight = 0;
  437. double dSWeight = 0;
  438. double dNWeight = 0;
  439. auto stdItm =pPartSTDData->GetSTDItemById( incId);
  440. if (incId == (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED)
  441. {
  442. a_GrpId = IDENTIFIED_INC_GRP_ID::Others;
  443. return true;
  444. }
  445. auto stdName = stdItm->GetName();
  446. // sulfide classification
  447. for (long i = 0; i < INC_SUL_SUB_ELEMENT_MAX; i++)
  448. {
  449. if (stdName.CompareNoCase(INC_SULFILSES_NAMES[i]) == 0 )
  450. {
  451. a_GrpId = IDENTIFIED_INC_GRP_ID::SULFIDE;
  452. return true;
  453. }
  454. }
  455. if (stdName.CompareNoCase(SULFIDE_STR) == 0 )
  456. {
  457. a_GrpId = IDENTIFIED_INC_GRP_ID::SULFIDE;
  458. return true;
  459. }
  460. //oxide classification
  461. for (long i = 0; i < INC_OXIDE_SUB_ELEMENT_MAX; i++)
  462. {
  463. if (stdName.CompareNoCase(INC_OXIDE_NAMES[i]) == 0)
  464. {
  465. a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE;
  466. return true;
  467. }
  468. }
  469. if (stdName.CompareNoCase(SPINEL_STR) == 0)
  470. {
  471. a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE;
  472. return true;
  473. }
  474. if (stdName.CompareNoCase(ALUMINATE12CaO_7Al2O3_STR) == 0)
  475. {
  476. a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE;
  477. return true;
  478. }
  479. if (stdName.CompareNoCase(ALUMINATE3CaO_Al2O3_STR) == 0)
  480. {
  481. a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE;
  482. return true;
  483. }
  484. if (stdName.CompareNoCase(ALUMINATE_STR) == 0)
  485. {
  486. a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE;
  487. return true;
  488. }
  489. if (stdName.CompareNoCase(Ca_ALUMINATE_STR) == 0)
  490. {
  491. a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE;
  492. return true;
  493. }
  494. for (long i = 0; i < INC_NITR_SUB_ELEMENT_MAX; i++)
  495. {
  496. if (stdName.CompareNoCase(INC_NITR_NAMES[i]) == 0)
  497. {
  498. a_GrpId = IDENTIFIED_INC_GRP_ID::CARBONNITRIDE_NITRIDE;
  499. return true;
  500. }
  501. }
  502. for (auto pElChem : a_listElChemsIncNoFe)
  503. {
  504. if (pElChem->GetName().CompareNoCase(STR_O) == 0)
  505. {
  506. dOWeight = pElChem->GetPercentage();
  507. }
  508. else if (pElChem->GetName().CompareNoCase(STR_SUL) == 0)
  509. {
  510. dSWeight = pElChem->GetPercentage();
  511. }
  512. else if (pElChem->GetName().CompareNoCase(STR_N) == 0)
  513. {
  514. dNWeight = pElChem->GetPercentage();
  515. }
  516. }
  517. if (dOWeight >= MIN_ELEMENT_SUM && dSWeight< MIN_ELEMENT_SUM )
  518. {
  519. a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE;
  520. }
  521. else if ( dSWeight >= MIN_ELEMENT_SUM && dOWeight < MIN_ELEMENT_SUM)
  522. {
  523. a_GrpId = IDENTIFIED_INC_GRP_ID::SULFIDE;
  524. }
  525. else if (dOWeight >= MIN_ELEMENT_SUM && dSWeight >= MIN_ELEMENT_SUM )
  526. {
  527. a_GrpId = IDENTIFIED_INC_GRP_ID::SULFIDE_OXIDE;
  528. }
  529. else if ( dNWeight >= MIN_ELEMENT_SUM)
  530. {
  531. a_GrpId = IDENTIFIED_INC_GRP_ID::CARBONNITRIDE_NITRIDE;
  532. }
  533. else
  534. {
  535. a_GrpId = IDENTIFIED_INC_GRP_ID::Others;
  536. }
  537. return TRUE;
  538. }
  539. BOOL COTSClassifyEng::GetGroupNameAndColorById(int grpId,std::string& grpName,std::string& grpColor)
  540. {
  541. if (grpId == (int)OTS_PARTICLE_TYPE::INVALID)
  542. {
  543. grpName = "Invalid";
  544. grpColor = "#000000";
  545. }
  546. if (grpId == (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED)
  547. {
  548. grpName = "Not Identified";
  549. grpColor = "#000000";
  550. }
  551. if (grpId == (int)OTS_PARTICLE_TYPE::ISNOT_INCLUTION)
  552. {
  553. grpName = "NOT_INCLUTION";
  554. grpColor = "#483D8B";
  555. }
  556. switch (grpId)
  557. {
  558. case (int)IDENTIFIED_INC_GRP_ID::OXIDE:
  559. grpName = "Oxide";
  560. grpColor = "#FF69B4";
  561. break;
  562. case (int)IDENTIFIED_INC_GRP_ID::SULFIDE:
  563. grpName = "Sulfide";
  564. grpColor = "#FF00FF";
  565. break;
  566. case (int)IDENTIFIED_INC_GRP_ID::SULFIDE_OXIDE:
  567. grpName = "Sulfide_Oxide";
  568. grpColor = "#0000FF";
  569. break;
  570. case (int)IDENTIFIED_INC_GRP_ID::CARBONNITRIDE_NITRIDE:
  571. grpName = "CarbonNitride/Nitride";
  572. grpColor = "#00FF7F";
  573. break;
  574. case (int)IDENTIFIED_INC_GRP_ID::Others:
  575. grpName = "Other";
  576. grpColor = "#B0C4DE";
  577. break;
  578. default:
  579. break;
  580. }
  581. return true;
  582. }
  583. // sulfides classification
  584. BOOL COTSClassifyEng::SulClassify(
  585. STEEL_TECHNOLOGY steelTech,
  586. CElementChemistriesList& a_listElChemsIncNoFe,
  587. double a_dMolarSumNoFe,
  588. int& a_nIncId)
  589. {
  590. // check if element chemistries list contain any sulfur
  591. CElementChemistryPtr pSulElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, STR_SUL);
  592. if (!pSulElChem)
  593. {
  594. // contains no sulfur, this is not a sulfide
  595. return TRUE;
  596. }
  597. // calculate sulfur 100 percentage molar
  598. double dSulMolar100 = Cal100NorValue(pSulElChem->GetMolarPercentage(), a_dMolarSumNoFe);
  599. // check if sulfur amount enough
  600. if (dSulMolar100 < MIN_SUL_MOLAR)
  601. {
  602. // no enough sulfur, this is not a sulfide
  603. return TRUE;
  604. }
  605. // this is a sulfide
  606. if (listSulfideSTD.empty())// any sulfides STD items
  607. {
  608. // no sulfides std items. can't identify sulfide
  609. // can't identify this inclusion
  610. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  611. return TRUE;
  612. }
  613. // mapping Mn first
  614. double dSulRemain;
  615. BOOL bMnMapped = FALSE;
  616. {
  617. CString strMn = INC_SUL_SUB_ELEMENT_NAMES[0];
  618. double dMappingRatio = INC_SULFILSES_MAPPING_RATIO[0];
  619. bMnMapped = ElementMatching(a_dMolarSumNoFe, a_listElChemsIncNoFe, pSulElChem, strMn, dMappingRatio, dSulRemain);
  620. }
  621. // process mapping if sulfur amount enough
  622. CString strProMappingSulName = _T("");
  623. BOOL bSteelTechMapped = FALSE;
  624. if (dSulRemain > MIN_SUL_MOLAR)// still have enough sulfur, mapping Ca, Mg or Ce, La
  625. {
  626. FilterOnSteelTech(steelTech, a_listElChemsIncNoFe);
  627. bSteelTechMapped = ElementMatchingOnSteelTech(a_dMolarSumNoFe, steelTech, a_listElChemsIncNoFe, pSulElChem, strProMappingSulName);
  628. }
  629. // set sulfide base name
  630. CString strSulfideBaseName = _T("");
  631. if (bMnMapped && bSteelTechMapped)
  632. {
  633. // both Mn and process mapped
  634. strSulfideBaseName = INC_SULFILSES_NAMES[0] + strProMappingSulName;
  635. }
  636. else if (bMnMapped)
  637. {
  638. // Mn mapped only
  639. strSulfideBaseName = INC_SULFILSES_NAMES[0];
  640. }
  641. else if (bSteelTechMapped)
  642. {
  643. // process mapped only
  644. strSulfideBaseName = strProMappingSulName;
  645. }
  646. else
  647. {
  648. // // mapped nothing, force sulfide base name as "Sulfide" if sulfur 100% molar value over cutting off value
  649. if (dSulMolar100 > SULFIDE_MOLAR_CUTOFF)
  650. {
  651. strSulfideBaseName = SULFIDE_STR;
  652. }
  653. else
  654. {
  655. // no enough sulfur, consider that it is not a sulfide
  656. return TRUE;
  657. }
  658. }
  659. // check if the rest element chemistries map an oxide
  660. int nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  661. if (!GetSulfildeOxideComplexItemId(a_listElChemsIncNoFe, a_dMolarSumNoFe, strSulfideBaseName, nIncId))
  662. {
  663. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  664. return FALSE;
  665. }
  666. if (nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED)
  667. {
  668. a_nIncId = nIncId;
  669. return TRUE;
  670. }
  671. nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  672. if (!GetSulfildeNitrideComplexItemId(a_listElChemsIncNoFe, a_dMolarSumNoFe, strSulfideBaseName, nIncId))
  673. {
  674. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  675. return FALSE;
  676. }
  677. if (nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED)
  678. {
  679. a_nIncId = nIncId;
  680. return TRUE;
  681. }
  682. // try to find the STD item // this is a general sulfide// confirm the sulfide id
  683. CSTDItemPtr pSulSTDItem = GetSTDItemByName(listSulfideSTD, strSulfideBaseName);
  684. if (pSulSTDItem)
  685. {
  686. a_nIncId = pSulSTDItem->GetSTDId();
  687. return TRUE;
  688. }
  689. // rename the sulfides name as "Sulfide" if it is not
  690. if (strSulfideBaseName.CompareNoCase(SULFIDE_STR) != 0)
  691. {
  692. strSulfideBaseName = SULFIDE_STR;
  693. pSulSTDItem = GetSTDItemByName(listSulfideSTD, strSulfideBaseName);
  694. if (pSulSTDItem)
  695. {
  696. // found the STD item
  697. a_nIncId = pSulSTDItem->GetSTDId();
  698. return TRUE;
  699. }
  700. }
  701. // can't identify this inclusion
  702. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  703. return TRUE;
  704. }
  705. // oxides classification
  706. BOOL COTSClassifyEng::OxideClassify(
  707. CElementChemistriesList& a_listElChemsIncNoFe,
  708. double a_dMolarSumNoFe,
  709. int& a_nIncId)
  710. {
  711. // check if element chemistries list contain any oxygen
  712. CElementChemistryPtr pOElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, STR_OXIDE);
  713. if (!pOElChem)
  714. {
  715. // contains no oxygen, this is not an oxide
  716. return TRUE;
  717. }
  718. // check if oxygen amount enough
  719. double dOMolar100 = Cal100NorValue(pOElChem->GetMolarPercentage(), a_dMolarSumNoFe);
  720. if (dOMolar100 < MIN_OXIDE_MOLAR)
  721. {
  722. // no enough oxygen, this is not an oxide
  723. return TRUE;
  724. }
  725. // this is an oxide
  726. // any oxide STD items
  727. if (listOxideSTD.empty())
  728. {
  729. // no oxide STD items, can't identify oxide
  730. // can't identify this inclusion
  731. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  732. return TRUE;
  733. }
  734. // build oxide sub elements list
  735. // =========================================
  736. // get all possible oxide sub element chemistries
  737. CElementChemistriesList listTempOxideSubElChems;
  738. double dTempOxideSubElMolarSum = 0;
  739. for (int i = 0; i < INC_OXIDE_SUB_ELEMENT_MAX; ++i)
  740. {
  741. // try to get the oxide sub element
  742. CElementChemistryPtr pSubElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, INC_OXIDE_SUB_ELEMENT_NAMES[i]);
  743. // found it?
  744. if (pSubElChem)
  745. {
  746. // got one
  747. // get the %molar value of the sub element chemistries
  748. double dSubElMolar = pSubElChem->GetMolarPercentage();
  749. // add the sub element chemistries into the oxides element chemistries list
  750. listTempOxideSubElChems.push_back(pSubElChem);
  751. dTempOxideSubElMolarSum += dSubElMolar;
  752. }
  753. }
  754. // clear oxide sub element chemistries list
  755. CElementChemistriesList listOxideSubElChems;
  756. double dOxideSubElMolarSum = 0;
  757. for (auto pElChem : listTempOxideSubElChems)
  758. {
  759. // get the %molar value of the sub element chemistries
  760. double dSubElMolar = pElChem->GetMolarPercentage();
  761. // the %molar value of the sub element chemistries of the sub element chemistries list
  762. double dSubElMolarMolar100 = Cal100NorValue(dSubElMolar, dTempOxideSubElMolarSum);
  763. // remove the sub element chemistries less than the cut off (2%)
  764. if (dSubElMolarMolar100 > MIN_OXIDE_SUB_MOLAR_CUTOFF)
  765. {
  766. // keep it
  767. listOxideSubElChems.push_back(pElChem);
  768. dOxideSubElMolarSum += dSubElMolar;
  769. }
  770. }
  771. // =========================================
  772. // check oxide elements list
  773. CString strOxideName = _T("");
  774. CString aluminateStr=_T("");
  775. if (listOxideSubElChems.empty())
  776. {
  777. // no oxide sub elements
  778. // consider this is not a oxide (may be it just is a dust)
  779. return TRUE;
  780. }
  781. // is a simple oxide?
  782. else if(IsASimpleOxide(listOxideSubElChems, dOxideSubElMolarSum, strOxideName))
  783. {
  784. // this is a simple oxide
  785. // named already during checking
  786. }
  787. // is it a REOxide (La-Ce-Oxide)?
  788. else if (IsAREOxide(listOxideSubElChems, dOxideSubElMolarSum))
  789. {
  790. // REOxcide
  791. strOxideName = REOXIDE_STR;
  792. }
  793. // should be a complex oxide
  794. // is it a REAlOxide?
  795. else if (IsAnREAlOxide(listOxideSubElChems, dOxideSubElMolarSum))
  796. {
  797. // REOxcide
  798. strOxideName = REALOXIDE_STR;
  799. }
  800. // is it a Spinel?
  801. else if (IsASpinel(listOxideSubElChems, dOxideSubElMolarSum))
  802. {
  803. // Spinel
  804. strOxideName = SPINEL_STR;
  805. }
  806. // is it a Silicate?
  807. else if (IsASilicate(listOxideSubElChems, dOxideSubElMolarSum))
  808. {
  809. // Silicate
  810. strOxideName = SILICATE_STR;
  811. }
  812. // is it an Aluminate?
  813. else if (IsAnCa_Aluminate(listOxideSubElChems, dOxideSubElMolarSum, aluminateStr))
  814. {
  815. // Aluminate
  816. strOxideName = aluminateStr;
  817. }
  818. // fit none of them, simply name it as an oxide
  819. else
  820. {
  821. strOxideName = OXIDE_STR;
  822. }
  823. // confirm the oxide id
  824. // try to find the STD
  825. auto pSTDItem = GetSTDItemByName(listOxideSTD, strOxideName);
  826. if (pSTDItem)
  827. {
  828. // found the STD item
  829. a_nIncId = pSTDItem->GetSTDId();
  830. return TRUE;
  831. }
  832. // rename the oxide as "Oxide" if it is not
  833. if (strOxideName.CompareNoCase(OXIDE_STR) != 0)
  834. {
  835. strOxideName = OXIDE_STR;
  836. auto pSTDItem = GetSTDItemByName(listOxideSTD, strOxideName);
  837. if (pSTDItem)
  838. {
  839. // found the STD item
  840. a_nIncId = pSTDItem->GetSTDId();
  841. return TRUE;
  842. }
  843. }
  844. // can't identify this inclusion
  845. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  846. return TRUE;
  847. }
  848. // nitrides classification
  849. BOOL COTSClassifyEng::NitrideClassify(
  850. CElementChemistriesList& a_listElChemsIncNoFe,
  851. double a_dMolarSumNoFe,
  852. int& a_nIncId)
  853. {
  854. // check if element chemistries list contain any nitrogen
  855. CElementChemistryPtr pNitrElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, STR_NITR);
  856. if (!pNitrElChem)
  857. {
  858. // contains no nitrogen, this is not a nitride
  859. return TRUE;
  860. }
  861. // check if nitrogen amount enough
  862. double dNitrMolar100 = Cal100NorValue(pNitrElChem->GetMolarPercentage(), a_dMolarSumNoFe);
  863. if (dNitrMolar100 < MIN_NITR_MOLAR)
  864. {
  865. // have no enough nitrogen, this is not a nitride
  866. return TRUE;
  867. }
  868. // this is a nitride
  869. // any nitride STD items
  870. if (listNitrideSTD.empty())
  871. {
  872. // no nitrides std items.
  873. // can't identify this inclusion
  874. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  875. return TRUE;
  876. }
  877. // mapping nitride sub elements
  878. CString strNitrideName = _T("");
  879. BOOL bMapped = FALSE;
  880. for (int i = 0; i < INC_NITR_SUB_ELEMENT_MAX; ++i)
  881. {
  882. CElementChemistryPtr pNitrSubElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, INC_NITR_SUB_ELEMENT_NAMES[i]);
  883. if (pNitrSubElChem)
  884. {
  885. // this is a nitride sub element chemistry
  886. // get %molar value of this sub element chemistry
  887. double dNitr_Sub_Molar = Cal100NorValue(pNitrSubElChem->GetMolarPercentage(), a_dMolarSumNoFe);
  888. // make sure the sub element molar value is over mapping min value
  889. if (dNitr_Sub_Molar > MIN_NITR_SUB_MOLAR)
  890. {
  891. // mapping this sub element chemistry
  892. double dMappingRadio = INC_NITR_MAPPING_RATIO[i];
  893. if (!ElementsMapping(a_dMolarSumNoFe, dMappingRadio, pNitrSubElChem, pNitrElChem, bMapped))
  894. {
  895. // something is wrong
  896. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NitrideClassify: failed to call ElementsMapping method."));
  897. return FALSE;
  898. }
  899. // mapping succeed?
  900. if(bMapped)
  901. {
  902. // is mapped Ti?
  903. if (i == 0)
  904. {
  905. // the first mapped nitride is "TiN"
  906. // try to map Nb
  907. BOOL bNbMapped = FALSE;
  908. // get molar % of the rest nitrogen
  909. dNitrMolar100 = Cal100NorValue(pNitrElChem->GetMolarPercentage(), a_dMolarSumNoFe);
  910. // make sure nitrogen amount is enough
  911. if (dNitrMolar100 > MIN_NITR_MOLAR)
  912. {
  913. // get element "Nb"
  914. CElementChemistryPtr pElChemNb = GetNamedElementChemistry(a_listElChemsIncNoFe, STR_Nb);
  915. // is there Nb in the list
  916. if (pElChemNb)
  917. {
  918. // get %molar value of Nb
  919. double dNb_Molar = Cal100NorValue(pElChemNb->GetMolarPercentage(), a_dMolarSumNoFe);
  920. // make sure Nb molar value is over mapping min value
  921. double dNbMappingRadio = INC_NITR_MAPPING_RATIO[2];
  922. if (dNb_Molar > MIN_NITR_SUB_MOLAR)
  923. {
  924. if (!ElementsMapping(a_dMolarSumNoFe, dNbMappingRadio, pElChemNb, pNitrElChem, bNbMapped))
  925. {
  926. // something is wrong
  927. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NitrideClassify: failed to call ElementsMapping method."));
  928. return FALSE;
  929. }
  930. }
  931. }
  932. }
  933. // mapped "Nb"
  934. if (bNbMapped)
  935. {
  936. // nitride name is "TiN-NbN"
  937. strNitrideName = INC_NITR_NAMES[0] + STR_CONNECT + INC_NITR_NAMES[2];
  938. }
  939. else
  940. {
  941. // nitride name is "TiN"
  942. strNitrideName = INC_NITR_NAMES[0];
  943. }
  944. }
  945. else
  946. {
  947. // get the nitride name
  948. strNitrideName = INC_NITR_NAMES[i];
  949. }
  950. // completed mapping, get out the loop
  951. break;
  952. }
  953. }
  954. }
  955. }
  956. // not mapped?
  957. if (!bMapped)
  958. {
  959. // force to name it as "Nitride" if N 100% molar value over cutting off value
  960. if (dNitrMolar100 > NITRIDE_MOLAR_CUTOFF)
  961. {
  962. strNitrideName = NITRIDE_STR;
  963. }
  964. else
  965. {
  966. // no enough nitride, consider that it is not a nitride
  967. return TRUE;
  968. }
  969. }
  970. // check if the rest element chemistries map an oxide
  971. int nIncId = (int)OTS_PARTICLE_TYPE::INVALID;
  972. if (!OxideClassify( a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId))
  973. {
  974. // something wrong
  975. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NitrideClassify: failed to call OxideClassify method."));
  976. return FALSE;
  977. }
  978. // mapped?
  979. if (nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED)
  980. {
  981. // this is an oxide nitride
  982. // confirm the oxide nitride id
  983. // get the STD item of the mapped oxide
  984. CSTDItemPtr pOxideSTDItem = pPartSTDData->GetSTDItemById(nIncId);
  985. if (pOxideSTDItem)
  986. {
  987. // get mapped oxide name
  988. CString strOxideName = pOxideSTDItem->GetName();
  989. // oxide nitride name: oxide + "-" + nitride base string
  990. CString strOxide_NitrName = strOxideName + STR_CONNECT + strNitrideName;
  991. // try to find the STD item
  992. CSTDItemPtr pOxideNitrSTDItem = GetSTDItemByName(listNitrideSTD, strOxide_NitrName);
  993. if (pOxideNitrSTDItem)
  994. {
  995. // found the STD item
  996. a_nIncId = pOxideNitrSTDItem->GetSTDId();
  997. return TRUE;
  998. }
  999. // can't find the STD item
  1000. // rename the oxide nitride name as "Oxide" + "-" + nitride base string
  1001. strOxide_NitrName = OXIDE_STR + STR_CONNECT + strOxide_NitrName;
  1002. // try to find the STD item
  1003. pOxideNitrSTDItem = GetSTDItemByName(listNitrideSTD, strOxide_NitrName);
  1004. if (pOxideNitrSTDItem)
  1005. {
  1006. // found the STD item
  1007. a_nIncId = pOxideNitrSTDItem->GetSTDId();
  1008. return TRUE;
  1009. }
  1010. // rename the oxide nitride name as strOxideName + "-" + "Nitride"
  1011. strOxide_NitrName = strOxideName + STR_CONNECT + NITRIDE_STR;
  1012. // try to find the STD item
  1013. pOxideNitrSTDItem = GetSTDItemByName(listNitrideSTD, strOxide_NitrName);
  1014. if (pOxideNitrSTDItem)
  1015. {
  1016. // found the STD item
  1017. a_nIncId = pOxideNitrSTDItem->GetSTDId();
  1018. return TRUE;
  1019. }
  1020. // rename the oxide nitride name as "Oxide" + "-" + "Nitride"
  1021. strOxide_NitrName = OXIDE_STR + STR_CONNECT + NITRIDE_STR;
  1022. // try to find the STD item
  1023. pOxideNitrSTDItem = GetSTDItemByName(listNitrideSTD, strOxide_NitrName);
  1024. if (pOxideNitrSTDItem)
  1025. {
  1026. // found the STD item
  1027. a_nIncId = pOxideNitrSTDItem->GetSTDId();
  1028. return TRUE;
  1029. }
  1030. // rename the oxide nitride name as "Nitride"
  1031. strOxide_NitrName = NITRIDE_STR;
  1032. // try to find the STD item
  1033. pOxideNitrSTDItem = GetSTDItemByName(listNitrideSTD, strOxide_NitrName);
  1034. if (pOxideNitrSTDItem)
  1035. {
  1036. // found the STD item
  1037. a_nIncId = pOxideSTDItem->GetSTDId();
  1038. return TRUE;
  1039. }
  1040. }
  1041. // can't identify this inclusion
  1042. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  1043. return TRUE;
  1044. }
  1045. // confirm the nitride id
  1046. // try to find the STD
  1047. auto pSTDItem = GetSTDItemByName(listNitrideSTD, strNitrideName);
  1048. if (pSTDItem)
  1049. {
  1050. // found the STD item
  1051. a_nIncId = pSTDItem->GetSTDId();
  1052. return TRUE;
  1053. }
  1054. // rename the nitride as "Nitride" if it is not
  1055. if (strNitrideName.CompareNoCase(NITRIDE_STR) != 0)
  1056. {
  1057. strNitrideName = NITRIDE_STR;
  1058. auto pSTDItem = GetSTDItemByName(listNitrideSTD, strNitrideName);
  1059. if (pSTDItem)
  1060. {
  1061. // found the STD item
  1062. a_nIncId = pSTDItem->GetSTDId();
  1063. return TRUE;
  1064. }
  1065. }
  1066. // can't identify this inclusion
  1067. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  1068. return TRUE;
  1069. }
  1070. // nitrides classification
  1071. BOOL COTSClassifyEng::CarbonClassify(
  1072. CElementChemistriesList& a_listElChemsIncNoFe,
  1073. double a_dMolarSumNoFe,
  1074. int& a_nIncId)
  1075. {
  1076. // check if element chemistries list contain any nitrogen
  1077. CElementChemistryPtr pCarElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, STR_CAR);
  1078. if (!pCarElChem)
  1079. {
  1080. // contains no nitrogen, this is not a nitride
  1081. return TRUE;
  1082. }
  1083. // check if nitrogen amount enough
  1084. double dCarMolar100 = Cal100NorValue(pCarElChem->GetMolarPercentage(), a_dMolarSumNoFe);
  1085. if (dCarMolar100 < MIN_CAR_MOLAR)
  1086. {
  1087. // have no enough nitrogen, this is not a nitride
  1088. return TRUE;
  1089. }
  1090. // this is a carbon
  1091. // any carbon STD items
  1092. if (listCarbonSTD.empty())
  1093. {
  1094. // no nitrides std items.
  1095. // can't identify this inclusion
  1096. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  1097. return TRUE;
  1098. }
  1099. // mapping carbon sub elements
  1100. CString strCarbonName = _T("");
  1101. BOOL bMapped = FALSE;
  1102. for (int i = 0; i < INC_CAR_SUB_ELEMENT_MAX; ++i)
  1103. {
  1104. CElementChemistryPtr pCarSubElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, INC_CAR_SUB_ELEMENT_NAMES[i]);
  1105. if (pCarSubElChem)
  1106. {
  1107. // this is a nitride sub element chemistry
  1108. // get %molar value of this sub element chemistry
  1109. double dCar_Sub_Molar = Cal100NorValue(pCarSubElChem->GetMolarPercentage(), a_dMolarSumNoFe);
  1110. // make sure the sub element molar value is over mapping min value
  1111. if (dCar_Sub_Molar > MIN_CAR_SUB_MOLAR)
  1112. {
  1113. // try to map Nb
  1114. BOOL bNbMapped = FALSE;
  1115. // get molar % of the rest nitrogen
  1116. dCarMolar100 = Cal100NorValue(pCarElChem->GetMolarPercentage(), a_dMolarSumNoFe);
  1117. // make sure nitrogen amount is enough
  1118. if (dCarMolar100 > MIN_CAR_MOLAR)
  1119. {
  1120. // get element "Nb"
  1121. CElementChemistryPtr pElChemNb = GetNamedElementChemistry(a_listElChemsIncNoFe, STR_Nb);
  1122. // is there Nb in the list
  1123. if (pElChemNb)
  1124. {
  1125. // get %molar value of Nb
  1126. double dNb_Molar = Cal100NorValue(pElChemNb->GetMolarPercentage(), a_dMolarSumNoFe);
  1127. // make sure Nb molar value is over mapping min value
  1128. double dNbMappingRatio = INC_NITR_MAPPING_RATIO[2];
  1129. if (dNb_Molar > MIN_CAR_SUB_MOLAR)
  1130. {
  1131. if (!ElementsMapping(a_dMolarSumNoFe, dNbMappingRatio, pElChemNb, pCarElChem, bNbMapped))
  1132. {
  1133. // something is wrong
  1134. LogErrorTrace(__FILE__, __LINE__, _T("CClassifyEng::NitrideClassify: failed to call ElementsMapping method."));
  1135. return FALSE;
  1136. }
  1137. }
  1138. }
  1139. }
  1140. // mapped "Nb"
  1141. if (bNbMapped)
  1142. {
  1143. // carbon name is "NbC"
  1144. strCarbonName = INC_CAR_NAMES[0];
  1145. }
  1146. // completed mapping, get out the loop
  1147. break;
  1148. }
  1149. }
  1150. }
  1151. // mapped?
  1152. if (a_nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED)
  1153. {
  1154. // this is an oxide nitride
  1155. // confirm the oxide nitride id
  1156. CSTDItemPtr pCarSTDItem = GetSTDItemByName(listCarbonSTD, strCarbonName);
  1157. // get the STD item of the mapped oxide
  1158. if (pCarSTDItem)
  1159. {
  1160. // found the STD item
  1161. a_nIncId = pCarSTDItem->GetSTDId();
  1162. return TRUE;
  1163. }
  1164. // can't identify this inclusion
  1165. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  1166. return TRUE;
  1167. }
  1168. // confirm the carben id
  1169. // try to find the STD
  1170. auto pSTDItem = GetSTDItemByName(listCarbonSTD, strCarbonName);
  1171. if (pSTDItem)
  1172. {
  1173. // found the STD item
  1174. a_nIncId = pSTDItem->GetSTDId();
  1175. return TRUE;
  1176. }
  1177. // rename the Carbon as "Carbon" if it is not
  1178. if (strCarbonName.CompareNoCase(CARBON_STR) != 0)
  1179. {
  1180. strCarbonName = NITRIDE_STR;
  1181. auto pSTDItem = GetSTDItemByName(listCarbonSTD, strCarbonName);
  1182. if (pSTDItem)
  1183. {
  1184. // found the STD item
  1185. a_nIncId = pSTDItem->GetSTDId();
  1186. return TRUE;
  1187. }
  1188. }
  1189. // can't identify this inclusion
  1190. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  1191. return TRUE;
  1192. }
  1193. // nominate element chemistries list
  1194. BOOL COTSClassifyEng::NomiNateElChemsList( CElementChemistriesList& a_listElChemsInc,
  1195. CElementChemistriesList& a_listNomiElChemsInc)
  1196. {
  1197. // return FALSE if nothing in the input list
  1198. if (a_listElChemsInc.empty())
  1199. {
  1200. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NomiNateElChemsList: invalid inclusion x-ray data."));
  1201. return FALSE;
  1202. }
  1203. // initialize outputs
  1204. a_listNomiElChemsInc.clear();
  1205. // go thought all element chemistry objects of the input lit
  1206. double dWeightPerSum = 0;
  1207. for (auto pElChem : a_listElChemsInc)
  1208. {
  1209. // create a new element chemistry
  1210. CElementChemistryPtr pElChemNew = CElementChemistryPtr(new CElementChemistry(*pElChem.get()));
  1211. // key element?
  1212. if (IsKeyElement(pElChem))
  1213. {
  1214. // this is a key element
  1215. // cal weight percentage sum
  1216. dWeightPerSum += pElChem->GetPercentage();
  1217. // add the element into the output list
  1218. a_listNomiElChemsInc.push_back(pElChemNew);
  1219. }
  1220. // sub element?
  1221. else if (IsSubElement(pElChem))
  1222. {
  1223. // this is a sub element
  1224. // Fe?
  1225. if (pElChem->GetName().CompareNoCase("Fe") != 0)
  1226. {
  1227. // cal weight percentage sum
  1228. dWeightPerSum += pElChem->GetPercentage();
  1229. // add the element into the output list
  1230. a_listNomiElChemsInc.push_back(pElChemNew);
  1231. }
  1232. }
  1233. }
  1234. // return FALSE if nothing in the input list or sum less than cut off value
  1235. if (a_listNomiElChemsInc.empty() || dWeightPerSum < INC_SUB_ELEMENT_CUT_OFF)
  1236. {
  1237. // something wrong
  1238. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NomiNateElChemsList: invalid inclusion x-ray data."));
  1239. return FALSE;
  1240. }
  1241. // go thought all element chemistry objects of the output lit
  1242. for (auto pElChem : a_listNomiElChemsInc)
  1243. {
  1244. // reset weight % value
  1245. // get weight % value
  1246. double dWeightPer = pElChem->GetPercentage();
  1247. // calculate new weight % value
  1248. double dWeightPerNew = Cal100NorValue(dWeightPer, dWeightPerSum);
  1249. // reset
  1250. pElChem->SetPercentage(dWeightPerNew);
  1251. }
  1252. // ok, return TRUE
  1253. return TRUE;
  1254. }
  1255. // protected
  1256. // check if this is a key element
  1257. BOOL COTSClassifyEng::IsKeyElement(CElementChemistryPtr a_pElChem)
  1258. {
  1259. // safety check
  1260. ASSERT(a_pElChem);
  1261. if (!a_pElChem)
  1262. {
  1263. // something wrong
  1264. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::IsKeyElement: invalid CElementChemistryPtr."));
  1265. return FALSE;
  1266. }
  1267. // go thought all key element
  1268. for (long i = 0; i < INC_KEY_ELEMENT_MAX; ++i)
  1269. {
  1270. // compare
  1271. if ((a_pElChem->GetName().CompareNoCase(INC_KEY_ELEMENT_NAMES[i]) == 0) && (a_pElChem->GetPercentage() >= INC_KEY_ELEMENT_CUT_OFF))
  1272. {
  1273. // this is a key element, return TRUE
  1274. return TRUE;
  1275. }
  1276. }
  1277. // this is not a key element, return FALSE
  1278. return FALSE;
  1279. }
  1280. // check if this is a sub element
  1281. BOOL COTSClassifyEng::IsSubElement(CElementChemistryPtr a_pElChem)
  1282. {
  1283. // safety check
  1284. ASSERT(a_pElChem);
  1285. if (!a_pElChem)
  1286. {
  1287. // something wrong
  1288. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::IsSubElement: invalid CElementChemistryPtr."));
  1289. return FALSE;
  1290. }
  1291. // go thought all sub element
  1292. for (long i = 0; i < INC_SUB_ELEMENT_MAX; ++i)
  1293. {
  1294. // compare
  1295. if ((a_pElChem->GetName().CompareNoCase(INC_SUB_ELEMENT_NAMES[i]) == 0) && (a_pElChem->GetPercentage() >= INC_SUB_ELEMENT_CUT_OFF))
  1296. {
  1297. // this is a key element, return TRUE
  1298. return TRUE;
  1299. }
  1300. }
  1301. // this is not a key element, return FALSE
  1302. return FALSE;
  1303. }
  1304. // get named element chemistry
  1305. CElementChemistryPtr COTSClassifyEng::GetNamedElementChemistry(CElementChemistriesList & a_listChemistriesElements, const CString a_strElementName)
  1306. {
  1307. CElementChemistryPtr pElChem = nullptr;
  1308. CString strName = a_strElementName;
  1309. auto itr = std::find_if(a_listChemistriesElements.begin(), a_listChemistriesElements.end(), [strName](CElementChemistryPtr& poElementChemistry) { return poElementChemistry->GetName().CompareNoCase(strName) == 0; });
  1310. if (itr != a_listChemistriesElements.end())
  1311. {
  1312. pElChem = *itr;
  1313. }
  1314. return pElChem;
  1315. }
  1316. bool SortBySTDID(const std::shared_ptr< CSTDItem> &v1, const std::shared_ptr< CSTDItem> &v2)
  1317. {
  1318. return v1->GetSTDId() < v2->GetSTDId();
  1319. }
  1320. // get classify STD items
  1321. BOOL COTSClassifyEng::GetClassifySTDItem(CInclutionSTDDataPtr a_pPartSTDDataPtr, INC_CLASSIFY_TYPE a_nClassifyType, CSTDItemsList& a_listSTDItems)
  1322. {
  1323. // cal STD item id value range
  1324. OTS_STD_ITEM_VALUE nSTDIdRangeMin = OTS_STD_ITEM_VALUE::INVALID;
  1325. OTS_STD_ITEM_VALUE nSTDIdRangeMax = OTS_STD_ITEM_VALUE::INVALID;
  1326. switch (a_nClassifyType)
  1327. {
  1328. case INC_CLASSIFY_TYPE::SIMPLE_OXIDE:
  1329. {
  1330. nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_SIMPLE_OXIDE_MIN;
  1331. nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_SIMPLE_OXIDE_MAX;
  1332. }
  1333. break;
  1334. case INC_CLASSIFY_TYPE::COMPLEX_OXIDE:
  1335. {
  1336. nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_COMPLEX_OXIDE_MIN;
  1337. nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_COMPLEX_OXIDE_MAX;
  1338. }
  1339. break;
  1340. case INC_CLASSIFY_TYPE::OXIDE:
  1341. {
  1342. nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_OXIDE_MIN;
  1343. nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_OXIDE_MAX;
  1344. }
  1345. break;
  1346. case INC_CLASSIFY_TYPE::SUL:
  1347. {
  1348. nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_SUL_MIN;
  1349. nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_SUL_MAX;
  1350. }
  1351. break;
  1352. case INC_CLASSIFY_TYPE::NITR:
  1353. {
  1354. nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_NITRIDE_MIN;
  1355. nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_NITRIDE_MAX;
  1356. }
  1357. break;
  1358. case INC_CLASSIFY_TYPE::CARBON:
  1359. {
  1360. nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_CARBON_MIN;
  1361. nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_CARBON_MAX;
  1362. }
  1363. break;
  1364. case INC_CLASSIFY_TYPE::USER:
  1365. {
  1366. nSTDIdRangeMin = OTS_STD_ITEM_VALUE::USER_MIN;
  1367. nSTDIdRangeMax = OTS_STD_ITEM_VALUE::USER_MAX;
  1368. }
  1369. break;
  1370. default:
  1371. {
  1372. // wrong classify type value, return FALSE
  1373. return FALSE;
  1374. }
  1375. break;
  1376. }
  1377. // go through all STD items
  1378. a_listSTDItems.clear();
  1379. for (auto pSTDItem : a_pPartSTDDataPtr->GetSTDItemsList())
  1380. {
  1381. // is matching STD item?
  1382. if (pSTDItem->GetSTDId() >= (int)nSTDIdRangeMin && pSTDItem->GetSTDId() <= (int)nSTDIdRangeMax)
  1383. {
  1384. // get matching STD item
  1385. a_listSTDItems.push_back(pSTDItem);
  1386. }
  1387. }
  1388. // sort std item by std id
  1389. sort(a_listSTDItems.begin(), a_listSTDItems.end(), SortBySTDID);
  1390. // ok, return TRUE
  1391. return TRUE;
  1392. }
  1393. BOOL COTSClassifyEng::GetSulfildeOxideComplexItemId(CElementChemistriesList& a_listElChemsIncNoFe, double a_dMolarSumNoFe, CString strSulfideBaseName, int& a_nIncId)
  1394. {
  1395. int nIncId;
  1396. if (!OxideClassify(a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId))
  1397. {
  1398. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  1399. return FALSE;
  1400. }
  1401. // mapped?
  1402. if (nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED)
  1403. {
  1404. // this is an oxide sulfide
  1405. // confirm the oxide sulfide id
  1406. // get the STD item of the mapped oxide
  1407. CSTDItemPtr pOxideSTDItem = pPartSTDData->GetSTDItemById(nIncId);
  1408. if (pOxideSTDItem)
  1409. {
  1410. // get mapped oxide name
  1411. CString strOxideName = pOxideSTDItem->GetName();
  1412. // oxide sulfide name: oxide + "-" + sulfide base string
  1413. CString strOxide_SulName = strOxideName + STR_CONNECT + strSulfideBaseName;
  1414. // try to find the STD item
  1415. CSTDItemPtr pOxideSulSTDItem = GetSTDItemByName(listSulfideSTD, strOxide_SulName);
  1416. if (pOxideSulSTDItem)
  1417. {
  1418. // found the STD item
  1419. a_nIncId = pOxideSulSTDItem->GetSTDId();
  1420. return TRUE;
  1421. }
  1422. // rename the oxide sulfide name as "Oxide" + "-" + sulfide base string
  1423. strOxide_SulName = OXIDE_STR + STR_CONNECT + strSulfideBaseName;
  1424. // try to find the STD item
  1425. pOxideSulSTDItem = GetSTDItemByName(listSulfideSTD, strOxide_SulName);
  1426. if (pOxideSulSTDItem)
  1427. {
  1428. // found the STD item
  1429. a_nIncId = pOxideSulSTDItem->GetSTDId();
  1430. return TRUE;
  1431. }
  1432. // rename the oxide sulfide name as strOxideName + "-" + "Sulfide"
  1433. strOxide_SulName = strOxideName + STR_CONNECT + SULFIDE_STR;
  1434. // try to find the STD item
  1435. pOxideSulSTDItem = GetSTDItemByName(listSulfideSTD, strOxide_SulName);
  1436. if (pOxideSulSTDItem)
  1437. {
  1438. // found the STD item
  1439. a_nIncId = pOxideSulSTDItem->GetSTDId();
  1440. return TRUE;
  1441. }
  1442. // rename the oxide sulfide name as "Oxide" + "-" + "Sulfide"
  1443. strOxide_SulName = OXIDE_STR + STR_CONNECT + SULFIDE_STR;
  1444. // try to find the STD item
  1445. pOxideSulSTDItem = GetSTDItemByName(listSulfideSTD, strOxide_SulName);
  1446. if (pOxideSulSTDItem)
  1447. {
  1448. // found the STD item
  1449. a_nIncId = pOxideSulSTDItem->GetSTDId();
  1450. return TRUE;
  1451. }
  1452. // rename the oxide sulfide name as "Sulfide"
  1453. strOxide_SulName = SULFIDE_STR;
  1454. // try to find the STD item
  1455. pOxideSulSTDItem = GetSTDItemByName(listSulfideSTD, strOxide_SulName);
  1456. if (pOxideSulSTDItem)
  1457. {
  1458. // found the STD item
  1459. a_nIncId = pOxideSulSTDItem->GetSTDId();
  1460. return TRUE;
  1461. }
  1462. }
  1463. // can't identify this inclusion
  1464. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  1465. return TRUE;
  1466. }
  1467. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  1468. return TRUE;
  1469. }
  1470. BOOL COTSClassifyEng::GetSulfildeNitrideComplexItemId(CElementChemistriesList& a_listElChemsIncNoFe, double a_dMolarSumNoFe, CString strSulfideBaseName, int& a_nIncId)
  1471. {
  1472. int nIncId;
  1473. if (!NitrideClassify(a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId))
  1474. {
  1475. a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED;
  1476. return FALSE;
  1477. }
  1478. if (nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED)
  1479. {
  1480. CSTDItemPtr pNitrideTDItem = pPartSTDData->GetSTDItemById(nIncId);
  1481. if (pNitrideTDItem)
  1482. {// get mapped oxide name
  1483. CString strNitrideName = pNitrideTDItem->GetName();
  1484. // oxide sulfide name: oxide + "-" + sulfide base string
  1485. CString strNitride_SulName = strNitrideName + STR_CONNECT + strSulfideBaseName;
  1486. // try to find the STD item
  1487. CSTDItemPtr pNitrideSulSTDItem = GetSTDItemByName(listSulfideSTD, strNitride_SulName);
  1488. if (pNitrideSulSTDItem)
  1489. {
  1490. // found the STD item
  1491. a_nIncId = pNitrideSulSTDItem->GetSTDId();
  1492. return TRUE;
  1493. }
  1494. // rename the oxide sulfide name as "Oxide" + "-" + sulfide base string
  1495. strNitride_SulName = NITRIDE_STR + STR_CONNECT + strSulfideBaseName;
  1496. // try to find the STD item
  1497. pNitrideSulSTDItem = GetSTDItemByName(listSulfideSTD, strNitride_SulName);
  1498. if (pNitrideSulSTDItem)
  1499. {
  1500. // found the STD item
  1501. a_nIncId = pNitrideSulSTDItem->GetSTDId();
  1502. return TRUE;
  1503. }
  1504. // rename the oxide sulfide name as strOxideName + "-" + "Sulfide"
  1505. strNitride_SulName = strNitrideName + STR_CONNECT + SULFIDE_STR;
  1506. // try to find the STD item
  1507. pNitrideSulSTDItem = GetSTDItemByName(listSulfideSTD, strNitride_SulName);
  1508. if (pNitrideSulSTDItem)
  1509. {
  1510. // found the STD item
  1511. a_nIncId = pNitrideSulSTDItem->GetSTDId();
  1512. return TRUE;
  1513. }
  1514. // rename the oxide sulfide name as "Oxide" + "-" + "Sulfide"
  1515. strNitride_SulName = NITRIDE_STR + STR_CONNECT + SULFIDE_STR;
  1516. // try to find the STD item
  1517. pNitrideSulSTDItem = GetSTDItemByName(listSulfideSTD, strNitride_SulName);
  1518. if (pNitrideSulSTDItem)
  1519. {
  1520. // found the STD item
  1521. a_nIncId = pNitrideSulSTDItem->GetSTDId();
  1522. return TRUE;
  1523. }
  1524. // rename the oxide sulfide name as "Sulfide"
  1525. strNitride_SulName = SULFIDE_STR;
  1526. // try to find the STD item
  1527. pNitrideSulSTDItem = GetSTDItemByName(listSulfideSTD, strNitride_SulName);
  1528. if (pNitrideSulSTDItem)
  1529. {
  1530. // found the STD item
  1531. a_nIncId = pNitrideSulSTDItem->GetSTDId();
  1532. return TRUE;
  1533. }
  1534. }
  1535. }
  1536. return true;
  1537. }
  1538. void COTSClassifyEng::FilterOnSteelTech(STEEL_TECHNOLOGY steelTech, CElementChemistriesList& a_listElChemsIncNoFe)
  1539. {
  1540. CElementChemistriesList listChemistriesToAnalysis;
  1541. switch (steelTech)
  1542. {
  1543. // Ca process
  1544. case STEEL_TECHNOLOGY::CaProcessMode:
  1545. {
  1546. //remove the Mg element first
  1547. CElementChemistryPtr pElChemMg = GetNamedElementChemistry(a_listElChemsIncNoFe, INC_SUL_SUB_ELEMENT_NAMES[2]);
  1548. if (pElChemMg)
  1549. {
  1550. for (auto el : a_listElChemsIncNoFe)
  1551. {
  1552. if (!el->GetName().CompareNoCase(INC_SUL_SUB_ELEMENT_NAMES[2]))
  1553. {
  1554. listChemistriesToAnalysis.push_back(el);
  1555. }
  1556. }
  1557. }
  1558. else
  1559. {
  1560. listChemistriesToAnalysis = a_listElChemsIncNoFe;
  1561. }
  1562. }
  1563. break;
  1564. // Mg process
  1565. case STEEL_TECHNOLOGY::MgProcessMode:
  1566. {
  1567. //remove the Ca element first
  1568. CElementChemistryPtr pElChemCa = GetNamedElementChemistry(a_listElChemsIncNoFe, INC_SUL_SUB_ELEMENT_NAMES[1]);
  1569. if (pElChemCa)
  1570. {
  1571. for (auto el : a_listElChemsIncNoFe)
  1572. {
  1573. if (!el->GetName().CompareNoCase(INC_SUL_SUB_ELEMENT_NAMES[1]))
  1574. {
  1575. listChemistriesToAnalysis.push_back(el);
  1576. }
  1577. }
  1578. }
  1579. else
  1580. {
  1581. listChemistriesToAnalysis = a_listElChemsIncNoFe;
  1582. }
  1583. }
  1584. break;
  1585. // real earth elements process
  1586. case STEEL_TECHNOLOGY::RareEarthMode:
  1587. {
  1588. listChemistriesToAnalysis = a_listElChemsIncNoFe;
  1589. }
  1590. break;
  1591. default:
  1592. listChemistriesToAnalysis = a_listElChemsIncNoFe;
  1593. break;
  1594. }
  1595. a_listElChemsIncNoFe = listChemistriesToAnalysis;
  1596. }
  1597. BOOL COTSClassifyEng::ElementMatching(double a_dMolarSum,CElementChemistriesList a_listElChemsInc, CElementChemistryPtr KeyEleChemistry,CString subEleName,double mappingRatio, double& dKeyEleRemainMolar100)
  1598. {
  1599. BOOL bMapped = FALSE;
  1600. {
  1601. CElementChemistryPtr psubChem = GetNamedElementChemistry(a_listElChemsInc, subEleName);
  1602. if (psubChem)
  1603. {
  1604. if (!ElementsMapping(a_dMolarSum, mappingRatio, psubChem, KeyEleChemistry, bMapped))
  1605. {
  1606. return FALSE;
  1607. }
  1608. }
  1609. }
  1610. // need to re-calculate 100% molar value if mapped
  1611. if (bMapped)
  1612. {
  1613. dKeyEleRemainMolar100 = Cal100NorValue(KeyEleChemistry->GetMolarPercentage(), a_dMolarSum);
  1614. }
  1615. return bMapped;
  1616. }
  1617. BOOL COTSClassifyEng::ElementMatchingOnSteelTech(double a_dMolarSumNoFe,STEEL_TECHNOLOGY steelTech, CElementChemistriesList a_listElChemsIncNoFe, CElementChemistryPtr pSulElChem,CString& strProMappingSulName)
  1618. {
  1619. BOOL bProMapped=false;
  1620. double dSulResidual;
  1621. switch (steelTech)
  1622. {
  1623. case STEEL_TECHNOLOGY::CaProcessMode:
  1624. {
  1625. BOOL bCaMapped = FALSE;
  1626. {
  1627. CString strEle = INC_SUL_SUB_ELEMENT_NAMES[1];
  1628. double dMappingRatio = INC_SULFILSES_MAPPING_RATIO[1];
  1629. bCaMapped = ElementMatching(a_dMolarSumNoFe, a_listElChemsIncNoFe, pSulElChem, strEle, dMappingRatio, dSulResidual);
  1630. }
  1631. bProMapped = bCaMapped;
  1632. if (bProMapped)
  1633. {
  1634. strProMappingSulName = INC_SULFILSES_NAMES[1];
  1635. }
  1636. }
  1637. break;
  1638. case STEEL_TECHNOLOGY::MgProcessMode:
  1639. {
  1640. BOOL bMgMapped = FALSE;
  1641. {
  1642. CString strEle = INC_SUL_SUB_ELEMENT_NAMES[2];
  1643. double dMappingRatio = INC_SULFILSES_MAPPING_RATIO[2];
  1644. bMgMapped = ElementMatching(a_dMolarSumNoFe, a_listElChemsIncNoFe, pSulElChem, strEle, dMappingRatio, dSulResidual);
  1645. }
  1646. bProMapped = bMgMapped;
  1647. if (bProMapped)
  1648. {
  1649. strProMappingSulName = INC_SULFILSES_NAMES[2];
  1650. }
  1651. }
  1652. break;
  1653. case STEEL_TECHNOLOGY::RareEarthMode:
  1654. {
  1655. BOOL bCeMapped = FALSE;
  1656. {
  1657. CString strEle = INC_SUL_SUB_ELEMENT_NAMES[3];
  1658. double dMappingRatio = INC_SULFILSES_MAPPING_RATIO[3];
  1659. bCeMapped = ElementMatching(a_dMolarSumNoFe, a_listElChemsIncNoFe, pSulElChem, strEle, dMappingRatio, dSulResidual);
  1660. }
  1661. BOOL bLaMapped = FALSE;
  1662. {
  1663. CString strEle = INC_SUL_SUB_ELEMENT_NAMES[4];
  1664. double dMappingRatio = INC_SULFILSES_MAPPING_RATIO[4];
  1665. bLaMapped = ElementMatching(a_dMolarSumNoFe, a_listElChemsIncNoFe, pSulElChem, strEle, dMappingRatio, dSulResidual);
  1666. }
  1667. if (bCeMapped && bLaMapped)
  1668. {
  1669. strProMappingSulName = INC_SULFILSES_NAMES[3] + STR_CONNECT + INC_SULFILSES_NAMES[4];
  1670. bProMapped = TRUE;
  1671. }
  1672. else if (bCeMapped)
  1673. {
  1674. strProMappingSulName = INC_SULFILSES_NAMES[3];
  1675. bProMapped = TRUE;
  1676. }
  1677. else if (bLaMapped)
  1678. {
  1679. strProMappingSulName = INC_SULFILSES_NAMES[4];
  1680. bProMapped = TRUE;
  1681. }
  1682. }
  1683. break;
  1684. default:
  1685. break;
  1686. }
  1687. return bProMapped;
  1688. }
  1689. // get STD item by name
  1690. CSTDItemPtr COTSClassifyEng::GetSTDItemByName(CSTDItemsList& a_listSTDItems, CString a_strName)
  1691. {
  1692. CSTDItemPtr pSTDItem = nullptr;
  1693. auto itr = std::find_if(a_listSTDItems.begin(), a_listSTDItems.end(), [a_strName](CSTDItemPtr& pSTD) { return pSTD->GetName().CompareNoCase(a_strName) == 0; });
  1694. if (itr != a_listSTDItems.end())
  1695. {
  1696. // found the STD item
  1697. pSTDItem = *itr;
  1698. }
  1699. return pSTDItem;
  1700. }
  1701. // get STD item name by id
  1702. CString COTSClassifyEng::GetSTDItemNameById(CSTDItemsList& a_listSTDItems, int a_nItemId)
  1703. {
  1704. CString strName = _T("");
  1705. CSTDItemPtr pSTDItem = nullptr;
  1706. auto itr = std::find_if(a_listSTDItems.begin(), a_listSTDItems.end(), [a_nItemId](CSTDItemPtr& pSTD) { return pSTD->GetSTDId() == a_nItemId; });
  1707. if (itr != a_listSTDItems.end())
  1708. {
  1709. // found the STD item
  1710. pSTDItem = *itr;
  1711. strName = pSTDItem->GetName();
  1712. }
  1713. return strName;
  1714. }
  1715. // elements mapping
  1716. BOOL COTSClassifyEng::ElementsMapping(double a_dMolarSumNoFe,
  1717. double a_dMappingRatio,
  1718. CElementChemistryPtr a_pFirstElChem,
  1719. CElementChemistryPtr a_pSecondElChem,
  1720. BOOL& a_bMapped)
  1721. {
  1722. // safety check
  1723. ASSERT(a_pFirstElChem);
  1724. ASSERT(a_pSecondElChem);
  1725. if (a_dMolarSumNoFe < MIN_ELEMENT_SUM)
  1726. {
  1727. return FALSE;
  1728. }
  1729. if (a_dMappingRatio < MIN_DOUBLE_VALUE)
  1730. {
  1731. return FALSE;
  1732. }
  1733. // set mapped flag to FALSE as default
  1734. a_bMapped = FALSE;
  1735. // get first mapping element molar value
  1736. double dFirstMolar = a_pFirstElChem->GetMolarPercentage();
  1737. // make sure molar value of the first mapping element chemistry is enough
  1738. double dFirstMolar100 = Cal100NorValue(dFirstMolar, a_dMolarSumNoFe);
  1739. if (dFirstMolar100 > ELEMENT_MAPPING_100MOLAR)
  1740. {
  1741. // get second mapping element chemistry molar value
  1742. double dSecondElMolar = a_pSecondElChem->GetMolarPercentage();
  1743. // make sure second mapping element chemistry value is enough
  1744. double dSecondElMolar100 = Cal100NorValue(dSecondElMolar, a_dMolarSumNoFe);
  1745. if (dSecondElMolar100 > ELEMENT_MAPPING_100MOLAR)
  1746. {
  1747. // set mapped flag to true
  1748. a_bMapped = TRUE;
  1749. // reset mapping element chemistry molar values
  1750. // is there any first element left?
  1751. if (dFirstMolar - dSecondElMolar * a_dMappingRatio > 0)
  1752. {
  1753. // no more second element chemistry left;
  1754. a_pSecondElChem->SetPercentage(0.0);
  1755. // still there are some first element left
  1756. // calculate left first element molar value
  1757. dFirstMolar = dFirstMolar - (dSecondElMolar * a_dMappingRatio);
  1758. dFirstMolar100 = Cal100NorValue(dFirstMolar100, a_dMolarSumNoFe);
  1759. // is there enough first element left?
  1760. if (dFirstMolar100 > ELEMENT_MAPPING_100MOLAR)
  1761. {
  1762. // still have enough first element left
  1763. a_pFirstElChem->SetMolarPercentage(dFirstMolar);
  1764. }
  1765. else
  1766. {
  1767. // no enough enough first element left, set to 0.0
  1768. a_pFirstElChem->SetPercentage(0.0);
  1769. }
  1770. }
  1771. else
  1772. {
  1773. // no more first element chemistry left
  1774. a_pFirstElChem->SetPercentage(0.0);
  1775. // still there are some second element left
  1776. // calculate left second element molar value
  1777. dSecondElMolar = dSecondElMolar - dFirstMolar / a_dMappingRatio;
  1778. dSecondElMolar100 = Cal100NorValue(dSecondElMolar, a_dMolarSumNoFe);
  1779. // is there enough second element left?
  1780. if (dSecondElMolar100 > ELEMENT_MAPPING_100MOLAR)
  1781. {
  1782. // still have enough second element left
  1783. a_pSecondElChem->SetMolarPercentage(dSecondElMolar);
  1784. }
  1785. else
  1786. {
  1787. // no enough enough second element left, set to 0.0
  1788. a_pSecondElChem->SetPercentage(0.0);
  1789. }
  1790. }
  1791. }
  1792. }
  1793. // ok, return TRUE
  1794. return TRUE;
  1795. }
  1796. // check if is a REOxide
  1797. BOOL COTSClassifyEng::IsASimpleOxide(CElementChemistriesList& a_listElChems, double a_dMolarSum, CString& a_strSimOxName)
  1798. {
  1799. // go through oxide sub element chemistries
  1800. for (auto pOxideSubElChems : a_listElChems)
  1801. {
  1802. // calculate the %molar value of the sub element chemistry in the list
  1803. double dSubElMolar100 = Cal100NorValue(pOxideSubElChems->GetMolarPercentage(), a_dMolarSum);
  1804. // over simple oxide cut_off
  1805. if (dSubElMolar100 > SIMPLE_OXIDE_MOLAR_CUTOFF)
  1806. {
  1807. // this is a simple oxide, name it
  1808. for (int i = 0; i < INC_OXIDE_SUB_ELEMENT_MAX; ++i)
  1809. {
  1810. if (pOxideSubElChems->GetName().CompareNoCase(INC_OXIDE_SUB_ELEMENT_NAMES[i]) == 0)
  1811. {
  1812. // found it
  1813. // assign simple oxide name
  1814. a_strSimOxName = INC_OXIDE_NAMES[i];
  1815. // return TRUE
  1816. return TRUE;
  1817. }
  1818. }
  1819. }
  1820. }
  1821. // not a simple oxide, return FALSE
  1822. return FALSE;
  1823. }
  1824. // check if is a REOxide (deal with La-Ce-Oxide)
  1825. BOOL COTSClassifyEng::IsAREOxide(CElementChemistriesList& a_listElChems, double a_dMolarSum)
  1826. {
  1827. // calculate real element molar %
  1828. double dREElementMolarSum = 0;
  1829. for (int i = 0; i < REOXIDE_KEY_ELEMENT_MAX; ++i)
  1830. {
  1831. CElementChemistryPtr pREElement = GetNamedElementChemistry(a_listElChems, REOXIDE_KEY_ELEMENT_NAMES[i]);
  1832. if (pREElement)
  1833. {
  1834. // got a real element
  1835. // calculate the %molar value of the real element chemistry in the list
  1836. double dSubElMolar100 = Cal100NorValue(pREElement->GetMolarPercentage(), a_dMolarSum);
  1837. // calculate real element molar %
  1838. dREElementMolarSum += dSubElMolar100;
  1839. }
  1840. }
  1841. // is real element molar % over REAlOxide elements molar % cut_off
  1842. if (dREElementMolarSum > REALOXIDE_ELEMELTS_MOLAR_CUTOFF)
  1843. {
  1844. // this is a REAlOxide, return TRUE
  1845. return TRUE;
  1846. }
  1847. // not a REOxide, return FALSE
  1848. return FALSE;
  1849. }
  1850. // check if is a REAlOxide
  1851. BOOL COTSClassifyEng::IsAnREAlOxide(CElementChemistriesList& a_listElChems, double a_dMolarSum)
  1852. {
  1853. // calculate real element molar %
  1854. double dREElementMolarSum = 0;
  1855. for (int i = 0; i < REOXIDE_KEY_ELEMENT_MAX; ++i)
  1856. {
  1857. CElementChemistryPtr pREElement = GetNamedElementChemistry(a_listElChems, REOXIDE_KEY_ELEMENT_NAMES[i]);
  1858. if (pREElement)
  1859. {
  1860. // got a real element
  1861. // calculate the %molar value of the real element chemistry in the list
  1862. double dSubElMolar100 = Cal100NorValue(pREElement->GetMolarPercentage(), a_dMolarSum);
  1863. // calculate real element molar %
  1864. dREElementMolarSum += dSubElMolar100;
  1865. }
  1866. }
  1867. // is real element molar % over REAlOxide element molar % min cut_off
  1868. if (dREElementMolarSum < REALOXIDE_ELEMENT_MOLAR_LOW_CUTOFF)
  1869. {
  1870. // no, this is not a REALOxide, return FALSE
  1871. return FALSE;
  1872. }
  1873. // calculate Al/Si elements molar %
  1874. double dAl_Si_ElementMolarSum = 0;
  1875. for (int i = 0; i < REALOXIDE_SUB_ELEMENT_MAX; ++i)
  1876. {
  1877. CElementChemistryPtr pAlSiElement = GetNamedElementChemistry(a_listElChems, REALOXIDE_SUB_ELEMENT_NAMES[i]);
  1878. if (pAlSiElement)
  1879. {
  1880. // got a Al or Si element
  1881. // calculate the %molar value of the Al and Si element chemistry in the list
  1882. double dAl_SiElMolar100 = Cal100NorValue(pAlSiElement->GetMolarPercentage(), a_dMolarSum);
  1883. // calculate Al/Si elements molar %
  1884. dAl_Si_ElementMolarSum += dAl_SiElMolar100;
  1885. }
  1886. }
  1887. // is Al/Si elements molar % over REAlOxide element molar % min cut_off
  1888. if (dAl_Si_ElementMolarSum < REALOXIDE_ELEMENT_MOLAR_LOW_CUTOFF)
  1889. {
  1890. // no, this is not a REALOxide, return FALSE
  1891. return FALSE;
  1892. }
  1893. // is real element molar % + Al/Si elements molar % over the cut off
  1894. if (dREElementMolarSum + dAl_Si_ElementMolarSum > SIMPLE_OXIDE_MOLAR_CUTOFF)
  1895. {
  1896. // this is a REAlOxide, return TRUE
  1897. return TRUE;
  1898. }
  1899. // not a REAlOxide, return FALSE
  1900. return FALSE;
  1901. }
  1902. // check if is a Spinel
  1903. BOOL COTSClassifyEng::IsASpinel(CElementChemistriesList& a_listElChems, double a_dMolarSum)
  1904. {
  1905. // we deal with Mg, Al Spinel only
  1906. // get the first key element of Spinel
  1907. CElementChemistryPtr pFirstElChem = GetNamedElementChemistry(a_listElChems, SPINEL_KEY_ELEMENT_NAMES[0]);
  1908. if (!pFirstElChem)
  1909. {
  1910. // not a Spinel, return FALSE
  1911. return FALSE;
  1912. }
  1913. // get the second key element of Spinel
  1914. CElementChemistryPtr pSecondElChem = GetNamedElementChemistry(a_listElChems, SPINEL_KEY_ELEMENT_NAMES[1]);
  1915. if (!pSecondElChem)
  1916. {
  1917. // not a Spinel, return FALSE
  1918. return FALSE;
  1919. }
  1920. // check ratio between the two elements
  1921. double dFirstElMolar = pFirstElChem->GetMolarPercentage();
  1922. double dSecondElMolar = pSecondElChem->GetMolarPercentage();
  1923. if (dFirstElMolar < MIN_DOUBLE_VALUE)
  1924. {
  1925. // something wrong
  1926. // not a Spinel, return FALSE
  1927. return FALSE;
  1928. }
  1929. double dRatio = dSecondElMolar / dFirstElMolar;
  1930. if (dRatio < SPINEL_ELEMENT_RATIO_MIN || dRatio > SPINEL_ELEMENT_RATIO_MAX)
  1931. {
  1932. // not a Spinel, return FALSE
  1933. return FALSE;
  1934. }
  1935. // molar % amount check
  1936. double dFirstElMolar100 = Cal100NorValue(dFirstElMolar, a_dMolarSum);
  1937. double dSecondElMolar100 = Cal100NorValue(dSecondElMolar, a_dMolarSum);
  1938. if (dFirstElMolar100 + dSecondElMolar100 > SPINEL_KEY_ELEMENT_MOLAR_TOTAL)
  1939. {
  1940. // this is a Spinel
  1941. return TRUE;
  1942. }
  1943. // not a Spinel, return FALSE
  1944. return FALSE;
  1945. }
  1946. // check if is a Silicate
  1947. BOOL COTSClassifyEng::IsASilicate(CElementChemistriesList& a_listElChems, double a_dMolarSum)
  1948. {
  1949. // get key element of Silicate
  1950. CElementChemistryPtr pKeyElChem = GetNamedElementChemistry(a_listElChems, SILICATE_KEY_ELEMENT_NAME);
  1951. if (!pKeyElChem)
  1952. {
  1953. // not a Silicate, return FALSE
  1954. return FALSE;
  1955. }
  1956. // molar % amount check
  1957. double dKeyElMolar100 = Cal100NorValue(pKeyElChem->GetMolarPercentage(), a_dMolarSum);
  1958. if (dKeyElMolar100 > SILICATE_KEY_ELEMENT_MOLAR_TOTAL_MIN && dKeyElMolar100 < SILICATE_KEY_ELEMENT_MOLAR_TOTAL_MAX)
  1959. {
  1960. // this is a Silicate, return TRUE
  1961. return TRUE;
  1962. }
  1963. // not a Silicate, return FALSE
  1964. return FALSE;
  1965. }
  1966. // check if is a Aluminate
  1967. BOOL COTSClassifyEng::IsAnCa_Aluminate(CElementChemistriesList& a_listElChems, double a_dMolarSum,CString& strName)
  1968. {
  1969. // get key element of Aluminate
  1970. CElementChemistryPtr pKeyElChem = GetNamedElementChemistry(a_listElChems, ALUMINATE_KEY_ELEMENT_NAME[0]);
  1971. if (!pKeyElChem)
  1972. {
  1973. // not an Aluminate, return FALSE
  1974. return FALSE;
  1975. }
  1976. // molar % amount check
  1977. double dKeyElMolar100 = Cal100NorValue(pKeyElChem->GetMolarPercentage(), a_dMolarSum);
  1978. if (dKeyElMolar100 > ALUMINAT_KEY_ELEMENT_MOLAR_TOTAL_MIN && dKeyElMolar100 < ALUMINAT_KEY_ELEMENT_MOLAR_TOTAL_MAX)
  1979. {
  1980. CElementChemistryPtr pKeyElChem2 = GetNamedElementChemistry(a_listElChems, ALUMINATE_KEY_ELEMENT_NAME[1]);
  1981. if (!pKeyElChem2|| pKeyElChem2->GetPercentage()< MIN_ELEMENT_SUM)
  1982. {
  1983. strName = ALUMINATE_STR;
  1984. return TRUE;
  1985. }
  1986. double dFirstElMolar = pKeyElChem->GetMolarPercentage();//Al
  1987. double dSecondElMolar = pKeyElChem2->GetMolarPercentage();//Ca
  1988. double dRatio = dFirstElMolar/dSecondElMolar ;// Al/Ca
  1989. if (dRatio < 1.3 || dRatio > 0.9)//12CaO-7Al2O3 14/12
  1990. {
  1991. // not a Spinel, return FALSE
  1992. strName = ALUMINATE12CaO_7Al2O3_STR;
  1993. return TRUE;
  1994. }
  1995. if (dRatio < 0.9 || dRatio > 0.4)//3CaO-Al2O3 2/3
  1996. {
  1997. // not a Spinel, return FALSE
  1998. strName = ALUMINATE3CaO_Al2O3_STR;
  1999. return TRUE;
  2000. }
  2001. else
  2002. {
  2003. strName = Ca_ALUMINATE_STR;
  2004. }
  2005. // this is a Aluminate, return TRUE
  2006. return TRUE;
  2007. }
  2008. // not a Aluminate, return FALSE
  2009. return FALSE;
  2010. }
  2011. // check if the element chemistries list matching the STD
  2012. BOOL COTSClassifyEng::MatchingSTD(CElementChemistriesList& a_listElChems, CSTDItemPtr a_pSTDItem, double a_dMolarSum)
  2013. {
  2014. // safety check
  2015. ASSERT(a_pSTDItem);
  2016. if (!a_pSTDItem)
  2017. {
  2018. // something wrong
  2019. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::MatchingSTD: invalid CSTDItemPtr."));
  2020. return FALSE;
  2021. }
  2022. if (a_dMolarSum < MIN_ELEMENT_SUM)
  2023. {
  2024. // something wrong
  2025. LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::MatchingSTD: invalid molar sum value."));
  2026. return FALSE;
  2027. }
  2028. // find out how many elements need for the STD
  2029. CElementRangeList& listElementRange = a_pSTDItem->GetElementRangeList();
  2030. int nElNoMin = 0;
  2031. for (auto pElmentRange : listElementRange)
  2032. {
  2033. int nStart = pElmentRange->GetRange()->GetStart();
  2034. if (nStart > 0)
  2035. {
  2036. // this element has to have
  2037. ++nElNoMin;
  2038. }
  2039. }
  2040. int nElNoMax = (int)listElementRange.size();
  2041. // a_listChemistriesElements size has to be between nElNoMin and nElNoMax
  2042. int nElementSize = (int)a_listElChems.size();
  2043. //if (nElementSize < nElNoMin || nElementSize > nElNoMax)
  2044. if (nElementSize < nElNoMin)
  2045. {
  2046. // a_listChemistriesElements size not match
  2047. return FALSE;
  2048. }
  2049. // all element chemistries have to be in listElementRange and in the range
  2050. for (auto pElChems : a_listElChems)
  2051. {
  2052. CString strElement = pElChems->GetName();
  2053. auto itr = std::find_if(listElementRange.begin(), listElementRange.end(), [strElement](CElementRangePtr& poElemenRange) { return poElemenRange->GetElement()->GetName().CompareNoCase(strElement) == 0; });
  2054. if (itr == listElementRange.end())
  2055. {
  2056. // not in the element range list, not match then
  2057. return FALSE;
  2058. }
  2059. // molar value has to be in the range
  2060. double dMolar = pElChems->GetMolarPercentage();
  2061. dMolar = Cal100NorValue(dMolar, a_dMolarSum);
  2062. if (dMolar < (double)(*itr)->GetRange()->GetStart() || dMolar >(double)(*itr)->GetRange()->GetEnd())
  2063. {
  2064. // molar value has to be in the range, not match then
  2065. return FALSE;
  2066. }
  2067. }
  2068. // the two are matching each other, return TRUE
  2069. return TRUE;
  2070. }
  2071. // calculate 100% normalize value (molar)
  2072. double COTSClassifyEng::Cal100NorValue(double a_dValue, double a_dSumValue)
  2073. {
  2074. double d100NorCalue = MIN_DOUBLE_VALUE;
  2075. // sum has a cut off
  2076. if (a_dSumValue < MIN_ELEMENT_SUM)
  2077. {
  2078. return d100NorCalue;
  2079. }
  2080. d100NorCalue = a_dValue / a_dSumValue * 100;
  2081. return d100NorCalue;
  2082. }
  2083. }