hexrd
hexrd copied to clipboard
A more user friendly initialization method for material.Material objects
I had a feature I wanted to add, but I want to make sure it doesn't already exist in a way I don't know about, and possibly have some experts weigh in on what to watch out for so I don't break any important features.
@donald-e-boyce @psavery @saransh13
Elevator Pitch of the Issue:
Allow users to more easily initalize Material
Class objects without initializing from an h5 or CIF.
The method commonly used in example scripts involves creating a default Nickel material, then selectively overwriting the relevant attributes. This requires some a-priori understanding of how the Materials class is organized and calculated in HEXRD, and can occasionally cause program-breaking errors if additional hidden attributes (eg, PlaneData
and UnitCell
objects) are not also overwritten in the correct order.
Longer Description
currently, initializing a material class WITHOUT an already existing hdf5 or cif calls Materials.init with the following defaults:
DFLT_NAME = 'material.xtal'
DFLT_XTAL = 'Ni'
DFLT_SGNUM = 225
DFLT_LPARMS = [_angstroms(3.61), _angstroms(3.61), _angstroms(3.61),
_degrees(90.0), _degrees(90.0), _degrees(90.0)]
DFLT_SSMAX = 100
DFLT_KEV = valWUnit('wavelength', 'energy', 80.725e0, 'keV')
DFLT_STR = 0.0025
DFLT_TTH = numpy.radians(0.25)
DFLT_TTHMAX = None
DFLT_ATOMINFO = numpy.array([[0., 0., 0., 1.]])
DFLT_U = numpy.array([6.33E-3])
DFLT_ATOMTYPE = numpy.array([28])
DFLT_CHARGE = numpy.array(["0"])
DFLT_DMIN = _angstroms(0.75)
DFLT_STIFFNESS = numpy.eye(6)
DFLT_SGSETTING = 0
If users want to create a new material outside of hexrdgui (say, testing a toy problem with randomly generated crystal structures or testing different beam energies), the easiest way is usually:
- create a default nickel material
- overwrite relevant default values
- know enough about how the material class works to know to rerun the relevant secondary initialization functions to regenerate the correct PlaneData, Unitcell, etc.
Often, users will write some variation of a generator function like the one below to automate this:
def make_matl(mat_name, sgnum, lparms, hkl_ssq_max=50):
matl = material.Material(mat_name)
matl.sgnum = sgnum
matl.latticeParameters = lparms
matl.hklMax = hkl_ssq_max
nhkls = len(matl.planeData.exclusions)
matl.planeData.set_exclusions(np.zeros(nhkls, dtype=bool))
return matl
This works, but it's clunky, and its also alienating to new users who do not know a priori how this function works or how to properly overwrite the correct values.
Synopsis of My Solution:
Instead of 20-odd default values that clutter up the namespace, there should just be a default values dictionary, and users should be able to selectively overwrite the values they want on initialization, as opposed to after the fact. this can be done both through custom dictionaries of changed values, or just by passing in wildcard keywords
Initial rules should stay unchanged: all the same inputs are still allowed, and values taken from a CIF or HDF5 still overwrite defaults. All I want is the ability to pass any of the following single lines and have all of them give a reasonable result
from hexrd.material import Material
ruby_1 = Material('Ruby', kev=78.6)
ruby_2 = Material('Ruby', kev=valWUnit("wavelength","ENERGY",78.6,"keV")
Mg1 = Material("Mg_alloy", sgsetting=[0.333,0.667,0.25,] A=3.17, B=3.17, C=5.14, alpha=90, beta=90, gamma=90)
Mg_alloy_from_file = Material("Mg_stretched,
different_me3 = Material('ME3', "materials.h5"], name="doped_me3",C=5.20)
DO NOTE: I am aware now that there are ways to initialize these materials using HEXRD as is, but they are not well documented or intuitive, and they slowed me down a lot while learning. this is less about expanding the capabilities, and more about simplifying the process and adding documentation so new users can have an easier time learning on their own.
I do support a simpler interface. If you have improvements then do submit a PR!
One concern I have in giving users too much freedom. For eg., if only alpha
angle is specified together with lattice parameters a
and b
, then that limits the space group to a subset of the 230. It just seems a lot of extra work to go through that.
I will point you to hexrd.mksupport.mk
for a command line tool for making a material. Here's how it looks for a FCC material
In [1]: from hexrd.mksupport import mk
In [2]: filename = "test.h5"
In [3]: xtalname = "testxtal"
In [4]: mk(filename, xtalname)
This is a program to create a HDF5 file for storing crystallographic information.
This format is the same format as used in the EMsoft (electron microscoy) suite.
The following inputs are required:
Crystal System:
1. Cubic
2. Tetragonal
3. Orthorhombic
4. Hexagonal
5. Trigonal
6. Monoclinic
7. Triclinic
Space group number
Atomic number (Z) for all species in unit cell
Asymmetric positions for all atoms in unit cell
Debye-Waller factors for all atoms in the unit cell
You'll be prompted for these values now
Note about the trigonal system:
-------------------------------
Primitive trigonal crystals are defined with respect to a HEXAGONAL
reference frame. Rhombohedral crystals can be referenced with
respect to a HEXAGONAL basis (first setting), or with respect to
a RHOMBOHEDRAL basis (second setting). The default setting for
trigonal symmetry is the hexagonal setting. When you select
crystal system 5 above, you will be prompted for the setting.
Crystal System (1-7 use the legend above): 1
a [nm] : 3
195: P 2 3 196: F 2 3 197: I 2 3 198: P 21 3
199: I 21 3 200: P m 3 201: P n 3 202: F m 3
203: F d 3 204: I m 3 205: P a 3 206: I a 3
207: P 4 3 2 208: P 42 3 2 209: F 4 3 2 210: F 41 3 2
211: I 4 3 2 212: P 43 3 2 213: P 41 3 2 214: I 41 3 2
215: P -4 3 m 216: F -4 3 m 217: I -4 3 m 218: P -4 3 n
219: F -4 3 c 220: I -4 3 d 221: P m 3 m 222: P n 3 n
223: P m 3 n 224: P n 3 m 225: F m 3 m 226: F m 3 c
227: F d 3 m 228: F d 3 c 229: I m 3 m 230: I a 3 d
Space group number (use legend above): 225
------------------------------------ Periodic Table of the Elements --------------------------------------
1:H 2:He
3:Li 4:Be 5:B 6:C 7:N 8:O 9:F 10:Ne
11:Na 12:Mg 13:Al 14:Si 15:P 16:S 17:Cl 18:Ar
19:K 20:Ca 21:Sc 22:Ti 23:V 24:Cr 25:Mn 26:Fe 27:Co 28:Ni 29:Cu 30:Zn 31:Ga 32:Ge 33:As 34:Se 35:Br 36:Kr
37:Rb 38:Sr 39:Y 40:Zr 41:Nb 42:Mo 43:Tc 44:Ru 45:Rh 46:Pd 47:Ag 48:Cd 49:In 50:Sn 51:Sb 52:Te 53: I 54:Xe
55:Cs 56:Ba ----- 72:Hf 73:Ta 74:W 75:Re 76:Os 77:Ir 78:Pt 79:Au 80:Hg 81:Tl 82:Pb 83:Bi 84:Po 85:At 86:Rn
87:Fr 88:Ra -----
57:La 58:Ce 59:Pr 60:Nd 61:Pm 62:Sm 63:Eu 64:Gd 65:Tb 66:Dy 67:Ho 68:Er 69:Tm 70:Yb 71:Lu
89:Ac 90:Th 91:Pa 92:U
----------------------------------------------------------------------------------------------------------
Enter atomic number of species : 28
Enter asymmetric position of atom in unit cell separated by comma (fractional coordinates) : 0,0,0
Enter site occupation : 1
Isotropic or anisotropic Debye-Waller factor?
1 for isotropic, 2 for anisotropic : 1
Enter isotropic Debye-Waller factor [nm^(-2)] : 0
Another atom? (y/n) : n
This creates a test.h5
file (screenshot below)
hmmmmm......... I didn't know about this. I might try wrapping a part of this into a generator.
My fear is that drastic changes are going to break some part of HEXRD I am unfamiliar with, and because HEXRD isn't fully covered by tests, It won't be obvious until someone reports some catastrophic break to their pipeline I hadn't considered.
My approach would retain all the existing keyword inputs, so it's guaranteed (in theory) not to break anything currently in place.
Modeling off the CL version is much nicer though, and having the CL and module methods use identical functions for generation would be a big improvement for maintainable code.....
I'll try both ways, see what happens, and start a PR.
@argerlt I would like to incorporate these changes into our upcoming restructuring of the library. Is this still on your radar? Would like to sync up about it at some point over the migration process.
@ZackAttack614, Sorry for the slow response. It is, but it took a major back seat to other work.
I can submit a PR of how I think such the class should be laid out, and you can keep/toss what you want. Just let me know what branch is best to work off of, in light of the restructuring. Also, if I'm going slow, feel free to lap me and do it yourself, I'm working on finishing my Thesis right now so I'm a bit slow in general.
In short though, I think as long as the end result:
- is ITOC-compliant
- Has basic unittests for testing Laue/Space/Point group combinations
- the CLI and the initiate-from-class approach produce identical results from the same inputs (not currently true in my experience)
- there is at least minimal documentation
I will be happy.