SincCity 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sinccity/__init__.py +42 -0
- sinccity/_console.py +115 -0
- sinccity/calculator.py +940 -0
- sinccity/debye.py +274 -0
- sinccity/dispersion.py +29 -0
- sinccity/elements.py +111 -0
- sinccity/model.py +449 -0
- sinccity/molecules.py +127 -0
- sinccity/plotting.py +235 -0
- sinccity/readers.py +750 -0
- sinccity-0.2.0.dist-info/METADATA +298 -0
- sinccity-0.2.0.dist-info/RECORD +15 -0
- sinccity-0.2.0.dist-info/WHEEL +5 -0
- sinccity-0.2.0.dist-info/licenses/LICENSE +28 -0
- sinccity-0.2.0.dist-info/top_level.txt +1 -0
sinccity/__init__.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Generic Scattering Calculator: I(q) of a real-space structure.
|
|
2
|
+
|
|
3
|
+
A notebook equivalent of the nuclear, 1D part of SasView's Generic Scattering
|
|
4
|
+
Calculator: load a PDB, GRO, SLD or VTK file, compute the orientationally averaged
|
|
5
|
+
I(q) by the exact Debye formula, and show the points and the curve. The
|
|
6
|
+
result converts to a sasdata ``Data1D``, which is how it reaches a fit (for
|
|
7
|
+
example ``IQuana.set_data``).
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
>>> from sinccity import GenericScatteringCalculator
|
|
11
|
+
>>> gsc = GenericScatteringCalculator()
|
|
12
|
+
>>> gsc.load_structure('particle.sld')
|
|
13
|
+
>>> gsc.plot_points()
|
|
14
|
+
>>> gsc.set_params(sld_solvent=6.34) # 10^-6 1/Ang^2, as in sasmodels
|
|
15
|
+
>>> profile = gsc.calculate()
|
|
16
|
+
>>> gsc.plot_profile()
|
|
17
|
+
>>> data = profile.to_data1d() # a Data1D for IQuana.set_data
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__version__ = '0.2.0'
|
|
21
|
+
|
|
22
|
+
from ._console import set_verbosity
|
|
23
|
+
from .calculator import GenericScatteringCalculator, ScatteringProfile
|
|
24
|
+
from .debye import CalculationInterrupted, DistanceSpectrum
|
|
25
|
+
from .model import RgResult, Structure, StructureError
|
|
26
|
+
from .readers import load, read_gro, read_pdb, read_sld, read_vtk
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
'CalculationInterrupted',
|
|
30
|
+
'DistanceSpectrum',
|
|
31
|
+
'GenericScatteringCalculator',
|
|
32
|
+
'RgResult',
|
|
33
|
+
'ScatteringProfile',
|
|
34
|
+
'Structure',
|
|
35
|
+
'StructureError',
|
|
36
|
+
'load',
|
|
37
|
+
'read_gro',
|
|
38
|
+
'read_pdb',
|
|
39
|
+
'read_sld',
|
|
40
|
+
'read_vtk',
|
|
41
|
+
'set_verbosity',
|
|
42
|
+
]
|
sinccity/_console.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Console output: the package logger and encoding-safe glyphs.
|
|
2
|
+
|
|
3
|
+
Status messages that are a side effect of a call (structure loaded, q grid
|
|
4
|
+
set, profile computed) go through ``logging.getLogger('sinccity')`` instead of
|
|
5
|
+
``print``, so a caller can turn them off::
|
|
6
|
+
|
|
7
|
+
import sinccity
|
|
8
|
+
sinccity.set_verbosity('quiet')
|
|
9
|
+
|
|
10
|
+
The logger owns a stdout handler and does not propagate, so by default the
|
|
11
|
+
messages simply appear and do not duplicate into an application's own logging
|
|
12
|
+
configuration. To hand them over to that configuration instead::
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
log = logging.getLogger('sinccity')
|
|
16
|
+
log.handlers.clear()
|
|
17
|
+
log.propagate = True
|
|
18
|
+
|
|
19
|
+
Tables the user asks for explicitly (``describe()``) still ``print``: they
|
|
20
|
+
*are* the result of the call rather than a side effect of it.
|
|
21
|
+
|
|
22
|
+
The glyph constants fall back to ASCII when the active stdout cannot encode
|
|
23
|
+
them. A legacy Windows console (cp1252) has no ``✓`` or ``⁻``, and printing
|
|
24
|
+
them there raises ``UnicodeEncodeError``.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import logging
|
|
28
|
+
import sys
|
|
29
|
+
from typing import Any
|
|
30
|
+
|
|
31
|
+
LOGGER_NAME = 'sinccity'
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(LOGGER_NAME)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class _StdoutHandler(logging.StreamHandler):
|
|
37
|
+
"""A ``StreamHandler`` that resolves ``sys.stdout`` at emit time.
|
|
38
|
+
|
|
39
|
+
``StreamHandler`` binds its stream at construction, which would miss every
|
|
40
|
+
later redirection: the Jupyter kernel's streams, pytest's capture,
|
|
41
|
+
``contextlib.redirect_stdout``. Resolving per emit keeps the logger
|
|
42
|
+
behaving like a ``print`` call.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def stream(self) -> Any:
|
|
47
|
+
return sys.stdout
|
|
48
|
+
|
|
49
|
+
@stream.setter
|
|
50
|
+
def stream(self, value: Any) -> None:
|
|
51
|
+
"""Ignore the stream ``StreamHandler.__init__`` tries to bind."""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _install_default_handler() -> None:
|
|
55
|
+
handler = _StdoutHandler()
|
|
56
|
+
handler.setFormatter(logging.Formatter('%(message)s'))
|
|
57
|
+
logger.addHandler(handler)
|
|
58
|
+
logger.setLevel(logging.INFO)
|
|
59
|
+
logger.propagate = False
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if not logger.handlers:
|
|
63
|
+
_install_default_handler()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
_LEVEL_ALIASES = {'quiet': logging.WARNING}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def set_verbosity(level: int | str = 'info') -> None:
|
|
70
|
+
"""Set how much the calculator reports about what it is doing.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
level: ``'quiet'`` to drop the progress messages and keep only
|
|
74
|
+
warnings, or any standard logging level as a name (``'info'``,
|
|
75
|
+
``'debug'``, ``'warning'``, ``'error'``) or as an integer. Pass
|
|
76
|
+
``logging.CRITICAL`` to suppress the warnings as well.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
ValueError: If *level* is not a recognized level name.
|
|
80
|
+
"""
|
|
81
|
+
if isinstance(level, str):
|
|
82
|
+
resolved = _LEVEL_ALIASES.get(level.lower(), logging.getLevelName(level.upper()))
|
|
83
|
+
if not isinstance(resolved, int):
|
|
84
|
+
raise ValueError(
|
|
85
|
+
f"Unknown verbosity '{level}'. Use 'quiet', 'info', 'debug', "
|
|
86
|
+
"'warning', 'error', or a logging level number."
|
|
87
|
+
)
|
|
88
|
+
level = resolved
|
|
89
|
+
logger.setLevel(level)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _encodable(text: str) -> bool:
|
|
93
|
+
"""Return True when the current stdout can encode *text*."""
|
|
94
|
+
encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8'
|
|
95
|
+
try:
|
|
96
|
+
text.encode(encoding)
|
|
97
|
+
except (LookupError, UnicodeEncodeError):
|
|
98
|
+
return False
|
|
99
|
+
return True
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _glyph(preferred: str, fallback: str) -> str:
|
|
103
|
+
return preferred if _encodable(preferred) else fallback
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
#: Prefix marking a completed action in a status message.
|
|
107
|
+
OK = _glyph('✓', '[ok]')
|
|
108
|
+
#: Unit of q.
|
|
109
|
+
INVERSE_ANGSTROM = _glyph('Å⁻¹', '1/Ang')
|
|
110
|
+
#: Unit of length.
|
|
111
|
+
ANGSTROM = _glyph('Å', 'Ang')
|
|
112
|
+
#: Unit of volume.
|
|
113
|
+
CUBIC_ANGSTROM = _glyph('ų', 'Ang^3')
|
|
114
|
+
#: Unit of scattering length density, as sasmodels parameters use it.
|
|
115
|
+
SLD_UNIT = _glyph('10⁻⁶ Å⁻²', '1e-6/Ang^2')
|