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.xray.scatter;
39
40 import java.util.HashMap;
41 import java.util.logging.Logger;
42
43 /**
44 * Represents neutron scattering parameters for a given atom, including its name, atomic number,
45 * and form factor.
46 * <p>
47 * This class uses a static cache to store precomputed neutron scattering parameters for atoms
48 * and allows for retrieval of these parameters by atom name.
49 *
50 * @see <a href="https://www.ncnr.nist.gov/resources/n-lengths/list.html" target="_blank">
51 * NIST Center for Neutron Research</a>
52 * @see <a href="http://dx.doi.org/10.1107/97809553602060000594" target="_blank"> V. F. Sears, Int.
53 * Tables Vol. C (2006). Table 4.4.4.1</a>
54 * @see <a href="http://dx.doi.org/10.1107/97809553602060000600" target="_blank"> B. T. M. Willis,
55 * Int. Tables Vol. C (2006). Chapter 6.1.3</a>
56 *
57 * @author Michael J. Schnieders
58 * @since 1.0
59 */
60 public record NeutronScatteringParameters(String name, int atomicNumber, double[] formFactor) {
61
62 private static final Logger logger = Logger.getLogger(NeutronScatteringParameters.class.getName());
63
64 /**
65 * Retrieves the neutron scattering parameters (form factor) for a specified atom.
66 * If the atom does not exist in the form factors map, returns null.
67 *
68 * @param atom the name of the atom for which the form factor is requested
69 * @return the neutron scattering parameters for the specified atom,
70 * or null if the atom is not found in the form factors map
71 */
72 public static NeutronScatteringParameters getFormFactor(String atom) {
73 if (formfactors.containsKey(atom)) {
74 return formfactors.get(atom);
75 } else {
76 String message = " Form factor for atom: " + atom + " not found!";
77 logger.severe(message);
78 }
79 return null;
80 }
81
82 /**
83 * Cache of created form factors.
84 */
85 private static final HashMap<String, NeutronScatteringParameters> formfactors = new HashMap<>();
86
87 private static final String[] atomNames = {
88 "H", "D", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S",
89 "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge",
90 "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In",
91 "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Sm", "Eu", "Gd", "Tb", "Dy",
92 "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb",
93 "Bi", "Th", "U"
94 };
95 private static final String[] atomicNumbers = {
96 "1_1", "1_2", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16",
97 "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32",
98 "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
99 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "62", "63", "64", "65", "66",
100 "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82",
101 "83", "90", "92"
102 };
103 private static final double[][] neutronFormFactors = {
104 {-3.7390, 0.0}, // H
105 {6.671, 0.0}, // D
106 {3.26, 0.0}, // He
107 {-1.90, 0.0}, // Li
108 {7.79, 0.0}, // Be
109 {5.30, 0.213}, // B
110 {6.6460, 0.0}, // C
111 {9.36, 0.0}, // N
112 {5.803, 0.0}, // O
113 {5.654, 0.0}, // F
114 {4.566, 0.0}, // Ne
115 {3.63, 0.0}, // Na
116 {5.375, 0.0}, // Mg
117 {3.449, 0.0}, // Al
118 {4.1491, 0.0}, // Si
119 {5.13, 0.0}, // P
120 {2.847, 0.0}, // S
121 {9.5770, 0.0}, // Cl
122 {1.909, 0.0}, // Ar
123 {3.67, 0.0}, // K
124 {4.70, 0.0}, // Ca
125 {12.29, 0.0}, // Sc
126 {-3.370, 0.0}, // Ti
127 {-0.3824, 0.0}, // V
128 {3.635, 0.0}, // Cr
129 {-3.750, 0.0}, // Mn
130 {9.45, 0.0}, // Fe
131 {2.49, 0.0}, // Co
132 {10.3, 0.0}, // Ni
133 {7.718, 0.0}, // Cu
134 {5.60, 0.0}, // Zn
135 {7.288, 0.0}, // Ga
136 {8.185, 0.0}, // Ge
137 {6.58, 0.0}, // As
138 {7.970, 0.0}, // Se
139 {6.795, 0.0}, // Br
140 {7.81, 0.0}, // Kr
141 {7.09, 0.0}, // Rb
142 {7.02, 0.0}, // Sr
143 {7.75, 0.0}, // Y
144 {7.16, 0.0}, // Zr
145 {7.054, 0.0}, // Nb
146 {6.715, 0.0}, // Mo
147 {6.80, 0.0}, // Tc
148 {7.03, 0.0}, // Ru
149 {5.88, 0.0}, // Rh
150 {5.91, 0.0}, // Pd
151 {5.922, 0.0}, // Ag
152 {4.87, -0.70}, // Cd
153 {4.065, -0.0539}, // In
154 {6.225, 0.0}, // Sn
155 {5.57, 0.0}, // Sb
156 {5.80, 0.0}, // Te
157 {5.28, 0.0}, // I
158 {4.92, 0.0}, // Xe
159 {5.42, 0.0}, // Cs
160 {5.07, 0.0}, // Ba
161 {8.24, 0.0}, // La
162 {4.84, 0.0}, // Ce
163 {4.58, 0.0}, // Pr
164 {7.69, 0.0}, // Nd
165 // No PM
166 {0.80, -1.65}, // Sm
167 {7.22, -1.26}, // Eu
168 {6.5, -13.82}, // Gd
169 {7.38, 0.0}, // Tb
170 {16.9, -0.276}, // Dy
171 {8.01, 0.0}, // Ho
172 {7.79, 0.0}, // Er
173 {7.07, 0.0}, // Tm
174 {12.43, 0.0}, // Yb
175 {7.21, 0.0}, // Lu
176 {7.77, 0.0}, // Hf
177 {6.91, 0.0}, // Ta
178 {4.86, 0.0}, // W
179 {9.2, 0.0}, // Re
180 {10.7, 0.0}, // Os
181 {10.6, 0.0}, // Ir
182 {9.60, 0.0}, // Pt
183 {7.63, 0.0}, // Au
184 {12.692, 0.0}, // Hg
185 {8.776, 0.0}, // Tl
186 {9.405, 0.0}, // Pb
187 {8.532, 0.0}, // Bi
188 {10.31, 0.0}, // Th
189 {8.417, 0.0} // U
190 };
191
192 // Load form factors.
193 static {
194 for (int i = 0; i < atomNames.length; i++) {
195 String number = atomicNumbers[i];
196 if (number.contains("_")) {
197 number = "1";
198 }
199 int atomicNumber = Integer.parseInt(number);
200 NeutronScatteringParameters parameters = new NeutronScatteringParameters(
201 atomNames[i], atomicNumber, neutronFormFactors[i]);
202 formfactors.put(atomicNumbers[i], parameters);
203 }
204 }
205
206 }