Skip to content

Commit

Permalink
Merge pull request #30 from DougBurke/user-models
Browse files Browse the repository at this point in the history
Use xspec_models_cxc_helpers
  • Loading branch information
DougBurke authored Oct 10, 2024
2 parents 491fcd4 + 5f90c0a commit 8e0993c
Show file tree
Hide file tree
Showing 18 changed files with 87 additions and 596 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changes in xspec-models-cxc

## 0.1.0

Separate out some logic to xspec-models-cxc-helper, which has
been released to PyPI. As has this module.

## 0.0.31

Drop support for Python 3.9 as I do not have time or energy to
Expand Down
35 changes: 18 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ developed for Sherpa and the CIAO contrib packages.

## How to build

I am not putting this on [PyPI](https://pypi.org/) yet as there are a
lot of things to work out first!

You need to have the XSPEC model library installed. The easiest way to
do this is to actually [build and install
XSPEC](https://heasarc.gsfc.nasa.gov/lheasoft/) directly, but it
Expand All @@ -39,22 +36,27 @@ is not guaranteed either!

You need to have the `HEADAS` environment variable set up and probably
have also sourced the `$HEADAS/headas-init.sh` or
`$HEADAS/headas-init.csh` script. Then you can

```
% git clone https://github.com/cxcsds/xspec-models-cxc
% cd xspec-models-cxc
```
`$HEADAS/headas-init.csh` script. I also **strongly** suggest using
a new venv or conda environment!

The code will guess whether to use g++ or clang++. This choice will be
over-ridden by setting the CXX environment variable (useful for cases
where XSPEC was built with clang but you also have gcc installed, as
the install defaults to g++ in this case).

I suggest creating a new venv or conda environment, and then install
with the following:
Then you can either

```
% pip install xspec_models_cxc[test] --verbose
```

(the `--verbose` is in case there's an error, as the default information
you get from `pip` on a failue is generally less-than useful), **or** you
can try

```
% git clone https://github.com/cxcsds/xspec-models-cxc
% cd xspec-models-cxc
% pip install .[test] --verbose
```

Expand All @@ -64,6 +66,8 @@ The build requires both
installed automatically if needed. Neither is required to use the
compiled module.

### How to test

Testing is done with (the actual output depends on the version of
XSPEC installed and the version of this module):

Expand Down Expand Up @@ -239,7 +243,7 @@ def add_version():
horizontalalignment="left")


egrid = np.arange(0.1, 11, 0.01)
egrid = np.arange(0.1, 20, 0.01)
emid = (egrid[:-1] + egrid[1:]) / 2

for kT in [0.1, 0.3, 0.5, 1, 3, 5, 10]:
Expand Down Expand Up @@ -304,7 +308,7 @@ The screen output is just

```
XSPEC version: 12.14.1d
Module version: 0.0.30
Module version: 0.1.0
```

and the plots are
Expand Down Expand Up @@ -1108,13 +1112,10 @@ We can plot this:
>>> plt.ylabel('Photons/cm$^2$/s')
```

to create
to create (although this is a slightly-more-complex version):

![smaug model](https://raw.githubusercontent.com/cxcsds/xspec-models-cxc/main/scripts/smaug.png "smaug model")

Note that in XSPEC 12.12.0 this crashed, but it now seems to work in
XSPEC 12.12.1.

### CFLUX convolution model (convolution, C++)

The `cflux` convolution model changes the normalization of the input
Expand Down
41 changes: 4 additions & 37 deletions helpers/report_xspec_directories.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,11 @@

"""Return the library and include directories.
This should just be $HEADAS/lib and $HEADAS/include, except for the
fact that the CXC xspec-modelsonly conda package does things a little
differently (or, perhaps, that XSPEC doesn't have the equivalent of a
share/ directory in which to place the extra files).
It is assumed that the HEADAS environment variable exists.
Is this actually useful anymore?
"""

from pathlib import Path
import os

HEADAS_ENV = os.getenv('HEADAS')
HEADAS = Path(HEADAS_ENV)

if (HEADAS / 'include').is_dir():
base_path = HEADAS
else:
base_path = (HEADAS / '..').resolve()

xspec_libdir = base_path / 'lib'
xspec_incdir = base_path / 'include'

if not xspec_libdir.is_dir():
sys.stderr.write('###########################################\n')
sys.stderr.write('ERROR: unable to find HEADAS lib directory.\n')
sys.stderr.write(str(HEADAS / platlibdir))
sys.stderr.write(str(HEADAS / '..' / platlibdir))
sys.stderr.write('###########################################\n')
sys.exit(1)

if not xspec_incdir.is_dir():
sys.stderr.write('###########################################\n')
sys.stderr.write('ERROR: unable to find HEADAS lib directory.\n')
sys.stderr.write(str(HEADAS / 'include'))
sys.stderr.write(str(HEADAS / '..' / 'include'))
sys.stderr.write('###########################################\n')
sys.exit(1)
import xspec_models_cxc_helpers as xu

print(xspec_incdir)
print(xspec_libdir)
print(xu.get_xspec_include_path())
print(xu.get_xspec_library_path())
46 changes: 4 additions & 42 deletions helpers/report_xspec_libraries.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,18 @@
"""

import glob
from pathlib import Path
import os
import sys
import sysconfig

import xspec_models_cxc_helpers as xu

def doit(libdir: str) -> None:
"""Given the library directory, find the libraries"""

xspec_libdir = Path(libdir)

# There's some attempt to be platform independent, but
# is it worth it?
#
if sysconfig.get_config_var("WITH_DYLD"):
suffix = ".dylib"
else:
# Should this just be hard-coded?
suffix = sysconfig.get_config_var('SHLIB_SUFFIX')

# The tricky thing is that we have XSFunctions, XSUtil, and XS as
# arguments. So we can not just look for XS*, as that will match
# multiple libraries. We also don't want to include all matches to XS
# as there are a number of matches we do not need.
#
def match(name: str) -> str:
# Would it make sense to take the lib prefix from sysconfig?
head = f"lib{name}{suffix}"
ms = glob.glob(str(xspec_libdir / head))
if len(ms) == 1:
return name

head = f"lib{name}_*{suffix}"
ms = glob.glob(str(xspec_libdir / head))
if len(ms) == 1:
return Path(ms[0]).stem[3:]

head = f"lib{name}-*{suffix}"
ms = glob.glob(str(xspec_libdir / head))
if len(ms) == 1:
return Path(ms[0]).stem[3:]

raise OSError(f"Unable to find a match for lib{name}*{suffix} in {xspec_libdir}")

for libname in ["XSFunctions", "XSUtil", "XS", "hdsp",
"cfitsio", "CCfits", "wcs"]:
# Note: not all names are versioned
print(match(libname))

out = xu.get_xspec_libs(xspec_libdir)
for name in out:
print(name)

if __name__ == "__main__":

Expand Down
26 changes: 2 additions & 24 deletions helpers/report_xspec_modelfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,6 @@
"""

from pathlib import Path
import os
import sys
import xspec_models_cxc_helpers as xu

HEADAS_ENV = os.getenv('HEADAS')
if HEADAS_ENV is None:
sys.stderr.write('##################################################\n')
sys.stderr.write('ERROR: unable to find HEADAS environment variable.\n')
sys.stderr.write('##################################################\n')
sys.exit(1)

HEADAS = Path(HEADAS_ENV)

modelfile = HEADAS / '../spectral/manager/model.dat'
modelfile = modelfile.resolve()

if not modelfile.is_file():
sys.stderr.write('##################################################\n')
sys.stderr.write('ERROR: model.dat file not found:\n')
sys.stderr.write(str(modelfile) + '\n')
sys.stderr.write('##################################################\n')
sys.exit(1)

print(str(modelfile))
sys.exit(0)
print(xu.get_xspec_model_path())
8 changes: 4 additions & 4 deletions helpers/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from parse_xspec.models import ModelDefinition, \
parse_xspec_model_description

import utils_template
import xspec_models_cxc_helpers as xu


def replace_term(txt: str, term: str, replace: str) -> str:
Expand All @@ -42,7 +42,7 @@ def apply_compiled(models: Sequence[ModelDefinition],
conmodels = []
mstrs = []
for model in models:
mdef, mtype, mdesc = utils_template.wrapmodel_compiled(model)
mdef, mtype, mdesc = xu.wrapmodel_compiled(model)
if mtype == "Add":
addmodels.append(mdesc)
elif mtype == "Mul":
Expand Down Expand Up @@ -82,7 +82,7 @@ def apply_python(modelfile: Path,

mstrs = []
for model in models:
mname, mdef = utils_template.wrapmodel_python(model)
mname, mdef = xu.wrapmodel_python(model)
mstrs.append(f" '{mname}': {mdef}")

with template.open(mode='rt') as ifh:
Expand Down Expand Up @@ -112,7 +112,7 @@ def find_models(modelfile: Path
sys.stderr.write(f'ERROR: unable to parse model.dat file: {modelfile}\n')
sys.exit(1)

supported, unsupported = utils_template.select_models(allmodels)
supported, unsupported = xu.select_models(allmodels)
if len(supported) == 0:
sys.stderr.write(f'ERROR: unable to find any models in: {modelfile}\n')
sys.exit(1)
Expand Down
Loading

0 comments on commit 8e0993c

Please sign in to comment.