Source code for tests.test_kvec

'''
test_kvec.py 
==============
Performs a series of tests on the k-vector search code.
'''

import os
import sys
import numpy as np
import pytest
import warnings

import importlib.util
if importlib.util.find_spec('GSASII') is None:
    home = os.path.dirname(__file__)
    sys.path.append(os.path.dirname(home))

import GSASII.k_vector_search as kvs

gen_pos = False

pcell = [
    [5.144191, -2.970000, -0.000000],
    [0.000000, 5.940000, -0.000000],
    [0.000000, 0.000000, 16.700001]
]

ppos = [
    [0.000000, 0.000000, 0.000000],
    [0.000000, 0.000000, 0.500000],
    [0.000000, 0.000000, 0.330000],
    [0.000000, 0.000000, 0.670000],
    [0.333333, 0.666667, 0.666667],
    [0.333333, 0.666667, 0.166667],
    [0.333333, 0.666667, 0.996667],
    [0.333333, 0.666667, 0.336667],
    [0.666667, 0.333333, 0.333333],
    [0.666667, 0.333333, 0.833333],
    [0.666667, 0.333333, 0.663333],
    [0.666667, 0.333333, 0.003333],
    [0.333000, 0.000000, 0.251000],
    [0.000000, 0.333000, 0.251000],
    [0.667000, 0.667000, 0.251000],
    [0.667000, 0.000000, 0.749000],
    [0.000000, 0.667000, 0.749000],
    [0.333000, 0.333000, 0.749000],
    [0.666333, 0.666667, 0.917667],
    [0.333333, 0.999667, 0.917667],
    [0.000333, 0.333667, 0.917667],
    [0.000333, 0.666667, 0.415667],
    [0.333333, 0.333667, 0.415667],
    [0.666333, 0.999667, 0.415667],
    [0.999667, 0.333333, 0.584333],
    [0.666667, 0.666333, 0.584333],
    [0.333667, 0.000333, 0.584333],
    [0.333667, 0.333333, 0.082333],
    [0.666667, 0.000333, 0.082333],
    [0.999667, 0.666333, 0.082333]
]

cr_atoms = [24 for _ in range(12)]
s_atoms = [16 for _ in range(18)]
nums = cr_atoms + s_atoms

nuc_p = list()
for i in range(6):
    for j in range(6):
        for k in range(6):
            nuc_p.append([i, j, k])

spos = [
    5.566667,
    4.916235,
    4.379751
]

threshold = 0.008
brav_type = "hR"

try:
    import seekpath
    # Suppress DeprecationWarning from spglib during module-level initialization
    # to prevent pytest from treating it as an error during test collection
    with warnings.catch_warnings():
        warnings.filterwarnings("ignore", category=DeprecationWarning)
        k_search = kvs.kVector(
            brav_type,
            pcell,
            ppos,
            nums,
            nuc_p,
            spos,
            threshold
        )
except ModuleNotFoundError:
    k_search = None

selftestlist = []
selftestquiet = True


def _ReportTest():
    '''Report name and doc string of current routine when ``selftestquiet``
    is False'
    '''
    if not selftestquiet:
        import inspect
        caller = inspect.stack()[1][3]
        doc = eval(caller).__doc__
        if doc is not None:
            print(
                f'testing {os.path.split(__file__)[1]}'
                f' with {caller}\n\t({doc})'
            )
        else:
            print(f'testing {os.path.split(__file__)[1]} with {caller}')


[docs] def test_AtomID(): '''self-test #0: test the unique ID generation routine''' _ReportTest() atom_types = ["Cr", "Cr", "Cr", "Sb", "Sb", "Se"] atom_types_id = kvs.unique_id_gen(atom_types) msg = "Unique ID generation failed" assert atom_types_id == [1, 1, 1, 2, 2, 3], msg print("test_AtomID passed")
selftestlist.append(test_AtomID)
[docs] @pytest.mark.skipif(k_search is None, reason='No seekpath module') def test_LatConstruct(): '''self-test #1: test the lattice vectors construction routine''' _ReportTest() cell_params = [5., 5., 5., 90, 90., 90.] latt_vec = kvs.lat_params_to_vec(cell_params) msg = "Lattice vectors construction failed" assert np.allclose(latt_vec[0], [5., 0., 0.]), msg assert np.allclose(latt_vec[1], [0., 5., 0.]), msg assert np.allclose(latt_vec[2], [0., 0., 5.]), msg cell_params = [ 5., 5., 10., 90., 90., 120. ] latt_vec = kvs.lat_params_to_vec(cell_params) assert np.allclose( latt_vec[0], [4.33013, -2.5, 0.], atol=1e-5 ), msg assert np.allclose( latt_vec[1], [0., 5.0, 0.], atol=1e-5 ), msg assert np.allclose( latt_vec[2], [0., 0., 10.], atol=1e-5 ), msg cell_params = [ 5., 6., 7., 91., 95., 112. ] latt_vec = kvs.lat_params_to_vec(cell_params) assert np.allclose( latt_vec[0], [4.61218, -1.88092, -0.43578], atol=1e-5 ), msg assert np.allclose( latt_vec[1], [0., 5.99909, -0.10471], atol=1e-5 ), msg assert np.allclose( latt_vec[2], [0., 0., 7.], atol=1e-5 ), msg print("test_LatConstruct passed")
selftestlist.append(test_LatConstruct)
[docs] @pytest.mark.skipif(k_search is None, reason='No seekpath module') def test_CriticalRoutines(): '''self-test #2: test the critical routines''' _ReportTest() hkl_p = k_search.hklConvToPrim(nuc_p[2][:3]) msg = "Test for conventional to primitive setting failed" assert np.allclose( hkl_p, [0.66667, 0.66667, 0.66667], atol=1e-5 ), msg msg = "Test for primitive to conventional setting failed" k_conv = k_search.kVecPrimToConv([0.5, 0.5, 0]) assert np.allclose( k_conv, [0., .5, 1.], atol=1e-5 ), msg
selftestlist.append(test_CriticalRoutines)
[docs] @pytest.mark.skipif(k_search is None, reason='No seekpath module') @pytest.mark.filterwarnings("ignore::DeprecationWarning") def test_KVecCandidateUpdate(): '''self-test #3: test the updating of the list of alternative k vectors''' _ReportTest() msg = "Test for updating the list of alternative k vectors failed" k_trial = [.5, .5, .5] # T point k_opt_list = list() k_opt_dist = list() k_opt_ad = list() k_opt_md = list() k_opt_out = k_search.updateCandidateList( k_trial, k_opt_list, k_opt_dist, k_opt_ad, k_opt_md, False ) (k_opt_list, k_opt_dist, k_opt_ad, k_opt_md) = k_opt_out k_trial = [.5, 0, .5] # F point k_opt_out = k_search.updateCandidateList( k_trial, k_opt_list, k_opt_dist, k_opt_ad, k_opt_md, False ) (k_opt_list, k_opt_dist, k_opt_ad, k_opt_md) = k_opt_out assert np.allclose( k_opt_list[0], [.5, 0., .5], atol=1e-5 ), msg+f'\nk_opt_list[0] {k_opt_list[0]}, [.5, 0., .5]' assert np.allclose( k_opt_dist[0], 0.08340, atol=1e-5 ), msg+f'\nk_opt_dist[0] {k_opt_dist[0]}, 0.08340' assert np.allclose( k_opt_list[1], [.5, .5, .5], atol=1e-1 ), msg+f'\nk_opt_list[1] {k_opt_list[1]}, [.5, .5, .5]' assert np.allclose( k_opt_dist[1], 0.11751, atol=1e-1 ), msg+f'\nk_opt_dist[1] {k_opt_dist[1]}, 0.11751' k_trial = [0, 0, 0] # Gamma point k_opt_out = k_search.updateCandidateList( k_trial, k_opt_list, k_opt_dist, k_opt_ad, k_opt_md, False ) (k_opt_list, k_opt_dist, k_opt_ad, k_opt_md) = k_opt_out assert np.allclose( k_opt_list[0], [0., 0., 0.], atol=1e-5 ), msg+f'\nk_opt_list[0] {k_opt_list[0]}, [0, 0, 0]' assert np.allclose( k_opt_dist[0], 0., atol=1e-5 ), msg+f'\nk_opt_dist[0] {k_opt_dist[0]}, 0.' k_opt_final, kd_opt_final, _, _ = k_search.kOptFinder() assert np.allclose( k_opt_final[0], [0., 0., 0.], atol=1e-5 ), msg+f'\nk_opt_final[0] {k_opt_final[0]}, [0, 0, 0]' assert np.allclose( kd_opt_final[0], 0., atol=1e-5 ), msg+f'\nkd_opt_final[0] {kd_opt_final[0]}, 0.0'
selftestlist.append(test_KVecCandidateUpdate)
[docs] @pytest.mark.skipif(k_search is None, reason='No seekpath module') @pytest.mark.filterwarnings("ignore::DeprecationWarning") def test_KVecSearch(): '''self-test #4: test the k vector search routine''' _ReportTest() # High symmetry point. lambda_val = 2.4109 two_thetas = [ 24.613175764104273, 35.08694489435111, 56.92736582327283, 62.945222217048965, 79.49838666374927, 84.75564148306853, 100.43822871252318, 105.78539737883935, 122.99828511273124, 129.45511757798127 ] spos_gen = list() for two_theta in two_thetas: d_tmp = lambda_val / (2. * np.sin(np.deg2rad(two_theta) / 2.)) spos_gen.append(d_tmp) latt_params = [ 5.655600, 5.655600, 5.655600, 90.000000, 90.000000, 90.000000 ] latt_vec = kvs.lat_params_to_vec(latt_params) atoms_labels = [1, 1, 1, 1] atom_pos_p1 = [ [0.000000, 0.000000, 0.000000], [0.000000, 0.500000, 0.500000], [0.500000, 0.000000, 0.500000], [0.500000, 0.500000, 0.000000] ] hkl_refls = list() for i in range(6): for j in range(6): for k in range(6): hkl_refls.append([i, j, k]) brav_type = "cF" threshold = 1.E-6 k_search = kvs.kVector( brav_type, latt_vec, atom_pos_p1, atoms_labels, hkl_refls, spos_gen, threshold, option=2, kstep=[0.002, 0.002, 0.002], processes=16 ) k_opt = k_search.kOptFinder() k_opt_final = k_search.kVecPrimToConv(k_opt[0]) msg = "Test for k vector search failed" assert np.allclose( k_opt_final[0], [0., 1., 0.], atol=1e-5 ), msg assert np.allclose( k_opt[1][0], 0., atol=1e-5 ), msg # High symmetry direction. lambda_val = 2.4109 two_thetas = [ 3.989827234732058, 24.694684773857567, 29.27168183349248, 31.061600212829333, 31.24029252242816, 34.877431565785194, 40.21710077021546, 46.02390422155341, 54.92232759586314, 62.073039736321064 ] spos_gen = list() for two_theta in two_thetas: d_tmp = lambda_val / (2. * np.sin(np.deg2rad(two_theta) / 2.)) spos_gen.append(d_tmp) latt_params = [ 5.598000, 5.598000, 8.955600, 90.000000, 90.000000, 120.000000 ] latt_vec = kvs.lat_params_to_vec(latt_params) atoms_labels = [1] atom_pos_p1 = [ [0.000000, 0.000000, 0.000000] ] hkl_refls = list() for i in range(6): for j in range(6): for k in range(6): hkl_refls.append([i, j, k]) brav_type = "hP" threshold = 1.E-6 k_search = kvs.kVector( brav_type, latt_vec, atom_pos_p1, atoms_labels, hkl_refls, spos_gen, threshold, option=2, kstep=[0.002, 0.002, 0.002], processes=16 ) k_opt = k_search.kOptFinder() k_opt_final = k_search.kVecPrimToConv(k_opt[0]) assert np.allclose( k_opt_final[0], [.14, 0., 0.], atol=1e-5 ), msg assert np.allclose( k_opt[1][0], 0., atol=1e-5 ), msg
selftestlist.append(test_KVecSearch) if __name__ == "__main__": selftestquiet = False for test in selftestlist: test() print("All k-vector tests passed.")