Skip to content

Commit 20a2daa

Browse files
daspushpitaPushpita Dasthjsal
authored
Merging the interpolated temperature function onto the main branch (#692)
* Adding the shell_interpolator following Das2025+ * temp_interp_everywhere: unify interpolation toggle and bug fixes - standardize interpolation activation on `use_interpolated_temperature` across `HotRegion`, `Elsewhere`, and `Everywhere` - keep `mycoolgrid` as a legacy alias with conflict checks to avoid ambiguous toggle state - fix ceding-region assignment bug in `HotRegion` so interpolated temperatures update `_cede_cellParamVecs` (not superseding cells) - preserve `first_spot`/`second_spot` compatibility and pass them through the shell interpolator flow - align callsites with shell interpolator API (`read_regrid()` / `read_average_shell(...)`) using object attributes for shared config - add robust NaN handling in interpolation (nearest fallback + finite clamp + `T_everywhere` floor) * Cleaning up and adding comments... * Phi-grid definition changed to match temperature map interpolation assumptions. * The error message for using the old temperature grid argument name added also to Elsewhere and Everywhere. * Changelog items added. * Cleaning of an extra line. * Mentioning "Adding docs" in the todo page. --------- Co-authored-by: Pushpita Das <pushpita@Pushpitas-MacBook-Pro-9.local> Co-authored-by: Tuomo Salmi <tuomo.salmi@helsinki.fi>
1 parent 6ffdd92 commit 20a2daa

9 files changed

Lines changed: 716 additions & 29 deletions

File tree

changelog.d/692.added.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added interpolated temperature functionality when using a pre-calculated temperature map.

changelog.d/692.attribution.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Pushpita Das

changelog.d/692.changed.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Phi-grid definition changed in cellmesh/global_mesh.pyx to match temperature map interpolation assumptions.

docs/source/todo.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ We are currently working on the following upgrades:
1313
* Having the option of specifying EOS model-informed mass-radius priors.
1414
* Testing the robustness of universal relations used in the code.
1515
* Improving plotting and graphics routines to visualize results.
16-
* Defining and implementing code standards
16+
* Defining and implementing code standards.
17+
* Providing documentation for the interpolated temperature map functionality implemented in v3.3.0.

xpsi/Elsewhere.py

Lines changed: 119 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from xpsi.Parameter import Parameter
88
from xpsi.ParameterSubspace import ParameterSubspace
9+
from xpsi.shell_interpolator import Temp_Interpolator_shells
910

1011
class AtmosError(xpsiError):
1112
""" Raised if the numerical atmosphere data were not preloaded. """
@@ -91,8 +92,39 @@ class Elsewhere(ParameterSubspace):
9192
on a surface (accounting for the surface tilt due to rotation), then
9293
the iteration over image orders terminates.
9394
95+
:param bool use_interpolated_temperature:
96+
If ``True``, replace the uniform elsewhere temperature field with
97+
temperatures interpolated from ``filename`` onto the X-PSI elsewhere
98+
mesh.
99+
100+
:param bool myelsewhere:
101+
Region selector passed to the interpolation helper for elsewhere-only
102+
shell data handling.
103+
104+
:param float T_everywhere:
105+
Lower floor applied to interpolated log10 temperatures after
106+
interpolation.
107+
108+
:param int coderes:
109+
Resolution of the input shell grid. The file is assumed to represent
110+
a ``coderes x coderes`` angular mesh.
111+
112+
:param str filename:
113+
Path to the shell data file used when
114+
``use_interpolated_temperature=True``.
115+
116+
:param bool bhac_data:
117+
If ``True``, derive temperatures from BHAC shell fluxes; otherwise
118+
read temperatures directly from the file.
119+
94120
"""
95121
required_names = ['elsewhere_temperature (if no custom specification)']
122+
optional_names = ['use_interpolated_temperature',
123+
'myelsewhere',
124+
'T_everywhere',
125+
'coderes',
126+
'filename',
127+
'bhac_data']
96128

97129
def __init__(self,
98130
sqrt_num_cells = 64,
@@ -101,16 +133,39 @@ def __init__(self,
101133
values = None,
102134
atm_ext="BB",
103135
custom = None,
104-
image_order_limit = None):
136+
image_order_limit = None,
137+
use_interpolated_temperature = None,
138+
myelsewhere = False,
139+
T_everywhere = 5.5,
140+
coderes = 512,
141+
filename = False,
142+
bhac_data = True,
143+
**kwargs):
144+
145+
if 'mycoolgrid' in kwargs:
146+
raise TypeError("The 'mycoolgrid' argument has been removed; "
147+
"use 'use_interpolated_temperature' instead.")
105148

106149
self.sqrt_num_cells = sqrt_num_cells
107150
self.num_rays = num_rays
108151
self.image_order_limit = image_order_limit
109152
self.atm_ext = atm_ext
110153

154+
requested_interp = use_interpolated_temperature
155+
156+
self.use_interpolated_temperature = bool(requested_interp)
157+
self.myelsewhere = myelsewhere
158+
self.T_everywhere = T_everywhere
159+
self.coderes = coderes
160+
self.filename = filename
161+
self.bhac_data = bhac_data
162+
111163
if bounds is None: bounds = {}
112164
if values is None: values = {}
113165

166+
if self.use_interpolated_temperature and self.filename is False:
167+
raise ValueError('Filename not given for interpolation')
168+
114169
if not custom: # setup default temperature parameter
115170
T = Parameter('elsewhere_temperature',
116171
strict_bounds = (3.0, 7.6), # very cold --> very hot
@@ -259,29 +314,74 @@ def _compute_cellParamVecs(self, *args):
259314
An *ndarray[n,n]* of mesh-point colatitudes.
260315
261316
"""
262-
if args: # hot region mesh shape information
263-
cellParamVecs = _np.ones((args[0].shape[0],
264-
args[0].shape[1],
265-
len(self.vector)+1),
266-
dtype=_np.double)
317+
if not self.use_interpolated_temperature:
318+
if args: # hot region mesh shape information
319+
cellParamVecs = _np.ones((args[0].shape[0],
320+
args[0].shape[1],
321+
len(self.vector)+1),
322+
dtype=_np.double)
267323

268-
# get self.vector because there may be fixed variables
269-
# that also need to be directed to the integrators
270-
# for intensity evaluation
271-
cellParamVecs[...,:-1] *= _np.array(self.vector)
324+
# get self.vector because there may be fixed variables
325+
# that also need to be directed to the integrators
326+
# for intensity evaluation
327+
cellParamVecs[...,:-1] *= _np.array(self.vector)
272328

273-
return cellParamVecs
329+
return cellParamVecs
274330

275-
else:
276-
self._cellParamVecs = _np.ones((self._theta.shape[0],
277-
self._theta.shape[1],
278-
len(self.vector)+1),
279-
dtype=_np.double)
331+
else:
332+
self._cellParamVecs = _np.ones((self._theta.shape[0],
333+
self._theta.shape[1],
334+
len(self.vector)+1),
335+
dtype=_np.double)
336+
337+
self._cellParamVecs[...,:-1] *= _np.array(self.vector)
280338

281-
self._cellParamVecs[...,:-1] *= _np.array(self.vector)
339+
for i in range(self._cellParamVecs.shape[1]):
340+
self._cellParamVecs[:,i,-1] *= self._effGrav
282341

283-
for i in range(self._cellParamVecs.shape[1]):
284-
self._cellParamVecs[:,i,-1] *= self._effGrav
342+
else:
343+
# Replace the uniform elsewhere temperature field with values read
344+
# from the shell file and interpolated onto the X-PSI mesh.
345+
shell_interp = Temp_Interpolator_shells()
346+
shell_interp.coderes = self.coderes
347+
shell_interp.filename = self.filename
348+
shell_interp.bhac_shell_avg = self.bhac_data
349+
shell_interp.elsewhere_xpsi = self.myelsewhere
350+
data_avg = shell_interp.read_average_shell(bhac_shell_avg=self.bhac_data)
351+
352+
if args: # hot region mesh shape information
353+
shell_interp.xpsi_theta = args[0]
354+
shell_interp.xpsi_phi = self._phi
355+
356+
cellParamVecs = _np.ones((args[0].shape[0],
357+
args[0].shape[1],
358+
len(self.vector)+1),
359+
dtype=_np.double)
360+
361+
temperature_interpolated = shell_interp.temp_interpolation_avg(
362+
thetacode=data_avg[0],
363+
phicode=data_avg[1],
364+
Tempcode=data_avg[2],
365+
T_everywhere=self.T_everywhere)
366+
cellParamVecs[:,:,0] = temperature_interpolated[:,:]
367+
return cellParamVecs
368+
369+
else:
370+
shell_interp.xpsi_theta = self._theta
371+
shell_interp.xpsi_phi = self._phi
372+
self._cellParamVecs = _np.ones((self._theta.shape[0],
373+
self._theta.shape[1],
374+
len(self.vector)+1),
375+
dtype=_np.double)
376+
377+
temperature_interpolated = shell_interp.temp_interpolation_avg(
378+
thetacode=data_avg[0],
379+
phicode=data_avg[1],
380+
Tempcode=data_avg[2],
381+
T_everywhere=self.T_everywhere)
382+
self._cellParamVecs[:,:,0] = temperature_interpolated[:,:]
383+
for i in range(self._cellParamVecs.shape[1]):
384+
self._cellParamVecs[:,i,-1] *= self._effGrav
285385

286386
def embed(self, spacetime, threads):
287387
""" Embed the photosphere elsewhere. """

xpsi/Everywhere.py

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from xpsi.Parameter import Parameter
88
from xpsi.ParameterSubspace import ParameterSubspace
9+
from xpsi.shell_interpolator import Temp_Interpolator_shells
910

1011
class AtmosError(xpsiError):
1112
""" Raised if the numerical atmosphere data were not preloaded. """
@@ -134,9 +135,41 @@ class Everywhere(ParameterSubspace):
134135
default global mesh (i.e., no subclassing) results in a time-invariant
135136
signal.
136137
138+
:param bool use_interpolated_temperature:
139+
If ``True``, replace the uniform global temperature field with
140+
temperatures interpolated from ``filename`` onto the X-PSI mesh.
141+
142+
:param bool myeverywhere:
143+
Legacy alias for enabling interpolated temperatures.
144+
145+
:param bool everywhere_flag:
146+
Legacy alias for enabling interpolated temperatures.
147+
148+
:param float T_everywhere:
149+
Lower floor applied to interpolated log10 temperatures after
150+
interpolation.
151+
152+
:param int coderes:
153+
Resolution of the input shell grid. The file is assumed to represent
154+
a ``coderes x coderes`` angular mesh.
155+
156+
:param str filename:
157+
Path to the shell data file used when
158+
``use_interpolated_temperature=True``.
159+
160+
:param bool bhac_data:
161+
If ``True``, derive temperatures from BHAC shell fluxes; otherwise
162+
read temperatures directly from the file.
163+
137164
"""
138165
required_names = ['temperature (if no custom specification)']
139-
166+
optional_names = ['use_interpolated_temperature',
167+
'myeverywhere (legacy)',
168+
'everywhere_flag (legacy)',
169+
'T_everywhere',
170+
'coderes',
171+
'filename',
172+
'bhac_data']
140173
def __init__(self,
141174
time_invariant,
142175
bounds = None,
@@ -150,7 +183,19 @@ def __init__(self,
150183
beam_opt=0,
151184
custom = None,
152185
image_order_limit = None,
153-
_integrator_toggle = False):
186+
_integrator_toggle = False,
187+
use_interpolated_temperature = None,
188+
myeverywhere = None,
189+
everywhere_flag = None,
190+
T_everywhere = 5.5,
191+
coderes = 512,
192+
filename=False,
193+
bhac_data = True,
194+
**kwargs):
195+
196+
if 'mycoolgrid' in kwargs:
197+
raise TypeError("The 'mycoolgrid' argument has been removed; "
198+
"use 'use_interpolated_temperature' instead.")
154199

155200
self.num_rays = num_rays
156201

@@ -194,6 +239,34 @@ def __init__(self,
194239
self.time_invariant = time_invariant
195240
self._integrator_toggle = _integrator_toggle
196241

242+
requested_interp = use_interpolated_temperature
243+
legacy_flags = [v for v in (myeverywhere, everywhere_flag) if v is not None]
244+
if legacy_flags:
245+
if any(bool(v) != bool(legacy_flags[0]) for v in legacy_flags[1:]):
246+
raise ValueError('Conflicting legacy interpolation flags: '
247+
'myeverywhere and everywhere_flag.')
248+
249+
legacy_flag = bool(legacy_flags[0])
250+
if requested_interp is not None and legacy_flag != bool(requested_interp):
251+
raise ValueError('Conflicting interpolation flags: '
252+
'use_interpolated_temperature and legacy '
253+
'flags (myeverywhere/everywhere_flag).')
254+
else:
255+
legacy_flag = None
256+
257+
if requested_interp is None:
258+
requested_interp = legacy_flag if legacy_flag is not None else False
259+
260+
self.use_interpolated_temperature = bool(requested_interp)
261+
self.myeverywhere = self.use_interpolated_temperature
262+
self.T_everywhere = T_everywhere
263+
self.coderes = coderes
264+
self.filename = filename
265+
self.bhac_data = bhac_data
266+
267+
if self.use_interpolated_temperature and self.filename is False:
268+
raise ValueError('Filename not given for interpolation')
269+
197270
@property
198271
def atm_ext(self):
199272
""" ... """
@@ -458,8 +531,25 @@ def _compute_cellParamVecs(self):
458531
2),
459532
dtype=_np.double)
460533

461-
self._cellParamVecs[...,:-1] *= _np.array([self.vector[0]])
462-
534+
if not self.use_interpolated_temperature:
535+
self._cellParamVecs[...,:-1] *= _np.array([self.vector[0]])
536+
else:
537+
# Replace the uniform everywhere temperature field with values
538+
# read from the shell file and interpolated onto the X-PSI mesh.
539+
shell_interp = Temp_Interpolator_shells()
540+
shell_interp.bhac_shell_avg = self.bhac_data
541+
shell_interp.coderes= self.coderes
542+
shell_interp.filename = self.filename
543+
shell_interp.everywhere_xpsi= self.myeverywhere
544+
shell_interp.xpsi_theta = self._theta
545+
shell_interp.xpsi_phi = self._phi
546+
data_avg = shell_interp.read_average_shell(bhac_shell_avg=self.bhac_data)
547+
548+
Temperature_interpolated = shell_interp.temp_interpolation_avg(thetacode=data_avg[0],phicode=data_avg[1],
549+
Tempcode=data_avg[2], T_everywhere = self.T_everywhere)
550+
551+
self._cellParamVecs[:,:,0] = Temperature_interpolated[:,:]
552+
463553
for i in range(self._cellParamVecs.shape[1]):
464554
self._cellParamVecs[:,i,-1] *= self._effGrav
465555

0 commit comments

Comments
 (0)