View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2024.
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;
39  
40  import static java.lang.System.arraycopy;
41  
42  import ffx.algorithms.Terminatable;
43  import ffx.crystal.ReflectionList;
44  import ffx.numerics.optimization.LBFGS;
45  import ffx.numerics.optimization.LineSearch.LineSearchResult;
46  import ffx.numerics.optimization.OptimizationListener;
47  import ffx.xray.SplineEnergy.Type;
48  
49  import javax.annotation.Nullable;
50  import java.util.logging.Level;
51  import java.util.logging.Logger;
52  
53  /**
54   * SplineMinimize class.
55   *
56   * @author Timothy D. Fenn
57   * @since 1.0
58   */
59  public class SplineMinimize implements OptimizationListener, Terminatable {
60  
61    private static final Logger logger = Logger.getLogger(SplineEnergy.class.getName());
62  
63    private final SplineEnergy splineEnergy;
64    private final int n;
65    private final double[] x;
66    private final double[] grad;
67    private final double[] scaling;
68    private boolean done = false;
69    private boolean terminate = false;
70    private double grms;
71    private int nSteps;
72  
73    /**
74     * Constructor for SplineMinimize.
75     *
76     * @param reflectionList a {@link ffx.crystal.ReflectionList} object.
77     * @param refinementData a {@link ffx.xray.DiffractionRefinementData} object.
78     * @param x an array of double.
79     * @param type a int.
80     */
81    public SplineMinimize(
82        ReflectionList reflectionList,
83        DiffractionRefinementData refinementData,
84        double[] x,
85        int type) {
86      this.x = x;
87      n = x.length;
88      splineEnergy = new SplineEnergy(reflectionList, refinementData, n, type);
89      grad = new double[n];
90      scaling = new double[n];
91      for (int i = 0; i < n; i++) {
92        if (type == Type.FOTOESQ || type == Type.FCTOESQ) {
93          x[i] = 0.1;
94        } else {
95          x[i] = 1.0;
96        }
97        scaling[i] = 1.0;
98      }
99    }
100 
101   /**
102    * getCoordinates.
103    *
104    * @param x an array of {@link double} objects.
105    * @return an array of {@link double} objects.
106    */
107   public double[] getCoordinates(@Nullable double[] x) {
108     if (x == null) {
109       x = new double[this.x.length];
110     }
111     arraycopy(this.x, 0, x, 0, this.x.length);
112     return x;
113   }
114 
115   /**
116    * getNumberOfVariables.
117    *
118    * @return a int.
119    */
120   public int getNumberOfVariables() {
121     return x.length;
122   }
123 
124   /**
125    * minimize
126    *
127    * @return a {@link ffx.xray.SplineEnergy} object.
128    */
129   public SplineEnergy minimize() {
130     return minimize(0.5);
131   }
132 
133   /**
134    * minimize
135    *
136    * @param eps a double.
137    * @return a {@link ffx.xray.SplineEnergy} object.
138    */
139   public SplineEnergy minimize(double eps) {
140     return minimize(5, eps);
141   }
142 
143   /**
144    * minimize
145    *
146    * @param m a int.
147    * @param eps a double.
148    * @return a {@link ffx.xray.SplineEnergy} object.
149    */
150   public SplineEnergy minimize(int m, double eps) {
151 
152     splineEnergy.setScaling(scaling);
153 
154     double e = splineEnergy.energyAndGradient(x, grad);
155 
156     done = false;
157     int status = LBFGS.minimize(n, m, x, e, grad, eps, splineEnergy, this);
158     done = true;
159     switch (status) {
160       case 0:
161         logger.fine(String.format("\n Optimization achieved convergence criteria: %8.5f\n", grms));
162         break;
163       case 1:
164         logger.fine(String.format("\n Optimization terminated at step %d.\n", nSteps));
165         break;
166       default:
167         logger.warning("\n Spline Optimization failed.\n");
168     }
169 
170     splineEnergy.setScaling(null);
171 
172     return splineEnergy;
173   }
174 
175   /** {@inheritDoc} */
176   @Override
177   public boolean optimizationUpdate(
178       int iter,
179       int nBFGS,
180       int nfun,
181       double grms,
182       double xrms,
183       double f,
184       double df,
185       double angle,
186       LineSearchResult info) {
187     this.grms = grms;
188     this.nSteps = iter;
189     if (terminate) {
190       logger.info(" The optimization received a termination request.");
191       // Tell the L-BFGS optimizer to terminate.
192       return false;
193     }
194     return true;
195   }
196 
197   /** {@inheritDoc} */
198   @Override
199   public void terminate() {
200     terminate = true;
201     while (!done) {
202       synchronized (this) {
203         try {
204           wait(1);
205         } catch (Exception e) {
206           logger.log(Level.WARNING, "Exception terminating minimization.\n", e);
207         }
208       }
209     }
210   }
211 
212   /**
213    * Getter for the field <code>splineEnergy</code>.
214    *
215    * @return a {@link ffx.xray.SplineEnergy} object.
216    */
217   SplineEnergy getSplineEnergy() {
218     return splineEnergy;
219   }
220 }