"""Conditional forward map and likelihood in a fixed observation coordinate.""" import math import numpy as np from spherical_halos import halo_speed_squared def forward(record,mass_to_light,density,scale,kind,distance_ratio=1.,inclination_degrees=None): if inclination_degrees is None:inclination_degrees=record['metadata']['inclinationDegrees'] if not all(math.isfinite(value) for value in [mass_to_light,density,scale,distance_ratio,inclination_degrees]):raise ValueError('Nonfinite requested parameter') if mass_to_light<0 or distance_ratio<=0 or not 30<=inclination_degrees<=85:raise ValueError('Outside conditional model domain') rows=np.asarray(record['rows']);radius=rows[:,0]*distance_ratio if np.any(radius<=0):raise ValueError('Nonpositive orbit radius') signed=lambda velocity:velocity*np.abs(velocity) if np.any(rows[:,5]!=0):raise ValueError('First fixed-object prototype supports zero bulge only') gas=distance_ratio*signed(rows[:,3]);disk=distance_ratio*mass_to_light*signed(rows[:,4]);bulge=np.zeros(len(rows)) halo=halo_speed_squared(radius,density,scale,kind);total=gas+disk+bulge+halo if np.any(~np.isfinite(total)) or np.any(total<=0):raise ValueError('No positive circular-speed solution') speed=np.sqrt(total);sine=math.sin(math.radians(inclination_degrees)) return {'radiusKpc':radius,'gasSignedSpeedSquared':gas,'diskSignedSpeedSquared':disk,'bulgeSignedSpeedSquared':bulge, 'haloSpeedSquared':halo,'totalSpeedSquared':total,'circularVelocityKms':speed,'referenceProjectedModelKms':speed*sine} def observation_coordinate(record): rows=np.asarray(record['rows']);sine=math.sin(math.radians(record['metadata']['inclinationDegrees'])) return rows[:,1]*sine,rows[:,2]*sine def log_likelihood(record,prediction): observed,error=observation_coordinate(record) residual=(observed-prediction['referenceProjectedModelKms'])/error return float(-.5*np.sum(residual*residual+np.log(2*math.pi*error*error)))