| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410 | #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 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 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 dNbMolar = 0;		double dOMolar = 0;		double dSiMolar = 0;		double dFeMolar = 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();				}							}			// 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();				}				else if (pElChem->GetName().CompareNoCase(STR_Nb) == 0)				{					dNbMolar = pElChem->GetMolarPercentage();				}												}			else if (pElChem->GetName().CompareNoCase(STR_FE) == 0)			{				dFeMolar = pElChem->GetMolarPercentage();			}			else if (pElChem->GetName().CompareNoCase(STR_C) == 0)			{				dCarbonMolar = pElChem->GetMolarPercentage();			}								}		// 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, return FALSE						a_nIncId = OTS_PARTCLE_TYPE::ISNOT_INCLUTION;						notIncId = NOT_INCLUTION_ID::FeO;						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 (a_dMolarSumNoFe < MIN_ELEMENT_SUM)		{			a_nIncId = OTS_PARTICLE_TYPE::INVALID;			return TRUE;		}		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(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(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;		}		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(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(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(		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(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(		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( 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(CElementChemistriesList& a_listElChemsIncNoFe, double a_dMolarSumNoFe, CString strSulfideBaseName, int& a_nIncId)	{		int nIncId;		if (!OxideClassify(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(CElementChemistriesList& a_listElChemsIncNoFe, double a_dMolarSumNoFe, CString strSulfideBaseName, int& a_nIncId)	{		int nIncId;		if (!NitrideClassify(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(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 (dRatio < 1.3 || dRatio > 0.9)//12CaO-7Al2O3  14/12			{				// not a Spinel, return FALSE				strName = ALUMINATE12CaO_7Al2O3_STR;				return TRUE;			}			if (dRatio < 0.9 || dRatio > 0.4)//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;	}}
 |