back to table · edit · history · where entries came from · files · download
3598 bytes, as of the version from 2026-10-30 06:27 (current). Recorded here, not run.
"""Tidal Love numbers of Newtonian polytropic stars -- numberdb.org/T619.
Run with SageMath (install numberdb once using sage -pip install numberdb):
sage -python generate.py # recompute and verify every stored row
sage -python generate.py --fill # fill this existing draft
Download tidal_solver.py and the attached files listed in `files` alongside
this script. Draft access needs NUMBERDB_API_KEY. The campaign wrapper accepts
a key on stdin when NUMBERDB_KEY_FROM_STDIN=1. --fill does not offer or publish.
The apsidal convention is half the induced/applied potential ratio. The n=0
surface density jump gives 3/[4(ell-1)] exactly. The n=1 expressions use Arb.
Other values use original-potential Riccati integration in t=sqrt(theta).
Two runs at 150/210 working decimal digits also change order (160/210),
step cap (1/12,1/18) and matching radius (1/2,2/3). Agreement is heuristic:
ODE truncation, propagation and endpoint errors are not rigorously bounded.
Only 100 significant digits are stored. No cached numerical input supplies
value(); its in-memory cache merely shares each background between ell=2,3.
See argument-selection.md for the mixed n groups and discrete ell selection.
The solver supports half-integer n, not every rational n in the domain.
"""
import os,sys
from functools import lru_cache
import numberdb.sage as numberdb
from sage.rings.real_arb import RealBallField
from sage.rings.rational_field import QQ
from tidal_solver import integrate
INDICES=('0','1/2','1','3/2','2','5/2','3','7/2','4','9/2')
CONFIG={150:(160,12,'1/2'),210:(210,18,'2/3')}
@lru_cache(maxsize=24)
def solution(n,working):return integrate(n,working,*CONFIG[working])
class PolytropicLove(numberdb.Generator):
table='T619'
parameters=('n','ell')
type='R'
digits=100
rigour='heuristic (agreement-checked)'
files=('generate.py','tidal_solver.py','compute.py','radial_check.py','readback_checks.py',
'dry_run.py','check.py','argument-selection.md','numerical-evidence.json',
'radial-evidence.json','skill-manifest.json','skill-evidence.json','source-manifest.json')
def enumerate(self):
for n in INDICES:
for ell in ('2','3'):yield {'n':n,'ell':ell}
def value(self,params,digits):
n=str(QQ(params['n']));ell=int(params['ell'])
if n not in INDICES or ell not in (2,3):raise ValueError('Use selected indices and ell=2,3.')
if digits>100:raise ValueError('Precision policy checked for at most 100 digits.')
if n=='0':
return {'number':QQ(3)/(4*(ell-1)),'comment':'The incompressible model includes the surface density jump.'}
if n=='1':
B=RealBallField(numberdb.bits(digits,losing=80));p=B.pi()**2
val=(15-p)/(2*p) if ell==2 else (105-10*p)/(6*p)
return {'number':val,'comment':r'The linear Lane–Emden model has $\theta_1(\xi)=\sin(\xi)/\xi$.'}
return numberdb.agreeing(lambda working:str(solution(n,working)[0][ell-2]),at=(150,210))
if __name__=='__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
token=sys.stdin.read().strip()
if '=' in token and token.split('=',1)[0].replace('_','').isalnum():token=token.split('=',1)[1].strip().strip('\"\'')
os.environ['NUMBERDB_API_KEY']=token
g=PolytropicLove()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH')=='1':print(g.publish(message='Add twenty Newtonian apsidal constants with analytic and independent radial checks.'))
else:
r=g.verify(sample=None);print(r);sys.exit(0 if r.ok else 1)