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

Improve the XSPEC interface #2216

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

DougBurke
Copy link
Contributor

@DougBurke DougBurke commented Jan 30, 2025

Summary

Add and extend routines in sherpa.astro.xspec: get_xsabundances now takes an optional table name, get_xsxset can be called with no argument, set_xsversion has been added to allow the nei and atomdb versions to be changed, get_xsversion can return the nei and atomdb versions, and clear_xsxset will clear the XSET database.

Details

This PR builds on #2215

The replacement for #1615 (what's left of it). I will note that in working on this code I have simplified some of the choices, so the exact functionality doesn't match #1615, but I believe we have what we need and the extra options provided in the earlier PRs are not actually needed.

Some of these code changes require C++11. They could be rewritten to not use C++11 features, but it does not seem worth it as our expected compilers have long-supported these capabilities.

A number of routines have been added or changed in sherpa.astro.xspec._xspec as this is treated as an "internal" module (i.e. if users are calling this directly then they have to expect changes). The user-level changes in sherpa.astro.xspec are intended to be more backwards-compatible, as normally we have just added routines or added optional arguments. There is one breaking change however, noted below.

Changes are:

  • added clear_xsxset as an "obvious" way to clear the XSXSET database (there was a hidden way to do this but you had to know XSPEC internals to do so, by setting the "INITIALIZE" key)
  • get_xsxset can now be called with no name, in which case it returns a dict containing all the settings
  • get_xsxset now raises a KeyError if given an invalid name (to make the dict-like behaviour cleaner) rather than returning an empty string
    • this is an explicit breaking change
  • set_xspath_manager can now be sent a Path or a str
  • added set_xspath_model (which can be sent Path or str)
  • get_xsversion can now return the nei and atomdb versions instead of the library version
  • set_xsversion has been added to allow the nei and atomdb versions to be changed
  • there have been internal changes to make set_xsabundances nicer, but it's not visible to the user, but it does mean that if you have set abundances from a file (or adjusted the values) then they will be recorded in the "xspec state"
  • added get_xsabundances_path as a way to get the Path to the abundances file used by XSPEC
    • this is not exported by default as it is expected to be rarely used
  • ensure you can't accidentally crash XSPEC by trying to set the abundances to "file" if you haven't actually loaded in any data (either from a file or by manual edits)
  • the set_xsabund C++ implementation has added comments to explain why we don't use FunctionUtility::readNewAbnudances() but still keep the code from when we only were able to use the xsFORTRAN interface (which does not have a "read abundances from a file" routine); basically the error handling and behaviour of readNewAbundances mean it's not worth changing our existing code
  • easy access to all the abundance tables, not just the currently loaded one, via get_xsabundances("lodd") etc
    • in earlier versions of this work I had many more ways to get this information, but for Sherpa users I think being able to just get all the abundances as a dict, labelled by element name, is all that we really need

This leaves out three future changes that are being worked on (and were in #1615, apart from, the DEM change)

  • support for XFLT keywords
  • support for the model database
  • access to DEM data

@DougBurke DougBurke marked this pull request as draft January 30, 2025 19:28
Copy link

codecov bot commented Jan 30, 2025

Codecov Report

Attention: Patch coverage is 92.85714% with 6 lines in your changes missing coverage. Please review.

Project coverage is 87.48%. Comparing base (3bc4957) to head (f165e31).

Files with missing lines Patch % Lines
sherpa/astro/xspec/__init__.py 92.85% 4 Missing and 2 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2216      +/-   ##
==========================================
+ Coverage   87.44%   87.48%   +0.03%     
==========================================
  Files          84       84              
  Lines       29866    29924      +58     
  Branches     3834     3842       +8     
==========================================
+ Hits        26116    26178      +62     
+ Misses       3640     3635       -5     
- Partials      110      111       +1     
Files with missing lines Coverage Δ
sherpa/astro/xspec/__init__.py 98.16% <92.85%> (-0.09%) ⬇️

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3bc4957...f165e31. Read the comment docs.

@DougBurke DougBurke force-pushed the xspec-use-12120-redux branch 2 times, most recently from e8b3983 to a044a56 Compare January 31, 2025 19:24
@DougBurke DougBurke mentioned this pull request Feb 6, 2025
@DougBurke DougBurke force-pushed the xspec-use-12120-redux branch 3 times, most recently from 5bca9b4 to 660c554 Compare February 7, 2025 18:57
@DougBurke DougBurke changed the title Xspec use 12120 redux Improve the XSPEC interface Feb 7, 2025
@DougBurke DougBurke force-pushed the xspec-use-12120-redux branch 2 times, most recently from ad5aa48 to 511e0a0 Compare February 9, 2025 18:59
@DougBurke DougBurke marked this pull request as ready for review February 10, 2025 14:08
@DougBurke DougBurke mentioned this pull request Feb 10, 2025
DougBurke and others added 6 commits February 13, 2025 13:39
Add a way to clear the XSET database - we already have one,
matching XSPEC, but it's not been advertised to the user, so
it makes sense to add a simple way to do it. The old way,
of calling `set_xsxset("INITIALIZE", ..)` has been marked as
deprecated.

Allow the full database to be returned, by calling get_xsxset
with no argument. This requires C++11 support.

We now raise an error if get_xsxset is called with an invalid
keyword, rather than returning an empty string, to better
match Python dictionaries.

The keywords should now be cleared if the "modelstrings"
entry is given (whether the empty dictionary or not), when
handling the xsstate method.
We can set the model path as well as the manager path, so do so.

This introduces the ability to send in a path as an actual Path
object, rather than just a string. There's a lot of discussion
about "how much Path is too much", but here

- these are not often used routines
- the overhead of supporting Path as well as str is low

There is the thought that we could return a Path rather than a
str, but that would be a larger, breaking change.

For get/set_xsstate, we could avoid tracking the paths settings,
but then we can not identify the difference between the user
explicitly setting the value to this is the default value. So we
track the values in xsstate["paths"].
These values are included in the XSPEC state. User-level
access is via get_xsversion and set_xsversion but the
direct access is via individual routines.
We can now send an array of abnudances to the C++ layer
rather than having to write the data to a file. This does
not change the UI layer (at least, for users of the
sherpa.astro.xspec module) but it simplifies some of the
internals of that module. In particular, it makes the
state handling a lot-more robust, as we can record the
actual values set, and so re-create them if necessary.

The get_xsabundances_path routine has been added: this is
a simplification of the low-level API, which seperates the
directory and file name, but for users of sherpa.astro.xspec
it does not seem worth maintaining that separation. This
routine is not automatically exported, as it is assumed to
be rarely used. The naming scheme here is a bit confusing:
does path mean a generic path or a Path object.

We could also support changing the path or filename, but it's not
obvious what the logic here is, in that changing the names does not
cause the data to be re-loaded.

There is currently no-way to access the cross-sections data as is
done for the abundances.
It turns out if you try to set the abundance setting to "file"
before reading in any data then you can crash XSPEC. So take
advantage of FunctionUtility::abundChanged to track this (as
this appears to be the reason for this method).

An alternative would be to ban "file" from the set_xsabund call,
but maybe people like switching between a file value and another
table (although there are other ways to do this in Sherpa).

I have also added some documentation to set_xsabund to explain
why we do not just call readNewAbundances but essentially
re-implement it (or, rather, now that we can use the C++ API
we keep the original code, as the xsFORTRAN interface did not
provide access to readNewAbundances). An alternative here
would be to drop the file-reading option from the C++ API and
make users read the data in Python and then use the
set_xsabundances routine to load in the data. This would
simplify the C++ code a bit *but*

- it would break existing code
- there is an advantage to having code that behaves as XSPEC
  does (in case there's subtle differences in reading in
  numbers and transferring them to the XSPEC internals)
The XSPEC API lets us ask for an abundance value from any of the
known tables, not just the selected one. So, how can we provide
this to the user? I have gone from having a very fine-grained
set of routines - e.g. providing access by name or by ion -
to a much simpler routine, where

- get_xsabundances can be used with or without a table name
- get_xsabund is stuck using the selected abundance table

I just don't think that users of Sherpa need that many ways to
get the data, and that

    get_xsabundances(table)

should cover all their needs.

The code in sherpa/astro/xspec/src/_xspec.cc has been written
to make it easier to read - so we have the existing get_abund
routine and the new get_abund_from_table routine. The logic
could have been all placed in get_abund but

- it just complicates things that we don't need to complicate
- the sherpa.astro.xspec._xspec module is really an
  internal-to-Sherpa module, so we can add/remove code here as
  we want; it is the sherpa.astro.xspec interface we want to
  try and keep backwards compatible
@DougBurke DougBurke force-pushed the xspec-use-12120-redux branch from 511e0a0 to f165e31 Compare February 13, 2025 18:40
@DougBurke
Copy link
Contributor Author

Rebased as #2215 has been merged.

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

Successfully merging this pull request may close these issues.

1 participant