Coverage for src/flexfrac1d/lib/displacement.py: 96%
43 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-07-03 16:40 +0200
« prev ^ index » next coverage.py v7.4.1, created at 2024-07-03 16:40 +0200
1import numpy as np
2from .constants import PI_D4, SQR2
3from . import numerical
6def _wavefield(x, c_amps, c_wavenumbers):
7 return np.imag(c_amps @ _unit_wavefield(x, c_wavenumbers))
10def _unit_wavefield(x, c_wavenumbers):
11 return np.exp((1j * c_wavenumbers[:, None]) * x)
14def _dis_par_amps(red_num: float, wave_params: tuple[np.ndarray]):
15 """Complex amplitudes of individual particular solutions"""
16 c_amplitudes, c_wavenumbers = wave_params
17 return c_amplitudes / (1 + 0.25 * (c_wavenumbers / red_num) ** 4)
20def _dis_hom_mat(red_num: float, length: float):
21 """Linear application to determine, from the BCs, the coefficients of
22 the four independent solutions to the homo ODE"""
23 adim = red_num * length
24 adim2 = 2 * adim
25 denom = (
26 -2
27 * red_num**2
28 * (np.expm1(-adim2) ** 2 + 2 * np.exp(-adim2) * (np.cos(adim2) - 1))
29 )
30 mat = np.array(
31 [
32 [
33 SQR2 * np.exp(-adim) * np.sin(adim2 + PI_D4) - np.exp(-3 * adim),
34 -SQR2 * np.cos(adim + PI_D4)
35 - 3 * np.exp(-adim2) * np.sin(adim)
36 + np.exp(-adim2) * np.cos(adim),
37 np.exp(-adim) * np.sin(adim2) - np.exp(-adim) + np.exp(-3 * adim),
38 np.cos(adim)
39 - 2 * np.exp(-adim2) * np.sin(adim)
40 - np.exp(-adim2) * np.cos(adim),
41 ],
42 [
43 -SQR2 * np.exp(-adim) * np.cos(adim2 + PI_D4)
44 + 2 * np.exp(-adim)
45 - np.exp(-3 * adim),
46 -SQR2 * np.sin(adim + PI_D4)
47 + SQR2 * np.exp(-adim2) * np.cos(adim + PI_D4),
48 -np.exp(-adim) * np.cos(adim2) + np.exp(-adim),
49 np.sin(adim) - np.exp(-adim2) * np.sin(adim),
50 ],
51 [
52 -1 + SQR2 * np.exp(-adim2) * np.cos(adim2 + PI_D4),
53 (3 * np.sin(adim) + np.cos(adim)) * np.exp(-adim)
54 - SQR2 * np.exp(-3 * adim) * np.sin(adim + PI_D4),
55 (np.sin(adim2) + 1) * np.exp(-adim2) - 1,
56 (-2 * np.sin(adim) + np.cos(adim)) * np.exp(-adim)
57 - np.exp(-3 * adim) * np.cos(adim),
58 ],
59 [
60 (SQR2 * np.sin(adim2 + PI_D4) - 2) * np.exp(-adim2) + 1,
61 -SQR2 * np.exp(-adim) * np.sin(adim + PI_D4)
62 + SQR2 * np.exp(-3 * adim) * np.cos(adim + PI_D4),
63 (-np.cos(adim2) + 1) * np.exp(-adim2),
64 np.exp(-adim) * np.sin(adim) - np.exp(-3 * adim) * np.sin(adim),
65 ],
66 ]
67 )
68 mat[:, 2:] /= red_num
70 return mat / denom
73def _dis_hom_rhs(floe_params: tuple[float], wave_params: tuple[np.ndarray]):
74 """Vector onto which apply the matrix, to extract the coefficients"""
75 red_num, length = floe_params
76 _, c_wavenumbers = wave_params
77 exp_arg = 1j * c_wavenumbers * length
79 r1 = c_wavenumbers**2 * _dis_par_amps(red_num, wave_params)
80 r2 = np.imag(r1 @ np.exp(exp_arg))
81 r3 = 1j * c_wavenumbers * r1
82 r4 = np.imag(r3 @ np.exp(exp_arg))
83 r1 = np.imag(r1).sum()
84 r3 = np.imag(r3).sum()
86 return np.array((r1, r2, r3, r4))
89def _dis_hom_coefs(
90 floe_params: tuple[float], wave_params: tuple[np.ndarray]
91) -> np.ndarray:
92 """Coefficients of the four orthogonal homogeneous solutions"""
93 return _dis_hom_mat(*floe_params) @ _dis_hom_rhs(floe_params, wave_params)
96def _dis_hom(x: np.ndarray, floe_params: tuple[float], wave_params: tuple[np.ndarray]):
97 """Homogeneous solution to the displacement ODE"""
98 red_num, length = floe_params
99 arr = red_num * x
100 cosx, sinx = np.cos(arr), np.sin(arr)
101 expx = np.exp(-red_num * (length - x))
102 exmx = np.exp(-arr)
103 return np.vstack(
104 ([expx * cosx, expx * sinx, exmx * cosx, exmx * sinx])
105 ).T @ _dis_hom_coefs(floe_params, wave_params)
108def _dis_par(x: np.ndarray, red_num: float, wave_params: tuple[np.ndarray]):
109 """Sum of the particular solutions to the displacement ODE"""
110 return _wavefield(x, _dis_par_amps(red_num, wave_params), wave_params[1])
113def displacement(
114 x,
115 floe_params: tuple[float],
116 wave_params: tuple[np.ndarray],
117 growth_params: tuple | None = None,
118 an_sol: bool | None = None,
119 num_params: dict | None = None,
120):
121 if numerical._use_an_sol(an_sol, floe_params[1], growth_params): 121 ↛ 125line 121 didn't jump to line 125, because the condition on line 121 was never false
122 return _dis_hom(x, floe_params, wave_params) + _dis_par(
123 x, floe_params[0], wave_params
124 )
125 return numerical.displacement(
126 x, floe_params, wave_params, growth_params, num_params
127 )