Method
NumCosmoXcorSolversolve
Declaration [src]
void
nc_xcor_solver_solve (
NcXcorSolver* solver,
NcXcor* xc,
NcHICosmo* cosmo
)
Description [src]
Computes every requested Cl block. Requires nc_xcor_solver_plan_blocks()
to have been called first. Replaces any results from a previous
nc_xcor_solver_solve() call.
When xc‘s method is kernel-space (NC_XCOR_METHOD_KERNEL_CUBATURE or
NC_XCOR_METHOD_KERNEL_EXACT), each distinct
kernel’s k-space closure (nc_xcor_kernel_get_eval_vectorized()) is built
once per $\ell$-block and shared across every request needing it in that
block, instead of rebuilding it once per pair the way nc_xcor_compute()
does — see plan doc dev-notes/xcor_ultralevin_batching_plan.md sec. 5-6.
Different $\ell$-blocks share no reusable operator state with each other (a
fresh NcmSBesselIntegratorLevin $\ell$-range rebuild is required regardless),
so blocks are additionally processed in parallel across an OpenMP team
(plan doc sec. 6.3). The registered kernels are shared by the team and are
prepared against cosmo before it starts, so they are only ever read inside
it; what is private to each thread is the per-block integrator and the
integrand cache built from it. No thread touches another’s integrand or
integrator state, so no locking is needed inside the per-block work itself.
They share that whole path and differ only in the outer quadrature (adaptive cubature, or exact Gauss-Legendre over the common refinement of each pair’s knot sets), so neither needs a solve loop of its own.
The redshift-space Limber methods (NC_XCOR_METHOD_LIMBER_Z_GSL,
NC_XCOR_METHOD_LIMBER_Z_CUBATURE) have no block-shared closure to reuse
(tier 1 stays untouched by design, plan doc sec. 8), so those requests are
computed directly with nc_xcor_compute(), one call per request, serially,
for correctness with no reuse.
Results are retrieved with nc_xcor_solver_get_result().