1 //****************************************************************************** 2 // 3 // Title: Force Field X. 4 // Description: Force Field X - Software for Molecular Biophysics. 5 // Copyright: Copyright (c) Michael J. Schnieders 2001-2025. 6 // 7 // This file is part of Force Field X. 8 // 9 // Force Field X is free software; you can redistribute it and/or modify it 10 // under the terms of the GNU General Public License version 3 as published by 11 // the Free Software Foundation. 12 // 13 // Force Field X is distributed in the hope that it will be useful, but WITHOUT 14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 // details. 17 // 18 // You should have received a copy of the GNU General Public License along with 19 // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple 20 // Place, Suite 330, Boston, MA 02111-1307 USA 21 // 22 // Linking this library statically or dynamically with other modules is making a 23 // combined work based on this library. Thus, the terms and conditions of the 24 // GNU General Public License cover the whole combination. 25 // 26 // As a special exception, the copyright holders of this library give you 27 // permission to link this library with independent modules to produce an 28 // executable, regardless of the license terms of these independent modules, and 29 // to copy and distribute the resulting executable under terms of your choice, 30 // provided that you also meet, for each linked independent module, the terms 31 // and conditions of the license of that module. An independent module is a 32 // module which is not derived from or based on this library. If you modify this 33 // library, you may extend this exception to your version of the library, but 34 // you are not obligated to do so. If you do not wish to do so, delete this 35 // exception statement from your version. 36 // 37 //****************************************************************************** 38 package ffx.algorithms.commands.test; 39 40 import edu.rit.pj.Comm; 41 import ffx.algorithms.cli.AlgorithmsCommand; 42 import ffx.utilities.FFXCommand; 43 import ffx.utilities.FFXBinding; 44 import picocli.CommandLine.Command; 45 import picocli.CommandLine.Option; 46 import picocli.CommandLine.Unmatched; 47 48 import java.util.ArrayList; 49 import java.util.List; 50 51 import static java.lang.String.format; 52 53 /** 54 * The ManyBodyPhScan script runs a pH scan with ManyBody optimization by executing another 55 * FFXScript multiple times across a pH range. It uses MPI for parallel execution. 56 * <br> 57 * Usage: 58 * <br> 59 * ffxc test.ManyBodyPhScan [options] <script-name> [script-args...] 60 */ 61 @Command(description = " Run a pH Scan with ManyBody.", name = "test.ManyBodyPHScan") 62 public class ManyBodyPhScan extends AlgorithmsCommand { 63 64 /** 65 * --spH --startpH Lower end of the pH range to be evaluated. 66 */ 67 @Option(names = {"--spH", "--startpH"}, paramLabel = "0.0", defaultValue = "0.0", 68 description = "Lower end of the pH range to be evaluated.") 69 private double start; 70 71 /** 72 * --epH --endpH Upper end of the pH range to be evaluated. 73 */ 74 @Option(names = {"--epH", "--endpH"}, paramLabel = "14.0", defaultValue = "14.0", 75 description = "Upper end of the pH range to be evaluated.") 76 private double end; 77 78 /** 79 * --ns --nSteps Number of steps for the given pH range. 80 */ 81 @Option(names = {"--ns", "--nSteps"}, paramLabel = "2.0", defaultValue = "2.0", 82 description = "Number of steps for a given pH range.") 83 private double nSteps; 84 85 /** 86 * The final argument(s) should be one or more filenames. 87 */ 88 @Unmatched 89 private List<String> unmatched; 90 91 /** 92 * ManyBodyPhScan Constructor. 93 */ 94 public ManyBodyPhScan() { 95 super(); 96 } 97 98 /** 99 * ManyBodyPhScan Constructor. 100 * @param binding The Binding to use. 101 */ 102 public ManyBodyPhScan(FFXBinding binding) { 103 super(binding); 104 } 105 106 /** 107 * ManyBodyPhScan constructor that sets the command line arguments. 108 * @param args Command line arguments. 109 */ 110 public ManyBodyPhScan(String[] args) { 111 super(args); 112 } 113 114 /** 115 * {@inheritDoc} 116 */ 117 @Override 118 public ManyBodyPhScan run() { 119 120 if (!init()) { 121 return this; 122 } 123 124 // Set a flag to avoid double use of MPI in downstream commands. 125 System.setProperty("pj.use.mpi", "false"); 126 127 Class<? extends FFXCommand> script = FFXCommand.getCommand(unmatched.get(0)); 128 Comm world = Comm.world(); 129 int numProc = world.size(); 130 int rank = world.rank(); 131 132 if (numProc > 1) { 133 logger.info(format(" Number of processes: %d", numProc)); 134 logger.info(format(" Rank of this process: %d", rank)); 135 } 136 137 // Remove ManyBodyPHScan command. 138 unmatched.remove(0); 139 140 double stepSize = (end - start) / (nSteps - 1); 141 142 int pHIndex = unmatched.indexOf("0.0"); 143 for (int i = 0; i < nSteps; i++) { 144 double pHValue = start + (stepSize * i); 145 List<String> commandArgs = new ArrayList<>(); 146 for (String arg : unmatched) { 147 unmatched.set(pHIndex, String.valueOf(pHValue)); 148 commandArgs.add(arg); 149 } 150 151 // Create a Binding for command line arguments. 152 FFXBinding binding = new FFXBinding(); 153 binding.setVariable("args", commandArgs); 154 155 try { 156 FFXCommand command = script.getDeclaredConstructor().newInstance(); 157 command.setBinding(binding); 158 command.run(); 159 } catch (Exception e) { 160 logger.info(format(" Exception for pH value: %s", pHValue)); 161 } 162 } 163 // Clear the pj.use.mpi flag. 164 System.clearProperty("pj.use.mpi"); 165 166 return this; 167 168 } 169 }