From 242da746d5c6139ef6b0192c617fd505f22bfe8d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 26 Oct 2026 17:29:22 -0400 Subject: [PATCH 1/2] fix: parse PDF metadata in PDFContribution.load_data load_data in pdfcontribution.py used ProfileParser, so the stype and qmax in a NOMAD file's free-text comment header were lost and get_scattering_type and get_qmax returned None. Use PDFParser, as diffpy.srfit does, and fix the docstring's parameter name. Co-Authored-By: Claude Opus 5.5 --- news/load-data-pdfparser.rst | 23 +++++++++++++++++++++++ src/diffpy/cmipdf/pdfcontribution.py | 14 +++++++++----- tests/test_pdfcontribution.py | 23 +++++++++++++++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 news/load-data-pdfparser.rst diff --git a/news/load-data-pdfparser.rst b/news/load-data-pdfparser.rst new file mode 100644 index 0000000..3863d17 --- /dev/null +++ b/news/load-data-pdfparser.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* Read the PDF metadata in the data file header in ``PDFContribution.load_data``, which used the generic ``ProfileParser`` and lost the scattering type and qmax from NOMAD files with a free-text instrument comment. + +**Security:** + +* diff --git a/src/diffpy/cmipdf/pdfcontribution.py b/src/diffpy/cmipdf/pdfcontribution.py index 0e69bed..a275bc5 100644 --- a/src/diffpy/cmipdf/pdfcontribution.py +++ b/src/diffpy/cmipdf/pdfcontribution.py @@ -23,7 +23,8 @@ from diffpy.cmipdf.debyepdfgenerator import DebyePDFGenerator from diffpy.cmipdf.pdfgenerator import PDFGenerator -from diffpy.srfit.fitbase import FitContribution, Profile, ProfileParser +from diffpy.cmipdf.pdfparser import PDFParser +from diffpy.srfit.fitbase import FitContribution, Profile class PDFContribution(FitContribution): @@ -109,14 +110,17 @@ def __init__(self, name): # Data methods def load_data(self, datafile): - """Load the data from a datafile. + """Load the data from a data file. + + This uses the PDFParser to load the data and then passes it to + the built-in profile with load_parsed_data. Parameters ---------- - data : str or Path - The path to the data file. + datafile : str or Path + The path to the file that contains the data. """ - parser = ProfileParser() + parser = PDFParser() parser.parse_file(datafile) # Pass it to the profile diff --git a/tests/test_pdfcontribution.py b/tests/test_pdfcontribution.py index 466a0d1..3761e17 100644 --- a/tests/test_pdfcontribution.py +++ b/tests/test_pdfcontribution.py @@ -126,3 +126,26 @@ def test_pickling(datafile): actual_residual = unpickled_contribution.residual() expected_residual = _make_ni_contribution(datafile, uiso=0.004).residual() assert np.allclose(actual_residual, expected_residual) + + +# load_data reads the PDF metadata in the data file header, so the +# contribution takes its scattering type and qmax from the file. +@pytest.mark.parametrize( + "input_filename, expected_settings", + [ + # C1: The header holds PDFgetX3 "name = value" lines. + # Expected: The scattering type "X" and qmax 27 from the header. + ("si-q27r60-xray.gr", ("X", 27.0)), + # C2: The header holds a free-text NOMAD instrument comment. + # Expected: The scattering type "N" and qmax 31.414 from the comment. + ("nom-mno-neutron.gr", ("N", 31.414)), + ], +) +def test_load_data_reads_metadata(datafile, input_filename, expected_settings): + contribution = PDFContribution("pdf") + contribution.load_data(datafile(input_filename)) + actual_settings = ( + contribution.get_scattering_type(), + contribution.get_qmax(), + ) + assert actual_settings == expected_settings From e56c71a612e67fca9aa13e682d265f3f40db0d4e Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 26 Oct 2026 17:34:19 -0400 Subject: [PATCH 2/2] test: move the load_data tests above the savetxt tests The use-cmistructure branch also appends tests to the end of test_pdfcontribution.py, so the two PRs conflicted. Putting the load_data tests next to the other metadata tests avoids that. Co-Authored-By: Claude Opus 5.5 --- tests/test_pdfcontribution.py | 46 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/tests/test_pdfcontribution.py b/tests/test_pdfcontribution.py index 3761e17..36e30fd 100644 --- a/tests/test_pdfcontribution.py +++ b/tests/test_pdfcontribution.py @@ -71,6 +71,29 @@ def test_get_qmax_from_profile(): assert actual_qmax == expected_qmax +# load_data reads the PDF metadata in the data file header, so the +# contribution takes its scattering type and qmax from the file. +@pytest.mark.parametrize( + "input_filename, expected_settings", + [ + # C1: The header holds PDFgetX3 "name = value" lines. + # Expected: The scattering type "X" and qmax 27 from the header. + ("si-q27r60-xray.gr", ("X", 27.0)), + # C2: The header holds a free-text NOMAD instrument comment. + # Expected: The scattering type "N" and qmax 31.414 from the comment. + ("nom-mno-neutron.gr", ("N", 31.414)), + ], +) +def test_load_data_reads_metadata(datafile, input_filename, expected_settings): + contribution = PDFContribution("pdf") + contribution.load_data(datafile(input_filename)) + actual_settings = ( + contribution.get_scattering_type(), + contribution.get_qmax(), + ) + assert actual_settings == expected_settings + + def test_savetxt(datafile): # C1: A contribution with data on r = 0 to 10 is evaluated and saved. # Expected: The file has a header line and one line for each of the @@ -126,26 +149,3 @@ def test_pickling(datafile): actual_residual = unpickled_contribution.residual() expected_residual = _make_ni_contribution(datafile, uiso=0.004).residual() assert np.allclose(actual_residual, expected_residual) - - -# load_data reads the PDF metadata in the data file header, so the -# contribution takes its scattering type and qmax from the file. -@pytest.mark.parametrize( - "input_filename, expected_settings", - [ - # C1: The header holds PDFgetX3 "name = value" lines. - # Expected: The scattering type "X" and qmax 27 from the header. - ("si-q27r60-xray.gr", ("X", 27.0)), - # C2: The header holds a free-text NOMAD instrument comment. - # Expected: The scattering type "N" and qmax 31.414 from the comment. - ("nom-mno-neutron.gr", ("N", 31.414)), - ], -) -def test_load_data_reads_metadata(datafile, input_filename, expected_settings): - contribution = PDFContribution("pdf") - contribution.load_data(datafile(input_filename)) - actual_settings = ( - contribution.get_scattering_type(), - contribution.get_qmax(), - ) - assert actual_settings == expected_settings