Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A more user friendly initialization method for material.Material objects #561

Open
argerlt opened this issue Oct 5, 2023 · 4 comments
Open
Labels
low priority low priority task

Comments

@argerlt
Copy link

argerlt commented Oct 5, 2023

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:

  1. create a default nickel material
  2. overwrite relevant default values
  3. 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.

@saransh13
Copy link
Member

saransh13 commented Oct 6, 2023

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)
Screenshot 2023-10-06 at 11 58 08 AM

@argerlt
Copy link
Author

argerlt commented Oct 9, 2023

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.

@ZackAttack614 ZackAttack614 added the low priority low priority task label Jul 30, 2024
@ZackAttack614
Copy link
Collaborator

@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.

@argerlt
Copy link
Author

argerlt commented Aug 6, 2024

@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:

  1. is ITOC-compliant
  2. Has basic unittests for testing Laue/Space/Point group combinations
  3. the CLI and the initiate-from-class approach produce identical results from the same inputs (not currently true in my experience)
  4. there is at least minimal documentation

I will be happy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
low priority low priority task
Projects
None yet
Development

No branches or pull requests

3 participants