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 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More