mailProposed solution to bug #6503.


Others Months | Index by Date | Thread Index
>>   [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Header


Content

Posted by Edward d'Auvergne on August 09, 2006 - 07:40:
Here is my proposed solution to bug #6503
(https://gna.org/bugs/?func=detailitem&item_id=6503).  I have used the
current 1.2 line as a reference and presented the diffs.  Feel free to
propose better solutions.

The first thing is the catching of the NaN and Inf after the grid
search and minimisation.  I propose to do the test within the
'self.minimise()' function of 'specific_fns/model_free.py' rather than
in the 'maths_fns/' or 'minimise/' code.  Here is the diff:
===================================================================
--- specific_fns/model_free.py  (revision 2527)
+++ specific_fns/model_free.py  (working copy)
@@ -2374,6 +2374,14 @@
            self.g_count = self.g_count + gc
            self.h_count = self.h_count + hc

+            # Catch infinite chi-squared values.
+            if self.func == float('inf'):
+                raise RelaxInfError
+
+            # Catch chi-squared values of NaN.
+            if isnan(self.func):
+                raise RelaxNaNError
+
            # Scaling.
            if scaling:
                self.param_vector =
matrixmultiply(self.scaling_matrix, self.param_vector)
===================================================================

As the function 'self.grid_search()' executes 'self.minimise()' this
single change will cover both the grid search and minimisation.  The
function 'isnan()' currently non-existent but could be implemented as
Gary previously mentioned by checking the hex bit pattern of NaN.
This avoids fpconst.py and the switch from Numeric to Numpy.  The
question is whether to use the RelaxErrors or set some warning?  Would
this be alleviated by Gary's proposal of saving the program state just
prior to throwing the error?  For example using the function
'self.save()' within 'generic_fns/state.py', printing the error
message, then quitting.

The next change is the addition of new RelaxErrors:
===================================================================
--- errors.py   (revision 2527)
+++ errors.py   (working copy)
@@ -462,3 +462,17 @@
    class RelaxInvalidColourError(BaseError):
        def __init__(self, colour):
            self.text = "The colour " + `colour` + " is invalid."
+
+
+    # Value errors.
+    ###############
+
+    # Infinity.
+    class RelaxInfError(BaseError):
+        def __init__(self, name):
+            self.text = "The invalid " + name + " floating point
value of infinity has occurred."
+
+    # NaN (Not a Number).
+    class RelaxNaNError(BaseError):
+        def __init__(self, name):
+            self.text = "The invalid " + name + " floating point
value of NaN (Not a Number) has occurred."
===================================================================

And as a preventative measure, the catching of zero length XH bond vectors:
===================================================================
--- generic_fns/pdb.py  (revision 2527)
+++ generic_fns/pdb.py  (working copy)
@@ -156,7 +156,11 @@
                    print "The PDB file " + `self.file_path` + "
cannot be found, no structures will be loaded."
                return

+        # Test that the nuclei have been correctly set.
+        if self.heteronuc == self.proton:
+            raise RelaxError, "The proton and heteronucleus are set
to the same atom."

+
        # Data creation.
        ################

@@ -256,10 +260,19 @@
                    # Get the heteronucleus position.
                    posX = pdb_res.atoms[self.heteronuc].position.array

-                    # Calculate the normalised vector.
+                    # Calculate the XH bond vector.
                    vector = posH - posX
-
self.relax.data.res[self.run][j].xh_vect.append(vector /
sqrt(dot(vector, vector)))

+                    # Normalisation factor.
+                    norm_factor = sqrt(dot(vector, vector))
+
+                    # Test for zero length.
+                    if norm_factor == 0.0:
+                        raise RelaxError, "The XH bond vector for
residue " + `self.relax.data.res[self.run][j].num` + " is of zero
length."
+
+                    # Calculate the normalised vector.
+
self.relax.data.res[self.run][j].xh_vect.append(vector / norm_factor)
+
        # Print out.
        if self.print_flag:
            if num_str > 1:
===================================================================

Finally, forcing termination of the backtracking line search (to break
the infinite loop):
===================================================================
--- minimise/line_search/backtrack.py   (revision 2527)
+++ minimise/line_search/backtrack.py   (working copy)
@@ -23,7 +23,7 @@

from Numeric import dot

-def backtrack(func, args, x, f, g, p, a_init=1.0, rho=0.5, c=1e-4):
+def backtrack(func, args, x, f, g, p, a_init=1.0, rho=0.5, c=1e-4,
max_iter=500):
    """Backtracking line search.

    Procedure 3.1, page 41, from 'Numerical Optimization' by Jorge
Nocedal and Stephen J. Wright,
@@ -63,8 +63,9 @@
    # Initialise values.
    a = a_init
    f_count = 0
+    i = 0

-    while 1:
+    while i <= max_iter:
        fk = apply(func, (x + a*p,)+args)
        f_count = f_count + 1

@@ -73,3 +74,6 @@
            return a, f_count
        else:
            a = rho*a
+
+        # Increment the counter.
+        i = i + 1
===================================================================

What do you think?  I think I covered most of the issues.  I've made a
branch of the 1.2 line located at
svn://svn.gna.org/svn/relax/branches/nan_catch_test which has all
these changes.  Feel free to play around and modify this branch.

Edward



Related Messages


Powered by MHonArc, Updated Thu Aug 10 10:00:28 2006