Skip to content

Scattering Amplitude Emulator

The Scattering Amplitude Emulator (SAE) is the primary user-facing class. Minimally, all the user should have to do is (1) pick an Interaction, (2) choose a set of parameter-space, training points, and (3) pick an $\ell_\max$. That's it. There is no step... well, there's no step 4 at least.

ScatteringAmplitudeEmulator(interaction_space, bases, l_max=None, angles=DEFAULT_ANGLE_MESH, s_0=6 * np.pi, verbose=True, Smatrix_abs_tol=1e-06, initialize_emulator=True)

Trains a reduced-basis emulator that computes differential and total cross sections (from emulated phase shifts).

Parameters:

Name Type Description Default
interaction_space InteractionSpace

local interaction up to (and including $\ell_\max$)

required
bases list[Basis]

list of Basis objects

required
l_max int

maximum angular momentum to include in the sum approximating the cross section

None
angles ndarray

Differential cross sections are functions of the angles. These are the specific values at which the user wants to emulate the cross section.

DEFAULT_ANGLE_MESH
s_0 float

$s$ point where the phase shift is extracted

6 * pi
verbose bool

Do you want the class to print out warnings?

True
Smatrix_abs_tol

absolute tolerance for deviation of real part of S-matrix amplitudes from 1, used as criteria to stop calculation ig higher partial waves are negligble

1e-06
initialize_emulator

build the low-order emulator (True required for emulation)

True

Attributes:

Name Type Description
l_max int

maximum angular momentum

angles ndarray

angle values at which the differential cross section is desired

rbes list

list of ReducedBasisEmulators; one for each partial wave (and total $j$ with spin-orbit)

ls ndarray

angular momenta; shape = (l_max+1, 1)

P_l_costheta ndarray

Legendre polynomials evaluated at angles

P_1_l_costheta ndarray

associated Legendre polynomials evalated at angles

k_c float

Coulomb momentum, $k\eta$

eta float

Sommerfeld parameter

sigma_l float

Coulomb phase shift

f_c ndarray

scattering amplitude

rutherford ndarray

Rutherford scattering

Source code in src/rose/scattering_amplitude_emulator.py
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
def __init__(
    self,
    interaction_space: InteractionSpace,
    bases: list,
    l_max: int = None,
    angles: np.array = DEFAULT_ANGLE_MESH,
    s_0: float = 6 * np.pi,
    verbose: bool = True,
    Smatrix_abs_tol=1.0e-6,
    initialize_emulator=True,
):
    r"""Trains a reduced-basis emulator that computes differential and total cross sections
        (from emulated phase shifts).

    Parameters:
        interaction_space (InteractionSpace): local interaction up to (and including $\ell_\max$)
        bases (list[Basis]): list of `Basis` objects
        l_max (int): maximum angular momentum to include in the sum approximating the cross section
        angles (ndarray): Differential cross sections are functions of the
            angles. These are the specific values at which the user wants to
            emulate the cross section.
        s_0 (float): $s$ point where the phase shift is extracted
        verbose (bool): Do you want the class to print out warnings?
        Smatrix_abs_tol : absolute tolerance for deviation of real part of S-matrix amplitudes
            from 1, used as criteria to stop calculation ig higher partial waves are negligble
        initialize_emulator : build the low-order emulator (True required for emulation)

    Attributes:
        l_max (int): maximum angular momentum
        angles (ndarray): angle values at which the differential cross section is desired
        rbes (list): list of `ReducedBasisEmulators`; one for each partial wave
            (and total $j$ with spin-orbit)
        ls (ndarray): angular momenta; shape = (`l_max`+1, 1)
        P_l_costheta (ndarray): Legendre polynomials evaluated at `angles`
        P_1_l_costheta (ndarray): **associated** Legendre polynomials evalated at `angles`
        k_c (float): Coulomb momentum, $k\eta$
        eta (float): Sommerfeld parameter
        sigma_l (float): Coulomb phase shift
        f_c (ndarray): scattering amplitude
        rutherford (ndarray): Rutherford scattering

    """
    # partial waves
    if l_max is None:
        l_max = interaction_space.l_max
    self.l_max = l_max
    self.Smatrix_abs_tol = Smatrix_abs_tol

    # construct bases
    self.rbes = []
    for interaction_list, basis_list in zip(interaction_space.interactions, bases):
        self.rbes.append(
            [
                ReducedBasisEmulator(
                    interaction,
                    basis,
                    s_0=s_0,
                    initialize_emulator=initialize_emulator,
                )
                for (interaction, basis) in zip(interaction_list, basis_list)
            ]
        )

    # Let's precompute the things we can.
    self.angles = angles.copy()
    self.ls = np.arange(self.l_max + 1)[:, np.newaxis]
    self.P_l_costheta = eval_legendre(self.ls, np.cos(self.angles))
    self.P_1_l_costheta = np.array(
        [eval_assoc_legendre(l, np.cos(self.angles)) for l in self.ls]
    )

    # Coulomb scattering amplitude
    if (
        self.rbes[0][0].interaction.k is not None
        and self.rbes[0][0].interaction.k_c > 0
    ):
        k = self.rbes[0][0].interaction.k
        self.k_c = self.rbes[0][0].interaction.k_c
        self.eta = self.k_c / k
        self.sigma_l = np.angle(gamma(1 + self.ls + 1j * self.eta))
        sin2 = np.sin(self.angles / 2) ** 2
        self.f_c = (
            -self.eta
            / (2 * k * sin2)
            * np.exp(
                2j * self.sigma_l[0]
                - 2j * self.eta * np.log(np.sin(self.angles / 2))
            )
        )
        self.rutherford = (
            10 * self.eta**2 / (4 * k**2 * np.sin(self.angles / 2) ** 4)
        )
    else:
        self.sigma_l = np.angle(gamma(1 + self.ls + 1j * 0))
        self.k_c = 0
        self.eta = 0
        self.f_c = 0.0 * np.exp(2j * self.sigma_l[0])
        self.rutherford = 0.0 / (np.sin(self.angles / 2) ** 4)

HIFI_solver(interaction_space, base_solver=None, l_max=None, angles=DEFAULT_ANGLE_MESH, verbose=True, Smatrix_abs_tol=1e-06, s_mesh=None) classmethod

Sets up a ScatteringAmplitudeEmulator without any emulation capabilities, for use purely as a high-fidelity solver, for which the exact_* functions will be used.

Parameters:

Name Type Description Default
interaction_space InteractionSpace

local interaction up to (and including $\ell_\max$)

required
base_solver

the solver used. Must be an instance of SchroedingerEquation or a derived class of it. The solvers for each interaction in interaction_space will be constructed using base_solver.clone_for_new_interaction. Defaults to the base class using Runge-Kutta; SchroedingerEquation

None
l_max int

maximum angular momentum to include in the sum approximating the cross section

None
angles ndarray

Differential cross sections are functions of the angles. These are the specific values at which the user wants to emulate the cross section.

DEFAULT_ANGLE_MESH
s_0 float

$s$ point where the phase shift is extracted

required
verbose bool

Do you want the class to print out warnings?

True
Smatrix_abs_tol

absolute tolerance for deviation of real part of S-matrix amplitudes from 1, used as criteria to stop calculation ig higher partial waves are negligble

1e-06
s_mesh ndarray

$s$ (or $\rho$) grid on which wave functions are evaluated

None

Returns:

Name Type Description
sae ScatteringAmplitudeEmulator

scattering amplitude emulator

Source code in src/rose/scattering_amplitude_emulator.py
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
@classmethod
def HIFI_solver(
    cls,
    interaction_space: InteractionSpace,
    base_solver: SchroedingerEquation = None,
    l_max: int = None,
    angles: np.array = DEFAULT_ANGLE_MESH,
    verbose: bool = True,
    Smatrix_abs_tol: float = 1.0e-6,
    s_mesh=None,
):
    r"""Sets up a ScatteringAmplitudeEmulator without any emulation capabilities, for use purely
        as a high-fidelity solver, for which the exact_* functions will be used.

    Parameters:
        interaction_space (InteractionSpace): local interaction up to (and including $\ell_\max$)
        base_solver : the solver used. Must be an instance of SchroedingerEquation or a derived
            class of it. The solvers for each `interaction` in `interaction_space` will be
            constructed using `base_solver.clone_for_new_interaction`. Defaults to the base class
            using Runge-Kutta; `SchroedingerEquation`
        l_max (int): maximum angular momentum to include in the sum approximating the cross section
        angles (ndarray): Differential cross sections are functions of the
            angles. These are the specific values at which the user wants to
            emulate the cross section.
        s_0 (float): $s$ point where the phase shift is extracted
        verbose (bool): Do you want the class to print out warnings?
        Smatrix_abs_tol : absolute tolerance for deviation of real part of S-matrix amplitudes
            from 1, used as criteria to stop calculation ig higher partial waves are negligble
        s_mesh (ndarray): $s$ (or $\rho$) grid on which wave functions are evaluated

    Returns:
        sae (ScatteringAmplitudeEmulator): scattering amplitude emulator

    """
    if base_solver is None:
        base_solver = SchroedingerEquation.make_base_solver()

    if s_mesh is None:
        s_mesh = np.linspace(
            base_solver.domain[0],
            base_solver.domain[1],
            SchroedingerEquation.DEFAULT_NUM_PTS,
        )

    assert (
        s_mesh[0] >= base_solver.domain[0] and s_mesh[-1] <= base_solver.domain[1]
    )

    bases = []
    for interaction_list in interaction_space.interactions:
        basis_list = []
        for interaction in interaction_list:
            solver = base_solver.clone_for_new_interaction(interaction)
            basis = Basis(solver, None, s_mesh, None)
            basis_list.append(basis)
        bases.append(basis_list)

    return cls(
        interaction_space,
        bases,
        l_max,
        angles,
        s_0=base_solver.s_0,
        verbose=verbose,
        Smatrix_abs_tol=Smatrix_abs_tol,
        initialize_emulator=False,
    )

calculate_xs(Splus, Sminus, alpha, angles=None)

Calculates the: - differential cross section in mb/Sr (as a ratio to a Rutherford xs if provided) - analyzing power - total and reacion cross sections in mb

Paramaters

Splus (ndarray) : spin-up phase shifs Sminus (ndarray) : spin-down phase shifts alpha (ndarray) : interaction parameters angles (ndarray) : (optional), angular grid on which to evaluate analyzing \ powers and differential cross section

Returns

cross sections (NucleonNucleusXS) :

Source code in src/rose/scattering_amplitude_emulator.py
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
def calculate_xs(
    self,
    Splus: np.array,
    Sminus: np.array,
    alpha: np.array,
    angles: np.array = None,
):
    r"""Calculates the:
        - differential cross section in mb/Sr (as a ratio to a Rutherford xs if provided)
        - analyzing power
        - total and reacion cross sections in mb

        Paramaters:
            Splus (ndarray) : spin-up phase shifs
            Sminus (ndarray) : spin-down phase shifts
            alpha (ndarray) : interaction parameters
            angles (ndarray) : (optional), angular grid on which to evaluate analyzing \
            powers and differential cross section

        Returns :
            cross sections (NucleonNucleusXS) :
    """
    k = self.rbes[0][0].interaction.momentum(alpha)

    # determine desired angle grid and precompute
    # Legendre functions if necessary
    if angles is None:
        angles = self.angles
        P_l_costheta = self.P_l_costheta
        P_1_l_costheta = self.P_1_l_costheta
        rutherford = self.rutherford
        f_c = self.f_c
    else:
        assert np.max(angles) <= np.pi and np.min(angles) >= 0
        P_l_costheta = np.array(
            [eval_legendre(l, np.cos(angles)) for l in range(self.l_max)]
        )
        P_1_l_costheta = np.array(
            [eval_assoc_legendre(l, np.cos(angles)) for l in range(self.l_max)]
        )
        sin2 = np.sin(angles / 2) ** 2
        rutherford = 10 * self.eta**2 / (4 * k**2 * sin2**2)
        f_c = (
            -self.eta
            / (2 * k * sin2)
            * np.exp(-1j * self.eta * np.log(sin2) + 2j * self.sigma_l[0])
        )

    if self.rbes[0][0].interaction.eta(alpha) > 0:
        return NucleonNucleusXS(
            *xs_calc_coulomb(
                k,
                angles,
                Splus,
                Sminus,
                P_l_costheta,
                P_1_l_costheta,
                f_c,
                self.sigma_l,
                rutherford,
            )
        )
    else:
        return NucleonNucleusXS(
            *xs_calc_neutral(
                k,
                angles,
                Splus,
                Sminus,
                P_l_costheta,
                P_1_l_costheta,
            )
        )

dsdo(alpha, Splus, Sminus)

Gives the differential cross section (dsigma/dOmega = dsdo) in mb/Sr.

Parameters:

Name Type Description Default
alpha ndarray

parameter-space vector

required
Splus ndarray

spin-up smatrix elements

required
Sminus ndarray

spin-down smatrix elements

required

Returns:

Name Type Description
dsdo ndarray

differential cross section (fm^2)

Source code in src/rose/scattering_amplitude_emulator.py
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
def dsdo(self, alpha: np.array, Splus: np.array, Sminus: np.array):
    r"""Gives the differential cross section (dsigma/dOmega = dsdo) in mb/Sr.

    Parameters:
        alpha (ndarray): parameter-space vector
        Splus (ndarray): spin-up smatrix elements
        Sminus (ndarray): spin-down smatrix elements

    Returns:
        dsdo (ndarray): differential cross section (fm^2)

    """
    k = self.rbes[0][0].interaction.momentum(alpha)

    Splus = Splus[:, np.newaxis]
    Sminus = Sminus[:, np.newaxis]
    lmax = Splus.shape[0]
    l = self.ls[:lmax]

    A = self.f_c + (1 / (2j * k)) * np.sum(
        np.exp(2j * self.sigma_l[:lmax])
        * ((l + 1) * (Splus - 1) + l * (Sminus - 1))
        * self.P_l_costheta[:lmax, ...],
        axis=0,
    )
    B = (1 / (2j * k)) * np.sum(
        np.exp(2j * self.sigma_l[:lmax])
        * (Splus - Sminus)
        * self.P_1_l_costheta[:lmax, ...],
        axis=0,
    )

    dsdo = 10 * (np.conj(A) * A + np.conj(B) * B).real
    if self.k_c > 0:
        return dsdo / self.rutherford
    else:
        return dsdo

emulate_dsdo(alpha)

Emulates the differential cross section (dsigma/dOmega = dsdo) in mb/Sr.

Parameters:

Name Type Description Default
alpha ndarray

parameter-space vector

required

Returns:

Name Type Description
dsdo ndarray

emulated differential cross section

Source code in src/rose/scattering_amplitude_emulator.py
310
311
312
313
314
315
316
317
318
319
320
321
def emulate_dsdo(self, alpha: np.array):
    r"""Emulates the differential cross section (dsigma/dOmega = dsdo) in mb/Sr.

    Parameters:
        alpha (ndarray): parameter-space vector

    Returns:
        dsdo (ndarray): emulated differential cross section

    """
    Splus, Sminus = self.emulate_smatrix_elements(alpha)
    return self.dsdo(alpha, Splus, Sminus)

emulate_phase_shifts(alpha)

Gives the phase shifts for each partial wave. Order is [l=0, l=1, ..., l=l_max-1].

Parameters:

Name Type Description Default
alpha ndarray

parameter-space vector

required

Returns:

Name Type Description
phase_shift list

emulated phase shifts

Source code in src/rose/scattering_amplitude_emulator.py
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
def emulate_phase_shifts(self, alpha: np.array):
    r"""Gives the phase shifts for each partial wave.  Order is [l=0, l=1,
        ..., l=l_max-1].

    Parameters:
        alpha (ndarray): parameter-space vector

    Returns:
        phase_shift (list): emulated phase shifts

    """
    return [
        [rbe.emulate_phase_shift(alpha) for rbe in rbe_list]
        for rbe_list in self.rbes
    ]

emulate_rmatrix_elements(alpha)

Returns: Rl_plus (ndarray) : l-s aligned R-matrix elements for partial waves Rl_minus (ndarray) : same as Splus, but l-s anti-aligned

Source code in src/rose/scattering_amplitude_emulator.py
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
def emulate_rmatrix_elements(self, alpha):
    r"""Returns:
    Rl_plus (ndarray) : l-s aligned R-matrix elements for partial waves
    Rl_minus (ndarray) : same as Splus, but l-s anti-aligned
    """
    Rplus = np.array(
        [
            rbe_list[0].R_matrix_element(alpha)
            for rbe_list in self.rbes[0 : self.l_max]
        ]
    )
    Rminus = np.array(
        [Rplus[0]]
        + [
            rbe_list[1].R_matrix_element(alpha)
            for rbe_list in self.rbes[1 : self.l_max]
        ]
    )
    return Rplus, Rminus

emulate_smatrix_elements(alpha)

Sl_plus (ndarray) : l-s aligned S-matrix elements for partial waves up to where Splus < Smatrix_abs_tol Sl_minus (ndarray) : same as Splus, but l-s anti-aligned

Source code in src/rose/scattering_amplitude_emulator.py
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
def emulate_smatrix_elements(self, alpha):
    r"""Returns:
    Sl_plus (ndarray) : l-s aligned S-matrix elements for partial waves up to where
        Splus < Smatrix_abs_tol
    Sl_minus (ndarray) : same as Splus, but l-s anti-aligned
    """
    Splus = np.zeros(self.l_max, dtype=np.complex128)
    Sminus = np.zeros(self.l_max, dtype=np.complex128)
    Splus[0] = self.rbes[0][0].S_matrix_element(alpha)
    Sminus[0] = Splus[0]
    for l in range(1, self.l_max):
        Splus[l] = self.rbes[l][0].S_matrix_element(alpha)
        Sminus[l] = self.rbes[l][1].S_matrix_element(alpha)
        if (
            np.absolute(Splus[l]) < self.Smatrix_abs_tol
            and np.absolute(Sminus[l]) < self.Smatrix_abs_tol
        ):
            break

    return Splus[:l], Sminus[:l]

emulate_wave_functions(alpha)

Gives the wave functions for each partial wave. Returns a list of arrays. Order is [l=0, l=1, ..., l=l_max-1].

Parameters:

Name Type Description Default
alpha ndarray

parameter-space vector

required

Returns:

Name Type Description
wave_functions list

emulated wave functions

Source code in src/rose/scattering_amplitude_emulator.py
372
373
374
375
376
377
378
379
380
381
382
383
384
def emulate_wave_functions(self, alpha: np.array):
    r"""Gives the wave functions for each partial wave.  Returns a list of
        arrays.  Order is [l=0, l=1, ..., l=l_max-1].

    Parameters:
        alpha (ndarray): parameter-space vector

    Returns:
        wave_functions (list): emulated wave functions


    """
    return [[x.emulate_wave_function(alpha) for x in rbe] for rbe in self.rbes]

emulate_xs(alpha, angles=None)

Emulates the: - differential cross section in mb/Sr (as a ratio to a Rutherford xs if provided) - analyzing power - total and reacion cross sections in mb

Paramaters

alpha (ndarray) : interaction parameters angles (ndarray) : (optional), angular grid on which to evaluate analyzing \ powers and differential cross section

Returns

cross sections (NucleonNucleusXS) :

Source code in src/rose/scattering_amplitude_emulator.py
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
def emulate_xs(self, alpha: np.array, angles: np.array = None):
    r"""Emulates the:
        - differential cross section in mb/Sr (as a ratio to a Rutherford xs if provided)
        - analyzing power
        - total and reacion cross sections in mb

        Paramaters:
            alpha (ndarray) : interaction parameters
            angles (ndarray) : (optional), angular grid on which to evaluate analyzing \
            powers and differential cross section

        Returns :
            cross sections (NucleonNucleusXS) :
    """
    # get phase shifts and wavenumber
    Splus, Sminus = self.emulate_smatrix_elements(alpha)
    return self.calculate_xs(Splus, Sminus, alpha, angles)

exact_dsdo(alpha)

Calculates the high-fidelity differential cross section (dsigma/dOmega = dsdo) in mb/Sr.

Parameters:

Name Type Description Default
alpha ndarray

parameter-space vector

required

Returns:

Name Type Description
dsdo ndarray

high-fidelity differential cross section

Source code in src/rose/scattering_amplitude_emulator.py
323
324
325
326
327
328
329
330
331
332
333
334
def exact_dsdo(self, alpha: np.array):
    r"""Calculates the high-fidelity differential cross section (dsigma/dOmega = dsdo) in mb/Sr.

    Parameters:
        alpha (ndarray): parameter-space vector

    Returns:
        dsdo (ndarray): high-fidelity differential cross section

    """
    Splus, Sminus = self.exact_smatrix_elements(alpha)
    return self.dsdo(alpha, Splus, Sminus)

exact_phase_shifts(alpha)

Gives the phase shifts for each partial wave. Order is [l=0, l=1, ..., l=l_max-1].

Parameters:

Name Type Description Default
alpha ndarray

parameter-space vector

required

Returns:

Name Type Description
phase_shift list

high-fidelity phase shifts

Source code in src/rose/scattering_amplitude_emulator.py
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
def exact_phase_shifts(self, alpha: np.array):
    r"""Gives the phase shifts for each partial wave. Order is [l=0, l=1,
        ..., l=l_max-1].

    Parameters:
        alpha (ndarray): parameter-space vector

    Returns:
        phase_shift (list): high-fidelity phase shifts

    """
    return [
        [rbe.basis.solver.delta(alpha) for rbe in rbe_list]
        for rbe_list in self.rbes
    ]

exact_rmatrix_elements(alpha)

Returns: Rl_plus (ndarray) : l-s aligned R-matrix elements for partial waves up to where Rl_minus (ndarray) : same as Splus, but l-s anti-aligned

Source code in src/rose/scattering_amplitude_emulator.py
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
def exact_rmatrix_elements(self, alpha):
    r"""Returns:
    Rl_plus (ndarray) : l-s aligned R-matrix elements for partial waves up to where
    Rl_minus (ndarray) : same as Splus, but l-s anti-aligned
    """
    Rplus = np.array(
        [
            rbe_list[0].basis.solver.rmatrix(alpha)
            for rbe_list in self.rbes[0 : self.l_max]
        ]
    )
    Rminus = np.array(
        [Rplus[0]]
        + [
            rbe_list[1].basis.solver.rmatrix(alpha)
            for rbe_list in self.rbes[1 : self.l_max]
        ]
    )
    return Rplus, Rminus

exact_smatrix_elements(alpha)

Sl_plus (ndarray) : l-s aligned S-matrix elements for partial waves up to where Splus.real - 1 < Smatrix_abs_tol Sl_minus (ndarray) : same as Splus, but l-s anti-aligned

Source code in src/rose/scattering_amplitude_emulator.py
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
def exact_smatrix_elements(self, alpha):
    r"""Returns:
    Sl_plus (ndarray) : l-s aligned S-matrix elements for partial waves up to where
        Splus.real - 1 < Smatrix_abs_tol
    Sl_minus (ndarray) : same as Splus, but l-s anti-aligned
    """

    Splus = np.zeros(self.l_max, dtype=np.complex128)
    Sminus = np.zeros(self.l_max, dtype=np.complex128)
    Splus[0] = self.rbes[0][0].basis.solver.smatrix(alpha)
    Sminus[0] = Splus[0]
    for l in range(1, self.l_max):
        Splus[l] = self.rbes[l][0].basis.solver.smatrix(alpha)
        Sminus[l] = self.rbes[l][1].basis.solver.smatrix(alpha)
        if (
            np.absolute(Splus[l] - 1) < self.Smatrix_abs_tol
            and np.absolute(Sminus[l] - 1) < self.Smatrix_abs_tol
        ):
            break

    return Splus[:l], Sminus[:l]

exact_wave_functions(alpha, s_mesh=None, **solver_kwargs)

Gives the wave functions for each partial wave. Returns a list of arrays. Order is [l=0, l=1, ..., l=l_max-1].

Parameters:

Name Type Description Default
alpha ndarray

parameter-space vector

required
s_mesh ndarray

s_mesh on which to evaluate phi, if different from the one used for emulation

None
solver_kwargs ndarray

passed to SchroedingerEquation.phi

{}

Returns:

Name Type Description
wave_functions list

emulated wave functions

Source code in src/rose/scattering_amplitude_emulator.py
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
def exact_wave_functions(
    self, alpha: np.array, s_mesh: np.array = None, **solver_kwargs
):
    r"""Gives the wave functions for each partial wave.  Returns a list of
        arrays.  Order is [l=0, l=1, ..., l=l_max-1].

    Parameters:
        alpha (ndarray): parameter-space vector
        s_mesh (ndarray): s_mesh on which to evaluate phi, if different from the one used
            for emulation
        solver_kwargs (ndarray): passed to SchroedingerEquation.phi

    Returns:
        wave_functions (list): emulated wave functions


    """
    if s_mesh is None:
        return [
            [x.basis.solver.phi(alpha, x.s_mesh, **solver_kwargs) for x in rbe]
            for rbe in self.rbes
        ]
    else:
        return [
            [x.basis.solver.phi(alpha, s_mesh, **solver_kwargs) for x in rbe]
            for rbe in self.rbes
        ]

exact_xs(alpha, angles=None)

Calculates the exact: - differential cross section in mb/Sr (as a ratio to a Rutherford xs if provided) - analyzing power - total and reacion cross sections in mb

Paramaters

alpha (ndarray) : interaction parameters angles (ndarray) : (optional), angular grid on which to evaluate analyzing \ powers and differential cross section

Returns

cross sections (NucleonNucleusXS) :

Source code in src/rose/scattering_amplitude_emulator.py
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
def exact_xs(self, alpha: np.array, angles: np.array = None):
    r"""Calculates the exact:
        - differential cross section in mb/Sr (as a ratio to a Rutherford xs if provided)
        - analyzing power
        - total and reacion cross sections in mb

        Paramaters:
            alpha (ndarray) : interaction parameters
            angles (ndarray) : (optional), angular grid on which to evaluate analyzing \
            powers and differential cross section

        Returns :
            cross sections (NucleonNucleusXS) :
    """
    # get phase shifts and wavenumber
    Splus, Sminus = self.exact_smatrix_elements(alpha)
    return self.calculate_xs(Splus, Sminus, alpha, angles)

from_train(interaction_space, alpha_train, base_solver=None, l_max=None, angles=DEFAULT_ANGLE_MESH, n_basis=4, use_svd=True, Smatrix_abs_tol=1e-06, s_mesh=None, **basis_kwargs) classmethod

Trains a reduced-basis emulator based on the provided interaction and training space.

Parameters:

Name Type Description Default
interaction_space InteractionSpace

local interaction up to (and including $\ell_\max$)

required
alpha_train ndarray

training points in parameter space; shape = (n_points, n_parameters)

required
base_solver

the solver used for training the emulator, and for calculations of exact observables. Must be an instance of SchroedingerEquation or a derived class of it. The solvers for each interaction in interaction_space will be constructed using

None
l_max int

maximum angular momentum to include in the sum approximating the cross section

None
angles ndarray

Differential cross sections are functions of the angles. These are the specific values at which the user wants to emulate the cross section.

DEFAULT_ANGLE_MESH
n_basis int

number of basis vectors for $\hat{\phi}$ expansion

4
use_svd bool

Use principal components of training wave functions?

True
s_mesh ndarray

$s$ (or $\rho$) grid on which wave functions are evaluated

None
s_0 float

$s$ point where the phase shift is extracted

required
Smatrix_abs_tol

absolute tolerance for deviation of real part of S-matrix amplitudes from 1, used as criteria to stop calculation ig higher partial waves are negligble

1e-06

Returns:

Name Type Description
sae ScatteringAmplitudeEmulator

scattering amplitude emulator

Source code in src/rose/scattering_amplitude_emulator.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
@classmethod
def from_train(
    cls,
    interaction_space: InteractionSpace,
    alpha_train: np.array,
    base_solver: SchroedingerEquation = None,
    l_max: int = None,
    angles: np.array = DEFAULT_ANGLE_MESH,
    n_basis: int = 4,
    use_svd: bool = True,
    Smatrix_abs_tol: float = 1.0e-6,
    s_mesh: np.array = None,
    **basis_kwargs,
):
    r"""Trains a reduced-basis emulator based on the provided interaction and training space.

    Parameters:
        interaction_space (InteractionSpace): local interaction up to (and including $\ell_\max$)
        alpha_train (ndarray): training points in parameter space; shape = (n_points, n_parameters)
        base_solver : the solver used for training the emulator, and for calculations of exact
            observables. Must be an instance of SchroedingerEquation or a derived class of it.
            The solvers for each `interaction` in `interaction_space` will be constructed using
        l_max (int): maximum angular momentum to include in the sum approximating the cross section
        angles (ndarray): Differential cross sections are functions of the
            angles. These are the specific values at which the user wants to
            emulate the cross section.
        n_basis (int): number of basis vectors for $\hat{\phi}$ expansion
        use_svd (bool): Use principal components of training wave functions?
        s_mesh (ndarray): $s$ (or $\rho$) grid on which wave functions are evaluated
        s_0 (float): $s$ point where the phase shift is extracted
        Smatrix_abs_tol : absolute tolerance for deviation of real part of S-matrix amplitudes
            from 1, used as criteria to stop calculation ig higher partial waves are negligble

    Returns:
        sae (ScatteringAmplitudeEmulator): scattering amplitude emulator

    """
    if base_solver is None:
        base_solver = SchroedingerEquation.make_base_solver()

    if l_max is None:
        l_max = interaction_space.l_max

    bases = []
    for interaction_list in tqdm(interaction_space.interactions):
        basis_list = []
        for interaction in interaction_list:
            solver = base_solver.clone_for_new_interaction(interaction)
            if s_mesh is None:
                s_mesh = np.linspace(
                    solver.domain[0],
                    solver.domain[1],
                    SchroedingerEquation.DEFAULT_NUM_PTS,
                )
            basis_list.append(
                RelativeBasis(
                    solver,
                    alpha_train,
                    s_mesh,
                    n_basis,
                    use_svd=use_svd,
                    **basis_kwargs,
                )
            )
        bases.append(basis_list)

    return cls(
        interaction_space,
        bases,
        l_max,
        angles=angles,
        s_0=base_solver.s_0,
        Smatrix_abs_tol=Smatrix_abs_tol,
    )

load(obj, filename) classmethod

Loads a previously trained emulator.

Parameters:

Name Type Description Default
filename string

name of file

required

Returns:

Name Type Description
emulator ScatteringAmplitudeEmulator

previously trainined ScatteringAmplitudeEmulator

Source code in src/rose/scattering_amplitude_emulator.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@classmethod
def load(obj, filename):
    r"""Loads a previously trained emulator.

    Parameters:
        filename (string): name of file

    Returns:
        emulator (ScatteringAmplitudeEmulator): previously trainined `ScatteringAmplitudeEmulator`

    """
    with open(filename, "rb") as f:
        sae = pickle.load(f)
    return sae

percent_explained_variance()

Returns:

Type Description

(float) : percent of variance explained in the training set by the first n_basis principal

components

Source code in src/rose/scattering_amplitude_emulator.py
609
610
611
612
613
614
615
616
617
618
def percent_explained_variance(self):
    r"""
    Returns:
        (float) : percent of variance explained in the training set by the first n_basis principal
        components
    """
    return [
        [rbe.basis.percent_explained_variance() for rbe in rbe_list]
        for rbe_list in self.rbes
    ]

save(filename)

Saves the emulator to the desired file.

Parameters:

Name Type Description Default
filename string

name of file

required
Source code in src/rose/scattering_amplitude_emulator.py
620
621
622
623
624
625
626
627
628
def save(self, filename):
    r"""Saves the emulator to the desired file.

    Parameters:
        filename (string): name of file

    """
    with open(filename, "wb") as f:
        pickle.dump(self, f)