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