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.numerics.switching;
39
40 import static java.lang.Boolean.parseBoolean;
41 import static java.lang.Double.parseDouble;
42 import static java.lang.String.format;
43 import static java.util.Arrays.copyOfRange;
44
45 import java.util.Arrays;
46
47 /**
48 * Static class responsible for parsing String arrays into univariate switching functions.
49 *
50 * @author Jacob M. Litman
51 * @author Michael J. Schnieders
52 */
53 public class UnivariateFunctionFactory {
54
55 /** Static only class. */
56 private UnivariateFunctionFactory() {
57 }
58
59 /**
60 * Parse an array of Strings terminating in the description of a univariate switching function.
61 *
62 * @param toks Array of Strings, terminating with the description of a function.
63 * @param offset Index of the first relevant token.
64 * @return A parsed univariate switching function.
65 */
66 public static UnivariateSwitchingFunction parseUSF(String[] toks, int offset) {
67 return parseUSF(copyOfRange(toks, offset, toks.length));
68 }
69
70 /**
71 * Parse an array of Strings describing a univariate switching function.
72 *
73 * @param toks Descriptive Strings.
74 * @return A parsed univariate switching function.
75 */
76 public static UnivariateSwitchingFunction parseUSF(String[] toks) {
77 String selectionString = toks[0].toUpperCase()
78 .replaceAll("-", "")
79 .replaceAll("_", "")
80 .replaceAll(" ", "");
81 return switch (selectionString) {
82 case "BELL", "BELLCURVE", "BELLCURVESWITCH" -> parseBell(toks);
83 case "CONSTANT", "NONE", "FLAT" -> new ConstantSwitch();
84 case "LINEARDERIVATIVE" -> new LinearDerivativeSwitch();
85 case "MULTIPLICATIVE", "PENTICHERMITE" -> parseMultiplicative(toks);
86 case "POWER" -> parsePower(toks);
87 case "LINEAR" -> parseSpecificPow(1.0, toks);
88 case "QUADRATIC" -> parseSpecificPow(2.0, toks);
89 case "CUBIC" -> parseSpecificPow(3.0, toks);
90 case "TRIGONOMETRIC", "TRIG", "SINSQUARED" -> parseTrig(toks);
91 default -> throw new IllegalArgumentException(
92 format(" Could not parse %s as a valid univariate switching function!",
93 Arrays.toString(toks)));
94 };
95 }
96
97 private static BellCurveSwitch parseBell(String[] toks) {
98 double midpoint = 0.5;
99 if (toks.length > 2) {
100 midpoint = parseDouble(toks[1]);
101 }
102 double width = 1.0;
103 if (toks.length > 3) {
104 width = parseDouble(toks[2]);
105 }
106 return new BellCurveSwitch(midpoint, width);
107 }
108
109 private static MultiplicativeSwitch parseMultiplicative(String[] toks) {
110 if (toks.length > 3) {
111 return new MultiplicativeSwitch(parseDouble(toks[2]), parseDouble(toks[1]));
112 } else {
113 return new MultiplicativeSwitch();
114 }
115 }
116
117 private static PowerSwitch parsePower(String[] toks) {
118 double pow = 1.0;
119 if (toks.length > 1) {
120 pow = parseDouble(toks[1]);
121 }
122 double alpha = 1.0;
123 if (toks.length > 2) {
124 alpha = parseDouble(toks[2]);
125 }
126 return new PowerSwitch(alpha, pow);
127 }
128
129 private static PowerSwitch parseSpecificPow(double pow, String[] toks) {
130 double alpha = 1.0;
131 if (toks.length > 1) {
132 alpha = parseDouble(toks[1]);
133 }
134 return new PowerSwitch(alpha, pow);
135 }
136
137 private static SquaredTrigSwitch parseTrig(String[] toks) {
138 boolean trig = false;
139 if (toks.length > 1) {
140 trig = parseBoolean(toks[1]);
141 }
142 if (toks.length > 2) {
143 return new SquaredTrigSwitch(parseDouble(toks[2]), trig);
144 } else {
145 return new SquaredTrigSwitch(trig);
146 }
147 }
148 }