Skip to content

Commit ad0e99a

Browse files
committed
change relative to abs distances for atoms perturbation
1 parent 091948e commit ad0e99a

File tree

6 files changed

+98
-102
lines changed

6 files changed

+98
-102
lines changed

README.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,12 @@ tuple(1,2,3) means don't copy atom configuration in x direction, make 2 copys in
163163

164164
# perturb
165165
dpdata will disturb the box size and shape and change atom coordinates randomly.
166-
```python3
167-
dpdata.System('./POSCAR').perturb(pert_num=3,
168-
box_pert_fraction=0.1,
169-
atom_pert_fraction=0.05,
166+
```python
167+
perturbed_system = dpdata.System('./POSCAR').perturb(pert_num=3,
168+
box_pert_fraction=0.05,
169+
atom_pert_distance=0.6,
170170
atom_pert_style='normal')
171+
print(perturbed_system.data)
171172
```
172173

173174
### `pert_num`
@@ -179,16 +180,13 @@ That means the command will return a system containing `frames of input system *
179180
A relative length that determines the length the box size change in each frame. It is just a fraction and doesn't have unit. Typlicaly, for cubic box with side length `side_length` , `side_length` will increase or decrease a random value from the intervel `[-side_length*box_pert_fraction, side_length*box_pert_fraction]`.
180181

181182
It will also change the shape of the box. That means an orthogonal box will become a non-orthogonal box after perturbing. The angle of inclination of the box is a random variable.
182-
`box_pert_fraction` is also relating to the probability distribution function of the angle.
183-
184-
See more details about how it will change the box below.
183+
`box_pert_fraction` is also relating to the probability distribution function of the angle.
185184

186-
### `atom_pert_fraction`
187-
A relative length that determines the length atom moves in each frame. It is just a fraction and doesn't have unit. Typlicaly, for a cubic box with side length `side_length` , the mean value of the distance that atom moves is approximate `a*atom_pert_fraction`.
185+
### `atom_pert_distance`
186+
unit:Angstrom. Determine the distance atoms move in each frame.
187+
The mean value of the distance that atom moves is about `atom_pert_distance`.
188188

189189
### `atom_pert_style`
190190
The probability distribution function used to change atom coordinates.
191-
available options:`'uniform' 'normal' 'const'`.
192-
191+
available options:`'uniform', 'normal', 'const'`.
193192
The direction atoms move and box deformation is random.
194-

dpdata/system.py

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ def replicate(self, ncopy):
627627
def perturb(self,
628628
pert_num,
629629
box_pert_fraction,
630-
atom_pert_fraction,
630+
atom_pert_distance,
631631
atom_pert_style='normal'):
632632
"""
633633
Perturb each frame in the system randomly.
@@ -643,23 +643,22 @@ def perturb(self,
643643
box_pert_fraction : float
644644
A fraction determines how much will box deform, typically less than 0.3.
645645
For a cubic box with side length `side_length`,
646-
`side_length` will increase or decrease with the max length `box_pert_fraction*side_length` .
646+
`side_length` will increase or decrease with the max value `box_pert_fraction*side_length` .
647647
If box_pert_fraction is not zero, the shape of the box will also be changed,
648-
and that means a orthogonal box will become a non-orthogonal box.
649-
atom_pert_fraction : float
650-
A fraction determines how far will atoms move, typically less than 0.3.
651-
For a cubic box with side length `side_length`,
652-
atoms will move about `atom_pert_fraction*side_length` in random direction.
653-
The distribution of the distance atoms move is also determined by atom_pert_style
654-
atom_pert_fraction : str
648+
and that means a orthogonal box will become a non-orthogonal one.
649+
atom_pert_distance: float
650+
unit: Angstrom. A distance determines how far atoms will move.
651+
Atoms will move about `atom_pert_distance` in random direction.
652+
The distribution of the distance atoms move is determined by atom_pert_style
653+
atom_pert_style : str
655654
Determines the distribution of the distance atoms move is subject to.
656655
Avaliable options are
657656
- `'normal'`: the `distance` will be object to `chi-square distribution with 3 degrees of freedom` after normalization.
658-
The mean value of the distance is about `atom_pert_fraction*side_length`
659-
- `'uniform'`: will generate uniformly random points in a 3D-balls and transform these points linearly as vectors to be used by atoms.
660-
And the max length of the distance atoms move is about `atom_pert_fraction*side_length`
661-
- `'const'`: The distance atoms move will be a constant `atom_pert_fraction*side_length` for cubic box.
662-
And for other shape boxes, the distance will not be constant
657+
The mean value of the distance is `atom_pert_fraction*side_length`
658+
- `'uniform'`: will generate uniformly random points in a 3D-balls with radius as `atom_pert_distance`.
659+
These points are treated as vector used by atoms to move.
660+
Obviously, the max length of the distance atoms move is `atom_pert_distance`.
661+
- `'const'`: The distance atoms move will be a constant `atom_pert_distance`.
663662
664663
Returns
665664
-------
@@ -675,9 +674,8 @@ def perturb(self,
675674
tmp_system.data['cells'][0] = np.matmul(tmp_system.data['cells'][0],box_perturb_matrix)
676675
tmp_system.data['coords'][0] = np.matmul(tmp_system.data['coords'][0],box_perturb_matrix)
677676
for kk in range(len(tmp_system.data['coords'][0])):
678-
atom_perturb_vector = get_atom_perturb_vector(atom_pert_fraction, atom_pert_style)
679-
atom_delta_vector = np.matmul(atom_perturb_vector,tmp_system.data['cells'][0])
680-
tmp_system.data['coords'][0][kk] += atom_delta_vector
677+
atom_perturb_vector = get_atom_perturb_vector(atom_pert_distance, atom_pert_style)
678+
tmp_system.data['coords'][0][kk] += atom_perturb_vector
681679
tmp_system.rot_lower_triangular()
682680
perturbed_system.append(tmp_system)
683681
return perturbed_system
@@ -694,28 +692,28 @@ def get_box_perturb_matrix(box_pert_fraction):
694692
)
695693
return box_pert_matrix
696694

697-
def get_atom_perturb_vector(atom_pert_fraction, atom_pert_style='normal'):
695+
def get_atom_perturb_vector(atom_pert_distance, atom_pert_style='normal'):
698696
random_vector = None
699-
if atom_pert_fraction < 0:
700-
raise RuntimeError('atom_pert_fraction can not be negative')
697+
if atom_pert_distance < 0:
698+
raise RuntimeError('atom_pert_distance can not be negative')
701699

702700
if atom_pert_style == 'normal':
703701
e = np.random.randn(3)
704-
random_vector=(atom_pert_fraction/np.sqrt(3))*e
702+
random_vector=(atom_pert_distance/np.sqrt(3))*e
705703
elif atom_pert_style == 'uniform':
706704
e = np.random.randn(3)
707705
while np.linalg.norm(e) < 0.1:
708706
e = np.random.randn(3)
709707
random_unit_vector = e/np.linalg.norm(e)
710708
v0 = np.random.rand(1)
711709
v = np.power(v0,1/3)
712-
random_vector = atom_pert_fraction*v*random_unit_vector
710+
random_vector = atom_pert_distance*v*random_unit_vector
713711
elif atom_pert_style == 'const' :
714712
e = np.random.randn(3)
715713
while np.linalg.norm(e) < 0.1:
716714
e = np.random.randn(3)
717715
random_unit_vector = e/np.linalg.norm(e)
718-
random_vector = atom_pert_fraction*random_unit_vector
716+
random_vector = atom_pert_distance*random_unit_vector
719717
else:
720718
raise RuntimeError('unsupported options atom_pert_style={}'.format(atom_pert_style))
721719
return random_vector

tests/poscars/POSCAR.SiC.const

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
C4 Si4
22
1.0
3-
3.9821590818265662e+00 -6.3518285952025531e-18 -1.3636822777448101e-18
4-
1.4441625743554549e-02 3.8797851714535434e+00 -3.8802125261354576e-18
5-
2.7058404544835651e-01 5.0846848186579174e-01 4.0806630199703786e+00
3+
3.9448633066729739e+00 -3.6344794672422329e-18 1.1581293029516294e-17
4+
1.6817409381958889e-01 4.0320777239133783e+00 -8.7954588948930866e-19
5+
1.4551929935812052e-01 3.9989012843738053e-01 3.9977352939318109e+00
66
C Si
77
4 4
88
Cartesian
9-
-0.1284024102 0.0411632429 2.5392886616
10-
1.6605207719 -0.0253819250 0.3618554716
11-
0.1640583101 2.1563760674 0.4480081454
12-
2.1989105171 1.7886495520 2.0950553386
13-
-0.1078475228 0.2108036732 -0.3228714337
14-
1.8447569702 2.1025290971 -0.4494344734
15-
1.6511638763 -0.0784401477 1.9721672179
16-
-0.0382262924 1.6485487817 1.9674381019
9+
0.0946327782 -0.2781320996 1.6927633385
10+
2.1395921916 -0.5505295607 0.3561009428
11+
-0.2623111485 2.0403483142 0.5289485573
12+
2.0291102621 2.0166734366 1.4189102698
13+
-0.4274609464 0.4275845699 -0.2870878166
14+
1.8398859643 1.9175800522 -0.7344827910
15+
1.5794721062 0.2698516856 1.5600233361
16+
0.2272461445 2.4170250626 2.4545090907

tests/poscars/POSCAR.SiC.normal

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
C4 Si4
22
1.0
3-
4.0972699470293215e+00 1.0149069314692106e-18 -1.2199095357777910e-17
4-
1.0494335660165277e-01 4.0313628735769402e+00 -4.8506301604322156e-19
5-
4.3100124938951284e-01 4.1459063237657107e-01 4.1291342816555661e+00
3+
4.0354487481064565e+00 1.1027270790560616e-17 2.5642993008475204e-17
4+
2.0693526054669642e-01 4.1066892997402196e+00 -8.6715682899078028e-18
5+
4.2891472979598610e-01 5.5796885749827474e-01 4.1100061517204542e+00
66
C Si
77
4 4
88
Cartesian
9-
-0.3125685718 0.3578306188 2.6198865483
10-
2.0773182946 -0.1374738727 0.1909202951
11-
-0.0358416028 2.2809266017 0.5372668691
12-
2.1005017067 2.2434342103 2.4385806771
13-
-0.1565383829 0.1676212247 -0.0494987290
14-
1.7296257122 1.9113469908 -0.0379209714
15-
2.4121509301 0.3178978635 2.4128037669
16-
-0.0098316038 1.8287827235 2.0661147519
9+
0.2840021179 -0.6003817253 2.7192043932
10+
1.7870636884 0.4043686026 -0.3468222936
11+
-0.4647946470 2.0243215781 -0.0624256251
12+
2.1747504767 2.0704389063 2.4228997681
13+
-0.3817468326 0.0611851697 0.1116535817
14+
2.1483270977 2.3528212071 -0.3719335435
15+
2.4540854549 0.7297685673 1.8434611305
16+
0.1075358778 2.0300985762 2.0687710181

tests/poscars/POSCAR.SiC.uniform

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
C4 Si4
22
1.0
3-
4.0393044668683302e+00 3.7866840715513190e-18 -3.4832403817178164e-18
4-
2.4199759881076477e-01 4.1312396844887331e+00 2.2713212548364351e-17
5-
4.4481025327383367e-01 2.0732581915669496e-01 4.0512745001512140e+00
3+
4.0817852422279959e+00 -8.0334347485565818e-20 1.4195449766884313e-17
4+
1.2315711101650186e-01 3.7860044730134366e+00 -1.7522489439993958e-18
5+
4.0639226354941010e-01 3.2444019947671882e-01 4.2124083393682454e+00
66
C Si
77
4 4
88
Cartesian
9-
-0.2187320173 -0.3278268312 1.9808168543
10-
1.7325893560 -0.2907437704 -0.1316407092
11-
0.1697204408 2.0456083784 -0.0881243869
12-
2.2762667222 2.3246948417 1.8605727611
13-
-0.0627770396 0.1611339796 0.0659268519
14-
2.0190368430 1.8199315498 -0.3333978387
15-
2.2452379290 -0.0729729887 2.3597409002
16-
0.0376749365 1.7102483986 2.1298706088
9+
-0.1022885809 0.5553879154 2.3401729917
10+
1.4574918226 -0.0391762715 0.0190932943
11+
-0.0904993945 1.7684440711 -0.1710987880
12+
2.0638159391 2.1681985074 2.4580083474
13+
-0.3261354126 0.1759255681 0.2236316249
14+
2.0738703301 2.3024191125 -0.5031567813
15+
2.3488610334 0.3825072268 1.7330866249
16+
-0.0534780340 1.5938442575 1.8486892947

tests/test_perturb.py

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,22 @@ def rand(self,number):
1818
@staticmethod
1919
def get_randn_generator():
2020
data = np.asarray([
21-
[-1.67097394, 1.00565478, 1.75499669],
22-
[ 0.40123822, -0.26832357, 0.51643976],
23-
[-0.70325165, 0.50154408, 1.98677553],
24-
[-0.13296745, 0.55434201, 1.54581177],
25-
[-0.44232103, 0.25854521, -0.43925698],
26-
[-0.86827367, -0.27676856, 0.44365476],
27-
[0.92187855, 1.09601508, 1.56535943],
28-
[-0.61866517, -0.96390108, -0.09593058]])
21+
[ 0.71878148, -2.20667426, 1.49373955],
22+
[-0.42728113, 1.43836059, -1.17553854],
23+
[-1.70793073, -0.39588759, -0.40880927],
24+
[ 0.17078291, -0.34856352, 1.04307936],
25+
[-0.99103413, -0.1886479, 0.13813131],
26+
[ 0.5839343, 1.04612646, -0.62631026],
27+
[ 0.9752889, 1.85932517, -0.47875828],
28+
[-0.23977172, -0.38373444, -0.04375488]])
2929
count = 0
3030
while True:
3131
yield data[count]
3232
count +=1
3333

3434
@staticmethod
3535
def get_rand_generator():
36-
yield np.asarray([0.38114487,0.68166018,0.72880982,0.59149848,0.9529526,0.4403747 ])
36+
yield np.asarray([0.23182233, 0.87106847, 0.68728511, 0.94180274, 0.92860453, 0.69191187])
3737

3838
class UniformGenerator(object):
3939
def __init__(self):
@@ -46,14 +46,14 @@ def rand(self,number):
4646

4747
@staticmethod
4848
def get_randn_generator():
49-
data = [[-0.6338632, -0.80482399, -0.51334222],
50-
[-1.18911393, -1.24521526, -1.34214803],
51-
[ 0.20640311, -0.52666381, -0.71929358],
52-
[ 0.51478689, 1.11296436, -0.61690281],
53-
[-0.77160527, 1.11681373, 0.31440837],
54-
[ 0.71732744, -1.56937797, -1.60701756],
55-
[ 0.6121493, -0.06944649, 2.58409679],
56-
[-0.86858833, -1.44664272, 0.40813879]]
49+
data = [[-0.19313281, 0.80194715, 0.14050915],
50+
[-1.47859926, 0.12921667, -0.17632456],
51+
[-0.60836805, -0.7700423, -0.8386948 ],
52+
[-0.03236753, 0.36690245, 0.5041072 ],
53+
[-1.59366933, 0.37069227, 0.89608291],
54+
[ 0.18165617, 0.53875315, -0.42233955],
55+
[ 0.74052496, 1.26627555, -1.12094823],
56+
[-0.89610092, -1.44247021, -1.3502529 ]]
5757
yield np.asarray([0.0001,0.0001,0.0001]) # test for not using small vector
5858
count = 0
5959
while True:
@@ -62,12 +62,12 @@ def get_randn_generator():
6262

6363
@staticmethod
6464
def get_rand_generator():
65-
data = np.asarray([[0.96216328], [0.50364801],
66-
[0.10566744], [0.82063694],
67-
[0.00212345], [0.3384801],
68-
[0.75329772], [0.59874454]])
65+
data = np.asarray([[0.71263084], [0.61339295],
66+
[0.22948181], [0.36087632],
67+
[0.17582222], [0.97926742],
68+
[0.84706761], [0.44495513]])
6969

70-
yield np.asarray([0.24009826,0.9346383,0.54357125,0.05932848,0.96751515,0.78645846])
70+
yield np.asarray([0.34453551, 0.0618966, 0.9327273, 0.43013654, 0.88624993, 0.48827425])
7171
count =0
7272
while True:
7373
yield np.asarray(data[count])
@@ -84,14 +84,14 @@ def rand(self,number):
8484

8585
@staticmethod
8686
def get_randn_generator():
87-
data = [[-0.37656207, -0.50545915, 1.23769463],
88-
[-0.77863147, 0.05874498, 0.81611906],
89-
[0.557889, 0.36082455, 1.89695245],
90-
[ 1.07846313, -1.07323247, 0.18513304],
91-
[-0.19418326, 0.75757126, -1.90317556],
92-
[ 0.16438486, 1.40294282, -1.6183854 ],
93-
[-1.71033533, -0.73018772, -0.19946578],
94-
[-0.29332031, -2.00584426, -0.49622181]]
87+
data = np.asarray([[ 0.95410606, -1.62338002, -2.05359934],
88+
[ 0.69213769, -1.26008667, 0.77970721],
89+
[-1.77926476, -0.39227219, 2.31677298],
90+
[ 0.08785233, -0.03966649, -0.45325656],
91+
[-0.53860887, 0.42536802, -0.46167309],
92+
[-0.26865791, -0.19901684, -2.51444768],
93+
[-0.31627314, 0.22076982, -0.36032225],
94+
[0.66731887, 1.2505806, 1.46112938]])
9595
yield np.asarray([0.0001,0.0001,0.0001]) # test for not using small vector
9696
count = 0
9797
while True:
@@ -100,7 +100,7 @@ def get_randn_generator():
100100

101101
@staticmethod
102102
def get_rand_generator():
103-
yield np.asarray([0.10497343,0.30020419,0.60592304, 0.85344648, 0.60080211, 0.22293347])
103+
yield np.asarray([0.01525907, 0.68387374, 0.39768541, 0.55596047, 0.26557088, 0.60883073])
104104

105105
# %%
106106
class TestPerturbNormal(unittest.TestCase, CompSys):
@@ -109,7 +109,7 @@ def setUp (self, random_mock):
109109
random_mock.rand = NormalGenerator().rand
110110
random_mock.randn = NormalGenerator().randn
111111
system_1_origin = dpdata.System('poscars/POSCAR.SiC',fmt='vasp/poscar')
112-
self.system_1 = system_1_origin.perturb(1,0.05,0.1,'normal')
112+
self.system_1 = system_1_origin.perturb(1,0.05,0.6,'normal')
113113
self.system_2 = dpdata.System('poscars/POSCAR.SiC.normal',fmt='vasp/poscar')
114114
self.places = 6
115115

@@ -119,7 +119,7 @@ def setUp (self, random_mock) :
119119
random_mock.rand = UniformGenerator().rand
120120
random_mock.randn = UniformGenerator().randn
121121
system_1_origin = dpdata.System('poscars/POSCAR.SiC',fmt='vasp/poscar')
122-
self.system_1 = system_1_origin.perturb(1,0.05,0.1,'uniform')
122+
self.system_1 = system_1_origin.perturb(1,0.05,0.6,'uniform')
123123
self.system_2 = dpdata.System('poscars/POSCAR.SiC.uniform',fmt='vasp/poscar')
124124
self.places = 6
125125

@@ -129,7 +129,7 @@ def setUp (self, random_mock) :
129129
random_mock.rand = ConstGenerator().rand
130130
random_mock.randn = ConstGenerator().randn
131131
system_1_origin = dpdata.System('poscars/POSCAR.SiC',fmt='vasp/poscar')
132-
self.system_1 = system_1_origin.perturb(1,0.05,0.1,'const')
132+
self.system_1 = system_1_origin.perturb(1,0.05,0.6,'const')
133133
self.system_2 = dpdata.System('poscars/POSCAR.SiC.const',fmt='vasp/poscar')
134134
self.places = 6
135135

0 commit comments

Comments
 (0)