Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 1006: minor fixes and several new unit tests for PSA module #1508

Merged
merged 13 commits into from
Dec 11, 2017

Conversation

sseyler
Copy link
Contributor

@sseyler sseyler commented Jul 18, 2017

Addresses Issue #1006 (increase code coverage in PSA) and related Issue #1507 (Some PSA module components don't behave as expected). Brings PSA code coverage up to 73% according to report from mda_nosetests:

./mda_nosetests -v --with-coverage --cover-erase --cover-package=MDAnalysis.analysis.psa analysis/test_psa.py

gives:

Name                         Stmts   Miss  Cover
------------------------------------------------
MDAnalysis/analysis/psa.py     530    143    73%

Changes made in this Pull Request:

  • MDAnalysis.analysis.psa.dist_mat_to_vec() now returns int type via explicit casting of return statements (Some PSA module components don't behave as expected #1507).
  • The Hausdorff pairs analysis, run_pairs_analysis(), now also gives the distance matrix, as with the simpler run() method, by default (Some PSA module components don't behave as expected #1507).
    • Also fixes a small issue in storing the distance matrix when a Python function is provided (e.g., psa.run(metric=PSA.hausdorff) versus psa.run(metric='hausdorff') as a kwarg and a filename isn't explicitly specified to psa.run().
  • Added 3 new unit tests applicable to PSAnalysis class (increase code coverage in PSA #1006)
    1. test_explicit_metric()—check that an explicit Python function reference, as opposed to a string specifier, works as keyword argument, i.e., psa.run(metric=psa.hausdorff) versus psa.run(metric='hausdorff')
    2. test_hausdorff_pairs_distances()—check that Hausdorff distances produced by Hausdorff pairs analysis from psa.run_pairs_analysis(neighbors=True, hausdorff_pairs=True) are equal to Hausdorff distances generated in the usual way with psa.run()
    3. test_distances_from_hausdorff_pairs_frames()—check, for all pairs of paths, that the actual distance (computed manually by utilizing psa.sqnorm()) between two frames corresponding to a Hausdorff pair is equal to the Hausdorff distance between the two corresponding paths.

PR Checklist

  • Tests
  • Docs?
  • CHANGELOG updated?
  • Issue raised/referenced?

@sseyler sseyler closed this Jul 18, 2017
@sseyler sseyler reopened this Jul 18, 2017
@sseyler
Copy link
Contributor Author

sseyler commented Jul 18, 2017

I just checked that the changes I made to the return statements in psa.dist_mat_to_vec() on lines 738 and 744 (undoing the explicit cast to int type) still give passing tests:

  • line 738: return int( (N*i) + j - (i+2)*(i+1)/2 ) --> return (N*i) + j - (i+2)*(i+1)/2
  • line 744: return int( (N*j) + i - (j+2)*(j+1)/2 ) --> return (N*j) + i - (j+2)*(j+1)/2

... and it appears that it doesn't:

======================================================================
ERROR: Test whether actual distances between frames of Hausdorff
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/nfs/homes3/sseyler/Repositories/python/mdanalysis/testsuite/MDAnalysisTests/analysis/test_psa.py", line 157, in test_distances_from_hausdorff_pairs_frames
    p, q = self.hausd_pairs[pairidx]['frames']
TypeError: list indices must be integers, not float

I will look more closely next chance I get to see if what the problem is (or if the problem is me).

@richardjgowers
Copy link
Member

@sseyler it might be the division causing floats?

@kain88-de
Copy link
Member

kain88-de commented Jul 18, 2017

@sseyler you can enforce the old style in division using double backslashes a // n.

@sseyler
Copy link
Contributor Author

sseyler commented Jul 18, 2017

@richardjgowers @kain88-de

Yep, that was the problem. Using double backslashes now.

@orbeckst
Copy link
Member

(Totally nit-picking here but the character / is called a (forward) slash; the backslash is the character \.)

Thanks for working on the coverage!

@orbeckst
Copy link
Member

Btw, you should rebase against the latest develop: there is no nose test anymore #884 . Make sure that this works with the latest and greatest.

@richardjgowers
Copy link
Member

@sseyler this is failing because of the linter. Add from __future__ import division at the top, and from six.moves import range and use range instead of xrange

…_wavg_weight() and test_asymmetric_avg_weight(); need diff names for each test.
 - Added future division and six.range to test_psa.py
 - Separated pairs analysis (_run_pairs_analysis) from _run; moved plotting before
 - Adding a couple distance matrix checks to PSAnalysis methods
 - PSAnalysis.cluster now uses generated distance matrix D by default
   and checks for proper dist matrix format if dist_mat kwarg is specified
 - updated docstring for PSAnalysis.cluster
@@ -254,6 +254,10 @@ def get_path_metric_func(name):
except KeyError as key:
print("Path metric {0} not found. Valid selections: ".format(key))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this raise a KeyError?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe change it to a value error. But I would keep the exception. An invalid selection does sound like a grave mistake

filename = kwargs.pop('filename', str(metric))
self.save_result(filename=filename)
filename = kwargs.pop('filename', metric)
if type(metric) is str:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if isinstance(metrix, six.string_types)

@orbeckst
Copy link
Member

orbeckst commented Jul 20, 2017 via email

@orbeckst
Copy link
Member

ping @sseyler

@@ -171,17 +171,13 @@ class TestPSAExceptions(TestCase):
def test_get_path_metric_func_bad_key(self):
'''Test that KeyError is caught by
get_path_metric_func().'''

try:
with self.assertRaises(KeyError):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with pytest.raises(KeyError):
    PSA.get_path_metric_func('foobar')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I put my changes on hold since, once I rebased properly, realized everything is now pytest-specific. Hoping to finish this PR within the week.

# raise KeyError(err_str)
err_str = "Path metric {0} not found. Valid selections: ".format(key)
err_str += " ".join(["\"{0}\"".format(name) for name in path_metrics.keys()])
raise KeyError(err_str)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use multiline strings

raise KeyError("Path metric {} not found. Valid Selections: {}".format(
                           key, ' '.join(['"{}"'.format(name) for name in path_metrics.keys()]))

@orbeckst
Copy link
Member

Ping Dr @sseyler , can you finish this up?

@orbeckst
Copy link
Member

orbeckst commented Dec 1, 2017

@sseyler said #1508 (comment):

Hoping to finish this PR within the week.

... on Aug 2. Time to finish it up before the year is over.

We should have the fixes for #1507 in 0.17.0 if possible (and the sooner we have higher test coverage the better!)

@orbeckst orbeckst added this to the 0.17.0 milestone Dec 1, 2017
@richardjgowers
Copy link
Member

Ok cool, this should be good to go. Make this a merge commit so that authorship isn't messed with

@richardjgowers richardjgowers merged commit 8867646 into MDAnalysis:develop Dec 11, 2017
@sseyler
Copy link
Contributor Author

sseyler commented Dec 20, 2017

@richardjgowers Forgot to say this earlier: Thanks, Richard! I was gonna have to do this over the holidays otherwise. I owe you a beer next time we meet!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants