Molar weight calculator


//EDIT: 2/23/16; optimised function "ElementCount"
// The function molwt(str) returns the molar weight of a chemical formula specified by "str", e.g. molwt("H2O") returns 18.0148 (in grams per mole). 
// The function is case-sensitive, e.g. molwt("h2o") will not return what you expect.
// The function ElementCount(input) returns a list of elements and their abundance, e.g. ElementCount("H2O") returns "H;2;O;1;"
// The element abundance in the input string MUST be a positive integer

function molwt(str)
	string str
	
	variable mw
	variable AN
	variable weight
	variable n
	variable i
	
	string List = ElementCount(str)
	string Element =""
	
	//initialise elements and atomic weights: list index equals atomic number	
	string el=""
	el += ";H;He;Li;Be;B;C;N;O;F;Ne;Na;Mg;Al;Si;P;S;Cl;Ar;"
	el += "K;Ca;Sc;Ti;V;Cr;Mn;Fe;Co;Ni;Cu;Zn;Ga;Ge;As;Se;Br;Kr;"
	el += "Rb;Sr;Y;Zr;Nb;Mo;Tc;Ru;Rh;Pd;Ag;Cd;In;Sn;Sb;Te;I;Xe;"
	el += "Cs;Ba;La;Ce;Pr;Nd;Pm;Sm;Eu;Gd;Tb;Dy;Ho;Er;Tm;Yb;Lu;"
	el += "Hf;Ta;W;Re;Os;Ir;Pt;Au;Hg;Tl;Pb;Bi;Po;At;Rn;"
	el += "Fr;Ra;Ac;Th;Pa;U;Np;Pu;"
	
	string aw=""
	aw+=";1.0079;4.0026;6.941;9.0122;10.811;12.011;14.007;15.999;18.998;20.18;22.99;24.305;26.982;28.085;30.974;32.065;35.453;39.948;"
	aw+="39.098;40.078;44.956;47.867;50.941;51.996;54.938;55.845;58.933;58.693;63.546;65.409;69.723;72.64;74.922;78.96;79.904;83.798;"
	aw+="85.468;87.62;88.906;91.224;92.906;95.94;98.906;101.07;102.91;106.42;107.87;112.41;114.82;118.71;121.76;127.6;126.9;131.29;"
	aw+="132.91;137.33;138.91;140.12;140.91;144.24;146.92;150.36;151.96;157.25;158.93;162.5;164.93;167.26;168.93;173.04;174.97;"
	aw+="178.49;180.95;183.84;186.21;190.23;192.22;195.08;196.97;200.59;204.38;207.2;208.98;208.98;209.99;222.02;223.02;"
	aw+="226.03;227.03;232.04;231.04;238.03;237.05;244.06;"
	

	do
		Element = StringFromList(i, List) 
		
		if ( strlen(Element) == 0) 
			break
		endif
		
		AN = WhichListItem(Element, el)
		weight = str2num(StringFromList(AN, aw))
		n =  str2num(StringFromList(i+1, List))
		
		mw += (n * weight) 
				
		i+=2
	while(1)
	
	return mw
end

function/S ElementCount(input)  // analyses input string for elements and number of elements
	String input
 
	string list = ""
	variable i
	variable TheEnd = StrLen(input)
	
	for(i=0;i<TheEnd; i+=1)
 
		// consider cases where string item is a letter and upper case		
		if (GrepString( input[i], "[[:alpha:]]")  &&  GrepString(input[i], "[[:upper:]]") )						
				list += input[i]
 
				// is it a two character element, e.g. Fe instead of F?
				if (GrepString(input[i+1], "[[:alpha:]]")  && GrepString(input[i+1], "[[:lower:]]") )	
					list +=  input[i+1]
					i+=1
				endif
 
 				//this element is covered
 				list +=";"
 				 				
				// test if next list item is numeric or string; if it is string, then the present element has a count of 1, add this to list ....
				// ...or check if i+1 is the last entry
				if (GrepString(input[i+1], "[[:alpha:]]") || i+1 == TheEnd)
					list += "1;"
				endif
				
				// we are done
				continue
 
		endif
 
		// consider cases where string item is a number			
		if (GrepString(input[i], "[[:digit:]]") )
 
				list +=input[i]
 
				// is there more than one numeric character?
				do
					if (GrepString(input[i+1] "[[:digit:]]"))
						list += input[i+1]
						i+=1						
					else
						break
					endif					
 
				while(1)
 
				List +=";"		
		endif			
	endfor

	return list
end 

I have one of these too. Not tested for typos etc, so caveat emptor!

Edit: I removed the code and added a link to the molar mass calculator project below.

Building on ChrLie's and Tony's code, I slightly enhanced the ElementCount function to deal with non-integer Stoichiometry and only parse actual element names

function/S ElementCountMM(input)  // analyses input string for elements and number of elements //adapted from the wavemetricsForum
//works with non-integer stoichiometry  
    String input
    string list = ""
    variable i,ii
    string dum
	make /free /n=0 /T Elem
	
	Elem = {"H","He","Li","Be","B","C","N","O","F","Ne"}
	Elem[10] = {"Na","Mg","Al","Si","P","S","Cl","Ar","K","Ca"}
	Elem[20] = {"Sc","Ti","V","Cr","Mn","Fe","Co","Ni","Cu","Zn"}
	Elem[30] = {"Ga","Ge","As","Se","Br","Kr","Rb","Sr","Y","Zr"}
	Elem[40] = {"Nb","Mo","Tc","Ru","Rh","Pd","Ag","Cd","In","Sn"}
	Elem[50] = {"Sb","Te","I","Xe","Cs","Ba","La","Ce","Pr","Nd"}
	Elem[60] = {"Pm","Sm","Eu","Gd","Tb","Dy","Ho","Er","Tm","Yb"}
	Elem[70] = {"Lu","Hf","Ta","W","Re","Os","Ir","Pt","Au","Hg"}
	Elem[80] = {"Tl","Pb","Bi","Po","At","Rn","Fr","Ra","Ac","Th"}
	Elem[90] = {"Pa","U","Np","Pu","Am","Cm","Bk","Cf","Es","Fm"}
	Elem[100] = {"Md","No","Lr","Rf","Db","Sg","Bh","Hs","Mt","Ds"}
	Elem[110] = {"Rg","Cn","Uut","Fl","Uup","Lv","Uus","Uuo"}
 
    variable TheEnd = StrLen(input)
	for(i=0;i<TheEnd; i+=1)
		// consider cases where string item is a letter and upper case     
		if (GrepString( input[i], "[[:alpha:]]")  &&  GrepString(input[i], "[[:upper:]]") )                    
			list += input[i]
			// is it a two character element, e.g. Fe instead of F?
			if (GrepString(input[i+1], "[[:alpha:]]")  && GrepString(input[i+1], "[[:lower:]]") )  
				list +=  input[i+1]
				i+=1
			endif
			//this element is covered
			list +=";"
			// test if next list item is numeric or string; if it is string, then the present element has a count of 1, add this to list ....
			// ...or check if i+1 is the last entry
			if (GrepString(input[i+1], "[[:alpha:]]") || i+1 == TheEnd)
				list += "1;"
                
				FindValue /TEXT=StringFromList(itemsinList(list)-2,list)/TXOP=7 /Z  Elem
				if (v_value==-1)
					list="" ; i=TheEnd ;Print "Could not resolve Chemical Formula";beep;beep;dowindow/h 
				endif
			endif
			continue
                
		endif
		if( grepstring(input[i],"[0-9]") )	
			dum=""
			do	
				if( grepstring(input[i],"[0-9\.]")) 
					dum+=input[i]
					i+=1
				else
					break
				endif	
			while(i<strlen(input))
			i-=1;
			list +=  dum+";"
		else
			list+=";"
		endif
	endfor
	return list
end

 

My version was later released as a project, here. I believe it deals with both non-integer values and parentheses properly, and only accepts valid elements.

•print molWt("(Mg0.9Fe0.1)2SiO4")
  147.001

 

I see. You might consider using a key list, then you can use NumberByKey to get the element count.

Execute DisplayHelpTopic "NumberByKey" for more info.

Forum

Support

Gallery

Igor Pro 10

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More