#pragma rtGlobals=1 // Use modern global access method. #pragma ModuleName=LatticeSym #pragma version = 3.35 #include "MaterialsLocate" // used to find the path to the materials files // // remember to execute InitLatticeSymPackage() // // with version 2.0, added a text description to the crystalStructure structure // // with version 3.0, fixed up and changed the symmetry operators, I now think that they are right // with version 3.1, only compute symmetry operations as needed // with version 3.2, fixed Trigonal, now can use rhombohedral axes // with version 3.3, fixed lowestAllowedHKL() made alpha, beta & gamma non-zero Menu "Analysis" SubMenu "Lattice" "Set Crystal Structure...",MakeLatticeParametersPanel("") help={"Define the crystal structure and lattice to be used"} "Show Crystal Structure",showCrystalStructure() help={"Shows the crystal structure and lattice that is currently defined"} "Load a new Crystal Structure",LoadCrystal("") help={"load a rystal structure from a fie"} "d[hkl]",/Q,get_dhkl(NaN,NaN,NaN,T=NaN) help={"show d-spacing for the hkl reflection"} "F[structure, hkl)]",getFstruct(NaN,NaN,NaN) help={"Crude Structure Factor using current lattice"} "angle between two hkl's",angleBetweenHKLs(NaN,NaN,NaN, NaN,NaN,NaN) End End Static Constant STRUCTURE_ATOMS_MAX=20 // max number of atom types in a material structure (for Si only need 1) Strconstant PresetLatticeStructures = "FCC:225;BCC:229;Diamond:227;Simple Cubic:221;Hexagonal:194;Wurtzite (B4):186;Sapphire:167;Triclinic:1;other" //OverRide Strconstant PresetLatticeStructures = "\"FCC:225;BCC:229;Diamond:227;Simple Cubic:221;Hexagonal:194;Wurtzite (B4):186;Sapphire:167;Triclinic:1;other\"" // ========================================================================= // ========================================================================= // Start of setting particular lattice constants Function MakeLatticeParametersPanel(strStruct) String strStruct // optional passed value of geo structure, this is used if passed if (strlen(WinList("LatticeSet",";","WIN:64"))) // window alreay exits, bring it to front DoWindow/F LatticeSet return 0 endif NewPanel /K=1 /W=(675,60,895,425) DoWindow/C LatticeSet FillLatticeParametersPanel(strStruct,"LatticeSet",0,0) End // prompts the user for lattice info, and set local structure. Store the information in a structure string in current datafolder Function setLattice() String strName="" Variable SpaceGroup //Space Group number, from International Tables Variable a,b,c,alpha,bet,gam String desc STRUCT crystalStructure xtal xtal.a = 0 FillCrystalStructDefault(xtal) //fill the lattice structure with default values a = xtal.a ; b = xtal.b ; c = xtal.c alpha = xtal.alpha ; bet = xtal.beta ; gam = xtal.gam SpaceGroup = xtal.SpaceGroup desc = xtal.desc if (GetLatticeConstants(xtal,SpaceGroup,strName,a,b,c,alpha,bet,gam,desc)) return 1 endif xtal.Unconventional00 = NaN updateCrystalStructureDefaults(xtal) return 0 End Function showCrystalStructure() // prints the structure that is currently being used STRUCT crystalStructure xtal if (FillCrystalStructDefault(xtal)) //fill the lattice structure with test values DoAlert 0, "no crystal structure found" return 1 endif String str, sym = getSymString(xtal.SpaceGroup) sprintf str, "'%s' %d atoms, #%d %s\r%.9g, %.9g, %.9gnm,\r%g¡, %g¡, %g¡",xtal.desc,xtal.N,xtal.SpaceGroup,sym,xtal.a,xtal.b,xtal.c,xtal.alpha,xtal.beta,xtal.gam DoAlert 1,str+"\r\tprint all details to history too?" if (V_flag==1) print_crystalStructure(xtal) // prints out the value in a crystalStructure structure else printf "currently using '%s' lattice is #%d %s %.9gnm, %.9gnm, %.9gnm, %g¡, %g¡, %g¡\r",xtal.desc,xtal.SpaceGroup,sym,xtal.a,xtal.b,xtal.c,xtal.alpha,xtal.beta,xtal.gam if (!(xtal.alphaT<=0)) printf "coefficient of thermal expansion is %g\r",xtal.alphaT endif endif return 0 End Structure crystalStructure // structure definition for a crystal lattice char desc[100] // name or decription of this crystal double a,b,c // latticde constants, length (nm) double alpha,beta,gam // angles (degree) int16 SpaceGroup // Space Group number from international tables, allowed range is [1, 230] double a0, b0, c0 // direct lattice from constants { a[], b[], c[] } double a1, b1, c1 double a2, b2, c2 double as0, bs0, cs0 // reciprocal lattice { a*[], b*[], c*[] } double as1, bs1, cs1 // a*,b*,c* already have the 2PI in them double as2, bs2, cs2 double Vc // volume of cell, triple product of (a[]xb[]).c double density // calculated density (g/cm^3) double alphaT // coef of thermal expansion, a = ao*(1+alphaT*(TempC-22.5)) int16 N // number of atoms described here Struct atomTypeStructure atom[STRUCTURE_ATOMS_MAX] double Unconventional00,Unconventional01,Unconventional02 // transform matrix for an unconventional unit cel double Unconventional10,Unconventional11,Unconventional12 double Unconventional20,Unconventional21,Unconventional22 char hashID[66] // hash function for this strucutre (needs to hold at least 64 chars) EndStructure // Structure atomTypeStructure // definines one type of atom in a crystal structure char name[60] // label for this atom, usually starts with atomic symbol int16 Zatom // Z of the atom double x // fractional coord along x lattice vector double y double z double occ // occupancy double Debye // Debye-Waller factor EndStructure Function print_crystalStructure(xtal) // prints out the value in a crystalStructure STRUCT crystalStructure &xtal // this sruct is printed in this routine Variable i,N=xtal.N if (strlen(xtal.desc)) printf "'%s' \t",xtal.desc else printf "\t\t\t" endif printf "Space Group = %d %s Vc = %g (nm^3)",xtal.SpaceGroup, getSymString(xtal.SpaceGroup),xtal.Vc if (xtal.density>0) printf " density = %g (g/cm^3)",xtal.density endif if (!(xtal.alphaT<=0)) printf " coefficient of thermal expansion is %g\r",xtal.alphaT else printf "\r" endif printf "lattice constants { %.15gnm, %.15gnm, %.15gnm, %.15g¡, %.15g¡, %.15g¡ }\r",xtal.a,xtal.b,xtal.c,xtal.alpha,xtal.beta,xtal.gam // printf "lattice constants { %.16gnm, %.16gnm, %.16gnm, %.16g¡, %.16g¡, %.16g¡ }\r",xtal.a,xtal.b,xtal.c,xtal.alpha,xtal.beta,xtal.gam if (N<1) print "No Atoms Defined" else Variable mult reMakeAtomXYZs(xtal) printf "atom locations:\r" for (i=0;i 0) printf " Debye-Waller = %g",xtal.atom[i].Debye endif mult = DimSize($("root:Packages:Lattices:atom"+num2istr(i)),0) if (mult>1) printf "\t\tmultiplicity = %d",mult endif printf "\r" endfor endif if (numtype(xtal.Unconventional00)==0) // Unconventional exists, transform the lattice by it printf "\rusing an Uncoventional Cell, the transform is:\r" printf "\t\t%+6.3f\t\t%+6.3f\t\t%+6.3f\r",xtal.Unconventional00,xtal.Unconventional01,xtal.Unconventional02 printf "\tT =\t%+6.3f\t\t%+6.3f\t\t%+6.3f\r",xtal.Unconventional10,xtal.Unconventional11,xtal.Unconventional12 printf "\t\t%+6.3f\t\t%+6.3f\t\t%+6.3f\r",xtal.Unconventional20,xtal.Unconventional21,xtal.Unconventional22 endif printf "\r" printf " a b c (nm)\r" printf "direct %+10.7f\t%+10.7f\t%+10.7f\r",xtal.a0,xtal.b0,xtal.c0 printf "lattice %+10.7f\t%+10.7f\t%+10.7f\r",xtal.a1,xtal.b1,xtal.c1 printf " %+10.7f\t%+10.7f\t%+10.7f\r",xtal.a2,xtal.b2,xtal.c2 printf "\r a* b* c* (1/nm)\r" printf "recip \t%+10.6f\t%+10.6f\t%+10.6f\r",xtal.as0,xtal.bs0,xtal.cs0 printf "lattice \t%+10.6f\t%+10.6f\t%+10.6f\r",xtal.as1,xtal.bs1,xtal.cs1 printf " \t%+10.6f\t%+10.6f\t%+10.6f\r",xtal.as2,xtal.bs2,xtal.cs2 // print "hash id = ",xtal.hashID End // gets lattice constants for known structures via dialogs, it uses Space Group numbers from the International Tables // known structures are: // FCC 225 // BCC 229 // Diamond 227 // Simple Cubic 221 // Hexagonal 194 // Sapphire 167 // Triclinic 1 Static Function GetLatticeConstants(xtal,SpaceGroup,structureName,a,b,c,alpha,bet,gam,desc) STRUCT crystalStructure &xtal // this sruct is set in this routine Variable SpaceGroup // same as for Internationl tables String structureName // see structures below for list of valid names Variable a,b,c,alpha,bet,gam // lattice constants, lengths in nm angles in degrees String desc // description of lattice (i.e. the name) a = numtype(a)||a<=0 ? 0.405 : a // default is aluminum b = numtype(b)||b<=0 ? a : b c = numtype(c)||c<=0 ? a : c alpha = numtype(alpha)||alpha<=0 ? 90 : alpha // for invalid angles, use 90¡ bet = numtype(bet)||bet<=0 ? 90 : bet gam = numtype(gam)||gam<=0 ? 90 : gam // Cubic [195,230] // a // Hexagonal [168,194] // a,c // Trigonal [143,167] // a,alpha // Tetragonal [75,142] // a,c // Orthorhombic [16,74] // a,b,c // Monoclinic [3,15] // a,b,c,gamma // Triclinic [1,2] // a,b,c,alpha,beta,gamma String item="",structures="FCC:225;BCC:229;Diamond:227;Simple Cubic:221;Hexagonal:194;Wurtzite (B4):186;Sapphire:167;Triclinic:1;other" if (strlen(xtal.desc)>0 && xtal.SpaceGroup==SpaceGroup) structures = xtal.desc+":"+num2istr(SpaceGroup)+";"+structures endif Variable i,N=ItemsInList(structures) if (SpaceGroup>=1 && SpaceGroup<=230) // valid SpaceGroup number structureName = "" for(i=0;i1) // a structureName passed SpaceGroup = -1 for(i=0;i=195) // Cubic DoPrompt/HELP="" "Cubic lattice constants",a b=a; c=a alpha=90; bet=90; gam=90 elseif(SpaceGroup>=168) // Hexagonal c = (a==c) ? 3*a : c DoPrompt/HELP="" "Hexagonal lattice constants",a,c b = a alpha=90; bet=90; gam=120 elseif(SpaceGroup>=143) // Trigonal, use the rhmbohedral cell DoPrompt/HELP="" "Trigonal lattice constants (rhombohedral cell)",a,alpha b=a ; c=a bet=alpha; gam=alpha // elseif(SpaceGroup>=143) // Trigonal, use the hexagonal cell // c = (a==c) ? 3*a : c // DoPrompt/HELP="" "Trigonal lattice constants",a,c // b = a // alpha=90; bet=90; gam=120 elseif(SpaceGroup>=75) // Tetragonal DoPrompt/HELP="" "Tetragonal lattice constants",a,c b = a alpha=90; bet=90; gam=90 elseif(SpaceGroup>=16) // Orthorhombic DoPrompt/HELP="" "Orthorhombic lattice constants",a,b,c alpha=90; bet=90; gam=90 elseif(SpaceGroup>=3) // Monoclinic DoPrompt/HELP="" "Monoclinic lattice constants",a,b,c,gam // alpha=90; bet=90 alpha=90; gam=90 else // Triclinic DoPrompt/HELP="" "Triclinic lattice constants",a,b,c,alpha,bet,gam endif xtal.a = a ; xtal.b = b ; xtal.c = c // put values into structure xtal.alpha = alpha ; xtal.beta = bet ; xtal.gam = gam xtal.SpaceGroup=SpaceGroup xtal.Unconventional00=NaN ForceLatticeToStructure(xtal) return 0 End // // forces lattice constants to match the Space Group number (e.g. for cubic, forces b and c to be a, and all angles 90) Static Function ForceLatticeToStructure(xtal) STRUCT crystalStructure &xtal // this sruct is set in this routine Variable SpaceGroup=xtal.SpaceGroup // local value for convienence if (SpaceGroup!=limit(SpaceGroup,1,230)) // invalid SpaceGroup, it must be in range [1,230] DoAlert 0, "invalid Space Group number "+num2str(SpaceGroup) return 1 endif // Cubic [195,230] // a // Hexagonal [168,194] // a,c // Trigonal [143,167] // a,alpha // Tetragonal [75,142] // a,c // Orthorhombic [16,74] // a,b,c // Monoclinic [3,15] // a,b,c,gamma // Triclinic [1,2] // a,b,c,alpha,beta,gamma Variable usingHexAxes = (abs(90-xtal.alpha)+abs(90-xtal.beta)+abs(120-xtal.gam))<1e-9 if (SpaceGroup>=195) // Cubic xtal.b = xtal.a xtal.c = xtal.a xtal.alpha=90; xtal.beta=90; xtal.gam=90 elseif(SpaceGroup>=168) // Hexagonal xtal.b = xtal.a xtal.alpha=90; xtal.beta=90; xtal.gam=120 elseif(SpaceGroup>=143) // Trigonal, use rhomohedral cell, unless obviously the hexagonal cell if (usingHexAxes) // use hexagonal xtal.b = xtal.a xtal.alpha=90 ; xtal.beta=90 ; xtal.gam=120 else // use rhombohedral xtal.b = xtal.a xtal.c = xtal.a xtal.beta = xtal.alpha xtal.gam = xtal.alpha endif // xtal.b = xtal.a // xtal.alpha=90; xtal.beta=90; xtal.gam=120 elseif(SpaceGroup>=75) // Tetragonal xtal.b = xtal.a xtal.alpha=90; xtal.beta=90; xtal.gam=90 elseif(SpaceGroup>=16) // Orthorhombic xtal.alpha=90; xtal.beta=90; xtal.gam=90 elseif(SpaceGroup>=3) // Monoclinic // xtal.alpha=90; xtal.beta=90 xtal.alpha=90; xtal.gam=90 // else // Triclinic endif String str if (xtal.a<=0 || xtal.b<=0 || xtal.c<=0 || numtype(xtal.a+xtal.b+xtal.c)) // check for valid a,b,c sprintf str,"invalid, (a,b,c) = (%g,%g,%g)",xtal.a,xtal.b,xtal.c DoAlert 0, str return 1 endif Variable alpha=xtal.alpha,bet=xtal.beta,gam=xtal.gam if (alpha<=0 || bet<=0 || gam<=0 || alpha>=180 || bet>=180 || gam>=180 || numtype(alpha+bet+gam)) // check for valid angles sprintf str,"invalid, (alpha,beta,gam) = (%g,%g,%g)",alpha,bet,gam DoAlert 0, str return 1 endif setDirectRecip(xtal) // update Vc, direct and recip, density, and also calculates atom positions return 0 End // Static Function setDirectRecip(xtal) // set direct and recip lattice vectors from a,b,c,..., also calculates Vc & density STRUCT crystalStructure &xtal Variable a=xtal.a, b=xtal.b, c=xtal.c Variable sa = sin((xtal.alpha)*PI/180), ca = cos((xtal.alpha)*PI/180) Variable cb = cos((xtal.beta)*PI/180), cg = cos((xtal.gam)*PI/180) Variable phi = sqrt(1.0 - ca*ca - cb*cb - cg*cg + 2*ca*cb*cg) // = Vc/(a*b*c) xtal.Vc = a*b*c * phi // volume of unit cell Variable pv = (2*PI) / (xtal.Vc) // used for scaling Variable a0,a1,a2, b0,b1,b2, c0,c1,c2 //components of the direct lattice vectors a0=a*phi/sa ; a1=a*(cg-ca*cb)/sa ; a2=a*cb b0=0 ; b1=b*sa ; b2=b*ca c0=0 ; c1=0 ; c2=c xtal.a0=a0 ; xtal.a1=a1 ; xtal.a2=a2 xtal.b0=b0 ; xtal.b1=b1 ; xtal.b2=b2 xtal.c0=c0 ; xtal.c1=c1 ; xtal.c2=c2 xtal.as0=(b1*c2-b2*c1)*pv ; xtal.as1=(b2*c0-b0*c2)*pv ; xtal.as2=(b0*c1-b1*c0)*pv // (b x c)*2¹/Vc xtal.bs0=(c1*a2-c2*a1)*pv ; xtal.bs1=(c2*a0-c0*a2)*pv ; xtal.bs2=(c0*a1-c1*a0)*pv // (c x a)*2¹/Vc xtal.cs0=(a1*b2-a2*b1)*pv ; xtal.cs1=(a2*b0-a0*b2)*pv ; xtal.cs2=(a0*b1-a1*b0)*pv // (a x b)*2¹/Vc if (numtype(xtal.Unconventional00)==0 && xtal.Unconventional00>-100 && xtal.Unconventional00<100) Make/N=(3,3)/O/D root:Packages:Lattices:Unconventional Wave Unconventional=root:Packages:Lattices:Unconventional Unconventional[0][0]=xtal.Unconventional00; Unconventional[0][1]=xtal.Unconventional01; Unconventional[0][2]=xtal.Unconventional02 Unconventional[1][0]=xtal.Unconventional10; Unconventional[1][1]=xtal.Unconventional11; Unconventional[1][2]=xtal.Unconventional12 Unconventional[2][0]=xtal.Unconventional20; Unconventional[2][1]=xtal.Unconventional21; Unconventional[2][2]=xtal.Unconventional22 else KillWaves/Z root:Packages:Lattices:Unconventional endif xtal.density = densityOfCrystalStructure(xtal) return 0 End Function densityOfCrystalStructure(xtal) // returns the density (g/cm^3) STRUCT crystalStructure &xtal // this sruct is filled by this routine Variable NA=6.02214199e23 // Avagadro's number String amuList // atomic mass of all of the elements amuList = "1.00794;4.002602;6.941;9.012182;10.811;12.0107;14.0067;15.9994;18.9984032;20.1797;22.98977;24.305;" amuList += "26.981538;28.0855;30.973761;32.065;35.453;39.948;39.0983;40.078;44.95591;47.867;50.9415;51.9961;" amuList += "54.938049;55.845;58.9332;58.6934;63.546;65.409;69.723;72.64;74.9216;78.96;79.904;83.798;85.4678;87.62;" amuList += "88.90585;91.224;92.90638;95.94;98;101.07;102.9055;106.42;107.8682;112.411;114.818;118.71;121.76;" amuList += "127.6;126.90447;131.293;132.90545;137.327;138.9055;140.116;140.90765;144.24;145;150.36;151.964;157.25;" amuList += "158.92534;162.5;164.93032;167.259;168.93421;173.04;174.967;178.49;180.9479;183.84;186.207;190.23;" amuList += "192.217;195.078;196.96655;200.59;204.3833;207.2;208.98038;209;210;222;223;226;227;232.0381;231.03588;" amuList += "238.02891;237;244;243;247;247;251;252;257;258;259;262;261;262;266;264;277;268" String name Variable amu // atomic mass of all atoms in cell Variable m, N=xtal.N reMakeAtomXYZs(xtal) for (m=0,amu=0; m 0.1 then it must be wrong if (numtype(h+k+l)) h = numtype(h) ? 0 : h k = numtype(k) ? 0 : k l = numtype(l) ? 2 : l Prompt h,"H" Prompt k,"K" Prompt l,"L" Prompt T,"Temperature, standard is 22.5, (C)" Variable askForT = (!ParamIsDefault(T) && !alphaTbad) if (askForT) DoPrompt "(hkl)",h,k,l,T else DoPrompt "(hkl)",h,k,l endif if (V_flag) return NaN endif endif if (numtype(h+k+l)) return NaN endif Variable d, usingT = !alphaTbad && numtype(T)==0 if (usingT) // both alphaT and T are valid d = dSpacing(xtal,h,k,l,T=T) else d = dSpacing(xtal,h,k,l) endif if (ItemsInList(GetRTStackInfo(0))<2) Variable places = placesOfPrecision(xtal.a) if (usingT) // both alphaT and T are valid printf "d['%s' (T=%g), (%s)] = %.9g nm\r",xtal.desc,T,hkl2str(h,k,l),roundSignificant(d,places) else printf "d['%s', (%s)] = %.9g nm\r",xtal.desc,hkl2str(h,k,l),roundSignificant(d,places) endif endif return d End // Function dSpacing(xtal,h,k,l,[T]) // returns d-spacing for the hkl (nm) STRUCT crystalStructure &xtal // this sruct is set in this routine Variable h,k,l Variable T Variable xx,yy,zz xx = h*xtal.as0 + k*xtal.bs0 + l*xtal.cs0 yy = h*xtal.as1 + k*xtal.bs1 + l*xtal.cs1 zz = h*xtal.as2 + k*xtal.bs2 + l*xtal.cs2 Variable d = 2*PI/sqrt(xx*xx + yy*yy + zz*zz) if (abs(xtal.alphaT)<0.1 && !ParamIsDefault(T)) // do if T passed, and valid alphaT T = limit(T,-273.15,Inf) // limit T to > absolute zero d = d*(1+xtal.alphaT*(T-22.5)) // apply temperature correction endif return d End // returns d-spacing (nm) given (hkl) and lattice constants, just a local utility Function dSpacingFromLatticeConstants(h,k,l,a,b,c,alpha,bet,gam) Variable h,k,l Variable a,b,c,alpha,bet,gam // lattice constants, lengths in nm angles in degrees STRUCT crystalStructure xtal // this sruct is only used locally xtal.a = a ; xtal.b = b ; xtal.c = c // put values into structure xtal.alpha = alpha ; xtal.beta = bet ; xtal.gam = gam xtal.SpaceGroup=1 ForceLatticeToStructure(xtal) Variable k0,k1,k2, d // k = {k0,k1,k2} = h*as + k*bs + l*cs k0 = h*xtal.as0 + k*xtal.bs0 + l*xtal.cs0 k1 = h*xtal.as1 + k*xtal.bs1 + l*xtal.cs1 k2 = h*xtal.as2 + k*xtal.bs2 + l*xtal.cs2 d = 2*PI/sqrt(k0*k0 + k1*k1 + k2*k2) // d = 2*pi/|k| return d End Function angleBetweenHKLs(h1,k1,l1, h2,k2,l2) // find angle between (h1,k1,l1) and (h2,k2,l2) Variable h1,k1,l1,h2,k2,l2 if (numtype(h1+k1+l1+h2+k2+l2) && ItemsInList(GetRTStackInfo(0))<2 ) h1 = numtype(h1) ? 0 : h1 k1 = numtype(k1) ? 0 : k1 l1 = numtype(l1) ? 2 : l1 h2 = numtype(h2) ? 1 : h2 k2 = numtype(k2) ? 1 : k2 l2= numtype(l2) ? 1 : l2 String hklStr1, hklStr2 sprintf hklStr1,"%g %g %g",h1,k1,l1 sprintf hklStr2,"%g %g %g",h2,k2,l2 Prompt hklStr1,"(hkl) of the first Q" Prompt hklStr2,"(hkl) of the second Q" DoPrompt "hkl max & font size",hklStr1,hklStr2 if (V_flag) return 1 endif sscanf hklStr1, "%g %g %g",h1,k1,l1 sscanf hklStr2, "%g %g %g",h2,k2,l2 endif STRUCT crystalStructure xtal if (FillCrystalStructDefault(xtal)) //fill the lattice structure with current values DoAlert 0, "No Lattice, please set one" return 1 endif Make/N=3/O/D hkl_angleBetweenHKLs1, hkl_angleBetweenHKLs2 Wave q1=hkl_angleBetweenHKLs1, q2=hkl_angleBetweenHKLs2 q1[0] = h1*xtal.as0+k1*xtal.bs0+l1*xtal.cs0 // q1 = recip x hkl1 q1[1] = h1*xtal.as1+k1*xtal.bs1+l1*xtal.cs1 q1[2] = h1*xtal.as2+k1*xtal.bs2+l1*xtal.cs2 q2[0] = h2*xtal.as0+k2*xtal.bs0+l2*xtal.cs0 // q2 = recip x hkl2 q2[1] = h2*xtal.as1+k2*xtal.bs1+l2*xtal.cs1 q2[2] = h2*xtal.as2+k2*xtal.bs2+l2*xtal.cs2 normalize(q1) normalize(q2) Variable angle = acos(limit(MatrixDot(q1,q2),-1,1)) angle *= 180/PI KillWaves hkl_angleBetweenHKLs1, hkl_angleBetweenHKLs2 if (ItemsInList(GetRTStackInfo(0))<2) printf "angle between (%s) and (%s) is %g¡\r",hkl2str(h1,k1,l1),hkl2str(h2,k2,l2),angle endif return angle End Function FillCrystalStructDefault(xtal) //fill the crystal structure with 'current' values STRUCT crystalStructure &xtal // returns 0 if something set, 1 is nothing done String strStruct=StrVarOrDefault(":crystalStructStr","")// set to values in current directory if (strlen(strStruct)<1) strStruct=StrVarOrDefault("root:Packages:Lattices:crystalStructStr","") // try the default values endif if (strlen(strStruct)>1) StructGet/S/B=2 xtal, strStruct // found structure information, load into xtal else LoadPackagePreferences/MIS=1 "LatticeSym","LatticeSymPrefs",1,xtal if (V_flag) return 1 // did nothing, nothing found endif endif setDirectRecip(xtal) // ensure that these are set return 0 End Function updateCrystalStructureDefaults(xtal) STRUCT crystalStructure &xtal // returns 0 if something set, 1 is nothing done String strStruct xtal.hashID = "" // re-set hash function to identify associated waves StructPut/S xtal, strStruct xtal.hashID = hash(strStruct,1) // save as defaults for further use if (exists(":crystalStructStr")==2) // use the global in this data folder SVAR crystalStructStr=:crystalStructStr elseif (exists("root:Packages:Lattices:crystalStructStr")==2) // use the global in the Packages SVAR crystalStructStr=root:Packages:Lattices:crystalStructStr else String/G crystalStructStr // no global, make one in this data folder endif StructPut/S/B=2 xtal, crystalStructStr // and write them to the global SavePackagePreferences/FLSH=1 "LatticeSym","LatticeSymPrefs",1,xtal return 0 End // End of setting particular lattice constants // ========================================================================= // ========================================================================= // ========================================================================= // ========================================================================= // Start of lattice set panel Function/T FillLatticeParametersPanel(strStruct,hostWin,left,top) String strStruct // optional passed value of xtal structure, this is used if passed String hostWin // name of home window Variable left, top // offsets from the left and top NewDataFolder/O root:Packages:Lattices:PanelValues // ensure that the needed data folders exist Variable new = !(NumVarOrDefault("root:Packages:Lattices:PanelValues:SpaceGroup",-1)>0) String/G root:Packages:Lattices:PanelValues:desc Variable/G root:Packages:Lattices:PanelValues:SpaceGroup Variable/G root:Packages:Lattices:PanelValues:a Variable/G root:Packages:Lattices:PanelValues:b Variable/G root:Packages:Lattices:PanelValues:c Variable/G root:Packages:Lattices:PanelValues:alpha Variable/G root:Packages:Lattices:PanelValues:beta Variable/G root:Packages:Lattices:PanelValues:gam Variable/G root:Packages:Lattices:PanelValues:alphaT Variable/G root:Packages:Lattices:PanelValues:dirty NVAR SpaceGroup=root:Packages:Lattices:PanelValues:SpaceGroup SVAR desc=root:Packages:Lattices:PanelValues:desc NVAR a=root:Packages:Lattices:PanelValues:a NVAR b=root:Packages:Lattices:PanelValues:b NVAR c=root:Packages:Lattices:PanelValues:c NVAR alpha=root:Packages:Lattices:PanelValues:alpha NVAR beta=root:Packages:Lattices:PanelValues:beta NVAR gam=root:Packages:Lattices:PanelValues:gam NVAR alphaT=root:Packages:Lattices:PanelValues:alphaT NVAR dirty=root:Packages:Lattices:PanelValues:dirty Variable/G root:Packages:Lattices:PanelValues:h Variable/G root:Packages:Lattices:PanelValues:k Variable/G root:Packages:Lattices:PanelValues:l Variable/G root:Packages:Lattices:PanelValues:dspace_nm Variable/G root:Packages:Lattices:PanelValues:Fr Variable/G root:Packages:Lattices:PanelValues:Fi String/G root:Packages:Lattices:PanelValues:crystalStructStr SVAR crystalStructStr = root:Packages:Lattices:PanelValues:crystalStructStr STRUCT crystalStructure xtal if (strlen(strStruct)) // start using the passed values StructGet/S/B=2 xtal, strStruct // found passed structure information, load into xtal dirty = 1 crystalStructStr = strStruct elseif(new) // no old values present, use usual defaults FillCrystalStructDefault(xtal) a=xtal.a ; b=xtal.b ; c=xtal.c alpha=xtal.alpha ; beta=xtal.beta ; gam=xtal.gam SpaceGroup=xtal.SpaceGroup alphaT=xtal.alphaT desc=xtal.desc dirty = 0 StructPut/S xtal, strStruct endif SetWindow kwTopWin,userdata(LatticePanelName)=hostWin+"#LatticePanel" NewPanel/K=1/W=(left,top,left+221,top+465)/HOST=$hostWin ModifyPanel frameStyle=0, frameInset=0 RenameWindow #,LatticePanel SetVariable setDesc,pos={4,13},size={211,18},title="name" SetVariable setDesc,help={"description of this lattice"},fSize=12,proc=LatticePanelParamProc SetVariable setDesc,limits={-inf,inf,0},value= root:Packages:Lattices:PanelValues:desc PopupMenu popLatticeStructure,pos={44,41},size={116,20},proc=LatticePanelPopMenuProc PopupMenu popLatticeStructure,font="Baskerville Semibold",fSize=12,fStyle=1 // PopupMenu popLatticeStructure,mode=5,popvalue="Hexagonal:194",value= #PresetLatticeStructures // PopupMenu popLatticeStructure,mode=5,value= #PresetLatticeStructures PopupMenu popLatticeStructure,mode=5,value= #"PresetLatticeStructures" SetVariable set_SpaceGroup,pos={45,67},size={110,18},proc=LatticePanelParamProc,title="structure" SetVariable set_SpaceGroup,fSize=12,format="%d",userdata(oldValue)=num2istr(SpaceGroup) SetVariable set_SpaceGroup,limits={1,230,0},value= root:Packages:Lattices:PanelValues:SpaceGroup TitleBox structureTitle,pos={25,95},size={82,15},title="\\JC" TitleBox structureTitle,fSize=16,frame=0,anchor= LC SetVariable set_a_nm,pos={45,125},size={128,18},proc=LatticePanelParamProc,title="a (nm)" SetVariable set_a_nm,fSize=12,format="%.7f" SetVariable set_a_nm,limits={0,inf,0},value= root:Packages:Lattices:PanelValues:a SetVariable set_b_nm,pos={45,145},size={128,18},proc=LatticePanelParamProc,title="b (nm)" SetVariable set_b_nm,fSize=12,format="%.7f" SetVariable set_b_nm,limits={0,inf,0},value= root:Packages:Lattices:PanelValues:b SetVariable set_c_nm,pos={45,165},size={128,18},proc=LatticePanelParamProc,title="c (nm)" SetVariable set_c_nm,fSize=12,format="%.7f" SetVariable set_c_nm,limits={0,inf,0},value= root:Packages:Lattices:PanelValues:c SetVariable set_alpha,pos={45,195},size={100,17},proc=LatticePanelParamProc,title="a°" SetVariable set_alpha,font="Symbol",fSize=14,format="%.5f" SetVariable set_alpha,limits={0,180,0},value= root:Packages:Lattices:PanelValues:alpha SetVariable set_beta,pos={45,215},size={100,17},proc=LatticePanelParamProc,title="b°" SetVariable set_beta,font="Symbol",fSize=14,format="%.5f" SetVariable set_beta,limits={0,180,0},value= root:Packages:Lattices:PanelValues:beta SetVariable set_gamma,pos={45,235},size={100,17},proc=LatticePanelParamProc,title="g°" SetVariable set_gamma,font="Symbol",fSize=14,format="%.5f" SetVariable set_gamma,limits={0,180,0},value= root:Packages:Lattices:PanelValues:gam Button buttonLatticeSave,pos={35,265},size={150,20},proc=LatticePanelButtonProc,title="Save" Button buttonLatticeSave,help={"Save these values as the current values"} Button buttonLatticeRevert,pos={35,290},size={150,20},proc=LatticePanelButtonProc,title="Revert" Button buttonLatticeRevert,help={"revert to the current default"} Button buttonLatticeFromFile,pos={35,315},size={150,20},proc=LatticePanelButtonProc,title="Load from a file" Button buttonLatticeFromFile,help={"Fill the values in this panel from a file"} Button buttonPrintLattice,pos={35,340},size={150,20},proc=LatticePanelButtonProc,title="Print Lattice to History" Button buttonPrintLattice,help={"print lattice values to the history"} SetVariable h_LatticeVar,pos={12,391},size={60,15},proc=LatticePanelParamProc,title="H",font="Lucida Grande",fSize=12 SetVariable h_LatticeVar,value= root:Packages:Lattices:PanelValues:h SetVariable k_LatticeVar,pos={84,391},size={60,15},proc=LatticePanelParamProc,title="K",font="Lucida Grande",fSize=12 SetVariable k_LatticeVar,value= root:Packages:Lattices:PanelValues:k SetVariable L_LatticeVar,pos={156,391},size={60,15},proc=LatticePanelParamProc,title="L",font="Lucida Grande",fSize=12 SetVariable L_LatticeVar,value= root:Packages:Lattices:PanelValues:l ValDisplay d_LatticeDisp,pos={57,412},size={123,17},title="d (nm)=",font="Lucida Grande",fSize=12,format="%.7f" ValDisplay d_LatticeDisp,limits={0,0,0},barmisc={0,1000},value=#"root:Packages:Lattices:PanelValues:dspace_nm" ValDisplay d_LatticeDisp,help={"d-spacing (nm) calculated using the lattice"},frame=0 ValDisplay Fr_3atticeDisp,pos={20,435},size={80,17},title="F =",value= #"root:Packages:Lattices:PanelValues:Fr" ValDisplay Fr_3atticeDisp,font="Lucida Grande",fSize=12,format="%.3f",limits={0,0,0},barmisc={0,1000} ValDisplay Fr_3atticeDisp,help={"d-spacing (nm) calculated using the lattice"},frame=0 ValDisplay Fi_3atticeDisp,pos={104,435},size={80,17},title="+i",value= #"root:Packages:Lattices:PanelValues:Fi" ValDisplay Fi_3atticeDisp,font="Lucida Grande",fSize=12,format="%.3f",limits={0,0,0},barmisc={0,1000} ValDisplay Fi_3atticeDisp,help={"d-spacing (nm) calculated using the lattice"},frame=0 LatticePanelParamProc("set_SpaceGroup",SpaceGroup,"","") return "#LatticePanel" End // Function LatticePanelPopMenuProc(ctrlName,popNum,popStr) : PopupMenuControl String ctrlName Variable popNum String popStr Variable SpaceGroup = str2num(StringFromList(1, popStr,":")) // String subWin = "microPanel#LatticePanel" String subWin = GetUserData("","","LatticePanelName") if (numtype(SpaceGroup)) // other, Space Group number is manually supplied SetVariable set_SpaceGroup,noedit=0 ,frame=1,fstyle=0,win=$subWin // enable else SetVariable set_SpaceGroup,noedit=1 ,frame=0,fstyle=2,win=$subWin // disable Space Group number NVAR num = root:Packages:Lattices:PanelValues:SpaceGroup num = SpaceGroup NVAR dirty=root:Packages:Lattices:PanelValues:dirty dirty = 1 endif LatticePanelParamProc("set_SpaceGroup",SpaceGroup,"","") End // Function LatticePanelParamProc(ctrlName,varNum,varStr,varName) : SetVariableControl String ctrlName Variable varNum String varStr String varName String subWin = GetUserData("","","LatticePanelName") NVAR a=root:Packages:Lattices:PanelValues:a NVAR b=root:Packages:Lattices:PanelValues:b NVAR c=root:Packages:Lattices:PanelValues:c NVAR alpha=root:Packages:Lattices:PanelValues:alpha NVAR beta=root:Packages:Lattices:PanelValues:beta NVAR gam=root:Packages:Lattices:PanelValues:gam NVAR alphaT=root:Packages:Lattices:PanelValues:alphaT NVAR SpaceGroup=root:Packages:Lattices:PanelValues:SpaceGroup NVAR dirty=root:Packages:Lattices:PanelValues:dirty if (stringmatch(ctrlName,"set_SpaceGroup")) if (!(1<=varNum && varNum<=230)) return 1 endif dirty = dirty || (varNum!=str2num(GetUserData(subWin,"set_SpaceGroup","oldValue"))) SetVariable set_SpaceGroup, userdata(oldValue)=num2istr(varNum),win=$subWin Variable i, usingHexAxes = (abs(90-alpha)+abs(90-beta)+abs(120-gam))<1e-9 for (i=ItemsInList(PresetLatticeStructures)-1;i>=0;i-=1) if (varNum==str2num(StringFromList(1,StringFromList(i,PresetLatticeStructures),":"))) break endif endfor if (i>=0) // if varNum is in the list, then change back to the popup menu PopupMenu popLatticeStructure,mode=(i+1), win=$subWin SetVariable set_SpaceGroup,noedit=1 ,frame=0,fstyle=2,win=$subWin // disable Space Group number else PopupMenu popLatticeStructure,mode=ItemsInList(PresetLatticeStructures), win=$subWin // set to 'other' endif String titleStr="\\JC" if (varNum>=195) // Cubic, a SetVariable set_a_nm,noedit=0,frame=1,win=$subWin // enable SetVariable set_b_nm,noedit=1,frame=0,win=$subWin // disable SetVariable set_c_nm,noedit=1,frame=0,win=$subWin SetVariable set_alpha,noedit=1,frame=0,win=$subWin SetVariable set_beta,noedit=1,frame=0,win=$subWin SetVariable set_gamma,noedit=1,frame=0,win=$subWin b=a ; c=a ; alpha=90 ; beta=90 ; gam=90 titleStr += "Cubic" elseif (varNum>=168) // Hexagonal, a, c SetVariable set_a_nm,noedit=0,frame=1,win=$subWin // enable SetVariable set_c_nm,noedit=0,frame=1,win=$subWin SetVariable set_b_nm,noedit=1,frame=0,win=$subWin // disable SetVariable set_alpha,noedit=1,frame=0,win=$subWin SetVariable set_beta,noedit=1,frame=0,win=$subWin SetVariable set_gamma,noedit=1,frame=0,win=$subWin b=a ; alpha=90 ; beta=90 ; gam=120 titleStr += "Hexagonal" elseif (varNum>=143) // Trigonal, a, alpha SetVariable set_a_nm,noedit=0,frame=1,win=$subWin // enable SetVariable set_alpha,noedit=0,frame=1,win=$subWin SetVariable set_b_nm,noedit=1,frame=0,win=$subWin // disable SetVariable set_c_nm,noedit=1,frame=0,win=$subWin SetVariable set_beta,noedit=1,frame=0,win=$subWin SetVariable set_gamma,noedit=1,frame=0,win=$subWin if (usingHexAxes) // obviously using hexagonal b=a alpha=90 ; beta=90 ; gam=120 else // use rhombohedral b=a ; c=a beta=alpha ; gam=alpha endif // b=a ; c=a ; beta=90 ; gam=90 titleStr += "Trigonal" elseif (varNum>=75) // Tetragonal, a, c SetVariable set_a_nm,noedit=0,frame=1,win=$subWin // enable SetVariable set_c_nm,noedit=0,frame=1,win=$subWin SetVariable set_b_nm,noedit=1,frame=0,win=$subWin // disable SetVariable set_alpha,noedit=1,frame=0,win=$subWin SetVariable set_beta,noedit=1,frame=0,win=$subWin SetVariable set_gamma,noedit=1,frame=0,win=$subWin b=a ; alpha=90 ; beta=90 ; gam=90 titleStr += "Tetragonal" elseif (varNum>=16) // Orthorhombic, a, b, c SetVariable set_a_nm,noedit=0,frame=1,win=$subWin // enable SetVariable set_b_nm,noedit=0,frame=1,win=$subWin SetVariable set_c_nm,noedit=0,frame=1,win=$subWin SetVariable set_alpha,noedit=1,frame=0,win=$subWin // disable SetVariable set_beta,noedit=1,frame=0,win=$subWin SetVariable set_gamma,noedit=1,frame=0,win=$subWin alpha=90 ; beta=90 ; gam=90 titleStr += "Orthorhombic" elseif (varNum>=3) // Monoclinic, a, b, c, gamma SetVariable set_a_nm,noedit=0,frame=1,win=$subWin // enable SetVariable set_b_nm,noedit=0,frame=1,win=$subWin SetVariable set_c_nm,noedit=0,frame=1,win=$subWin SetVariable set_beta,noedit=0,frame=1,win=$subWin SetVariable set_alpha,noedit=1,frame=0,win=$subWin // disable SetVariable set_gamma,noedit=1,frame=0,win=$subWin // alpha=90 ; beta=90 alpha=90 ; gam=90 titleStr += "Monoclinic" else // Triclinic, a, b, c, alpha, beta, gamma SetVariable set_a_nm,noedit=0,frame=1,win=$subWin // enable all SetVariable set_b_nm,noedit=0,frame=1,win=$subWin SetVariable set_c_nm,noedit=0,frame=1,win=$subWin SetVariable set_alpha,noedit=0,frame=1,win=$subWin SetVariable set_beta,noedit=0,frame=1,win=$subWin SetVariable set_gamma,noedit=0,frame=1,win=$subWin titleStr += "Triclinic" endif titleStr += " \\F'Courier'"+getSymString(varNum) titleStr = minus2bar(titleStr) // change all minuses to a bar over following character TitleBox structureTitle,title=titleStr,win=$subWin elseif (!(stringmatch(ctrlName,"h_LatticeVar")||stringmatch(ctrlName,"k_LatticeVar")||stringmatch(ctrlName,"L_LatticeVar"))) dirty = 1 // Cubic [195,230] // a // Hexagonal [168,194] // a,c // Trigonal [143,167] // a,alpha // Tetragonal [75,142] // a,c // Orthorhombic [16,74] // a,b,c // Monoclinic [3,15] // a,b,c,gamma // Triclinic [1,2] // a,b,c,alpha,beta,gamma if (SpaceGroup>=195) // Cubic, a b=a ; c=a elseif (SpaceGroup>=168) // Hexagonal, a, c b=a elseif (SpaceGroup>=143) // Trigonal, a, alpha b=a ; c=a ; beta=alpha ; gam=alpha elseif (SpaceGroup>=75) // Tetragonal, a, c b=a endif endif NVAR h=root:Packages:Lattices:PanelValues:h, k=root:Packages:Lattices:PanelValues:k, l=root:Packages:Lattices:PanelValues:l NVAR dspace_nm=root:Packages:Lattices:PanelValues:dspace_nm NVAR Fr=root:Packages:Lattices:PanelValues:Fr, Fi=root:Packages:Lattices:PanelValues:Fi STRUCT crystalStructure xtal // returns 0 if something set, 1 is nothing done FillCrystalStructDefault(xtal) //fill the crystal structure with 'current' values dspace_nm = dSpacing(xtal,h,k,l) Variable/C Fc = Fstruct(xtal,h,k,l) Fr = real(Fc) Fi = imag(Fc) // set buttons to enable/disable, based upon 'dirty' if (dirty) Button buttonLatticeSave disable=0,fColor=(57346,65535,49151),title="Save (Needed)",win=$subWin Button buttonLatticeRevert disable=0,fColor=(65535,65534,49151),win=$subWin else Button buttonLatticeSave disable=2,fColor=(0,0,0),title="Saved",win=$subWin Button buttonLatticeRevert disable=2,fColor=(0,0,0),win=$subWin endif return 0 End // Function LatticePanelButtonProc(ctrlName) : ButtonControl String ctrlName SVAR desc=root:Packages:Lattices:PanelValues:desc NVAR SpaceGroup=root:Packages:Lattices:PanelValues:SpaceGroup NVAR a=root:Packages:Lattices:PanelValues:a NVAR b=root:Packages:Lattices:PanelValues:b NVAR c=root:Packages:Lattices:PanelValues:c NVAR alpha=root:Packages:Lattices:PanelValues:alpha NVAR beta=root:Packages:Lattices:PanelValues:beta NVAR gam=root:Packages:Lattices:PanelValues:gam NVAR alphaT=root:Packages:Lattices:PanelValues:alphaT NVAR dirty = root:Packages:Lattices:PanelValues:dirty SVAR crystalStructStr = root:Packages:Lattices:PanelValues:crystalStructStr STRUCT crystalStructure xtal StructGet/S/B=2 xtal, crystalStructStr // pre-load with current information if (stringmatch(ctrlName,"buttonLatticeRevert")) // close window, do not save numbers FillCrystalStructDefault(xtal) //fill the lattice structure with default values a=xtal.a ; b=xtal.b ; c=xtal.c alpha=xtal.alpha ; beta=xtal.beta ; gam=xtal.gam SpaceGroup=xtal.SpaceGroup alphaT = xtal.alphaT desc = xtal.desc dirty = 0 SetVariable set_SpaceGroup, userdata(oldValue)=num2istr(SpaceGroup),win=$ GetUserData("","","LatticePanelName") LatticePanelParamProc("set_SpaceGroup",SpaceGroup,"","") StructPut/S xtal, crystalStructStr elseif (stringmatch(ctrlName,"buttonLatticeSave") && dirty) xtal.a = a ; xtal.b = b ; xtal.c = c xtal.alpha = alpha ; xtal.beta = beta ; xtal.gam = gam xtal.SpaceGroup = SpaceGroup xtal.alphaT = alphaT xtal.desc = desc ForceLatticeToStructure(xtal) updateCrystalStructureDefaults(xtal) dirty = 0 LatticePanelParamProc("set_SpaceGroup",SpaceGroup,"","") elseif (stringmatch(ctrlName,"buttonLatticeFromFile")) if (readCrystalStructure(xtal,"")) DoAlert 0,"nothing read" endif a=xtal.a ; b=xtal.b ; c=xtal.c alpha=xtal.alpha ; beta=xtal.beta ; gam=xtal.gam SpaceGroup=xtal.SpaceGroup desc=xtal.desc alphaT=xtal.alphaT dirty = 1 StructPut/S xtal, crystalStructStr LatticePanelParamProc("set_SpaceGroup",SpaceGroup,"","") elseif (stringmatch(ctrlName,"buttonPrintLattice")) // print shown lattice parameters to the history xtal.a = a ; xtal.b = b ; xtal.c = c xtal.alpha = alpha ; xtal.beta = beta ; xtal.gam = gam xtal.SpaceGroup = SpaceGroup xtal.desc = desc xtal.alphaT = alphaT ForceLatticeToStructure(xtal) print " " print_crystalStructure(xtal) endif return 0 End // End of lattice set panel // ========================================================================= // ========================================================================= // ========================================================================= // ========================================================================= // Start of reading/writing lattice paremeters to a file Function LoadCrystal(fname) String fname STRUCT crystalStructure xtal // this sruct is filled by this routine readCrystalStructure(xtal,fname) End //Function testReadCrystal() // STRUCT crystalStructure xtal // this sruct is filled by this routine // readCrystalStructure(xtal,"") // print_crystalStructure(xtal) //End Function readCrystalStructure(xtal,fname) STRUCT crystalStructure &xtal // this sruct is filled by this routine String fname PathInfo materials if (strlen(S_path)<1) // make it if it does not exist NewPath/Z materials, ParseFilePath(1,FunctionPath("MaterialsAreHere"),":",1,0) endif PathInfo materials if (strlen(S_path)<1) // make it if it does not exist PathInfo Igor NewPath/Z materials, S_path+"User Procedures:materials" endif String list = keyStrFromFile(fname,"CrystalStructure","materials") if (strlen(list)<1) // try old style return read_cri_fileOLD(xtal,fname) endif Variable a,b,c,alpha,bet,gam, SpaceGroup, alphaT sscanf StringByKey("latticeParameters",list,"="), "{ %g, %g, %g, %g, %g, %g }" , a,b,c,alpha,bet,gam if (V_flag!=6) return 1 endif SpaceGroup = str2num(StringByKey("SpaceGroup",list,"=")) if (numtype(SpaceGroup)) return 1 endif String unit = StringByKey("lengthUnit",list,"=") if (stringmatch(unit,"Ang*") || stringmatch(unit,"*")) a*= 10 ; b*= 10 ; c*= 10 endif alphaT = str2num(StringByKey("latticeAlphaT",list,"=")) xtal.a = a ; xtal.b = b ; xtal.c = c xtal.alpha = alpha ; xtal.beta = bet ; xtal.gam = gam xtal.SpaceGroup = SpaceGroup xtal.alphaT = !(alphaT>0) ? 0 : alphaT ForceLatticeToStructure(xtal) xtal.desc = StringByKey("structureDesc",list,"=") if (strlen(xtal.desc)==0) xtal.desc = StringByKey("latticeDesc",list,"=") endif Variable N=0 Variable i,xx,yy,zz, occ,Debye=0 String str,item do item = StringByKey("AtomDesctiption"+num2istr(N+1),list,"=") sscanf item, "{%s %g %g %g %g}",str,xx,yy,zz,occ if (V_flag!=5) sscanf item, "{%s %g %g %g}",str,xx,yy,zz if (V_flag!=4) break endif occ = 1 endif xtal.atom[N].name = str xtal.atom[N].Zatom = ZfromLabel(str) xtal.atom[N].x = xx xtal.atom[N].y = yy xtal.atom[N].z = zz xtal.atom[N].occ = occ xtal.atom[N].Debye = Debye N += 1 while(strlen(str) && N=1 && SpaceGroup<=230)) Close f return 1 endif xtal.SpaceGroup = SpaceGroup FReadLine f, line sscanf line, "%g %g %g %g %g %g",a,b,c,alpha,bet,gam if (V_flag!=6) Close f return 1 endif xtal.a = a xtal.b = b xtal.c = c xtal.alpha = alpha xtal.beta = bet xtal.gam = gam FReadLine f, line Variable N = str2num(line) if (!(N>=1 && N<=STRUCTURE_ATOMS_MAX)) Close f return 1 endif xtal.N = N Variable i,xx,yy,zz, occ String str for (i=0;i122) symb = symb[0,0] endif Variable iz = WhichListItem(symb,symbols)+1 return ((iz>0) ? iz : NaN) End // //Function testRead() // STRUCT crystalStructure xtal // this sruct is filled by this routine // read_cri_fileOLD(xtal,"") // print_crystalStructure(xtal) //End // Al2O3 crystal (hexagonal axis) // 167 // 0.47580 0.47580 1.2991 90.00000 90.00000 120.00000 // 2 // Al001 0.00000 0.00000 0.35230 1.00000 // O0001 0.30640 0.00000 0.25000 1.00000 // //Function ReadLatticeFromKeyFile(fileName,path,xtal) // read in the geometry structure from a keyword file // String fileName // full path name to the file // String path // name of an Igor path to use // STRUCT crystalStructure &xtal // the structure to fill from the file // // Variable tempPath = 0 // if (strlen(path)<1) // path = "userMaterials" // PathInfo userMaterials // if (V_flag) // else // PathInfo Igor // NewPath/Z/Q userMaterials,S_path+"User Procedures:materials:" // tempPath = !V_flag // if (V_flag) // path = "home" // no materials folder, just look in home // endif // endif // endif // String list = keyStrFromFile(fileName,"LatticeFile",path)// read in all of the tagged values into a keyword list // if (strlen(list)<1) // return 1 // endif // if (tempPath) // KillPath/Z $path // endif // // Variable a,b,c,alpha,beta,gam, SpaceGroup, alphaT // sscanf StringByKey("latticeParameters",list,"="), "{ %g, %g, %g, %g, %g, %g }" , a,b,c,alpha,beta,gam // if (V_flag!=6) // return 1 // endif // SpaceGroup = str2num(StringByKey("SpaceGroup",list,"=")) // if (numtype(SpaceGroup)) // return 1 // endif // String unit = StringByKey("lengthUnit",list,"=") // if (stringmatch(unit,"Ang*")) // a*= 10 ; b*= 10 ; c*= 10 // endif // alphaT = str2num(StringByKey("latticeAlphaT",list,"=")) // // xtal.a = a ; xtal.b = b ; xtal.c = c // xtal.alpha = alpha ; xtal.beta = beta ; xtal.gam = gam // xtal.SpaceGroup = SpaceGroup // xtal.desc = StringByKey("latticeDesc",list,"=") //// xtal.alphaT = !(alphaT>0) ? 0 : alphaT // xtal.alphaT = !(abs(alphaT)<0.1) ? 0 : alphaT // alphaT can be negative, but it must be small // ForceLatticeToStructure(xtal) // printf "Loaded lattice information from '%s' using units of '%s'\r",StringByKey("keyStrFileName",list,"="),unit // return 0 //End Static Function/S keyStrFromFile(fname,ftype,path) // read in all of the tagged values from a file into a keyword list String fname // full path name to file with tagged geometry values String ftype // the required file identifier, included as a tag (ftype is optional) String path // name of Igor path Variable refNum String fullName="" PathInfo/S materials GetFileFolderInfo/P=$path/Q/Z fname fullName = S_Path if (!V_isFile) Open/D/M="file with a lattice keyword list"/P=$path/R/T=".xtl" refNum as fname fullName = S_fileName endif if (strlen(fullName)<1) return "" else Open/P=$path/R/Z=1 refNum as fullName fullName = S_fileName endif if (strlen(fullName)<1 || !refNum) return "" endif // the above 12 lines should not be necessary, the /Z=2 switch does not work right String tagStr,valStr,line if (strlen(ftype)) // an ftype is present, so check the file FReadLine refNum, line extractTagValueFromLine(line,tagStr,valStr) // check both ways if (!stringmatch(tagStr,ftype) && !(stringmatch(tagStr,"filetype") && stringmatch(valStr,ftype))) printf "The file must start with '%s', but the first line is '%s'\r",ftype,line Close refNum return "" endif endif String list = ReplaceStringByKey("keyStrFileName","",fullName,"=") Variable i,dollar = char2num("$") do FReadLine refNum, line extractTagValueFromLine(line,tagStr,valStr) if (strlen(tagStr)) // check if tag is already in list, only take the first instance of a tag, not the last if (keyInList(tagStr,list,"=","")) // check if this key is already in list continue endif list = ReplaceStringByKey(tagStr,list,valStr,"=") endif while (strlen(line)) // go until EOF Close refNum return list End // Static Function extractTagValueFromLine(line,tagStr,valStr) String line // input line, presumably starting with a %tag String &tagStr // returned String &valStr // returned tagStr = "" // init both to empty valStr = "" if (char2num(line)!=char2num("$")) // if it does not starts with a $, do not process return 0 endif Variable i = strsearch(line,"//",0) // strip off comments if (i>=0) line = line[0,i-1] endif for (i=0;char2num(line[i+1])>32;i+=1) // find end of tag, it ends with a space or lower endfor tagStr = ReplaceString(";",line[1,i],":") tagStr = ReplaceString("=",tagStr,"_") if (strlen(tagStr)<1) return 1 endif for (i=i+1;char2num(line[i])<=32;i+=1) // find first non-white space endfor valStr = line[i,Inf] // value associated with tagStr for (i=strlen(valStr)-1;char2num(valStr[i])<=32 && i>0;i-=1) // strip off trailing whitespace endfor valStr = ReplaceString(";",valStr[0,i],":") valStr = ReplaceString("=",valStr,"_") return 1 End // End of of reading/writing lattice paremeters to a file // ========================================================================= // ========================================================================= // ========================================================================= // ========================================================================= // Start of crystal symmetry stuff Static Constant TRICLINIC=0,MONOCLINIC=1,ORTHORHOMBIC=2,TETRAGONAL=3,TRIGONAL=4,HEXAGONAL=5,CUBIC=6 Static Constant P_CENTER=0,F_CENTER=1,B_CENTER=2,RHOMBOHEDRAL=3,C_CENTER=4,A_CENTER=5 Static Constant FCC=225,BCC=229,DIA=227,SIMPLE_CUBIC=221,SAPPHIRE=167 // generic Space Group numbers Function/C getFstruct(h,k,l) // user interface to getting F for current crystal structure Variable h,k,l if (numtype(h+k+l)) h = numtype(h) ? 0 : h k = numtype(k) ? 0 : k l = numtype(l) ? 2 : l Prompt h,"H" Prompt k,"K" Prompt l,"L" DoPrompt "(hkl)",h,k,l if (V_flag) return cmplx(NaN,NaN) endif if (numtype(h+k+l)) return cmplx(NaN,NaN) endif endif STRUCT crystalStructure xtal // this sruct is filled by this routine FillCrystalStructDefault(xtal) Variable/C Fc = Fstruct(xtal,h,k,l) Variable Freal=real(Fc),Fimag=imag(Fc) printf "F('%s', %d %d %d) = %g %s i%g, |F|^2 = %g\r",xtal.desc,h,k,l,real(Fc),SelectString(imag(Fc)<0,"+","-"),abs(imag(Fc)),magsqr(Fc) return Fc End Function/C Fstruct(xtal,h,k,l) STRUCT crystalStructure &xtal // this sruct is filled by this routine Variable h,k,l Variable SpaceGroup=xtal.SpaceGroup if (!(SpaceGroup>=1 || SpaceGroup<=230) || numtype(h+k+l)) return cmplx(NaN,NaN) // bad inputs endif Variable latticeCentering // lattice centering, ie face centered, body centered, ... Variable multiplicity=1 Variable/C zero=cmplx(0,0) Variable usingHexAxes = (abs(90-xtal.alpha)+abs(90-xtal.beta)+abs(120-xtal.gam))<1e-9 String sym // symmetry symbol Variable system = latticeSystem(SpaceGroup) sym = getSymString(SpaceGroup) // get sym[] latticeCentering = strsearch("PFIRCA",sym[0,0],0) // takes on number [0,5] switch (latticeCentering) case F_CENTER: if (!ALLOW_FC(h,k,l)) return zero endif multiplicity = 4 break case B_CENTER: if (!ALLOW_BC(h,k,l)) return zero endif multiplicity = 2 break case C_CENTER: if (!ALLOW_CC(h,k,l)) return zero endif multiplicity = 2 break case A_CENTER: if (!ALLOW_AC(h,k,l)) return zero endif multiplicity = 2 break case RHOMBOHEDRAL: if (usingHexAxes) if (!ALLOW_RHOM_HEX(h,k,l)) return zero endif endif break // using rhombohedral axes endswitch if (system==HEXAGONAL) if (!ALLOW_HEXAGONAL(h,k,l)) return zero endif endif Variable Freal=0,Fimag=0 Variable na,i Variable arg Variable fatom String name Variable m,N=xtal.N reMakeAtomXYZs(xtal) if (N>0) for (m=0;m 0.01) End // returns info about the symmetry of a structure // sym holds the symmetry info on return, and xyz holds the atom positions. It returns the number of atom positions put in xyz // which is always at least 1. If you call with a bad wave ref for xyz, then it only returns the sym string, and the returned value is 0 Function/S getSymString(SpaceGroup) Variable SpaceGroup //Space Group number, from International Tables if (SpaceGroup<1 || SpaceGroup>230) return "" // invalid SpaceGroup number endif // there are 230 items in this list String symms="P1;P-1;P2:b;P21:b;C2:b1;Pm:b;Pc:b1;" symms += "Cm:b1;Cc:b1;P2/m:b;P21/m:b;C2/m:b1;P2/c:b1;" symms += "P21/c:b1;C2/c:b1;P222;P2221;P21212;P212121;" symms += "C2221;C222;F222;I222;I212121;Pmm2;Pmc21;" symms += "Pcc2;Pma2;Pca21;Pnc2;Pmn21;Pba2;Pna21;" symms += "Pnn2;Cmm2;Cmc21;Ccc2;Amm2;Abm2;Ama2;Aba2;" symms += "Fmm2;Fdd2;Imm2;Iba2;Ima2;Pmmm;Pnnn:1;Pccm;" symms += "Pban:1;Pmma;Pnna;Pmna;Pcca;Pbam;Pccn;Pbcm;" symms += "Pnnm;Pmmn:1;Pbcn;Pbca;Pnma;Cmcm;Cmca;Cmmm;" symms += "Cccm;Cmma;Ccca:1;Fmmm;Fddd:1;Immm;Ibam;Ibca;" symms += "Imma;P4;P41;P42;P43;I4;I41;P-4;I-4;" symms += "P4/m;P42/m;P4/n:1;P42/n:1;I4/m;I41/a:1;P422;" symms += "P4212;P4122;P41212;P4222;P42212;P4322;P43212;" symms += "I422;I4122;P4mm;P4bm;P42cm;P42nm;P4cc;" symms += "P4nc;P42mc;P42bc;I4mm;I4cm;I41md;I41cd;" symms += "P-42m;P-42c;P-421m;P-421c;P-4m2;P-4c2;P-4b2;" symms += "P-4n2;I-4m2;I-4c2;I-42m;I-42d;P4/mmm;P4/mcc;" symms += "P4/nbm:1;P4/nnc:1;P4/mbm;P4/mnc;P4/nmm:1;P4/ncc:1;" symms += "P42/mmc;P42/mcm;P42/nbc:1;P42/nnm:1;P42/mbc;P42/mnm;" symms += "P42/nmc:1;P42/ncm:1;I4/mmm;I4/mcm;I41/amd:1;" symms += "I41/acd:1;P3;P31;P32;R3:H;P-3;R-3:H;P312;" symms += "P321;P3112;P3121;P3212;P3221;R32:H;P3m1;P31m;" symms += "P3c1;P31c;R3m:H;R3c:H;P-31m;P-31c;P-3m1;P-3c1;" symms += "R-3m:H;R-3c:H;P6;P61;P65;P62;P64;P63;P-6;" symms += "P6/m;P63/m;P622;P6122;P6522;P6222;P6422;P6322;" symms += "P6mm;P6cc;P63cm;P63mc;P-6m2;P-6c2;P-62m;P-62c;" symms += "P6/mmm;P6/mcc;P63/mcm;P63/mmc;P23;F23;I23;P213;" symms += "I213;Pm-3;Pn-3:1;Fm-3;Fd-3:1;Im-3;Pa-3;Ia-3;" symms += "P432;P4232;F432;F4132;I432;P4332;P4132;I4132;" symms += "P-43m;F-43m;I-43m;P-43n;F-43c;I-43d;Pm-3m;" symms += "Pn-3n:1;Pm-3n;Pn-3m:1;Fm-3m;Fm-3c;Fd-3m:1;Fd-3c:1;" symms += "Im-3m;Ia-3d;" return StringFromList(SpaceGroup-1,symms) // set the symmetry symbol End Static Function latticeSystem(SpaceGroup) Variable SpaceGroup //Space Group number, from International Tables if (SpaceGroup>230) return -1 // invalid elseif (SpaceGroup>=195) return CUBIC elseif (SpaceGroup>=168) return HEXAGONAL elseif (SpaceGroup>=143) return TRIGONAL // Trigonal, (using the hexagonal cell axes) elseif (SpaceGroup>=75) return TETRAGONAL elseif (SpaceGroup>=16) return ORTHORHOMBIC elseif (SpaceGroup>=3) return MONOCLINIC elseif (SpaceGroup>0) return TRICLINIC endif return -1 // invalid End // #define ALLOW_FC(H,K,L) (!(((H)+(K))%2) && !(((K)+(L))%2)) // H,K,L all even or all odd // #define ALLOW_BC(H,K,L) (!(((H)+(K)+(L))%2)) // !mod(round(h+k+l),2) // #define ALLOW_CC(H,K,L) (!((H)+(K))%2) // !mod(round(h+k),2) // #define ALLOW_AC(H,K,L) (!((K)+(L))%2) // !mod(round(k+l),2) // #define ALLOW_RHOM_HEX(H,K,L) (((-(H)+(K)+(L))%3)==0 || (((H)-(K)+(L))%3)==0) // allowed are -H+K+L=3n or H-K+L=3n // #define ALLOW_HEXAGONAL(H,K,L) ((((H)+2*(K))%3) || !((L)%2)) // forbidden are: H+2K=3N with L odd // Static Function ALLOW_FC(h,k,l) // for face-centered, hkl must be all even or all odd Variable h,k,l return !mod(h+k,2) && !mod(k+l,2) End // Static Function ALLOW_BC(h,k,l) // for body-centered, !mod(round(h+k+l),2) Variable h,k,l return !mod(round(h+k+l),2) End // Static Function ALLOW_CC(h,k,l) // for C-centered, !mod(round(h+k),2) Variable h,k,l return !mod(round(h+k),2) End // Static Function ALLOW_AC(h,k,l) // for A-centered, !mod(round(k+l),2) Variable h,k,l return !mod(round(k+l),2) End // Static Function ALLOW_RHOM_HEX(h,k,l) // for rhombohedral hexagonal, allowed are -H+K+L=3n or H-K+L=3n Variable h,k,l return !mod(-h+k+l,3) || !mod(h-k+l,3) End // Static Function ALLOW_HEXAGONAL(h,k,l) // for hexagonal, // forbidden are: H+2K=3N with L odd Variable h,k,l return mod(h+2*k,3) || !mod(l,2) End // End of crystal symmetry stuff // ========================================================================= // ========================================================================= // ========================================================================= // ========================================================================= // Start of some utility routines // changes hkl[3] to the lowest order hkl, ignores whether a reflection is allowed, just removes common factors Function lowestOrderHKL(h,k,l) Variable &h,&k,&l // these hkl are returned with all common factors removed Variable maxDiv // max possible divisor Variable i maxDiv = max(abs(h),abs(k)) // the maximum divisor cannot be bigger than the smallest of hkl maxDiv = max(maxDiv,abs(l)) for (i=maxDiv;i>=2;i-=1) // check all divisorts in range [2, maxDiv] if (mod(h,i) || mod(k,i) || mod(l,i)) // i is not a factor of h, k, and l continue endif h /= i k /= i l /= i endfor End // changes hkl[3] to the lowest order allowed hkl (ie for FCC, 0,0,12 -> 002 not 001 Function lowestAllowedHKL(h,k,l,SpaceGroup) Variable &h,&k,&l Variable SpaceGroup // number denoting Space Group, see "#define" for FCC, BCC, etc. STRUCT crystalStructure xtal // temporary crystal structure xtal.SpaceGroup = SpaceGroup xtal.alpha=80 ; xtal.beta=80 ; xtal.gam=80 // just needed to prevent errors xtal.a=1 xtal.b=1 xtal.c=1 ForceLatticeToStructure(xtal) xtal.N = 1 xtal.atom[0].x = 0 xtal.atom[0].y = 0 xtal.atom[0].z = 0 xtal.atom[0].Zatom = 1 // Z of the atom xtal.atom[0].occ = 1 Variable i Variable hh=h, kk=k, ll=l lowestOrderHKL(hh,kk,ll) // remove all common factors for (i=1;i<16;i+=1) // never need more than 16 to reach an allowed reflection h = i*hh // try each of the multiples to reach an allowed reflection k = i*kk l = i*ll if (allowedHKL(h,k,l,xtal)) return 0 endif endfor return 0 End Function/S hkl2str(h,k,l) // format h,k,l into a string of acceptable minimal length Variable h,k,l if (numtype(h+k+l)) return "(NaN,NaN,NaN)" endif String hkl if (abs(mod(h,1))+abs(mod(k,1))+abs(mod(l,1)) > 1e-6) // hkl are non-integers sprintf hkl,"%g, %g, %g",h,k,l elseif (k<0 || l<0) sprintf hkl,"%.0f, %.0f, %.0f",h,k,l elseif (abs(h)<10 && k<10 && l<10) sprintf hkl,"%.0f%.0f%.0f",h,k,l else sprintf hkl,"%.0f %.0f %.0f",h,k,l endif return hkl End Function/T minus2bar(str) // change an Igor string that has minuses to one using a bar over following character String str String bs Variable i for (i=0; i<=9 && strsearch(str,"-",0)>=0; i+=1) sprintf bs, "\\[%d\\SÑ\\M\\X%d",i,i str = ReplaceString("-",str,bs,0,1) endfor return str End Static Function placesOfPrecision(a) // number of significant figures in a number Variable a a = roundSignificant(abs(a),17) Variable i for (i=1;i<18;i+=1) if (abs(a-roundSignificant(a,i))/a<1e-15) break endif endfor return i End // End of utility // ========================================================================= // ========================================================================= // // ================================================================================ // // This section creates the wave definitions used in InitLatticeSymPackage() // Function InitLatticeSymPackage() // used to initialize this package NewDataFolder/O root:Packages NewDataFolder/O root:Packages:Lattices NewDataFolder/O root:Packages:Lattices:SymOps End // // ================================================================================ // // This section is for making the matricies for the symmetry operations for Space Groups // Static Function SetSymOpsForSpaceGroup(SpaceGroup) // make the symmetry operations mats and vecs (if needed), returns number of operations Variable SpaceGroup Wave mats = $("root:Packages:Lattices:SymOps:equivXYZM"+num2istr(SpaceGroup)) Wave bvecs = $("root:Packages:Lattices:SymOps:equivXYZB"+num2istr(SpaceGroup)) Variable numSymOps if (WaveExists(mats) && WaveExists(bvecs)) // check if they exist numSymOps = NumberByKey("numSymOps",note(mats),"=") return numtype(numSymOps) ? 0 : numSymOps // do not re-make, just return number of operations endif if (SpaceGroup<1 || 230