#pragma once #include "stdafx.h" #include "OTSClassifyEng.h" #include "OTSHelper.h" namespace OTSClassifyEngine { using namespace OTSClassifyEngine; const double MIN_ELEMENT_SUM = 0.02; const long INC_DEFAULTSIZE = 100; const long INC_ELEMENTSIZE_MIN = 0; const CString STR_CONNECT = _T("-"); const CString STR_FE = _T("Fe"); const CString STR_C = _T("C"); const CString STR_SI = _T("Si"); const CString STR_O = _T("O"); const CString STR_SUL = _T("S"); const CString STR_N = _T("N"); const CString STR_CR = _T("Cr"); const CString STR_P = _T("P"); const CString STR_Na = _T("Na"); const CString STR_F = _T("F"); const double SIC_MOLAR_CUTOFF = 85.0; const double NBC_MOLAR_CUTOFF = 30.0; const double FEO_MOLAR_CUTOFF = 85.0; // key element const long INC_KEY_ELEMENT_MAX = 4; const double INC_KEY_ELEMENT_CUT_OFF = 0.02; // weight% const double INC_KEY_ELEMENT_TOTAL_100 = 5.0; // total molar value const CString INC_KEY_ELEMENT_NAMES[INC_KEY_ELEMENT_MAX] = { _T("S"),_T("N"),_T("O") }; // sub element const long INC_SUB_ELEMENT_MAX = 12; const double INC_SUB_ELEMENT_CUT_OFF = 0.02; // weight% const double INC_SUB_ELEMENT_TOTAL_100 = 5.0; // molar value const CString INC_SUB_ELEMENT_NAMES[INC_SUB_ELEMENT_MAX] = { _T("Mg"),_T("Al"),_T("Si"),_T("Ca"),_T("Ti"),_T("V"),_T("Mn"),_T("Zr"),_T("Nb"),_T("Mo"),_T("Ce"),_T("La") }; // element 100 % molar value mapping cut off const double ELEMENT_MAPPING_100MOLAR = 2.0; // sulfur classification const double MIN_SUL_MOLAR = ELEMENT_MAPPING_100MOLAR; const double MIN_SUL_SUB_MOLAR = ELEMENT_MAPPING_100MOLAR; const long INC_SUL_SUB_ELEMENT_MAX = 5; const CString INC_SUL_SUB_ELEMENT_NAMES[INC_SUL_SUB_ELEMENT_MAX] = { _T("Mn"),_T("Ca"),_T("Mg"),_T("Ce"),_T("La") }; const CString INC_SULFILSES_NAMES[INC_SUL_SUB_ELEMENT_MAX] = { _T("MnS"),_T("CaS"),_T("MgS"),_T("Ce(La)2S3"),_T("Ce(La)2S3") }; const double INC_SULFILSES_MAPPING_RATIO[INC_SUL_SUB_ELEMENT_MAX] = { 1.0, 1.0, 1.0, 1.5, 1.5 }; const double SULFIDE_MOLAR_CUTOFF = 5.0; const CString SULFIDE_STR = _T("Sulfide"); // O classification const long INC_OXIDE_SUB_ELEMENT_MAX = 9; const CString INC_OXIDE_SUB_ELEMENT_NAMES[INC_OXIDE_SUB_ELEMENT_MAX] = { _T("Al"),_T("Mg"),_T("Si"),_T("Mn"),_T("Ca"),_T("Ce"),_T("Cr"),_T("Ti"),_T("La") }; const CString INC_OXIDE_NAMES[INC_OXIDE_SUB_ELEMENT_MAX] = { _T("Al2O3"),_T("MgO"),_T("SiO2"),_T("MnO"),_T("CaO"),_T("CeO"),_T("Oxide"),_T("Oxide"),_T("REOxide") }; const double SIMPLE_OXIDE_MOLAR_CUTOFF = 90.0; const long REOXIDE_KEY_ELEMENT_MAX = 2; const CString REOXIDE_KEY_ELEMENT_NAMES[REOXIDE_KEY_ELEMENT_MAX] = { _T("Ce"),_T("La") }; const CString REOXIDE_STR = _T("REOxide"); const long REALOXIDE_SUB_ELEMENT_MAX = 2; const CString REALOXIDE_SUB_ELEMENT_NAMES[REALOXIDE_SUB_ELEMENT_MAX] = { _T("Si"),_T("Al") }; const double REALOXIDE_ELEMELTS_MOLAR_CUTOFF = 90.0; const CString REALOXIDE_STR = _T("REAlOxide"); const long SPINEL_KEY_ELEMENT_MAX = 2; const double REALOXIDE_ELEMENT_MOLAR_LOW_CUTOFF = 20; const CString SPINEL_KEY_ELEMENT_NAMES[SPINEL_KEY_ELEMENT_MAX] = { _T("Mg"),_T("Al") }; const double SPINEL_KEY_ELEMENT_MOLAR_TOTAL = 90.0; const double SPINEL_ELEMENT_RATIO_MIN = 1.6; const double SPINEL_ELEMENT_RATIO_MAX = 2.4; const CString SPINEL_STR = _T("Spinel"); const CString SILICATE_KEY_ELEMENT_NAME = _T("Si"); const double SILICATE_KEY_ELEMENT_MOLAR_TOTAL_MIN = 10.0; const double SILICATE_KEY_ELEMENT_MOLAR_TOTAL_MAX = 90.0; const CString SILICATE_STR = _T("Silicate"); const long ALUMINATE_KEY_ELEMENT_MAX = 2; const CString ALUMINATE_KEY_ELEMENT_NAME[ALUMINATE_KEY_ELEMENT_MAX] = { _T("Al"),_T("Ca") }; const double ALUMINAT_KEY_ELEMENT_MOLAR_TOTAL_MIN = 10.0; const double ALUMINAT_KEY_ELEMENT_MOLAR_TOTAL_MAX = 90.0; const CString ALUMINATE12CaO_7Al2O3_STR = _T("12CaO-7Al2O3"); const CString ALUMINATE3CaO_Al2O3_STR = _T("3CaO-Al2O3"); const CString ALUMINATE_STR = _T("Aluminate"); const CString Ca_ALUMINATE_STR = _T("Ca-Aluminate"); const CString STR_OXIDE = _T("O"); const double MIN_OXIDE_MOLAR = 5.0; const double MIN_OXIDE_SUB_MOLAR_TOTAL = 5.0; const double MIN_OXIDE_SUB_MOLAR_CUTOFF = ELEMENT_MAPPING_100MOLAR; const CString OXIDE_STR = _T("Oxide"); // nitrogen classification const long INC_NITR_SUB_ELEMENT_MAX = 8; const CString INC_NITR_SUB_ELEMENT_NAMES[INC_NITR_SUB_ELEMENT_MAX] = { _T("Ti"),_T("V"),_T("Nb"),_T("Al"),_T("Zr"),_T("Cr"),_T("La"),_T("Ce") }; const CString INC_NITR_NAMES[INC_NITR_SUB_ELEMENT_MAX] = { _T("TiN"),_T("VN"),_T("NbN"),_T("AlN"),_T("Nitride"),_T("Nitride"),_T("Nitride"),_T("Nitride") }; const double INC_NITR_MAPPING_RATIO[INC_NITR_SUB_ELEMENT_MAX] = { 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0 }; const CString STR_NITR = _T("N"); const CString STR_Nb = _T("Nb"); const CString STR_Mn = _T("Mn"); const double MIN_NITR_MOLAR = ELEMENT_MAPPING_100MOLAR; const double MIN_NITR_SUB_MOLAR = ELEMENT_MAPPING_100MOLAR; const double NITRIDE_MOLAR_CUTOFF = 5.0; const CString NITRIDE_STR = _T("Nitride"); #pragma region // carbon classification const long INC_CAR_SUB_ELEMENT_MAX = 1; const CString INC_CAR_SUB_ELEMENT_NAMES[INC_CAR_SUB_ELEMENT_MAX] = { _T("Nb") }; const CString INC_CAR_NAMES[INC_CAR_SUB_ELEMENT_MAX] = { _T("NbC") }; const double INC_CAR_MAPPING_RATIO[INC_CAR_SUB_ELEMENT_MAX] = { 1.0 }; const CString STR_CAR = _T("C"); const double MIN_CAR_MOLAR = ELEMENT_MAPPING_100MOLAR; const double MIN_CAR_SUB_MOLAR = ELEMENT_MAPPING_100MOLAR; const double CARBON_MOLAR_CUTOFF = 5.0; const CString CARBON_STR = _T("Carbon"); #pragma endregion COTSClassifyEng::COTSClassifyEng(CInclutionSTDDataPtr a_pPartSTDData) // constructor { ASSERT(a_pPartSTDData); // get all sulfides STD items pPartSTDData = a_pPartSTDData; if (!GetClassifySTDItem(a_pPartSTDData, INC_CLASSIFY_TYPE::SUL, listSulfideSTD)) { // something is wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::SulClassify: failed to call GetClassifySTDItem method.")); } // get all oxides STD items if (!GetClassifySTDItem(a_pPartSTDData, INC_CLASSIFY_TYPE::OXIDE, listOxideSTD)) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::OxideClassify: failed to call GetClassifySTDItem method.")); } // get all nitride STD items if (!GetClassifySTDItem(a_pPartSTDData, INC_CLASSIFY_TYPE::NITR, listNitrideSTD)) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NitrideClassify: failed to call GetClassifySTDItem method.")); } } COTSClassifyEng::~COTSClassifyEng() // detractor { } //Dispose ClassifyXray BOOL COTSClassifyEng::ClassifyXray( STEEL_TECHNOLOGY steelTech, CElementChemistriesList& a_listElementChemistries, int& a_nIncId, int& a_GrpId) { // the element chemistries list is an inclusion CElementChemistriesList listElChemsIncNoFe; double dMolarSumNoFe = 0.0f; OTS_PARTICLE_TYPE incId; NOT_INCLUTION_ID notAIncId;// is not an inc but we can identify if (!FilterInvalidIncXRay(a_listElementChemistries, listElChemsIncNoFe,dMolarSumNoFe, incId, notAIncId)) { LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::failed to call IsAnValidIncXRay")); return FALSE; } if (incId == OTS_PARTCLE_TYPE::ISNOT_INCLUTION)// this is not an inclution particle,but we can identify. { a_nIncId =(int) notAIncId; a_GrpId = (int)OTS_PARTCLE_TYPE::ISNOT_INCLUTION; return TRUE; } if (incId == OTS_PARTCLE_TYPE::INVALID)// this is not an valid inclution particle. { a_nIncId = (int)OTS_PARTCLE_TYPE::INVALID; a_GrpId = (int)OTS_PARTCLE_TYPE::INVALID; return TRUE; } // system STD classification int nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; if (!SystemClassify( steelTech, listElChemsIncNoFe, dMolarSumNoFe, nIncId)) { LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::ClassifyXray: failed to call SystemClassify method.")); a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return FALSE; } // identified? if (nIncId > (int)OTS_PARTICLE_TYPE::IDENTIFIED) {// identified, return TRUE a_nIncId = nIncId; IDENTIFIED_INC_GRP_ID grpid; GroupClassify(a_listElementChemistries,nIncId, grpid); a_GrpId = (int)grpid; return TRUE; } // identified? if (nIncId > (int)OTS_PARTICLE_TYPE::IDENTIFIED) { // identified, return TRUE a_nIncId = nIncId; IDENTIFIED_INC_GRP_ID grpid; GroupClassify(a_listElementChemistries,nIncId, grpid); a_GrpId = (int)grpid; return TRUE; } // can't identify this inclusion a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; IDENTIFIED_INC_GRP_ID grpid; GroupClassify(a_listElementChemistries,nIncId, grpid); a_GrpId = (int)grpid; return TRUE; } // public // check if the x-ray is an inc x-ray, BOOL COTSClassifyEng::FilterInvalidIncXRay(CElementChemistriesList a_listElementChemistries, CElementChemistriesList& a_listElChemsIncNoFe, double& a_dMolarSumNoFe, OTS_PARTICLE_TYPE& a_nIncId, NOT_INCLUTION_ID& notIncId) { // go through all elementS a_listElChemsIncNoFe.clear(); a_dMolarSumNoFe = 0; double dSumKeyElements = 0; double dSumSubElements = 0; double dCarbonMolar = 0; double dCarbonWeight = 0; double dNbMolar = 0; double dMnWeight = 0; double dOMolar = 0; double dOweight = 0; double dSiMolar = 0; double dFeMolar = 0; double dFeWeight = 0; double dPWeight = 0; double dNaWeight = 0; double dFWeight = 0; for (auto pElChem : a_listElementChemistries) { // create a new element chemistry CElementChemistryPtr pElChemNew = CElementChemistryPtr(new CElementChemistry(*pElChem.get())); // key element? S,O,N if (IsKeyElement(pElChem)) { // this is a key element // get molar percentage of this element double dMolarPercentage = pElChem->GetMolarPercentage(); // cal molar percentage sum (both lists) a_dMolarSumNoFe += dMolarPercentage; // cal key element molar percentage sum dSumKeyElements += dMolarPercentage; // add the element into the two lists a_listElChemsIncNoFe.push_back(pElChemNew); if (pElChem->GetName().CompareNoCase(STR_O) == 0) { dOMolar = pElChem->GetMolarPercentage(); dOweight = pElChem->GetPercentage(); } } // sub element?, include Fe else if (IsSubElement(pElChem)) { // this is a sub element // get molar percentage of this element double dMolarPercentage = pElChem->GetMolarPercentage(); // cal molar percentage sum list (no Fe) a_dMolarSumNoFe += pElChem->GetMolarPercentage(); // cal key element molar percentage sum dSumSubElements += dMolarPercentage; // add the element into the list (no Fe) a_listElChemsIncNoFe.push_back(pElChemNew); // Si if (pElChem->GetName().CompareNoCase(STR_SI) == 0) { dSiMolar = pElChem->GetMolarPercentage(); } if (pElChem->GetName().CompareNoCase(STR_Nb) == 0) { dNbMolar = pElChem->GetMolarPercentage(); } if (pElChem->GetName().CompareNoCase(STR_Mn) == 0) { dMnWeight = pElChem->GetPercentage(); } } else if (pElChem->GetName().CompareNoCase(STR_FE) == 0) { dFeMolar = pElChem->GetMolarPercentage(); dFeWeight = pElChem->GetPercentage(); } else if (pElChem->GetName().CompareNoCase(STR_C) == 0) { dCarbonMolar = pElChem->GetMolarPercentage(); dCarbonWeight = pElChem->GetPercentage(); } else if (pElChem->GetName().CompareNoCase(STR_P) == 0) { dPWeight = pElChem->GetPercentage(); } else if (pElChem->GetName().CompareNoCase(STR_Na) == 0) { dNaWeight = pElChem->GetPercentage(); } else if (pElChem->GetName().CompareNoCase(STR_F) == 0) { dFWeight = pElChem->GetPercentage(); } } // not a inc if this is a SiC //========================================= // any carbon? if (dCarbonMolar > MIN_DOUBLE_VALUE) { // calculate molar % of C + Si double dMolarC_Si = Cal100NorValue(dCarbonMolar + dSiMolar, a_dMolarSumNoFe + dCarbonMolar); if (dMolarC_Si > SIC_MOLAR_CUTOFF && dSiMolar> INC_SUB_ELEMENT_CUT_OFF) { // this is a SiC, not a inclusion, return FALSE a_nIncId =OTS_PARTCLE_TYPE::ISNOT_INCLUTION; notIncId = NOT_INCLUTION_ID::SiC; return TRUE; } double dMolarC_Nb = Cal100NorValue(dCarbonMolar + dNbMolar, a_dMolarSumNoFe + dCarbonMolar); if (dMolarC_Nb > NBC_MOLAR_CUTOFF && dNbMolar > INC_SUB_ELEMENT_CUT_OFF) { // this is a SiC, not a inclusion, return FALSE a_nIncId = OTS_PARTCLE_TYPE::ISNOT_INCLUTION; notIncId = NOT_INCLUTION_ID::NbC; return TRUE; } } //========================================= //FeO if (dOMolar > MIN_DOUBLE_VALUE) { // calculate molar % of Fe + O double dMolarFe_O = Cal100NorValue(dOMolar + dFeMolar, a_dMolarSumNoFe + dCarbonMolar); if (dMolarFe_O > FEO_MOLAR_CUTOFF) { if (a_listElementChemistries.size() == 2)//there is only Fe and O { 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()) { //this is a FeO, not a inclusion a_nIncId = OTS_PARTCLE_TYPE::ISNOT_INCLUTION; notIncId = NOT_INCLUTION_ID::FeO; return TRUE; } } } if (dMolarFe_O > FEO_MOLAR_CUTOFF && dMnWeight < 20 && dMnWeight>0) { if (a_listElementChemistries.size() == 3)//there is only Fe and O and Mn(<20) { a_nIncId = OTS_PARTCLE_TYPE::ISNOT_INCLUTION; notIncId = NOT_INCLUTION_ID::FeO; return TRUE; } if (a_listElementChemistries.size() == 4)//there is only Fe and O and Mn(<20) and C { if (dCarbonWeight > 0) { a_nIncId = OTS_PARTCLE_TYPE::ISNOT_INCLUTION; notIncId = NOT_INCLUTION_ID::FeO; return TRUE; } } } } if (a_dMolarSumNoFe < MIN_ELEMENT_SUM) { a_nIncId = OTS_PARTICLE_TYPE::INVALID; return TRUE; } double sumOfCarboOxideFe=0; if (dCarbonWeight > 0 || dFeWeight > 0) { sumOfCarboOxideFe = dOweight + dCarbonWeight + dFeWeight; } if (sumOfCarboOxideFe > 95)// contain too much c o fe then classify it as invalid { a_nIncId = OTS_PARTICLE_TYPE::INVALID; return TRUE; } if (dPWeight > 0 || dNaWeight > 0)// contain any of P Na then set it as invalid. { a_nIncId = OTS_PARTICLE_TYPE::INVALID; return TRUE; } // both key molar percentage sum and sub molar percentage sum have to be over certain values double dSumKeyElementsMolar = Cal100NorValue(dSumKeyElements, a_dMolarSumNoFe); double dSumSubElementsMolar = Cal100NorValue(dSumSubElements, a_dMolarSumNoFe); if (dSumKeyElementsMolar > INC_KEY_ELEMENT_TOTAL_100 && dSumSubElementsMolar > INC_SUB_ELEMENT_TOTAL_100) { a_nIncId = OTS_PARTCLE_TYPE::NOT_IDENTIFIED; return TRUE; } else { a_nIncId = OTS_PARTICLE_TYPE::INVALID; return TRUE; } } // system classification BOOL COTSClassifyEng::SystemClassify( STEEL_TECHNOLOGY steelTech, CElementChemistriesList& a_listElChemsIncNoFe, double a_dMolarSumNoFe, int& a_nIncId) { // try sulfide classification int nIncId = (int)OTS_PARTICLE_TYPE::INVALID; if (!SulClassify(steelTech, a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId)) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::ClassifyXray: failed to call SulClassify method.")); a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return FALSE; } // inclusion identified? if (nIncId != (int)OTS_PARTICLE_TYPE::INVALID) { // yes, this is a sulfide a_nIncId = nIncId; return TRUE; } // nitride classification if (!NitrideClassify(steelTech,a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId)) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::ClassifyXray: failed to call NitrideClassify method.")); a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return FALSE; } // inclusion identified? if (nIncId != (int)OTS_PARTICLE_TYPE::INVALID) { // yes, this is a nitride a_nIncId = nIncId; return TRUE; } // oxide classification if (!OxideClassify(steelTech, a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId)) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::ClassifyXray: failed to call OxideClassify method.")); a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return FALSE; } // inclusion identified? if (nIncId != (int)OTS_PARTICLE_TYPE::INVALID) { // yes, this is a oxide a_nIncId = nIncId; return TRUE; } // can't identify this inclusion a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return TRUE; } BOOL COTSClassifyEng::GroupClassify(CElementChemistriesList& a_listElChemsIncNoFe,int incId, IDENTIFIED_INC_GRP_ID& a_GrpId) { double dOWeight = 0; double dSWeight = 0; double dNWeight = 0; auto stdItm =pPartSTDData->GetSTDItemById( incId); if (incId == (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED) { a_GrpId = IDENTIFIED_INC_GRP_ID::Others; return true; } auto stdName = stdItm->GetName(); // sulfide classification for (long i = 0; i < INC_SUL_SUB_ELEMENT_MAX; i++) { if (stdName.CompareNoCase(INC_SULFILSES_NAMES[i]) == 0 ) { a_GrpId = IDENTIFIED_INC_GRP_ID::SULFIDE; return true; } } if (stdName.CompareNoCase(SULFIDE_STR) == 0 ) { a_GrpId = IDENTIFIED_INC_GRP_ID::SULFIDE; return true; } //oxide classification for (long i = 0; i < INC_OXIDE_SUB_ELEMENT_MAX; i++) { if (stdName.CompareNoCase(INC_OXIDE_NAMES[i]) == 0) { a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE; return true; } } if (stdName.CompareNoCase(SPINEL_STR) == 0) { a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE; return true; } if (stdName.CompareNoCase(ALUMINATE12CaO_7Al2O3_STR) == 0) { a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE; return true; } if (stdName.CompareNoCase(ALUMINATE3CaO_Al2O3_STR) == 0) { a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE; return true; } if (stdName.CompareNoCase(ALUMINATE_STR) == 0) { a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE; return true; } if (stdName.CompareNoCase(Ca_ALUMINATE_STR) == 0) { a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE; return true; } if (stdName.CompareNoCase(SILICATE_STR) == 0) { a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE; return true; } for (long i = 0; i < INC_NITR_SUB_ELEMENT_MAX; i++) { if (stdName.CompareNoCase(INC_NITR_NAMES[i]) == 0) { a_GrpId = IDENTIFIED_INC_GRP_ID::CARBONNITRIDE_NITRIDE; return true; } } for (auto pElChem : a_listElChemsIncNoFe) { if (pElChem->GetName().CompareNoCase(STR_O) == 0) { dOWeight = pElChem->GetPercentage(); } else if (pElChem->GetName().CompareNoCase(STR_SUL) == 0) { dSWeight = pElChem->GetPercentage(); } else if (pElChem->GetName().CompareNoCase(STR_N) == 0) { dNWeight = pElChem->GetPercentage(); } } if ( dSWeight >= MIN_ELEMENT_SUM && dOWeight < MIN_ELEMENT_SUM && dNWeight <= MIN_ELEMENT_SUM) { a_GrpId = IDENTIFIED_INC_GRP_ID::SULFIDE; } else if (dOWeight >= MIN_ELEMENT_SUM && dSWeight >= MIN_ELEMENT_SUM && dNWeight<=MIN_ELEMENT_SUM) { a_GrpId = IDENTIFIED_INC_GRP_ID::SULFIDE_OXIDE; } else if ( dNWeight >= MIN_ELEMENT_SUM) { a_GrpId = IDENTIFIED_INC_GRP_ID::CARBONNITRIDE_NITRIDE; }else if (dOWeight >= MIN_ELEMENT_SUM && dSWeight < MIN_ELEMENT_SUM) { a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE; } else { a_GrpId = IDENTIFIED_INC_GRP_ID::Others; } return TRUE; } BOOL COTSClassifyEng::GroupClassify1(CElementChemistriesList& a_listElChemsIncNoFe, int incId, IDENTIFIED_INC_GRP_ID& a_GrpId) { double dOWeight = 0; double dSWeight = 0; double dNWeight = 0; for (auto pElChem : a_listElChemsIncNoFe) { if (pElChem->GetName().CompareNoCase(STR_O) == 0) { dOWeight = pElChem->GetPercentage(); } else if (pElChem->GetName().CompareNoCase(STR_SUL) == 0) { dSWeight = pElChem->GetPercentage(); } else if (pElChem->GetName().CompareNoCase(STR_N) == 0) { dNWeight = pElChem->GetPercentage(); } } auto stdItm = pPartSTDData->GetSTDItemById(incId); INC_CLASSIFY_TYPE claType = INC_CLASSIFY_TYPE::INVALID; this->GetClassifyTypeOfSTDItem(incId, claType); if (claType == INC_CLASSIFY_TYPE::COMPLEX_OXIDE || claType == INC_CLASSIFY_TYPE::OXIDE || claType == INC_CLASSIFY_TYPE::SIMPLE_OXIDE) { a_GrpId = IDENTIFIED_INC_GRP_ID::OXIDE; return true; } else if (claType == INC_CLASSIFY_TYPE::SUL) { if (dOWeight >= MIN_ELEMENT_SUM && dSWeight <= 1) { a_GrpId = IDENTIFIED_INC_GRP_ID::SULFIDE_OXIDE; } else { a_GrpId = IDENTIFIED_INC_GRP_ID::SULFIDE; } } else if (claType == INC_CLASSIFY_TYPE::NITR) { a_GrpId = IDENTIFIED_INC_GRP_ID::CARBONNITRIDE_NITRIDE; } else { a_GrpId = IDENTIFIED_INC_GRP_ID::Others; } return TRUE; } BOOL COTSClassifyEng::GetGroupNameAndColorById(int grpId,std::string& grpName,std::string& grpColor) { if (grpId == (int)OTS_PARTICLE_TYPE::INVALID) { grpName = "Invalid"; grpColor = "#000000"; } if (grpId == (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED) { grpName = "Not Identified"; grpColor = "#000000"; } if (grpId == (int)OTS_PARTICLE_TYPE::ISNOT_INCLUTION) { grpName = "NOT_INCLUTION"; grpColor = "#483D8B"; } switch (grpId) { case (int)IDENTIFIED_INC_GRP_ID::OXIDE: grpName = "Oxide"; grpColor = "#FF69B4"; break; case (int)IDENTIFIED_INC_GRP_ID::SULFIDE: grpName = "Sulfide"; grpColor = "#FF00FF"; break; case (int)IDENTIFIED_INC_GRP_ID::SULFIDE_OXIDE: grpName = "Sulfide_Oxide"; grpColor = "#0000FF"; break; case (int)IDENTIFIED_INC_GRP_ID::CARBONNITRIDE_NITRIDE: grpName = "CarbonNitride/Nitride"; grpColor = "#00FF7F"; break; case (int)IDENTIFIED_INC_GRP_ID::Others: grpName = "Other"; grpColor = "#B0C4DE"; break; default: break; } return true; } // sulfides classification BOOL COTSClassifyEng::SulClassify( STEEL_TECHNOLOGY steelTech, CElementChemistriesList& a_listElChemsIncNoFe, double a_dMolarSumNoFe, int& a_nIncId) { // check if element chemistries list contain any sulfur CElementChemistryPtr pSulElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, STR_SUL); if (!pSulElChem) { // contains no sulfur, this is not a sulfide return TRUE; } // calculate sulfur 100 percentage molar double dSulMolar100 = Cal100NorValue(pSulElChem->GetMolarPercentage(), a_dMolarSumNoFe); // check if sulfur amount enough if (dSulMolar100 < MIN_SUL_MOLAR) { // no enough sulfur, this is not a sulfide return TRUE; } // this is a sulfide if (listSulfideSTD.empty())// any sulfides STD items { // no sulfides std items. can't identify sulfide // can't identify this inclusion a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return TRUE; } // mapping Mn first double dSulRemain; BOOL bMnMapped = FALSE; { CString strMn = INC_SUL_SUB_ELEMENT_NAMES[0]; double dMappingRatio = INC_SULFILSES_MAPPING_RATIO[0]; bMnMapped = ElementMatching(a_dMolarSumNoFe, a_listElChemsIncNoFe, pSulElChem, strMn, dMappingRatio, dSulRemain); } // process mapping if sulfur amount enough CString strProMappingSulName = _T(""); BOOL bSteelTechMapped = FALSE; if (dSulRemain > MIN_SUL_MOLAR)// still have enough sulfur, mapping Ca, Mg or Ce, La { FilterOnSteelTech(steelTech, a_listElChemsIncNoFe); bSteelTechMapped = ElementMatchingOnSteelTech(a_dMolarSumNoFe, steelTech, a_listElChemsIncNoFe, pSulElChem, strProMappingSulName); } // set sulfide base name CString strSulfideBaseName = _T(""); if (bMnMapped && bSteelTechMapped) { // both Mn and process mapped strSulfideBaseName = INC_SULFILSES_NAMES[0] + strProMappingSulName; } else if (bMnMapped) { // Mn mapped only strSulfideBaseName = INC_SULFILSES_NAMES[0]; } else if (bSteelTechMapped) { // process mapped only strSulfideBaseName = strProMappingSulName; } else { // // mapped nothing, force sulfide base name as "Sulfide" if sulfur 100% molar value over cutting off value if (dSulMolar100 > SULFIDE_MOLAR_CUTOFF) { strSulfideBaseName = SULFIDE_STR; } else { // no enough sulfur, consider that it is not a sulfide return TRUE; } } // check if the rest element chemistries map an oxide int nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; if (!GetSulfildeOxideComplexItemId(steelTech,a_listElChemsIncNoFe, a_dMolarSumNoFe, strSulfideBaseName, nIncId)) { a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return FALSE; } if (nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED) { a_nIncId = nIncId; return TRUE; } nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; if (!GetSulfildeNitrideComplexItemId(steelTech,a_listElChemsIncNoFe, a_dMolarSumNoFe, strSulfideBaseName, nIncId)) { a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return FALSE; } if (nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED) { a_nIncId = nIncId; return TRUE; } // try to find the STD item // this is a general sulfide// confirm the sulfide id CSTDItemPtr pSulSTDItem = GetSTDItemByName(listSulfideSTD, strSulfideBaseName); if (pSulSTDItem) { a_nIncId = pSulSTDItem->GetSTDId(); return TRUE; } // rename the sulfides name as "Sulfide" if it is not if (strSulfideBaseName.CompareNoCase(SULFIDE_STR) != 0) { strSulfideBaseName = SULFIDE_STR; pSulSTDItem = GetSTDItemByName(listSulfideSTD, strSulfideBaseName); if (pSulSTDItem) { // found the STD item a_nIncId = pSulSTDItem->GetSTDId(); return TRUE; } } // can't identify this inclusion a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return TRUE; } // oxides classification BOOL COTSClassifyEng::OxideClassify(STEEL_TECHNOLOGY steelTech, CElementChemistriesList& a_listElChemsIncNoFe, double a_dMolarSumNoFe, int& a_nIncId) { // check if element chemistries list contain any oxygen CElementChemistryPtr pOElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, STR_OXIDE); if (!pOElChem) { // contains no oxygen, this is not an oxide return TRUE; } // check if oxygen amount enough double dOMolar100 = Cal100NorValue(pOElChem->GetMolarPercentage(), a_dMolarSumNoFe); if (dOMolar100 < MIN_OXIDE_MOLAR) { // no enough oxygen, this is not an oxide return TRUE; } // this is an oxide // any oxide STD items if (listOxideSTD.empty()) { // no oxide STD items, can't identify oxide // can't identify this inclusion a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return TRUE; } // build oxide sub elements list // ========================================= // get all possible oxide sub element chemistries CElementChemistriesList listTempOxideSubElChems; double dTempOxideSubElMolarSum = 0; for (int i = 0; i < INC_OXIDE_SUB_ELEMENT_MAX; ++i) { // try to get the oxide sub element CElementChemistryPtr pSubElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, INC_OXIDE_SUB_ELEMENT_NAMES[i]); // found it? if (pSubElChem) { // got one // get the %molar value of the sub element chemistries double dSubElMolar = pSubElChem->GetMolarPercentage(); // add the sub element chemistries into the oxides element chemistries list listTempOxideSubElChems.push_back(pSubElChem); dTempOxideSubElMolarSum += dSubElMolar; } } // clear oxide sub element chemistries list CElementChemistriesList listOxideSubElChems; double dOxideSubElMolarSum = 0; for (auto pElChem : listTempOxideSubElChems) { // get the %molar value of the sub element chemistries double dSubElMolar = pElChem->GetMolarPercentage(); // the %molar value of the sub element chemistries of the sub element chemistries list double dSubElMolarMolar100 = Cal100NorValue(dSubElMolar, dTempOxideSubElMolarSum); // remove the sub element chemistries less than the cut off (2%) if (dSubElMolarMolar100 > MIN_OXIDE_SUB_MOLAR_CUTOFF) { // keep it listOxideSubElChems.push_back(pElChem); dOxideSubElMolarSum += dSubElMolar; } } // ========================================= // check oxide elements list CString strOxideName = _T(""); CString aluminateStr=_T(""); if (listOxideSubElChems.empty()) { // no oxide sub elements // consider this is not a oxide (may be it just is a dust) return TRUE; } // is a simple oxide? else if(IsASimpleOxide(listOxideSubElChems, dOxideSubElMolarSum, strOxideName)) { // this is a simple oxide // named already during checking } // is it a REOxide (La-Ce-Oxide)? else if (IsAREOxide(listOxideSubElChems, dOxideSubElMolarSum)) { // REOxcide strOxideName = REOXIDE_STR; } // should be a complex oxide // is it a REAlOxide? else if (IsAnREAlOxide(listOxideSubElChems, dOxideSubElMolarSum)) { // REOxcide strOxideName = REALOXIDE_STR; } // is it a Spinel? else if (IsASpinel(listOxideSubElChems, dOxideSubElMolarSum)) { // Spinel strOxideName = SPINEL_STR; } // is it a Silicate? else if (IsASilicate(listOxideSubElChems, dOxideSubElMolarSum)) { // Silicate strOxideName = SILICATE_STR; } // is it an Aluminate? else if (IsAnCa_Aluminate(steelTech, listOxideSubElChems, dOxideSubElMolarSum, aluminateStr)) { // Aluminate strOxideName = aluminateStr; } // fit none of them, simply name it as an oxide else { strOxideName = OXIDE_STR; } // confirm the oxide id // try to find the STD auto pSTDItem = GetSTDItemByName(listOxideSTD, strOxideName); if (pSTDItem) { // found the STD item a_nIncId = pSTDItem->GetSTDId(); return TRUE; } // rename the oxide as "Oxide" if it is not if (strOxideName.CompareNoCase(OXIDE_STR) != 0) { strOxideName = OXIDE_STR; auto pSTDItem = GetSTDItemByName(listOxideSTD, strOxideName); if (pSTDItem) { // found the STD item a_nIncId = pSTDItem->GetSTDId(); return TRUE; } } // can't identify this inclusion a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return TRUE; } // nitrides classification BOOL COTSClassifyEng::NitrideClassify(STEEL_TECHNOLOGY steelTech, CElementChemistriesList& a_listElChemsIncNoFe, double a_dMolarSumNoFe, int& a_nIncId) { // check if element chemistries list contain any nitrogen CElementChemistryPtr pNitrElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, STR_NITR); if (!pNitrElChem) { // contains no nitrogen, this is not a nitride return TRUE; } // check if nitrogen amount enough double dNitrMolar100 = Cal100NorValue(pNitrElChem->GetMolarPercentage(), a_dMolarSumNoFe); if (dNitrMolar100 < MIN_NITR_MOLAR) { // have no enough nitrogen, this is not a nitride return TRUE; } // this is a nitride // any nitride STD items if (listNitrideSTD.empty()) { // no nitrides std items. // can't identify this inclusion a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return TRUE; } // mapping nitride sub elements CString strNitrideName = _T(""); BOOL bMapped = FALSE; for (int i = 0; i < INC_NITR_SUB_ELEMENT_MAX; ++i) { CElementChemistryPtr pNitrSubElChem = GetNamedElementChemistry(a_listElChemsIncNoFe, INC_NITR_SUB_ELEMENT_NAMES[i]); if (pNitrSubElChem) { // this is a nitride sub element chemistry // get %molar value of this sub element chemistry double dNitr_Sub_Molar = Cal100NorValue(pNitrSubElChem->GetMolarPercentage(), a_dMolarSumNoFe); // make sure the sub element molar value is over mapping min value if (dNitr_Sub_Molar > MIN_NITR_SUB_MOLAR) { // mapping this sub element chemistry double dMappingRadio = INC_NITR_MAPPING_RATIO[i]; if (!ElementsMapping(a_dMolarSumNoFe, dMappingRadio, pNitrSubElChem, pNitrElChem, bMapped)) { // something is wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NitrideClassify: failed to call ElementsMapping method.")); return FALSE; } // mapping succeed? if(bMapped) { // is mapped Ti? if (i == 0) { // the first mapped nitride is "TiN" // try to map Nb BOOL bNbMapped = FALSE; // get molar % of the rest nitrogen dNitrMolar100 = Cal100NorValue(pNitrElChem->GetMolarPercentage(), a_dMolarSumNoFe); // make sure nitrogen amount is enough if (dNitrMolar100 > MIN_NITR_MOLAR) { // get element "Nb" CElementChemistryPtr pElChemNb = GetNamedElementChemistry(a_listElChemsIncNoFe, STR_Nb); // is there Nb in the list if (pElChemNb) { // get %molar value of Nb double dNb_Molar = Cal100NorValue(pElChemNb->GetMolarPercentage(), a_dMolarSumNoFe); // make sure Nb molar value is over mapping min value double dNbMappingRadio = INC_NITR_MAPPING_RATIO[2]; if (dNb_Molar > MIN_NITR_SUB_MOLAR) { if (!ElementsMapping(a_dMolarSumNoFe, dNbMappingRadio, pElChemNb, pNitrElChem, bNbMapped)) { // something is wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NitrideClassify: failed to call ElementsMapping method.")); return FALSE; } } } } // mapped "Nb" if (bNbMapped) { // nitride name is "TiN-NbN" strNitrideName = INC_NITR_NAMES[0] + STR_CONNECT + INC_NITR_NAMES[2]; } else { // nitride name is "TiN" strNitrideName = INC_NITR_NAMES[0]; } } else { // get the nitride name strNitrideName = INC_NITR_NAMES[i]; } // completed mapping, get out the loop break; } } } } // not mapped? if (!bMapped) { // force to name it as "Nitride" if N 100% molar value over cutting off value if (dNitrMolar100 > NITRIDE_MOLAR_CUTOFF) { strNitrideName = NITRIDE_STR; } else { // no enough nitride, consider that it is not a nitride return TRUE; } } // check if the rest element chemistries map an oxide int nIncId = (int)OTS_PARTICLE_TYPE::INVALID; if (!OxideClassify(steelTech, a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId)) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NitrideClassify: failed to call OxideClassify method.")); return FALSE; } // mapped? if (nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED) { // this is an oxide nitride // confirm the oxide nitride id // get the STD item of the mapped oxide CSTDItemPtr pOxideSTDItem = pPartSTDData->GetSTDItemById(nIncId); if (pOxideSTDItem) { // get mapped oxide name CString strOxideName = pOxideSTDItem->GetName(); // oxide nitride name: oxide + "-" + nitride base string CString strOxide_NitrName = strOxideName + STR_CONNECT + strNitrideName; // try to find the STD item CSTDItemPtr pOxideNitrSTDItem = GetSTDItemByName(listNitrideSTD, strOxide_NitrName); if (pOxideNitrSTDItem) { // found the STD item a_nIncId = pOxideNitrSTDItem->GetSTDId(); return TRUE; } // can't find the STD item // rename the oxide nitride name as "Oxide" + "-" + nitride base string strOxide_NitrName = OXIDE_STR + STR_CONNECT + strOxide_NitrName; // try to find the STD item pOxideNitrSTDItem = GetSTDItemByName(listNitrideSTD, strOxide_NitrName); if (pOxideNitrSTDItem) { // found the STD item a_nIncId = pOxideNitrSTDItem->GetSTDId(); return TRUE; } // rename the oxide nitride name as strOxideName + "-" + "Nitride" strOxide_NitrName = strOxideName + STR_CONNECT + NITRIDE_STR; // try to find the STD item pOxideNitrSTDItem = GetSTDItemByName(listNitrideSTD, strOxide_NitrName); if (pOxideNitrSTDItem) { // found the STD item a_nIncId = pOxideNitrSTDItem->GetSTDId(); return TRUE; } // rename the oxide nitride name as "Oxide" + "-" + "Nitride" strOxide_NitrName = OXIDE_STR + STR_CONNECT + NITRIDE_STR; // try to find the STD item pOxideNitrSTDItem = GetSTDItemByName(listNitrideSTD, strOxide_NitrName); if (pOxideNitrSTDItem) { // found the STD item a_nIncId = pOxideNitrSTDItem->GetSTDId(); return TRUE; } // rename the oxide nitride name as "Nitride" strOxide_NitrName = NITRIDE_STR; // try to find the STD item pOxideNitrSTDItem = GetSTDItemByName(listNitrideSTD, strOxide_NitrName); if (pOxideNitrSTDItem) { // found the STD item a_nIncId = pOxideSTDItem->GetSTDId(); return TRUE; } } // can't identify this inclusion a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return TRUE; } // confirm the nitride id // try to find the STD auto pSTDItem = GetSTDItemByName(listNitrideSTD, strNitrideName); if (pSTDItem) { // found the STD item a_nIncId = pSTDItem->GetSTDId(); return TRUE; } // rename the nitride as "Nitride" if it is not if (strNitrideName.CompareNoCase(NITRIDE_STR) != 0) { strNitrideName = NITRIDE_STR; auto pSTDItem = GetSTDItemByName(listNitrideSTD, strNitrideName); if (pSTDItem) { // found the STD item a_nIncId = pSTDItem->GetSTDId(); return TRUE; } } // can't identify this inclusion a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return TRUE; } // nominate element chemistries list BOOL COTSClassifyEng::NominateElChemsList( CElementChemistriesList& a_listElChemsInc, CElementChemistriesList& a_listNomiElChemsInc) { // return FALSE if nothing in the input list if (a_listElChemsInc.empty()) { //LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NomiNateElChemsList: invalid inclusion x-ray data.")); return FALSE; } // initialize outputs a_listNomiElChemsInc.clear(); // go thought all element chemistry objects of the input lit double dWeightPerSum = 0; for (auto pElChem : a_listElChemsInc) { // create a new element chemistry CElementChemistryPtr pElChemNew = CElementChemistryPtr(new CElementChemistry(*pElChem.get())); // key element? if (IsKeyElement(pElChem)) { // this is a key element // cal weight percentage sum dWeightPerSum += pElChem->GetPercentage(); // add the element into the output list a_listNomiElChemsInc.push_back(pElChemNew); } // sub element? else if (IsSubElement(pElChem)) { // this is a sub element // Fe? if (pElChem->GetName().CompareNoCase("Fe") != 0) { // cal weight percentage sum dWeightPerSum += pElChem->GetPercentage(); // add the element into the output list a_listNomiElChemsInc.push_back(pElChemNew); } } } // return FALSE if nothing in the input list or sum less than cut off value if (a_listNomiElChemsInc.empty() || dWeightPerSum < INC_SUB_ELEMENT_CUT_OFF) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::NomiNateElChemsList: invalid inclusion x-ray data.")); return FALSE; } // go thought all element chemistry objects of the output lit for (auto pElChem : a_listNomiElChemsInc) { // reset weight % value // get weight % value double dWeightPer = pElChem->GetPercentage(); // calculate new weight % value double dWeightPerNew = Cal100NorValue(dWeightPer, dWeightPerSum); // reset pElChem->SetPercentage(dWeightPerNew); } // ok, return TRUE return TRUE; } // protected // check if this is a key element BOOL COTSClassifyEng::IsKeyElement(CElementChemistryPtr a_pElChem) { // safety check ASSERT(a_pElChem); if (!a_pElChem) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::IsKeyElement: invalid CElementChemistryPtr.")); return FALSE; } // go thought all key element for (long i = 0; i < INC_KEY_ELEMENT_MAX; ++i) { // compare if ((a_pElChem->GetName().CompareNoCase(INC_KEY_ELEMENT_NAMES[i]) == 0) && (a_pElChem->GetPercentage() >= INC_KEY_ELEMENT_CUT_OFF)) { // this is a key element, return TRUE return TRUE; } } // this is not a key element, return FALSE return FALSE; } // check if this is a sub element BOOL COTSClassifyEng::IsSubElement(CElementChemistryPtr a_pElChem) { // safety check ASSERT(a_pElChem); if (!a_pElChem) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::IsSubElement: invalid CElementChemistryPtr.")); return FALSE; } // go thought all sub element for (long i = 0; i < INC_SUB_ELEMENT_MAX; ++i) { // compare if ((a_pElChem->GetName().CompareNoCase(INC_SUB_ELEMENT_NAMES[i]) == 0) && (a_pElChem->GetPercentage() >= INC_SUB_ELEMENT_CUT_OFF)) { // this is a key element, return TRUE return TRUE; } } // this is not a key element, return FALSE return FALSE; } // get named element chemistry CElementChemistryPtr COTSClassifyEng::GetNamedElementChemistry(CElementChemistriesList & a_listChemistriesElements, const CString a_strElementName) { CElementChemistryPtr pElChem = nullptr; CString strName = a_strElementName; auto itr = std::find_if(a_listChemistriesElements.begin(), a_listChemistriesElements.end(), [strName](CElementChemistryPtr& poElementChemistry) { return poElementChemistry->GetName().CompareNoCase(strName) == 0; }); if (itr != a_listChemistriesElements.end()) { pElChem = *itr; } return pElChem; } bool SortBySTDID(const std::shared_ptr< CSTDItem> &v1, const std::shared_ptr< CSTDItem> &v2) { return v1->GetSTDId() < v2->GetSTDId(); } // get classify STD items BOOL COTSClassifyEng::GetClassifySTDItem(CInclutionSTDDataPtr a_pPartSTDDataPtr, INC_CLASSIFY_TYPE a_nClassifyType, CSTDItemsList& a_listSTDItems) { // cal STD item id value range OTS_STD_ITEM_VALUE nSTDIdRangeMin = OTS_STD_ITEM_VALUE::INVALID; OTS_STD_ITEM_VALUE nSTDIdRangeMax = OTS_STD_ITEM_VALUE::INVALID; switch (a_nClassifyType) { case INC_CLASSIFY_TYPE::SIMPLE_OXIDE: { nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_SIMPLE_OXIDE_MIN; nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_SIMPLE_OXIDE_MAX; } break; case INC_CLASSIFY_TYPE::COMPLEX_OXIDE: { nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_COMPLEX_OXIDE_MIN; nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_COMPLEX_OXIDE_MAX; } break; case INC_CLASSIFY_TYPE::OXIDE: { nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_OXIDE_MIN; nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_OXIDE_MAX; } break; case INC_CLASSIFY_TYPE::SUL: { nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_SUL_MIN; nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_SUL_MAX; } break; case INC_CLASSIFY_TYPE::NITR: { nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_NITRIDE_MIN; nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_NITRIDE_MAX; } break; case INC_CLASSIFY_TYPE::CARBON: { nSTDIdRangeMin = OTS_STD_ITEM_VALUE::SYS_CARBON_MIN; nSTDIdRangeMax = OTS_STD_ITEM_VALUE::SYS_CARBON_MAX; } break; case INC_CLASSIFY_TYPE::USER: { nSTDIdRangeMin = OTS_STD_ITEM_VALUE::USER_MIN; nSTDIdRangeMax = OTS_STD_ITEM_VALUE::USER_MAX; } break; default: { // wrong classify type value, return FALSE return FALSE; } break; } // go through all STD items a_listSTDItems.clear(); for (auto pSTDItem : a_pPartSTDDataPtr->GetSTDItemsList()) { // is matching STD item? if (pSTDItem->GetSTDId() >= (int)nSTDIdRangeMin && pSTDItem->GetSTDId() <= (int)nSTDIdRangeMax) { // get matching STD item a_listSTDItems.push_back(pSTDItem); } } // sort std item by std id sort(a_listSTDItems.begin(), a_listSTDItems.end(), SortBySTDID); // ok, return TRUE return TRUE; } BOOL COTSClassifyEng::GetClassifyTypeOfSTDItem(int a_nIncId, INC_CLASSIFY_TYPE& a_nClassifyType) { a_nClassifyType = INC_CLASSIFY_TYPE::INVALID; if (a_nIncId >=(int) OTS_STD_ITEM_VALUE::SYS_SIMPLE_OXIDE_MIN && a_nIncId < (int)OTS_STD_ITEM_VALUE::SYS_SIMPLE_OXIDE_MAX) { a_nClassifyType = INC_CLASSIFY_TYPE::SIMPLE_OXIDE; }else if(a_nIncId >= (int) OTS_STD_ITEM_VALUE::SYS_COMPLEX_OXIDE_MIN && a_nIncId < (int)OTS_STD_ITEM_VALUE::SYS_COMPLEX_OXIDE_MAX) { a_nClassifyType = INC_CLASSIFY_TYPE::COMPLEX_OXIDE; } else if (a_nIncId >= (int)OTS_STD_ITEM_VALUE::SYS_OXIDE_MIN && a_nIncId < (int)OTS_STD_ITEM_VALUE::SYS_OXIDE_MAX) { a_nClassifyType = INC_CLASSIFY_TYPE::OXIDE; } else if (a_nIncId >= (int)OTS_STD_ITEM_VALUE::SYS_SUL_MIN && a_nIncId < (int)OTS_STD_ITEM_VALUE::SYS_SUL_MAX) { a_nClassifyType = INC_CLASSIFY_TYPE::SUL; } else if (a_nIncId >= (int)OTS_STD_ITEM_VALUE::SYS_NITRIDE_MIN && a_nIncId < (int)OTS_STD_ITEM_VALUE::SYS_NITRIDE_MAX) { a_nClassifyType = INC_CLASSIFY_TYPE::NITR; } return true; } BOOL COTSClassifyEng::GetSulfildeOxideComplexItemId(STEEL_TECHNOLOGY steelTech, CElementChemistriesList& a_listElChemsIncNoFe, double a_dMolarSumNoFe, CString strSulfideBaseName, int& a_nIncId) { int nIncId; if (!OxideClassify(steelTech,a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId)) { a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return FALSE; } // mapped? if (nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED) { // this is an oxide sulfide // confirm the oxide sulfide id // get the STD item of the mapped oxide CSTDItemPtr pOxideSTDItem = pPartSTDData->GetSTDItemById(nIncId); if (pOxideSTDItem) { // get mapped oxide name CString strOxideName = pOxideSTDItem->GetName(); // oxide sulfide name: oxide + "-" + sulfide base string CString strOxide_SulName = strOxideName + STR_CONNECT + strSulfideBaseName; // try to find the STD item CSTDItemPtr pOxideSulSTDItem = GetSTDItemByName(listSulfideSTD, strOxide_SulName); if (pOxideSulSTDItem) { // found the STD item a_nIncId = pOxideSulSTDItem->GetSTDId(); return TRUE; } // rename the oxide sulfide name as "Oxide" + "-" + sulfide base string strOxide_SulName = OXIDE_STR + STR_CONNECT + strSulfideBaseName; // try to find the STD item pOxideSulSTDItem = GetSTDItemByName(listSulfideSTD, strOxide_SulName); if (pOxideSulSTDItem) { // found the STD item a_nIncId = pOxideSulSTDItem->GetSTDId(); return TRUE; } // rename the oxide sulfide name as strOxideName + "-" + "Sulfide" strOxide_SulName = strOxideName + STR_CONNECT + SULFIDE_STR; // try to find the STD item pOxideSulSTDItem = GetSTDItemByName(listSulfideSTD, strOxide_SulName); if (pOxideSulSTDItem) { // found the STD item a_nIncId = pOxideSulSTDItem->GetSTDId(); return TRUE; } // rename the oxide sulfide name as "Oxide" + "-" + "Sulfide" strOxide_SulName = OXIDE_STR + STR_CONNECT + SULFIDE_STR; // try to find the STD item pOxideSulSTDItem = GetSTDItemByName(listSulfideSTD, strOxide_SulName); if (pOxideSulSTDItem) { // found the STD item a_nIncId = pOxideSulSTDItem->GetSTDId(); return TRUE; } // rename the oxide sulfide name as "Sulfide" strOxide_SulName = SULFIDE_STR; // try to find the STD item pOxideSulSTDItem = GetSTDItemByName(listSulfideSTD, strOxide_SulName); if (pOxideSulSTDItem) { // found the STD item a_nIncId = pOxideSulSTDItem->GetSTDId(); return TRUE; } } // can't identify this inclusion a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return TRUE; } a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return TRUE; } BOOL COTSClassifyEng::GetSulfildeNitrideComplexItemId(STEEL_TECHNOLOGY steelTech, CElementChemistriesList& a_listElChemsIncNoFe, double a_dMolarSumNoFe, CString strSulfideBaseName, int& a_nIncId) { int nIncId; if (!NitrideClassify(steelTech,a_listElChemsIncNoFe, a_dMolarSumNoFe, nIncId)) { a_nIncId = (int)OTS_PARTICLE_TYPE::NOT_IDENTIFIED; return FALSE; } if (nIncId >= (int)OTS_PARTICLE_TYPE::IDENTIFIED) { CSTDItemPtr pNitrideTDItem = pPartSTDData->GetSTDItemById(nIncId); if (pNitrideTDItem) {// get mapped oxide name CString strNitrideName = pNitrideTDItem->GetName(); // oxide sulfide name: oxide + "-" + sulfide base string CString strNitride_SulName = strNitrideName + STR_CONNECT + strSulfideBaseName; // try to find the STD item CSTDItemPtr pNitrideSulSTDItem = GetSTDItemByName(listSulfideSTD, strNitride_SulName); if (pNitrideSulSTDItem) { // found the STD item a_nIncId = pNitrideSulSTDItem->GetSTDId(); return TRUE; } // rename the oxide sulfide name as "Oxide" + "-" + sulfide base string strNitride_SulName = NITRIDE_STR + STR_CONNECT + strSulfideBaseName; // try to find the STD item pNitrideSulSTDItem = GetSTDItemByName(listSulfideSTD, strNitride_SulName); if (pNitrideSulSTDItem) { // found the STD item a_nIncId = pNitrideSulSTDItem->GetSTDId(); return TRUE; } // rename the oxide sulfide name as strOxideName + "-" + "Sulfide" strNitride_SulName = strNitrideName + STR_CONNECT + SULFIDE_STR; // try to find the STD item pNitrideSulSTDItem = GetSTDItemByName(listSulfideSTD, strNitride_SulName); if (pNitrideSulSTDItem) { // found the STD item a_nIncId = pNitrideSulSTDItem->GetSTDId(); return TRUE; } // rename the oxide sulfide name as "Oxide" + "-" + "Sulfide" strNitride_SulName = NITRIDE_STR + STR_CONNECT + SULFIDE_STR; // try to find the STD item pNitrideSulSTDItem = GetSTDItemByName(listSulfideSTD, strNitride_SulName); if (pNitrideSulSTDItem) { // found the STD item a_nIncId = pNitrideSulSTDItem->GetSTDId(); return TRUE; } // rename the oxide sulfide name as "Sulfide" strNitride_SulName = SULFIDE_STR; // try to find the STD item pNitrideSulSTDItem = GetSTDItemByName(listSulfideSTD, strNitride_SulName); if (pNitrideSulSTDItem) { // found the STD item a_nIncId = pNitrideSulSTDItem->GetSTDId(); return TRUE; } } } return true; } void COTSClassifyEng::FilterOnSteelTech(STEEL_TECHNOLOGY steelTech, CElementChemistriesList& a_listElChemsIncNoFe) { CElementChemistriesList listChemistriesToAnalysis; switch (steelTech) { // Ca process case STEEL_TECHNOLOGY::CaProcessMode: { //remove the Mg element first CElementChemistryPtr pElChemMg = GetNamedElementChemistry(a_listElChemsIncNoFe, INC_SUL_SUB_ELEMENT_NAMES[2]); if (pElChemMg) { for (auto el : a_listElChemsIncNoFe) { if (!el->GetName().CompareNoCase(INC_SUL_SUB_ELEMENT_NAMES[2])) { listChemistriesToAnalysis.push_back(el); } } } else { listChemistriesToAnalysis = a_listElChemsIncNoFe; } } break; // Mg process case STEEL_TECHNOLOGY::MgProcessMode: { //remove the Ca element first CElementChemistryPtr pElChemCa = GetNamedElementChemistry(a_listElChemsIncNoFe, INC_SUL_SUB_ELEMENT_NAMES[1]); if (pElChemCa) { for (auto el : a_listElChemsIncNoFe) { if (!el->GetName().CompareNoCase(INC_SUL_SUB_ELEMENT_NAMES[1])) { listChemistriesToAnalysis.push_back(el); } } } else { listChemistriesToAnalysis = a_listElChemsIncNoFe; } } break; // real earth elements process case STEEL_TECHNOLOGY::RareEarthMode: { listChemistriesToAnalysis = a_listElChemsIncNoFe; } break; default: listChemistriesToAnalysis = a_listElChemsIncNoFe; break; } a_listElChemsIncNoFe = listChemistriesToAnalysis; } BOOL COTSClassifyEng::ElementMatching(double a_dMolarSum,CElementChemistriesList a_listElChemsInc, CElementChemistryPtr KeyEleChemistry,CString subEleName,double mappingRatio, double& dKeyEleRemainMolar100) { BOOL bMapped = FALSE; { CElementChemistryPtr psubChem = GetNamedElementChemistry(a_listElChemsInc, subEleName); if (psubChem) { if (!ElementsMapping(a_dMolarSum, mappingRatio, psubChem, KeyEleChemistry, bMapped)) { return FALSE; } } } // need to re-calculate 100% molar value if mapped if (bMapped) { dKeyEleRemainMolar100 = Cal100NorValue(KeyEleChemistry->GetMolarPercentage(), a_dMolarSum); } return bMapped; } BOOL COTSClassifyEng::ElementMatchingOnSteelTech(double a_dMolarSumNoFe,STEEL_TECHNOLOGY steelTech, CElementChemistriesList a_listElChemsIncNoFe, CElementChemistryPtr pSulElChem,CString& strProMappingSulName) { BOOL bProMapped=false; double dSulResidual; switch (steelTech) { case STEEL_TECHNOLOGY::CaProcessMode: { BOOL bCaMapped = FALSE; { CString strEle = INC_SUL_SUB_ELEMENT_NAMES[1]; double dMappingRatio = INC_SULFILSES_MAPPING_RATIO[1]; bCaMapped = ElementMatching(a_dMolarSumNoFe, a_listElChemsIncNoFe, pSulElChem, strEle, dMappingRatio, dSulResidual); } bProMapped = bCaMapped; if (bProMapped) { strProMappingSulName = INC_SULFILSES_NAMES[1]; } } break; case STEEL_TECHNOLOGY::MgProcessMode: { BOOL bMgMapped = FALSE; { CString strEle = INC_SUL_SUB_ELEMENT_NAMES[2]; double dMappingRatio = INC_SULFILSES_MAPPING_RATIO[2]; bMgMapped = ElementMatching(a_dMolarSumNoFe, a_listElChemsIncNoFe, pSulElChem, strEle, dMappingRatio, dSulResidual); } bProMapped = bMgMapped; if (bProMapped) { strProMappingSulName = INC_SULFILSES_NAMES[2]; } } break; case STEEL_TECHNOLOGY::RareEarthMode: { BOOL bCeMapped = FALSE; { CString strEle = INC_SUL_SUB_ELEMENT_NAMES[3]; double dMappingRatio = INC_SULFILSES_MAPPING_RATIO[3]; bCeMapped = ElementMatching(a_dMolarSumNoFe, a_listElChemsIncNoFe, pSulElChem, strEle, dMappingRatio, dSulResidual); } BOOL bLaMapped = FALSE; { CString strEle = INC_SUL_SUB_ELEMENT_NAMES[4]; double dMappingRatio = INC_SULFILSES_MAPPING_RATIO[4]; bLaMapped = ElementMatching(a_dMolarSumNoFe, a_listElChemsIncNoFe, pSulElChem, strEle, dMappingRatio, dSulResidual); } if (bCeMapped && bLaMapped) { strProMappingSulName = INC_SULFILSES_NAMES[3] + STR_CONNECT + INC_SULFILSES_NAMES[4]; bProMapped = TRUE; } else if (bCeMapped) { strProMappingSulName = INC_SULFILSES_NAMES[3]; bProMapped = TRUE; } else if (bLaMapped) { strProMappingSulName = INC_SULFILSES_NAMES[4]; bProMapped = TRUE; } } break; default: break; } return bProMapped; } // get STD item by name CSTDItemPtr COTSClassifyEng::GetSTDItemByName(CSTDItemsList& a_listSTDItems, CString a_strName) { CSTDItemPtr pSTDItem = nullptr; auto itr = std::find_if(a_listSTDItems.begin(), a_listSTDItems.end(), [a_strName](CSTDItemPtr& pSTD) { return pSTD->GetName().CompareNoCase(a_strName) == 0; }); if (itr != a_listSTDItems.end()) { // found the STD item pSTDItem = *itr; } return pSTDItem; } // get STD item name by id CString COTSClassifyEng::GetSTDItemNameById(CSTDItemsList& a_listSTDItems, int a_nItemId) { CString strName = _T(""); CSTDItemPtr pSTDItem = nullptr; auto itr = std::find_if(a_listSTDItems.begin(), a_listSTDItems.end(), [a_nItemId](CSTDItemPtr& pSTD) { return pSTD->GetSTDId() == a_nItemId; }); if (itr != a_listSTDItems.end()) { // found the STD item pSTDItem = *itr; strName = pSTDItem->GetName(); } return strName; } // elements mapping BOOL COTSClassifyEng::ElementsMapping(double a_dMolarSumNoFe, double a_dMappingRatio, CElementChemistryPtr a_pFirstElChem, CElementChemistryPtr a_pSecondElChem, BOOL& a_bMapped) { // safety check ASSERT(a_pFirstElChem); ASSERT(a_pSecondElChem); if (a_dMolarSumNoFe < MIN_ELEMENT_SUM) { return FALSE; } if (a_dMappingRatio < MIN_DOUBLE_VALUE) { return FALSE; } // set mapped flag to FALSE as default a_bMapped = FALSE; // get first mapping element molar value double dFirstMolar = a_pFirstElChem->GetMolarPercentage(); // make sure molar value of the first mapping element chemistry is enough double dFirstMolar100 = Cal100NorValue(dFirstMolar, a_dMolarSumNoFe); if (dFirstMolar100 > ELEMENT_MAPPING_100MOLAR) { // get second mapping element chemistry molar value double dSecondElMolar = a_pSecondElChem->GetMolarPercentage(); // make sure second mapping element chemistry value is enough double dSecondElMolar100 = Cal100NorValue(dSecondElMolar, a_dMolarSumNoFe); if (dSecondElMolar100 > ELEMENT_MAPPING_100MOLAR) { // set mapped flag to true a_bMapped = TRUE; // reset mapping element chemistry molar values // is there any first element left? if (dFirstMolar - dSecondElMolar * a_dMappingRatio > 0) { // no more second element chemistry left; a_pSecondElChem->SetPercentage(0.0); // still there are some first element left // calculate left first element molar value dFirstMolar = dFirstMolar - (dSecondElMolar * a_dMappingRatio); dFirstMolar100 = Cal100NorValue(dFirstMolar100, a_dMolarSumNoFe); // is there enough first element left? if (dFirstMolar100 > ELEMENT_MAPPING_100MOLAR) { // still have enough first element left a_pFirstElChem->SetMolarPercentage(dFirstMolar); } else { // no enough enough first element left, set to 0.0 a_pFirstElChem->SetPercentage(0.0); } } else { // no more first element chemistry left a_pFirstElChem->SetPercentage(0.0); // still there are some second element left // calculate left second element molar value dSecondElMolar = dSecondElMolar - dFirstMolar / a_dMappingRatio; dSecondElMolar100 = Cal100NorValue(dSecondElMolar, a_dMolarSumNoFe); // is there enough second element left? if (dSecondElMolar100 > ELEMENT_MAPPING_100MOLAR) { // still have enough second element left a_pSecondElChem->SetMolarPercentage(dSecondElMolar); } else { // no enough enough second element left, set to 0.0 a_pSecondElChem->SetPercentage(0.0); } } } } // ok, return TRUE return TRUE; } // check if is a REOxide BOOL COTSClassifyEng::IsASimpleOxide(CElementChemistriesList& a_listElChems, double a_dMolarSum, CString& a_strSimOxName) { // go through oxide sub element chemistries for (auto pOxideSubElChems : a_listElChems) { // calculate the %molar value of the sub element chemistry in the list double dSubElMolar100 = Cal100NorValue(pOxideSubElChems->GetMolarPercentage(), a_dMolarSum); // over simple oxide cut_off if (dSubElMolar100 > SIMPLE_OXIDE_MOLAR_CUTOFF) { // this is a simple oxide, name it for (int i = 0; i < INC_OXIDE_SUB_ELEMENT_MAX; ++i) { if (pOxideSubElChems->GetName().CompareNoCase(INC_OXIDE_SUB_ELEMENT_NAMES[i]) == 0) { // found it // assign simple oxide name a_strSimOxName = INC_OXIDE_NAMES[i]; // return TRUE return TRUE; } } } } // not a simple oxide, return FALSE return FALSE; } // check if is a REOxide (deal with La-Ce-Oxide) BOOL COTSClassifyEng::IsAREOxide(CElementChemistriesList& a_listElChems, double a_dMolarSum) { // calculate real element molar % double dREElementMolarSum = 0; for (int i = 0; i < REOXIDE_KEY_ELEMENT_MAX; ++i) { CElementChemistryPtr pREElement = GetNamedElementChemistry(a_listElChems, REOXIDE_KEY_ELEMENT_NAMES[i]); if (pREElement) { // got a real element // calculate the %molar value of the real element chemistry in the list double dSubElMolar100 = Cal100NorValue(pREElement->GetMolarPercentage(), a_dMolarSum); // calculate real element molar % dREElementMolarSum += dSubElMolar100; } } // is real element molar % over REAlOxide elements molar % cut_off if (dREElementMolarSum > REALOXIDE_ELEMELTS_MOLAR_CUTOFF) { // this is a REAlOxide, return TRUE return TRUE; } // not a REOxide, return FALSE return FALSE; } // check if is a REAlOxide BOOL COTSClassifyEng::IsAnREAlOxide(CElementChemistriesList& a_listElChems, double a_dMolarSum) { // calculate real element molar % double dREElementMolarSum = 0; for (int i = 0; i < REOXIDE_KEY_ELEMENT_MAX; ++i) { CElementChemistryPtr pREElement = GetNamedElementChemistry(a_listElChems, REOXIDE_KEY_ELEMENT_NAMES[i]); if (pREElement) { // got a real element // calculate the %molar value of the real element chemistry in the list double dSubElMolar100 = Cal100NorValue(pREElement->GetMolarPercentage(), a_dMolarSum); // calculate real element molar % dREElementMolarSum += dSubElMolar100; } } // is real element molar % over REAlOxide element molar % min cut_off if (dREElementMolarSum < REALOXIDE_ELEMENT_MOLAR_LOW_CUTOFF) { // no, this is not a REALOxide, return FALSE return FALSE; } // calculate Al/Si elements molar % double dAl_Si_ElementMolarSum = 0; for (int i = 0; i < REALOXIDE_SUB_ELEMENT_MAX; ++i) { CElementChemistryPtr pAlSiElement = GetNamedElementChemistry(a_listElChems, REALOXIDE_SUB_ELEMENT_NAMES[i]); if (pAlSiElement) { // got a Al or Si element // calculate the %molar value of the Al and Si element chemistry in the list double dAl_SiElMolar100 = Cal100NorValue(pAlSiElement->GetMolarPercentage(), a_dMolarSum); // calculate Al/Si elements molar % dAl_Si_ElementMolarSum += dAl_SiElMolar100; } } // is Al/Si elements molar % over REAlOxide element molar % min cut_off if (dAl_Si_ElementMolarSum < REALOXIDE_ELEMENT_MOLAR_LOW_CUTOFF) { // no, this is not a REALOxide, return FALSE return FALSE; } // is real element molar % + Al/Si elements molar % over the cut off if (dREElementMolarSum + dAl_Si_ElementMolarSum > SIMPLE_OXIDE_MOLAR_CUTOFF) { // this is a REAlOxide, return TRUE return TRUE; } // not a REAlOxide, return FALSE return FALSE; } // check if is a Spinel BOOL COTSClassifyEng::IsASpinel(CElementChemistriesList& a_listElChems, double a_dMolarSum) { // we deal with Mg, Al Spinel only // get the first key element of Spinel CElementChemistryPtr pFirstElChem = GetNamedElementChemistry(a_listElChems, SPINEL_KEY_ELEMENT_NAMES[0]); if (!pFirstElChem) { // not a Spinel, return FALSE return FALSE; } // get the second key element of Spinel CElementChemistryPtr pSecondElChem = GetNamedElementChemistry(a_listElChems, SPINEL_KEY_ELEMENT_NAMES[1]); if (!pSecondElChem) { // not a Spinel, return FALSE return FALSE; } // check ratio between the two elements double dFirstElMolar = pFirstElChem->GetMolarPercentage(); double dSecondElMolar = pSecondElChem->GetMolarPercentage(); if (dFirstElMolar < MIN_DOUBLE_VALUE) { // something wrong // not a Spinel, return FALSE return FALSE; } double dRatio = dSecondElMolar / dFirstElMolar; if (dRatio < SPINEL_ELEMENT_RATIO_MIN || dRatio > SPINEL_ELEMENT_RATIO_MAX) { // not a Spinel, return FALSE return FALSE; } // molar % amount check double dFirstElMolar100 = Cal100NorValue(dFirstElMolar, a_dMolarSum); double dSecondElMolar100 = Cal100NorValue(dSecondElMolar, a_dMolarSum); if (dFirstElMolar100 + dSecondElMolar100 > SPINEL_KEY_ELEMENT_MOLAR_TOTAL) { // this is a Spinel return TRUE; } // not a Spinel, return FALSE return FALSE; } // check if is a Silicate BOOL COTSClassifyEng::IsASilicate(CElementChemistriesList& a_listElChems, double a_dMolarSum) { // get key element of Silicate CElementChemistryPtr pKeyElChem = GetNamedElementChemistry(a_listElChems, SILICATE_KEY_ELEMENT_NAME); if (!pKeyElChem) { // not a Silicate, return FALSE return FALSE; } // molar % amount check double dKeyElMolar100 = Cal100NorValue(pKeyElChem->GetMolarPercentage(), a_dMolarSum); if (dKeyElMolar100 > SILICATE_KEY_ELEMENT_MOLAR_TOTAL_MIN && dKeyElMolar100 < SILICATE_KEY_ELEMENT_MOLAR_TOTAL_MAX) { // this is a Silicate, return TRUE return TRUE; } // not a Silicate, return FALSE return FALSE; } // check if is a Aluminate BOOL COTSClassifyEng::IsAnCa_Aluminate(STEEL_TECHNOLOGY steelTech,CElementChemistriesList& a_listElChems, double a_dMolarSum,CString& strName) { // get key element of Aluminate CElementChemistryPtr pKeyElChem = GetNamedElementChemistry(a_listElChems, ALUMINATE_KEY_ELEMENT_NAME[0]); if (!pKeyElChem) { // not an Aluminate, return FALSE return FALSE; } // molar % amount check double dKeyElMolar100 = Cal100NorValue(pKeyElChem->GetMolarPercentage(), a_dMolarSum); if (dKeyElMolar100 > ALUMINAT_KEY_ELEMENT_MOLAR_TOTAL_MIN && dKeyElMolar100 < ALUMINAT_KEY_ELEMENT_MOLAR_TOTAL_MAX) { CElementChemistryPtr pKeyElChem2 = GetNamedElementChemistry(a_listElChems, ALUMINATE_KEY_ELEMENT_NAME[1]); if (!pKeyElChem2|| pKeyElChem2->GetPercentage()< MIN_ELEMENT_SUM) { strName = ALUMINATE_STR; return TRUE; } double dFirstElMolar = pKeyElChem->GetMolarPercentage();//Al double dSecondElMolar = pKeyElChem2->GetMolarPercentage();//Ca double dRatio = dFirstElMolar/dSecondElMolar ;// Al/Ca if (steelTech == STEEL_TECHNOLOGY::CaProcessMode) { if (dRatio < 1.2 || dRatio > 1.0)//12CaO-7Al2O3 14/12 { // not a Spinel, return FALSE strName = ALUMINATE12CaO_7Al2O3_STR; return TRUE; } if (dRatio < 0.9 || dRatio > 0.6)//3CaO-Al2O3 2/3 { // not a Spinel, return FALSE strName = ALUMINATE3CaO_Al2O3_STR; return TRUE; } } else { strName = Ca_ALUMINATE_STR; } // this is a Aluminate, return TRUE return TRUE; } // not a Aluminate, return FALSE return FALSE; } // check if the element chemistries list matching the STD BOOL COTSClassifyEng::MatchingSTD(CElementChemistriesList& a_listElChems, CSTDItemPtr a_pSTDItem, double a_dMolarSum) { // safety check ASSERT(a_pSTDItem); if (!a_pSTDItem) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::MatchingSTD: invalid CSTDItemPtr.")); return FALSE; } if (a_dMolarSum < MIN_ELEMENT_SUM) { // something wrong LogErrorTrace(__FILE__, __LINE__, _T("COTSClassifyEng::MatchingSTD: invalid molar sum value.")); return FALSE; } // find out how many elements need for the STD CElementRangeList& listElementRange = a_pSTDItem->GetElementRangeList(); int nElNoMin = 0; for (auto pElmentRange : listElementRange) { int nStart = pElmentRange->GetRange()->GetStart(); if (nStart > 0) { // this element has to have ++nElNoMin; } } int nElNoMax = (int)listElementRange.size(); // a_listChemistriesElements size has to be between nElNoMin and nElNoMax int nElementSize = (int)a_listElChems.size(); //if (nElementSize < nElNoMin || nElementSize > nElNoMax) if (nElementSize < nElNoMin) { // a_listChemistriesElements size not match return FALSE; } // all element chemistries have to be in listElementRange and in the range for (auto pElChems : a_listElChems) { CString strElement = pElChems->GetName(); auto itr = std::find_if(listElementRange.begin(), listElementRange.end(), [strElement](CElementRangePtr& poElemenRange) { return poElemenRange->GetElement()->GetName().CompareNoCase(strElement) == 0; }); if (itr == listElementRange.end()) { // not in the element range list, not match then return FALSE; } // molar value has to be in the range double dMolar = pElChems->GetMolarPercentage(); dMolar = Cal100NorValue(dMolar, a_dMolarSum); if (dMolar < (double)(*itr)->GetRange()->GetStart() || dMolar >(double)(*itr)->GetRange()->GetEnd()) { // molar value has to be in the range, not match then return FALSE; } } // the two are matching each other, return TRUE return TRUE; } // calculate 100% normalize value (molar) double COTSClassifyEng::Cal100NorValue(double a_dValue, double a_dSumValue) { double d100NorCalue = MIN_DOUBLE_VALUE; // sum has a cut off if (a_dSumValue < MIN_ELEMENT_SUM) { return d100NorCalue; } d100NorCalue = a_dValue / a_dSumValue * 100; return d100NorCalue; } }