Skip to content

Commit 929ba36

Browse files
committed
finishing up the implementation for k vector routine to isodistort
1 parent c5b8222 commit 929ba36

File tree

3 files changed

+112
-37
lines changed

3 files changed

+112
-37
lines changed

GSASII/GSASIIpwdGUI.py

Lines changed: 77 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import random as ran
2121
import pickle
2222
import scipy.interpolate as si
23+
from sympy import symbols, nsimplify, Rational as SRational
24+
from fractions import Fraction
2325
from . import GSASIIpath
2426
from . import GSASIImath as G2mth
2527
from . import GSASIIpwd as G2pwd
@@ -5197,7 +5199,6 @@ def _get_opt_val(opt_name, out):
51975199

51985200
def grab_all_kvecs(out_html):
51995201
"""Extract all k-vectors from the ISODISTORT output HTML."""
5200-
from fractions import Fraction
52015202
import re
52025203

52035204
kvec1_pattern = r'<SELECT NAME="kvec1">(.*?)</SELECT>'
@@ -5224,49 +5225,77 @@ def grab_all_kvecs(out_html):
52245225
else:
52255226
return None
52265227

5227-
def setup_kvec_input(k_vec, k_vec_dict, symmetry=None):
5228+
a, b, g = symbols('a b g')
5229+
5230+
def frac_str(value, max_den=1000):
5231+
# Try to get a rational exactly; if huge, fall back to bounded approximation
5232+
try:
5233+
rat = nsimplify(value, rational=True, maxsteps=50)
5234+
if isinstance(rat, SRational):
5235+
num, den = rat.as_numer_denom()
5236+
num, den = int(num), int(den)
5237+
if den <= max_den:
5238+
return f"{num}/{den}" if den != 1 else str(num)
5239+
except Exception:
5240+
pass
5241+
5242+
# Best rational with denominator <= max_den
5243+
try:
5244+
f = Fraction(value).limit_denominator(max_den)
5245+
except TypeError:
5246+
f = Fraction(float(value)).limit_denominator(max_den)
5247+
5248+
return f"{f.numerator}/{f.denominator}" if f.denominator != 1 else str(f.numerator)
5249+
5250+
def to_fraction_strs(d, keys=(a, b, g), max_den=1000):
5251+
out = {}
5252+
for k in keys:
5253+
if k in d:
5254+
out[str(k)] = frac_str(d[k], max_den)
5255+
return out
5256+
5257+
def setup_kvec_input(k_vec, k_vec_dict, isocif_cif):
52285258
"""Set up the input for isodistort post request
52295259
52305260
Args:
52315261
k_vec (str): The k-vector to use for the isodistort request.
52325262
k_vec_dict (dict): The dictionary containing the k-vector
5233-
form extracted from isodistort.
5234-
symmetry (str, optional): The crystal system.
5263+
form extracted from isodistort.
5264+
isocif_cif (str): The CIF file content exported from ISOCIF.
52355265
52365266
Returns:
52375267
dict: New entries and those need to be corrected in the data
52385268
to be used in the post request.
52395269
"""
52405270
k_forms = k_vec_dict.items()
5271+
all_keys = list(k_forms)
52415272

5242-
k_vec_form = match_vector_pattern(k_vec, k_vec_dict, symmetry="cubic")
5273+
spg_num = kvsolve.grab_spg_num(isocif_cif)
5274+
k_vec_sol = kvsolve.find_kvec_form_param(spg_num, isocif_cif, k_vec, k_forms)
5275+
k_vec_form = all_keys[k_vec_sol[0]]
52435276

52445277
data_update = dict()
52455278
data_update['kvec1'] = k_vec_form
5246-
kvec_template = k_vec_dict[k_vec_form]
5247-
if isinstance(kvec_template[0], str):
5248-
num = k_vec[0].numerator
5249-
den = k_vec[0].denominator
5250-
data_update['kparam11'] = f"{num}/{den}"
5251-
if isinstance(kvec_template[1], str):
5252-
num = k_vec[1].numerator
5253-
den = k_vec[1].denominator
5254-
data_update['kparam21'] = f"{num}/{den}"
5255-
if isinstance(kvec_template[2], str):
5256-
num = k_vec[2].numerator
5257-
den = k_vec[2].denominator
5258-
data_update['kparam31'] = f"{num}/{den}"
5279+
k_vec_params = to_fraction_strs(k_vec_sol[1], max_den=1000)
5280+
5281+
if "a" in k_vec_params:
5282+
data_update['kparam11'] = k_vec_params["a"]
5283+
if "b" in k_vec_params:
5284+
data_update['kparam21'] = k_vec_params["b"]
5285+
if "g" in k_vec_params:
5286+
data_update['kparam31'] = k_vec_params["g"]
52595287

52605288
return data_update
52615289

52625290
# start of OnISODISTORT_kvec computations
52635291
import tempfile
52645292
import re
52655293
import requests
5266-
from fractions import Fraction
52675294
from GSASII.exports import G2export_CIF
52685295
from . import ISODISTORT as ISO
52695296
isoformsite = 'https://iso.byu.edu/isodistortform.php'
5297+
isocifformsite = 'https://iso.byu.edu/isocifform.php'
5298+
isocifuploadsite = 'https://iso.byu.edu/isocifuploadfile.php'
52705299

52715300
if not G2frame.kvecSearch['mode']:
52725301
return
@@ -5354,9 +5383,37 @@ def setup_kvec_input(k_vec, k_vec_dict, symmetry=None):
53545383
data['input'] = 'kvector'
53555384
data['irrepcount'] = '1'
53565385

5386+
# We need to upload the CIF file to ISOCIF and export from there, since
5387+
# some of the routines for k vector form solving only works with the
5388+
# CIF coming out from ISOCIF.
5389+
init_cif = ISO.UploadCIF(parentcif, upload_site=isocifuploadsite)
5390+
isocif_up = {'submit': 'OK', 'input': 'uploadcif', 'filename': init_cif}
5391+
isocif_out_1 = requests.post(isocifformsite, data=isocif_up).text
5392+
5393+
isocif_form = re.split(
5394+
'</form',
5395+
next(
5396+
i for i in re.split('<form', isocif_out_1, flags=re.IGNORECASE)
5397+
if 'Detect higher' in i
5398+
),
5399+
flags=re.IGNORECASE
5400+
)[0]
5401+
5402+
isocif_formDict = {}
5403+
for f in isocif_form.split('<'):
5404+
try:
5405+
name = re.split('name=',f,flags=re.IGNORECASE)[1].split('"')[1]
5406+
value = re.split('value=',f,flags=re.IGNORECASE)[1].split('"')[1]
5407+
isocif_formDict[name] = value
5408+
except IndexError:
5409+
pass
5410+
isocif_formDict['input'] = 'savecif'
5411+
5412+
isocif_out_cif = requests.post(isocifformsite, data=isocif_formDict).text
5413+
53575414
kvec_dict = grab_all_kvecs(out2)
53585415
lat_sym = Phase['General']['SGData']
5359-
data_update = setup_kvec_input(kpoint, kvec_dict, symmetry=lat_sym)
5416+
data_update = setup_kvec_input(kpoint, kvec_dict, isocif_out_cif, lat_sym)
53605417
for key, value in data_update.items():
53615418
data[key] = value
53625419

GSASII/ISODISTORT.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ def HandleError(out):
2626
except:
2727
print('Could not open URL')
2828

29-
def UploadCIF(cifname):
30-
#upload cif file to BYU web site
29+
def UploadCIF(cifname, upload_site=isouploadsite):
30+
#upload cif file to BYU web site
3131
ciffile = open(cifname,'rb')
3232
up1 = {'toProcess':(cifname,ciffile),}
33-
out1 = requests.post(isouploadsite,files=up1).text
33+
out1 = requests.post(upload_site,files=up1).text
3434
ciffile.close()
3535

3636
#retrieve BYU temp file name for cif file

GSASII/k_vec_solve/k_vec_solve.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,27 +129,45 @@ def grab_user_conv_transform(trans_str):
129129
return user_to_conv
130130

131131

132-
def grab_user_conv_line(cif_file):
132+
def grab_spg_num(cif_contents):
133+
"""Grab the space group number from the '_symmetry_Int_Tables_number' line in a given CIF file.
134+
135+
Args:
136+
cif_contents (str): Contents of the CIF file.
137+
138+
Returns:
139+
str: The space group number, or None if not found.
140+
"""
141+
spg_num = None
142+
lines = cif_contents.splitlines()
143+
for line in lines:
144+
if '_symmetry_Int_Tables_number' in line:
145+
parts = line.split()
146+
if len(parts) > 1:
147+
spg_num = parts[1]
148+
break
149+
150+
return spg_num
151+
152+
153+
def grab_user_conv_line(cif_contents):
133154
"""Grab the user to conventional setting transformation from the
134155
'_space_group.transform_Pp_abc' line in a given CIF file.
135156
136157
Args:
137-
cif_file (str): Full path to the input CIF file.
158+
cif_contents (str): Contents of the CIF file.
138159
139160
Returns:
140161
str: The user to conventional setting transformation string, or None if not found.
141162
"""
142163
trans_str = None
143-
try:
144-
with open(cif_file, 'r', encoding='utf-8') as file:
145-
for line in file:
146-
if '_space_group.transform_Pp_abc' in line:
147-
parts = line.split()
148-
if len(parts) > 1:
149-
trans_str = parts[1].strip()
150-
break
151-
except FileNotFoundError:
152-
print(f"The file {cif_file} was not found.")
164+
lines = cif_contents.splitlines()
165+
for line in lines:
166+
if '_space_group.transform_Pp_abc' in line:
167+
parts = line.split()
168+
if len(parts) > 1:
169+
trans_str = parts[1].strip()
170+
break
153171

154172
return trans_str
155173

@@ -211,7 +229,7 @@ def find_kvec_form_param(spg_num, isocif_cif, k_vec, k_forms):
211229
212230
Args:
213231
spg_num (int): Space group number.
214-
isocif_cif (str): Path to the CIF file exported from ISOCIF.
232+
isocif_cif (str): Contents of the CIF file exported from ISOCIF.
215233
k_vec (list): k vector
216234
k_forms (list): List of symbolic alternative k vector forms.
217235
Entries should be in the form of sympy expressions.
@@ -243,7 +261,7 @@ def find_kvec_form_param(spg_num, isocif_cif, k_vec, k_forms):
243261
def sort_keys(dict_entry):
244262
# Sort keys by priority: a, then b, then g
245263
key_priority = {a: 1, b: 2, g: 3}
246-
return [key_priority.get(key, float('inf')) for key in dict_entry.keys()]
264+
return [key_priority.get(key, float('inf')) for key in dict_entry]
247265

248266
k_vec_pr_arms = np.matmul(k_vec_pr, ref_pt_ops[0:3, 0:3])
249267
alt_solutions = []

0 commit comments

Comments
 (0)