-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathGenJanus.py
140 lines (122 loc) · 7.17 KB
/
GenJanus.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# This script will generate an input .dat file for LAMMPS to simulate di- or tri-JBBCP self-assembly
# Authors: R.Liu & Z.Sun
defaultParams = {'xlo': 0.0, 'xhi': 13.3, 'zlo': 0.0, 'zhi': 13.3, # in-plane box range
'ylo': 0.0, 'yhi': 24.0, # height
'rho': 5.0, # bead density
'frac_sol': 0.1} # fraction of solvent beads
globals().update(defaultParams)
def JBBCP(N_backbone_pla, N_backbone_branched, N_pla, N_ps, N_pdms, **kwargs):
print('\nJBBCP config: ', end='')
if N_backbone_pla: print('[PLA%d]%d-b-'%(N_pla, N_backbone_pla), end='')
print('[PS%d-br-PDMS%d]%d'%(N_ps, N_pdms, N_backbone_branched))
params = defaultParams.copy()
params.update(kwargs)
globals().update(params) # override default parameters
print('Box config: ', end='')
print(params)
n_total_beads = round((xhi-xlo)*(yhi-ylo)*(zhi-zlo)*rho)
M_backbone = round( # total number of JBBCP macromolecules in the box
n_total_beads*(1-frac_sol)/(N_backbone_pla*(1+N_pla)+N_backbone_branched*(1+N_pdms+N_ps)))
n_sol_exact = ( # total number of solvent beads
n_total_beads)-(N_backbone_pla*(1+N_pla)+N_backbone_branched*(1+N_pdms+N_ps))*M_backbone
n_sol_rough = n_total_beads * frac_sol # the rough # solvent beads calculated from `frac_sol`, but will not rigorously lead to the set `rho` value
print("# solvent beads:")
print(" exact # =", n_sol_exact, "; rough # =", n_sol_rough)
# We will use the exact value, though in most cases, these two values do not differ much
# solvent beads will be generated by LAMMPS
AtomTypes = 7 # total number of bead types. 1=backbone; 2=B=PS; 3=A=PDMS; 4=upper boundary=air(not used); 5=lower boundary=substrate(not used); 6=solvent; 7=C=PLA
BondTypes = 1 # only one type of harmonic bonds
if N_backbone_pla:
AngleTypes = 2 # two types of angle potentials for backbones (K^A=1 for homo-C backbone and 2 for A-branch-B backbone)
outputFilename = "%dT-C%d_%d-A%dB%d_%d.dat" % (M_backbone, N_pla, N_backbone_pla, N_pdms, N_ps, N_backbone_branched)
else: # diblock
AngleTypes = 1
outputFilename = "%dD-A%dB%d_%d.dat" % (M_backbone, N_pdms, N_ps, N_backbone_branched)
# total numbers
N_backbone = N_backbone_pla + N_backbone_branched
AtomNo = M_backbone * (N_backbone_branched + N_backbone_pla + (N_pdms + N_ps) * N_backbone_branched + N_pla * N_backbone_pla)
BondNo = M_backbone * ((N_backbone_branched+N_backbone_pla - 1) + (N_pdms + N_ps) * N_backbone_branched + N_pla*N_backbone_pla)
AngleNo= (N_backbone_branched+N_backbone_pla-2) * M_backbone
# hyperparameters here. In principle, we desire more uniform initial state; in reality, it does not matter because of the premixing step
from math import ceil
x_step = N_ps+N_pdms
x_num = ceil((xhi-xlo)/x_step)
y_shift = 0.25 # if substrates are introduced, all beads should be shifted away from them (both upper and lower boundaries) in order not to get stuck
y_num = ceil(M_backbone/x_num)
y_step = (yhi-ylo-2*y_shift)/(y_num-1)
AtomList = [] # [AtomId MoleculeId AtomType charge=0 x y z]
BondList = [] # [BondId BondType A B]
AngleList= [] # [AngleId AngleType A B C]
for m in range(0, M_backbone):
for n in range(1, N_backbone + 1):
currentID = n + m * N_backbone
if n < N_backbone_pla: # Angle Type 1
AngleList.append([currentID-2*m, 1, currentID, currentID+1, currentID+2])
elif n < N_backbone-1: # Angle Type 2
AngleList.append([currentID-2*m, AngleTypes, currentID, currentID+1, currentID+2])
for n in range(1, N_backbone_pla+1):
x_pos = m // y_num * x_step
y_pos = round(m % y_num * y_step + y_shift, 3)
z_pos = n
# for AtomID, we first number all backbones, then all PLA side chains, and finally PS/PDMS side chains
currentID = n + m * N_backbone
currentPlaID = M_backbone * N_backbone + m * N_pla * N_backbone_pla + (n - 1) * N_pla
AtomList.append([currentID, m + 1, 1, 0, x_pos, y_pos, z_pos])
# we assign the same BondID to all beads on the same backbone bead
BondList.append([currentID-m, 1, currentID, currentID + 1])
BondList.append([currentID-m, 1, currentID, currentPlaID + 1])
for n_pla in range(1, N_pla + 1):
# branch points to the x+ direction if n is even; x- if odd
sign = 1-2*(n % 2)
AtomList.append([currentPlaID + n_pla, m + 1, 7, 0, x_pos + n_pla*sign, y_pos, z_pos])
if n_pla != N_pla:
BondList.append([currentID-m, 1, currentPlaID + n_pla, currentPlaID + n_pla + 1])
for n in range(N_backbone_pla+1, N_backbone+1):
x_pos = m // y_num * x_step
y_pos = round(m % y_num * y_step + y_shift, 3)
z_pos = n
currentID = n + m * N_backbone
currentPsdmsID = M_backbone * N_backbone + M_backbone * N_backbone_pla * N_pla + (
m * N_backbone_branched + n - N_backbone_pla-1) * (N_ps + N_pdms)
M_backbone * N_backbone + m * N_pla * N_backbone_pla + (n - 1) * N_pla
AtomList.append([currentID, m + 1, 1, 0, x_pos, y_pos, z_pos])
if n != N_backbone:
BondList.append([currentID-m, 1, currentID, currentID + 1])
BondList.append([currentID-m, 1, currentID, currentPsdmsID + 1])
for n_pdms in range(1, N_pdms + 1):
AtomList.append([currentPsdmsID + n_pdms, m + 1, 3, 0, x_pos + n_pdms, y_pos, z_pos])
if n_pdms != N_pdms:
BondList.append([currentID-m, 1, currentPsdmsID + n_pdms, currentPsdmsID + n_pdms + 1])
BondList.append([currentID-m, 1, currentID, currentPsdmsID + N_pdms + 1])
for n_ps in range(1, N_ps + 1):
AtomList.append([currentPsdmsID + N_pdms + n_ps, m + 1, 2, 0, x_pos - n_ps, y_pos, z_pos])
if n_ps != N_ps:
BondList.append([currentID-m, 1, currentPsdmsID + N_pdms + n_ps, currentPsdmsID + N_pdms + n_ps + 1])
f = open(outputFilename, 'w', newline='\n')
f.write('LAMMPS data file: JBBCPs in a periodic box\n\n')
f.write(str(AtomNo) + ' atoms\n')
f.write(str(AtomTypes) + ' atom types\n')
f.write(str(BondNo) + ' bonds\n')
f.write(str(BondTypes) + ' bond types\n')
f.write(str(AngleNo) + ' angles\n')
f.write(str(AngleTypes) + ' angle types\n\n')
f.write(str(xlo) + ' ' + str(xhi) + ' xlo xhi\n')
f.write(str(ylo) + ' ' + str(yhi) + ' ylo yhi\n')
f.write(str(zlo) + ' ' + str(zhi) + ' zlo zhi\n\n')
f.write('Masses\n\n')
for i in range(AtomTypes):
f.write(str(i + 1) + ' 1\n')
f.write('\nAtoms\n\n')
for i in range(AtomNo):
f.write(" ".join(map(str, AtomList[i])) + '\n')
f.write('\nBonds\n\n')
for i in range(BondNo):
f.write(" ".join(map(str, BondList[i])) + '\n')
f.write('\nAngles\n\n')
for i in range(AngleNo):
f.write(" ".join(map(str, AngleList[i])) + '\n')
f.close()
print('dat file saved to '+outputFilename)
if __name__ == '__main__':
JBBCP(0, 20, 0, 7, 4, yhi=13.3) # for diblock set N_backbone_pla=0
JBBCP(20, 20, 10, 7, 4)