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 package ffx.potential.commands;
39
40 import ffx.crystal.Crystal;
41 import ffx.crystal.SpaceGroup;
42 import ffx.crystal.SymOp;
43 import ffx.numerics.Potential;
44 import ffx.potential.ForceFieldEnergy;
45 import ffx.potential.bonded.Atom;
46 import ffx.potential.cli.PotentialCommand;
47 import ffx.utilities.FFXBinding;
48 import org.apache.commons.configuration2.CompositeConfiguration;
49 import picocli.CommandLine.Command;
50 import picocli.CommandLine.Option;
51 import picocli.CommandLine.Parameters;
52
53 import java.io.BufferedReader;
54 import java.io.BufferedWriter;
55 import java.io.File;
56 import java.io.FileReader;
57 import java.io.FileWriter;
58 import java.io.IOException;
59 import java.io.PrintWriter;
60 import java.util.ArrayList;
61 import java.util.Collections;
62 import java.util.List;
63
64 import static ffx.crystal.ReplicatesCrystal.replicatesCrystalFactory;
65 import static ffx.crystal.SpaceGroupDefinitions.spaceGroupFactory;
66 import static ffx.crystal.SpaceGroupInfo.getCCDCPercent;
67 import static ffx.crystal.SpaceGroupInfo.getPDBRank;
68 import static ffx.crystal.SymOp.applyCartesianSymOp;
69 import static ffx.crystal.SymOp.randomSymOpFactory;
70 import static java.lang.String.format;
71 import static org.apache.commons.io.FilenameUtils.getName;
72 import static org.apache.commons.io.FilenameUtils.removeExtension;
73
74
75
76
77
78
79
80 @Command(name = "PrepareSpaceGroups", description = " Create sub-directories for selected space groups.")
81 public class PrepareSpaceGroups extends PotentialCommand {
82
83
84 @Option(names = {"-r", "--PDB"}, paramLabel = "231", defaultValue = "231",
85 description = "Only consider space groups populated in the PDB above the specified rank (231 excludes none).")
86 private int rank = 231;
87
88
89 @Option(names = {"-p", "--CSD"}, paramLabel = "1.0", defaultValue = "0.0",
90 description = "Only consider space groups populated above the specified percentage in the CSD.")
91 private double percent = 0.0;
92
93
94 @Option(names = {"-c", "--chiral"}, paramLabel = "false", defaultValue = "false",
95 description = "Only consider chiral space groups.")
96 private boolean chiral = false;
97
98
99 @Option(names = {"-a", "--achiral"}, paramLabel = "false", defaultValue = "false",
100 description = "Only consider achiral space groups.")
101 private boolean achiral = false;
102
103
104 @Option(names = {"--rsym", "--randomSymOp"}, paramLabel = "Arg", defaultValue = "1.0",
105 description = "Random Cartesian sym op will choose a translation in the range -Arg .. Arg (default of 1.0 A).")
106 private double symScalar = 1.0;
107
108
109 @Option(names = {"-d", "--density"}, paramLabel = "1.0", defaultValue = "1.0",
110 description = "Random unit cell axes will be used to achieve the specified density (default of 1.0 g/cc).")
111 private double density = 1.0;
112
113
114 @Option(names = {"--sg", "--spacegroup"}, description = "Prepare a directory for a single spacegroup.")
115 private String sg;
116
117
118 @Parameters(arity = "1", paramLabel = "file",
119 description = "The atomic coordinate file in PDB or XYZ format.")
120 private String filename = null;
121
122
123 public int numberCreated = 0;
124
125 private ForceFieldEnergy energy;
126
127 public PrepareSpaceGroups() { super(); }
128 public PrepareSpaceGroups(FFXBinding binding) { super(binding); }
129 public PrepareSpaceGroups(String[] args) { super(args); }
130
131 @Override
132 public PrepareSpaceGroups run() {
133
134 if (!init()) {
135 return this;
136 }
137
138
139 System.setProperty("mpoleterm", "false");
140
141
142 System.setProperty("spacegroup", "P1");
143 System.setProperty("a-axis", "10.0");
144
145
146 activeAssembly = getActiveAssembly(filename);
147 if (activeAssembly == null) {
148 logger.info(helpString());
149 return this;
150 }
151
152
153 filename = activeAssembly.getFile().getAbsolutePath();
154
155 logger.info("\n Preparing space group directories for " + filename);
156
157 energy = activeAssembly.getPotentialEnergy();
158 CompositeConfiguration properties = activeAssembly.getProperties();
159
160 File propertyFile = new File(properties.getString("propertyFile"));
161
162 Atom[] atoms = activeAssembly.getAtomArray();
163 double mass = activeAssembly.getMass();
164 if (density < 0.0) {
165 density = 1.0;
166 }
167
168
169 String dirString = getBaseDirString(filename);
170 String name = getName(filename);
171
172 for (int num = 1; num <= 230; num++) {
173 SpaceGroup spacegroup = spaceGroupFactory(num);
174
175
176 SpaceGroup spacegroup2;
177 if (sg != null && !sg.isEmpty()) {
178 spacegroup2 = spaceGroupFactory(sg);
179 if (spacegroup2 == null) {
180 logger.info(format("\n Space group %s was not recognized.\n", sg));
181 clearProps();
182 return this;
183 }
184 if (spacegroup2.number != spacegroup.number) {
185 continue;
186 }
187 } else {
188 spacegroup2 = spacegroup;
189 }
190
191 if (chiral && !spacegroup.respectsChirality()) {
192 continue;
193 }
194
195 if (achiral && spacegroup.respectsChirality()) {
196 continue;
197 }
198
199 if (getCCDCPercent(num) < percent) {
200 continue;
201 }
202
203 if (getPDBRank(spacegroup) > rank) {
204 continue;
205 }
206
207 logger.info(format("\n Preparing %d %s (CSD percent: %7.4f, PDB Rank: %d)",
208 num, spacegroup2.shortName, getCCDCPercent(num), getPDBRank(spacegroup)));
209
210
211 String sgDirName = spacegroup2.shortName.replace('/', '_');
212 File sgDir = new File(dirString + sgDirName);
213
214 if (!sgDir.exists()) {
215 logger.info("\n Creating space group directory: " + sgDir);
216
217 sgDir.mkdir();
218 }
219
220 double[] abc = spacegroup2.latticeSystem.resetUnitCellParams();
221 Crystal crystal = new Crystal(abc[0], abc[1], abc[2], abc[3], abc[4], abc[5],
222 spacegroup2.shortName);
223 crystal.setDensity(density, mass);
224 double cutoff2 = energy.getCutoffPlusBuffer() * 2.0;
225
226 if (cutoff2 == Double.POSITIVE_INFINITY) {
227 cutoff2 = 0.1;
228 }
229 crystal = replicatesCrystalFactory(crystal, cutoff2);
230
231 crystal.setSpecialPositionCutoff(0.0);
232 crystal.getUnitCell().setSpecialPositionCutoff(0.0);
233 energy.setCrystal(crystal);
234
235 activeAssembly.moveAllIntoUnitCell();
236
237 if (symScalar > 0.0) {
238 SymOp symOp = randomSymOpFactory(symScalar);
239 logger.info(format("\n Applying random Cartesian SymOp:\n %s", symOp));
240 double[] xyz = new double[3];
241 for (Atom atom : atoms) {
242 atom.getXYZ(xyz);
243 applyCartesianSymOp(xyz, xyz, symOp);
244 atom.setXYZ(xyz);
245 }
246 }
247
248
249 File sgFile = new File(sgDir.getAbsolutePath() + File.separator + name);
250 logger.info(" Saving " + sgDirName + " coordinates to: " + sgFile);
251 potentialFunctions.save(activeAssembly, sgFile);
252
253 File keyFile = new File(removeExtension(sgFile.getAbsolutePath()) + ".properties");
254 logger.info(" Saving " + sgDirName + " properties to: " + keyFile);
255
256 numberCreated++;
257
258
259 try (BufferedReader keyReader = new BufferedReader(new FileReader(propertyFile));
260 PrintWriter keyWriter = new PrintWriter(new BufferedWriter(new FileWriter(keyFile)))) {
261 String line;
262 while ((line = keyReader.readLine()) != null) {
263 line = line.trim();
264 if (!line.isEmpty()) {
265 String[] tokens = line.split(" +");
266 if (tokens.length > 1) {
267 String first = tokens[0].toLowerCase();
268 if (first.equals("a-axis") || first.equals("b-axis") || first.equals("c-axis") ||
269 first.equals("alpha") || first.equals("beta") || first.equals("gamma") ||
270 first.equals("spacegroup")) {
271
272 logger.fine(format(" Updating : %s", line));
273 } else if (first.equals("parameters")) {
274 if (tokens.length > 1) {
275 if (tokens[1].startsWith("/") || tokens[1].startsWith("\\")) {
276
277 keyWriter.println(format("parameters %s", tokens[1]));
278 } else {
279 keyWriter.println(format("parameters ../%s", tokens[1]));
280 }
281 } else {
282 logger.warning("Parameter file may not have been specified");
283 }
284 } else {
285 keyWriter.println(line);
286 }
287 } else {
288 keyWriter.println(line);
289 }
290 }
291 }
292
293
294 keyWriter.println(format("spacegroup %s", spacegroup2.shortName));
295 Crystal unitCell = crystal.getUnitCell();
296 keyWriter.println(format("a-axis %12.8f", unitCell.a));
297 keyWriter.println(format("b-axis %12.8f", unitCell.b));
298 keyWriter.println(format("c-axis %12.8f", unitCell.c));
299 keyWriter.println(format("alpha %12.8f", unitCell.alpha));
300 keyWriter.println(format("beta %12.8f", unitCell.beta));
301 keyWriter.println(format("gamma %12.8f", unitCell.gamma));
302 } catch (IOException ex) {
303 logger.warning(" Exception writing keyfile." + ex);
304 }
305 }
306
307 clearProps();
308 return this;
309 }
310
311 private static void clearProps() {
312
313 System.clearProperty("mpoleterm");
314 System.clearProperty("spacegroup");
315 System.clearProperty("a-axis");
316 }
317
318 @Override
319 public List<Potential> getPotentials() {
320 if (energy == null) {
321 return Collections.emptyList();
322 } else {
323 List<Potential> list = new ArrayList<>();
324 list.add(energy);
325 return list;
326 }
327 }
328 }