lated 0.1.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.
Files changed (66) hide show
  1. lated/__init__.py +35 -0
  2. lated/cli.py +72 -0
  3. lated/config.py +258 -0
  4. lated/data/filters/F070W.dat +201 -0
  5. lated/data/filters/F090W.dat +255 -0
  6. lated/data/filters/F1000W.dat +479 -0
  7. lated/data/filters/F1130W.dat +342 -0
  8. lated/data/filters/F115W.dat +342 -0
  9. lated/data/filters/F1280W.dat +609 -0
  10. lated/data/filters/F140M.dat +257 -0
  11. lated/data/filters/F1500W.dat +817 -0
  12. lated/data/filters/F150W.dat +447 -0
  13. lated/data/filters/F150W2.dat +1502 -0
  14. lated/data/filters/F162M.dat +296 -0
  15. lated/data/filters/F164N.dat +72 -0
  16. lated/data/filters/F1800W.dat +1035 -0
  17. lated/data/filters/F182M.dat +384 -0
  18. lated/data/filters/F187N.dat +80 -0
  19. lated/data/filters/F200W.dat +611 -0
  20. lated/data/filters/F2100W.dat +1455 -0
  21. lated/data/filters/F210M.dat +337 -0
  22. lated/data/filters/F212N.dat +85 -0
  23. lated/data/filters/F250M.dat +237 -0
  24. lated/data/filters/F2550W.dat +1482 -0
  25. lated/data/filters/F277W.dat +806 -0
  26. lated/data/filters/F300M.dat +457 -0
  27. lated/data/filters/F322W2.dat +1367 -0
  28. lated/data/filters/F323N.dat +89 -0
  29. lated/data/filters/F335M.dat +559 -0
  30. lated/data/filters/F356W.dat +918 -0
  31. lated/data/filters/F360M.dat +555 -0
  32. lated/data/filters/F405N.dat +124 -0
  33. lated/data/filters/F410M.dat +631 -0
  34. lated/data/filters/F430M.dat +333 -0
  35. lated/data/filters/F444W.dat +1029 -0
  36. lated/data/filters/F460M.dat +382 -0
  37. lated/data/filters/F466N.dat +135 -0
  38. lated/data/filters/F470N.dat +131 -0
  39. lated/data/filters/F480M.dat +455 -0
  40. lated/data/filters/F560W.dat +338 -0
  41. lated/data/filters/F770W.dat +539 -0
  42. lated/data/filters/RomanF062.dat +70 -0
  43. lated/data/filters/RomanF087.dat +62 -0
  44. lated/data/filters/RomanF106.dat +75 -0
  45. lated/data/filters/RomanF129.dat +90 -0
  46. lated/data/filters/RomanF146.dat +243 -0
  47. lated/data/filters/RomanF158.dat +109 -0
  48. lated/data/filters/RomanF184.dat +98 -0
  49. lated/data/filters/RomanF213.dat +109 -0
  50. lated/dust.py +40 -0
  51. lated/engine.py +582 -0
  52. lated/filters.py +198 -0
  53. lated/lines.py +183 -0
  54. lated/presets.py +26 -0
  55. lated/server/__init__.py +0 -0
  56. lated/server/app.py +140 -0
  57. lated/server/static/app.css +579 -0
  58. lated/server/static/app.js +1147 -0
  59. lated/server/static/index.html +244 -0
  60. lated/server/static/plot.js +718 -0
  61. lated-0.1.0.dist-info/METADATA +157 -0
  62. lated-0.1.0.dist-info/RECORD +66 -0
  63. lated-0.1.0.dist-info/WHEEL +5 -0
  64. lated-0.1.0.dist-info/entry_points.txt +2 -0
  65. lated-0.1.0.dist-info/licenses/LICENSE +21 -0
  66. lated-0.1.0.dist-info/top_level.txt +1 -0
lated/__init__.py ADDED
@@ -0,0 +1,35 @@
1
+ """lated: photometric emission-line recovery.
2
+
3
+ Fit a transparent continuum + emission-line model through real filter
4
+ transmission curves to recover line fluxes, rest EWs and line ratios
5
+ (with upper limits) from broad/medium-band photometry.
6
+
7
+ >>> from lated import FitConfig, fit
8
+ >>> cfg = FitConfig.three_band(z=3.05) # paper 3-band mode
9
+ >>> res = fit({"F200W": (0.0136, 0.0019),
10
+ ... "F277W": (0.0249, 0.0016),
11
+ ... "F356W": (0.0040, 0.0014)}, cfg)
12
+ >>> res.ratios[0].name, res.ratios[0].is_limit
13
+ ('R3', ...)
14
+ """
15
+
16
+ from .config import (ContinuumConfig, DustConfig, FitConfig, LineConfig,
17
+ MCConfig, RatioConfig, default_lines)
18
+ from .engine import FitResult, LineResult, RatioResult, fit, model_spectrum
19
+ from .filters import Filter, FilterSet, default_filters, filter_group
20
+ from .lines import (BALMER_CASES, BALMER_TABLE, CASE_A_TEMPERATURES,
21
+ CASE_B_DENSITIES, CASE_B_TEMPERATURES, LINE_WAVELENGTHS,
22
+ balmer_ratios, case_b_ratios)
23
+ from .presets import WINDOW_PRESETS, WindowPreset
24
+
25
+ __version__ = "0.1.0"
26
+
27
+ __all__ = [
28
+ "ContinuumConfig", "DustConfig", "FitConfig", "LineConfig", "MCConfig",
29
+ "RatioConfig", "default_lines", "FitResult", "LineResult", "RatioResult",
30
+ "fit", "model_spectrum", "Filter", "FilterSet", "default_filters",
31
+ "filter_group", "LINE_WAVELENGTHS", "WINDOW_PRESETS", "WindowPreset",
32
+ "BALMER_CASES", "BALMER_TABLE", "CASE_A_TEMPERATURES",
33
+ "CASE_B_DENSITIES", "CASE_B_TEMPERATURES", "balmer_ratios",
34
+ "case_b_ratios", "__version__",
35
+ ]
lated/cli.py ADDED
@@ -0,0 +1,72 @@
1
+ """Command-line interface: serve the web app, or fit from a JSON file.
2
+
3
+ lated serve [--host H] [--port P]
4
+ lated fit input.json # {"photometry": {...}, "config": {...}}
5
+ lated bands # list bundled filters
6
+ lated lines # show the default line registry
7
+ """
8
+
9
+ import argparse
10
+ import json
11
+ import sys
12
+
13
+
14
+ def main(argv=None):
15
+ ap = argparse.ArgumentParser(
16
+ prog="lated",
17
+ description=(__doc__ or "LATED line recovery").splitlines()[0])
18
+ sub = ap.add_subparsers(dest="cmd", required=True)
19
+
20
+ ap_serve = sub.add_parser("serve", help="run the web application")
21
+ ap_serve.add_argument("--host", default="127.0.0.1")
22
+ ap_serve.add_argument("--port", type=int, default=8321)
23
+
24
+ ap_fit = sub.add_parser("fit", help="fit photometry from a JSON file")
25
+ ap_fit.add_argument("input", help="JSON with 'photometry' and 'config'")
26
+
27
+ sub.add_parser("bands", help="list available filters")
28
+ sub.add_parser("lines", help="show the default line registry")
29
+
30
+ args = ap.parse_args(argv)
31
+
32
+ if args.cmd == "serve":
33
+ import uvicorn
34
+ from .server.app import create_app
35
+ uvicorn.run(create_app(), host=args.host, port=args.port)
36
+ elif args.cmd == "fit":
37
+ from pydantic import ValidationError
38
+
39
+ from .config import FitConfig
40
+ from .engine import fit
41
+ try:
42
+ with open(args.input) as fh:
43
+ payload = json.load(fh)
44
+ phot_in = payload["photometry"]
45
+ cfg = FitConfig.model_validate(payload["config"])
46
+ phot = {b: (float(v[0]), float(v[1]))
47
+ for b, v in phot_in.items()}
48
+ res = fit(phot, cfg)
49
+ except KeyError as exc:
50
+ sys.exit(f"error: input JSON needs 'photometry' (band -> "
51
+ f"[flux_uJy, err_uJy]) and 'config' (missing {exc})")
52
+ except (ValidationError, ValueError, TypeError, OSError,
53
+ json.JSONDecodeError) as exc:
54
+ sys.exit(f"error: {exc}")
55
+ json.dump(res.model_dump(), sys.stdout, indent=2, allow_nan=False)
56
+ print()
57
+ elif args.cmd == "bands":
58
+ from .filters import default_filters, filter_group
59
+ fs = default_filters()
60
+ for name in fs.names():
61
+ f = fs[name]
62
+ print(f"{name:12s} {filter_group(name):22s} "
63
+ f"pivot {f.pivot:9.1f} AA")
64
+ elif args.cmd == "lines":
65
+ from .config import default_lines
66
+ for l in default_lines():
67
+ tie = (f" = {l.ratio:.4f} x {l.tied_to}" if l.role == "tied" else "")
68
+ print(f"{l.name:12s} {l.rest_wave:9.2f} AA {l.role:5s}{tie}")
69
+
70
+
71
+ if __name__ == "__main__":
72
+ main()
lated/config.py ADDED
@@ -0,0 +1,258 @@
1
+ """Fit configuration: every model parameter with an explicit role.
2
+
3
+ The spectral model is
4
+
5
+ f_lambda(lam) = C (lam/lam0)^beta + sum_l F_l delta(lam - lam_l (1+z))
6
+
7
+ and every parameter is declared here as *free*, *fixed* or *tied*:
8
+
9
+ =============================== =========================================
10
+ parameter role
11
+ =============================== =========================================
12
+ C (continuum amplitude) always free (>= 0)
13
+ beta (continuum slope) free (grid-searched) or fixed (with an
14
+ optional Gaussian sigma folded into the
15
+ Monte-Carlo error budget)
16
+ z always fixed (the Lya-slice redshift);
17
+ z_sigma > 0 propagates its uncertainty
18
+ A_V, dust law fixed; enters only as a differential on
19
+ tied line ratios
20
+ F_l (one per line) free (>= 0), tied (ratio x another line),
21
+ or off (excluded from the model)
22
+ =============================== =========================================
23
+
24
+ Unknown keys are rejected (``extra='forbid'``), so a misspelled option is an
25
+ error instead of a silent no-op.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ from typing import List, Literal, Optional
31
+
32
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
33
+
34
+ from .lines import (DEFAULT_REGISTRY, LINE_WAVELENGTHS, balmer_ratios,
35
+ contaminant_ties)
36
+
37
+
38
+ class ContinuumConfig(BaseModel):
39
+ """The power-law continuum C (lam/lam0)^beta.
40
+
41
+ The amplitude C is always free (non-negative). The slope beta is either
42
+ ``free`` (grid-searched over [grid_min, grid_max]) or ``fixed`` at
43
+ ``beta`` — required when only the three selection bands are given, where
44
+ the slope is degenerate with the amplitudes. When fixed, ``beta_sigma``
45
+ (default 0.3) marginalises the assumed slope in the Monte-Carlo so the
46
+ systematic enters the error budget."""
47
+ model_config = ConfigDict(extra="forbid")
48
+
49
+ beta_mode: Literal["free", "fixed"] = "free"
50
+ beta: float = -2.0
51
+ beta_sigma: Optional[float] = Field(
52
+ None, ge=0, description="None -> 0.3 if fixed, 0.0 if free")
53
+ grid_min: float = -3.5
54
+ grid_max: float = 1.0
55
+ grid_n: int = Field(61, ge=2, le=1001)
56
+ pivot_wavelength: float = Field(20000.0, gt=0,
57
+ description="lam0 [AA, observed]")
58
+
59
+ @property
60
+ def beta_sigma_effective(self) -> float:
61
+ if self.beta_sigma is not None:
62
+ return self.beta_sigma
63
+ return 0.3 if self.beta_mode == "fixed" else 0.0
64
+
65
+ @model_validator(mode="after")
66
+ def _check_grid(self) -> "ContinuumConfig":
67
+ if self.beta_mode == "free" and self.grid_min >= self.grid_max:
68
+ raise ValueError("continuum grid_min must be < grid_max")
69
+ if self.beta_mode == "free" and self.beta_sigma:
70
+ raise ValueError(
71
+ "beta_sigma is only meaningful with beta_mode='fixed' (it is "
72
+ "the Gaussian prior on the assumed slope); with beta_mode="
73
+ "'free' the slope is profiled over the grid instead")
74
+ return self
75
+
76
+
77
+ class LineConfig(BaseModel):
78
+ """One emission line in the model.
79
+
80
+ role='free': amplitude F >= 0 is a fit parameter.
81
+ role='tied': F = ratio x F(tied_to) x dust differential; tie chains
82
+ (e.g. Hgamma -> Hbeta -> Halpha) resolve to a free root.
83
+ role='off': excluded from the model entirely.
84
+ """
85
+ model_config = ConfigDict(extra="forbid")
86
+
87
+ name: str
88
+ rest_wave: float = Field(..., gt=0, description="rest wavelength [AA]")
89
+ role: Literal["free", "tied", "off"] = "free"
90
+ tied_to: Optional[str] = None
91
+ ratio: Optional[float] = Field(None, gt=0,
92
+ description="F_this / F_tied_to, intrinsic")
93
+
94
+ @model_validator(mode="after")
95
+ def _check_tie(self) -> "LineConfig":
96
+ if self.role == "tied":
97
+ if not self.tied_to or self.ratio is None:
98
+ raise ValueError(
99
+ f"line {self.name!r}: role='tied' requires tied_to and ratio")
100
+ return self
101
+
102
+
103
+ class DustConfig(BaseModel):
104
+ """Attenuation applied differentially to tied line ratios.
105
+
106
+ Like the fixed continuum slope, A_V carries a Gaussian uncertainty
107
+ ``av_sigma`` (default 0 +/- 0.01) that is propagated through the
108
+ Monte-Carlo error budget (draws are truncated at A_V >= 0)."""
109
+ model_config = ConfigDict(extra="forbid")
110
+
111
+ av: float = Field(0.0, ge=0)
112
+ av_sigma: float = Field(0.01, ge=0)
113
+ law: Literal["calzetti", "smc"] = "calzetti"
114
+
115
+
116
+ class MCConfig(BaseModel):
117
+ """Monte-Carlo error budget.
118
+
119
+ method='bootstrap' (paper default): resample the photometry ``n`` times
120
+ and refit; read percentiles of the refits. Near the non-negativity
121
+ boundary these can collapse to zero (an undetected line whose band
122
+ fluctuated low returns an upper limit of exactly 0), so for honest
123
+ limits prefer method='posterior': sample the truncated-Gaussian
124
+ posterior of the amplitudes (flat prior on F >= 0) with the slope
125
+ drawn from its profile weight (free) or Gaussian prior (fixed).
126
+
127
+ ``fast`` (bootstrap only) pins the slope at the best fit instead of
128
+ re-searching the grid per resample. ``seed`` fixes the random stream;
129
+ vary it across a catalogue if you stack results (a shared seed
130
+ correlates the noise realisations)."""
131
+ model_config = ConfigDict(extra="forbid")
132
+
133
+ n: int = Field(300, ge=10, le=10000)
134
+ seed: int = 9496
135
+ fast: bool = False
136
+ method: Literal["bootstrap", "posterior"] = "bootstrap"
137
+ keep_draws: bool = Field(
138
+ False, description="return the (thinned) MC draws of the free "
139
+ "parameters in FitResult.posterior_draws, e.g. for corner plots")
140
+
141
+
142
+ class RatioConfig(BaseModel):
143
+ """A derived line ratio to report, with upper-limit handling."""
144
+ model_config = ConfigDict(extra="forbid")
145
+
146
+ name: str = "R3"
147
+ numerator: str = "OIII5007"
148
+ denominator: str = "Hbeta"
149
+
150
+
151
+ def default_lines() -> List[LineConfig]:
152
+ """The paper's default registry (see :mod:`lated.lines`)."""
153
+ return [LineConfig(name=n, rest_wave=LINE_WAVELENGTHS[n], role=role,
154
+ tied_to=tied_to, ratio=ratio)
155
+ for n, role, tied_to, ratio in DEFAULT_REGISTRY]
156
+
157
+
158
+ class FitConfig(BaseModel):
159
+ """Complete, explicit specification of one fit."""
160
+ model_config = ConfigDict(extra="forbid")
161
+
162
+ z: float = Field(..., gt=0, description="Lya-slice redshift (fixed)")
163
+ z_sigma: float = Field(0.0, ge=0)
164
+ continuum: ContinuumConfig = Field(default_factory=ContinuumConfig)
165
+ lines: List[LineConfig] = Field(default_factory=default_lines)
166
+ dust: DustConfig = Field(default_factory=DustConfig)
167
+ mc: MCConfig = Field(default_factory=MCConfig)
168
+ ratios: List[RatioConfig] = Field(default_factory=lambda: [RatioConfig()])
169
+
170
+ @model_validator(mode="after")
171
+ def _check_lines(self) -> "FitConfig":
172
+ names = [l.name for l in self.lines]
173
+ if len(set(names)) != len(names):
174
+ dupes = sorted({n for n in names if names.count(n) > 1})
175
+ raise ValueError(f"duplicate line names: {dupes}")
176
+ enabled = {l.name: l for l in self.lines if l.role != "off"}
177
+ if not any(l.role == "free" for l in enabled.values()):
178
+ raise ValueError("at least one line must have role='free'")
179
+ for l in enabled.values():
180
+ if l.role != "tied":
181
+ continue
182
+ seen, cur = {l.name}, l
183
+ while cur.role == "tied":
184
+ target = enabled.get(cur.tied_to)
185
+ if target is None:
186
+ raise ValueError(
187
+ f"line {cur.name!r} is tied to {cur.tied_to!r}, which "
188
+ "is off or undefined")
189
+ if target.name in seen:
190
+ raise ValueError(f"tie cycle involving {target.name!r}")
191
+ seen.add(target.name)
192
+ cur = target
193
+ for r in self.ratios:
194
+ for side in (r.numerator, r.denominator):
195
+ if side not in enabled:
196
+ raise ValueError(
197
+ f"ratio {r.name!r} references {side!r}, which is not "
198
+ "an enabled line")
199
+ return self
200
+
201
+ # ---- convenience constructors matching the paper's two modes ----------
202
+ @classmethod
203
+ def paper_default(cls, z: float, **kwargs) -> "FitConfig":
204
+ """Multi-band mode: slope fitted, Halpha + [O III] free, Case B ties."""
205
+ return cls(z=z, **kwargs)
206
+
207
+ @classmethod
208
+ def three_band(cls, z: float, beta: float = -2.0, **kwargs) -> "FitConfig":
209
+ """Selection-band mode: slope fixed (default beta = -2, the metal-poor
210
+ expectation) with the 0.3 slope prior in the error budget."""
211
+ return cls(z=z, continuum=ContinuumConfig(beta_mode="fixed", beta=beta),
212
+ **kwargs)
213
+
214
+ def with_line_role(self, name: str, role: str,
215
+ tied_to: Optional[str] = None,
216
+ ratio: Optional[float] = None) -> "FitConfig":
217
+ """Copy of this config with one line's role changed. The copy is
218
+ fully re-validated, so e.g. switching off a line that others are
219
+ tied to raises immediately rather than failing inside fit()."""
220
+ if name not in {l.name for l in self.lines}:
221
+ raise KeyError(f"no line named {name!r}")
222
+ data = self.model_dump()
223
+ for l in data["lines"]:
224
+ if l["name"] == name:
225
+ l["role"] = role
226
+ l["tied_to"] = tied_to if role == "tied" else None
227
+ l["ratio"] = ratio if role == "tied" else None
228
+ return FitConfig.model_validate(data)
229
+
230
+ def with_contaminant_mode(self, frac: float = 0.35) -> "FitConfig":
231
+ """Tie [N II]+[S II] to Halpha (metal-rich contaminant mode)."""
232
+ cfg = self
233
+ for name, ratio in contaminant_ties(frac).items():
234
+ cfg = cfg.with_line_role(name, "tied", tied_to="Halpha", ratio=ratio)
235
+ return cfg
236
+
237
+ def with_balmer(self, case: str = "B", te: float = 10000.0,
238
+ ne: float = 100.0) -> "FitConfig":
239
+ """Copy with the Balmer tie ratios set for the given recombination
240
+ case at (T_e, n_e) (see :func:`lated.lines.balmer_ratios`).
241
+ Only lines that are currently tied to their default parent
242
+ (Hbeta -> Halpha, higher orders -> Hbeta) are rewritten; free/off
243
+ lines and custom ties are left alone. Case B at
244
+ (1e4 K, 1e2 cm^-3) reproduces the paper defaults."""
245
+ ratios = balmer_ratios(case, te, ne)
246
+ parent = {"Hbeta": "Halpha"}
247
+ data = self.model_dump()
248
+ for l in data["lines"]:
249
+ r = ratios.get(l["name"])
250
+ if (r is not None and l["role"] == "tied"
251
+ and l["tied_to"] == parent.get(l["name"], "Hbeta")):
252
+ l["ratio"] = r
253
+ return FitConfig.model_validate(data)
254
+
255
+ def with_case_b(self, te: float = 10000.0,
256
+ ne: float = 100.0) -> "FitConfig":
257
+ """Backwards-compatible alias for :meth:`with_balmer` (case='B')."""
258
+ return self.with_balmer("B", te, ne)
@@ -0,0 +1,201 @@
1
+ 6031.5 0.000309961
2
+ 6041.5 0.00123754
3
+ 6051.5 0.00409764
4
+ 6061.5 0.010342
5
+ 6071.5 0.0207281
6
+ 6081.5 0.0345091
7
+ 6091.5 0.0494549
8
+ 6101.5 0.0632327
9
+ 6111.5 0.0743233
10
+ 6121.5 0.0825961
11
+ 6131.5 0.0884712
12
+ 6141.5 0.0931323
13
+ 6151.5 0.097091
14
+ 6161.5 0.101308
15
+ 6171.5 0.105977
16
+ 6181.5 0.110771
17
+ 6191.5 0.115565
18
+ 6201.5 0.119845
19
+ 6211.5 0.123279
20
+ 6221.5 0.126114
21
+ 6231.5 0.128232
22
+ 6241.5 0.130247
23
+ 6251.5 0.13192
24
+ 6261.5 0.133178
25
+ 6271.5 0.134178
26
+ 6281.5 0.134887
27
+ 6291.5 0.135268
28
+ 6301.5 0.135521
29
+ 6311.5 0.135661
30
+ 6321.5 0.135902
31
+ 6331.5 0.137156
32
+ 6341.5 0.139277
33
+ 6351.5 0.14183
34
+ 6361.5 0.144646
35
+ 6371.5 0.14706
36
+ 6381.5 0.149009
37
+ 6391.5 0.150766
38
+ 6401.5 0.152204
39
+ 6411.5 0.153924
40
+ 6421.5 0.155673
41
+ 6431.5 0.157162
42
+ 6441.5 0.158391
43
+ 6451.5 0.159284
44
+ 6461.5 0.159984
45
+ 6471.5 0.160807
46
+ 6481.5 0.161983
47
+ 6491.5 0.16336
48
+ 6501.5 0.165113
49
+ 6511.5 0.166385
50
+ 6521.5 0.167236
51
+ 6531.5 0.167801
52
+ 6541.5 0.168033
53
+ 6551.5 0.167927
54
+ 6561.5 0.167929
55
+ 6571.5 0.167631
56
+ 6581.5 0.167511
57
+ 6591.5 0.167843
58
+ 6601.5 0.168728
59
+ 6611.5 0.169699
60
+ 6621.5 0.1713
61
+ 6631.5 0.173464
62
+ 6641.5 0.176055
63
+ 6651.5 0.178398
64
+ 6661.5 0.180203
65
+ 6671.5 0.18098
66
+ 6681.5 0.181266
67
+ 6691.5 0.181391
68
+ 6701.5 0.181189
69
+ 6711.5 0.180787
70
+ 6721.5 0.180361
71
+ 6731.5 0.180272
72
+ 6741.5 0.180103
73
+ 6751.5 0.179942
74
+ 6761.5 0.180319
75
+ 6771.5 0.181147
76
+ 6781.5 0.182099
77
+ 6791.5 0.183778
78
+ 6801.5 0.18605
79
+ 6811.5 0.188199
80
+ 6821.5 0.189765
81
+ 6831.5 0.190714
82
+ 6841.5 0.191931
83
+ 6851.5 0.192864
84
+ 6861.5 0.194002
85
+ 6871.5 0.194906
86
+ 6881.5 0.196068
87
+ 6891.5 0.197647
88
+ 6901.5 0.198913
89
+ 6911.5 0.199266
90
+ 6921.5 0.198333
91
+ 6931.5 0.196206
92
+ 6941.5 0.193351
93
+ 6951.5 0.190192
94
+ 6961.5 0.187901
95
+ 6971.5 0.187081
96
+ 6981.5 0.187895
97
+ 6991.5 0.190337
98
+ 7001.5 0.193836
99
+ 7011.5 0.197938
100
+ 7021.5 0.200988
101
+ 7031.5 0.203635
102
+ 7041.5 0.205375
103
+ 7051.5 0.206029
104
+ 7061.5 0.206845
105
+ 7071.5 0.207391
106
+ 7081.5 0.20855
107
+ 7091.5 0.209964
108
+ 7101.5 0.210253
109
+ 7111.5 0.209846
110
+ 7121.5 0.208012
111
+ 7131.5 0.205859
112
+ 7141.5 0.204222
113
+ 7151.5 0.203804
114
+ 7161.5 0.204045
115
+ 7171.5 0.204292
116
+ 7181.5 0.203746
117
+ 7191.5 0.202009
118
+ 7201.5 0.19976
119
+ 7211.5 0.19814
120
+ 7221.5 0.198677
121
+ 7231.5 0.20182
122
+ 7241.5 0.206824
123
+ 7251.5 0.212809
124
+ 7261.5 0.218645
125
+ 7271.5 0.223363
126
+ 7281.5 0.226589
127
+ 7291.5 0.228757
128
+ 7301.5 0.229885
129
+ 7311.5 0.229396
130
+ 7321.5 0.228432
131
+ 7331.5 0.22666
132
+ 7341.5 0.224067
133
+ 7351.5 0.221453
134
+ 7361.5 0.219258
135
+ 7371.5 0.217786
136
+ 7381.5 0.217562
137
+ 7391.5 0.218243
138
+ 7401.5 0.219014
139
+ 7411.5 0.219954
140
+ 7421.5 0.220665
141
+ 7431.5 0.222086
142
+ 7441.5 0.224779
143
+ 7451.5 0.228542
144
+ 7461.5 0.232279
145
+ 7471.5 0.236426
146
+ 7481.5 0.239395
147
+ 7491.5 0.241841
148
+ 7501.5 0.243029
149
+ 7511.5 0.243551
150
+ 7521.5 0.24347
151
+ 7531.5 0.241723
152
+ 7541.5 0.239053
153
+ 7551.5 0.234895
154
+ 7561.5 0.230498
155
+ 7571.5 0.226996
156
+ 7581.5 0.225189
157
+ 7591.5 0.224385
158
+ 7601.5 0.224738
159
+ 7611.5 0.225587
160
+ 7621.5 0.226597
161
+ 7631.5 0.228928
162
+ 7641.5 0.232252
163
+ 7651.5 0.236955
164
+ 7661.5 0.241852
165
+ 7671.5 0.24604
166
+ 7681.5 0.247924
167
+ 7691.5 0.248015
168
+ 7701.5 0.24673
169
+ 7711.5 0.244373
170
+ 7721.5 0.241802
171
+ 7731.5 0.238095
172
+ 7741.5 0.233777
173
+ 7751.5 0.22837
174
+ 7761.5 0.222046
175
+ 7771.5 0.213078
176
+ 7781.5 0.199583
177
+ 7791.5 0.180581
178
+ 7801.5 0.156823
179
+ 7811.5 0.130334
180
+ 7821.5 0.103585
181
+ 7831.5 0.0788306
182
+ 7841.5 0.0576372
183
+ 7851.5 0.0406466
184
+ 7861.5 0.0277262
185
+ 7871.5 0.018528
186
+ 7881.5 0.012305
187
+ 7891.5 0.00826874
188
+ 7901.5 0.00570614
189
+ 7911.5 0.00400084
190
+ 7921.5 0.00286948
191
+ 7931.5 0.00203922
192
+ 7941.5 0.00146461
193
+ 7951.5 0.00106776
194
+ 7961.5 0.000784746
195
+ 7971.5 0.000581088
196
+ 7981.5 0.000432432
197
+ 7991.5 0.000324602
198
+ 8001.5 0.000246103
199
+ 8011.5 0.000187665
200
+ 8021.5 0.000143742
201
+ 8031.5 0.000111208