Shock wave solvers
If you are looking for a rapid way to compute all the ratios across the shock wave, you have come to the right place.
Two solvers are implemented: 1. shockwave_solver
: use this to solve for normal or oblique shock waves. 2. conical_shockwave_solver
: use this to solve for conical shock wave.
In the following, a few examples are presented to show how to use them and to understand some of the limitations.
[1]:
from pygasflow import (
shockwave_solver,
conical_shockwave_solver
)
shockwave_solver
Let’s look at the documentation for this function to see how it works:
[2]:
help(shockwave_solver)
Help on function shockwave_solver in module pygasflow.solvers.shockwave:
shockwave_solver(p1_name, p1_value, p2_name='beta', p2_value=90, gamma=1.4, flag='weak')
Try to compute all the ratios, angles and mach numbers across the shock wave.
Remember: a normal shock wave has a wave angle beta=90 deg.
Parameters
----------
p1_name : string
Name of the first parameter given in input. Can be either one of:
* ``'pressure'``: Pressure Ratio P2/P1
* ``'temperature'``: Temperature Ratio T2/T1
* ``'density'``: Density Ratio rho2/rho1
* ``'total_pressure'``: Total Pressure Ratio P02/P01
* ``'m1'``: Mach upstream of the shock wave
* ``'mn1'``: Normal Mach upstream of the shock wave
* ``'mn2'``: Normal Mach downstream of the shock wave
* ``'beta'``: The shock wave angle [in degrees]. It can only be used
if ``p2_name='theta'``.
* ``'theta'``: The deflection angle [in degrees]. It can only be
used if ``p2_name='beta'``.
If the parameter is a ratio, it is in the form downstream/upstream:
p1_value : float
Actual value of the parameter.
p2_name : string, optional
Name of the second parameter. It could either be:
* ``'beta'``: Shock wave angle.
* ``'theta'``: Flow deflection angle.
* ``'mn1'``: Input Normal Mach number.
Default to ``'beta'``.
p2_value : float, optional
Value of the angle in degrees.
Default to 90 degrees (normal shock wave).
gamma : float, optional
Specific heats ratio. Default to 1.4. Must be > 1.
flag : string, optional
Chose what solution to compute if the angle 'theta' is provided.
Can be either ``'weak'`` or ``'strong'``. Default to ``'weak'``.
Returns
-------
M1 : float
Mach number upstream of the shock wave.
Mn1 : float
Normal Mach number upstream of the shock wave.
M2 : float
Mach number downstream of the shock wave.
Mn2 : float
Normal Mach number downstream of the shock wave.
beta : float
Shock wave angle in degrees.
theta : float
Flow deflection angle in degrees.
pr : float
Pressure ratio across the shock wave.
dr : float
Density ratio across the shock wave.
tr : float
Temperature ratio across the shock wave.
tpr : float
Total Pressure ratio across the shock wave.
As we can see, it is really quite simple to use it. Just insert the name of the known parameter, its value, the name of the angle and its value, the specific heats ratio and you are good to go.
Let’s first create a simple function to print the results:
[3]:
def print_oblique_shockwave(M1, MN1, M2, MN2, beta, theta, pr, dr, tr, tpr):
print("M1 \t\t {}".format(M1))
print("Mn1 \t\t {}".format(MN1))
print("M2 \t\t {}".format(M2))
print("Mn2 \t\t {}".format(MN2))
print("beta \t\t {}".format(beta))
print("theta \t\t {}".format(theta))
print("p2/p1 \t\t {}".format(pr))
print("rho2/rho1 \t {}".format(dr))
print("t2/t1 \t\t {}".format(tr))
print("p02/p01 \t {}".format(tpr))
print()
Normal Shock Wave
By default, this function can be used to solve normal shock wave on air (specific heats ratio \(\gamma=1.4\) and shock wave angle \(\beta=90\)):
[4]:
result = shockwave_solver("m1", 4)
print_oblique_shockwave(*result)
M1 4.0
Mn1 4.0
M2 0.43495883620084
Mn2 0.43495883620084
beta 90.0
theta 1.2529838033097996e-14
p2/p1 18.5
rho2/rho1 4.571428571428572
t2/t1 4.046874999999999
p02/p01 0.13875622089168838
Because this function is designed to solve also oblique shock waves, we have some parameters that we can discard: 1. Mn1, the normal Mach number upstream of the shock wave, which is obviously equal to M1. 2. Mn2, the normal Mach number downstream of the shock wave, which is obviously equal to M2. 3. beta, the shock wave angle, obviously \(90°\) since we are solving a normal shock wave. 4. theta, the deflection angle. We notice a very small value. Indeed, in this case it should be 0, but numerical errors are preventing this result. Anyway, since we are solving a normal shock wave, we do not need to worry about this angle.
Let’s look at the same example, but inserting different parameters. We expect the very same results, and indeed we get them.
[5]:
r1 = shockwave_solver("pressure", 18.5)
r2 = shockwave_solver("density", 4.571428571428572)
r3 = shockwave_solver("temperature", 4.046874999999999)
r4 = shockwave_solver("mn2", 0.43495883620084)
print_oblique_shockwave(*r1)
print_oblique_shockwave(*r2)
print_oblique_shockwave(*r3)
print_oblique_shockwave(*r4)
M1 4.0
Mn1 4.0
M2 0.43495883620084
Mn2 0.43495883620084
beta 90
theta 1.2529838033097996e-14
p2/p1 18.5
rho2/rho1 4.571428571428572
t2/t1 4.046874999999999
p02/p01 0.13875622089168838
M1 4.0
Mn1 4.0
M2 0.43495883620084
Mn2 0.43495883620084
beta 90
theta 1.2529838033097996e-14
p2/p1 18.5
rho2/rho1 4.571428571428572
t2/t1 4.046874999999999
p02/p01 0.13875622089168838
M1 4.0
Mn1 4.0
M2 0.43495883620084
Mn2 0.43495883620084
beta 90
theta 1.2529838033097996e-14
p2/p1 18.5
rho2/rho1 4.571428571428572
t2/t1 4.046874999999999
p02/p01 0.13875622089168838
M1 4.0
Mn1 4.0
M2 0.43495883620084
Mn2 0.43495883620084
beta 90
theta 1.2529838033097996e-14
p2/p1 18.5
rho2/rho1 4.571428571428572
t2/t1 4.046874999999999
p02/p01 0.13875622089168838
What if I want to solve a normal shock wave on a gas different than air? Obviously I need to change the specific heats ratio:
[6]:
result = shockwave_solver("m1", 4, gamma=1.2)
print_oblique_shockwave(*result)
M1 4.0
Mn1 4.0
M2 0.3689521031926255
Mn2 0.3689521031926255
beta 90.0
theta 2.024050759192753e-14
p2/p1 17.36363636363636
rho2/rho1 6.769230769230771
t2/t1 2.5650826446280983
p02/p01 0.06095825251291948
Oblique Shock Wave
Let’s now consider an oblique shock wave. Let’s start with air, upstream Mach number \(M_{1} = 4\) and a deflection angle \(\theta = 20°\).
[7]:
result = shockwave_solver("m1", 4, 'theta', 20)
print_oblique_shockwave(*result)
M1 4.0
Mn1 2.147072259523833
M2 2.5686168890322807
Mn2 0.5543701693902555
beta 32.46389685027039
theta 20.0
p2/p1 5.211572502219574
rho2/rho1 2.8782256018884964
t2/t1 1.8106893701453053
p02/p01 0.6524015014542756
As we have seen from the documentation, if the deflection angle \(\theta\) is provided, by default the function will solve for the *weak shock solution*. If we want to solve for the *strong shock solution*, we must change the flag
argument. But in doing so, we also need to specify the specific heats ratio.
[8]:
result = shockwave_solver("m1", 4, 'theta', 20, gamma=1.4, flag='strong')
print_oblique_shockwave(*result)
M1 4.0
Mn1 3.977010652739413
M2 0.48523272499938425
Mn2 0.43558154682352673
beta 83.85418932598304
theta 20.0
p2/p1 18.286049354003236
rho2/rho1 4.5588434129476605
t2/t1 4.011115912002739
p02/p01 0.14147889026890678
Note that the solver is able to detect detachment. Let’s say we provide a flow deflection angle greater that the maximum allowed for the provided upstream Mach number (see Oblique Shock Diagram):
[9]:
result = shockwave_solver("m1", 2, 'theta', 30)
print_oblique_shockwave(*result)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [9], in <module>
----> 1 result = shockwave_solver("m1", 2, 'theta', 30)
2 print_oblique_shockwave(*result)
File ~/Documents/Development/pygasflow/pygasflow/utils/decorators.py:206, in as_array.<locals>.decorator.<locals>.wrapper_function(*args, **kwargs)
204 if i < len(args):
205 args[i] = convert_to_ndarray(args[i])
--> 206 return original_function(*args, **kwargs)
File ~/Documents/Development/pygasflow/pygasflow/utils/decorators.py:121, in check_shockwave.<locals>.decorator.<locals>.wrapper_function(*args, **kwargs)
118 if "flag" in all_param.keys() and len(args) == len(all_param.keys()):
119 args[-1] = _check_flag_shockwave(all_param["flag"])
--> 121 res = original_function(*args, **kwargs)
122 return ret_correct_vals(res)
File ~/Documents/Development/pygasflow/pygasflow/solvers/shockwave.py:163, in shockwave_solver(p1_name, p1_value, p2_name, p2_value, gamma, flag)
160 M2 = MN2 / np.sin(np.deg2rad(beta - theta))
161 elif M1 is not None:
162 # at this point, either beta or theta is set, not both!
--> 163 MN1 = normal_mach_upstream.__no_check(M1, beta, theta, gamma, flag)
164 # compute the different ratios
165 pr, dr, tr, tpr, MN2 = get_ratios_from_normal_mach_upstream.__no_check(MN1, gamma)
File ~/Documents/Development/pygasflow/pygasflow/utils/decorators.py:125, in check_shockwave.<locals>.decorator.<locals>.no_check_function(*args, **kwargs)
124 def no_check_function(*args, **kwargs):
--> 125 res = original_function(*args, **kwargs)
126 return ret_correct_vals(res)
File ~/Documents/Development/pygasflow/pygasflow/shockwave.py:497, in normal_mach_upstream(M1, beta, theta, gamma, flag)
495 theta_max = max_theta_from_mach(M1, gamma)
496 if np.any(theta > theta_max):
--> 497 raise ValueError("Detachment detected: can't solve the flow when theta > theta_max.\n" +
498 "M1 = {}\n".format(M1) +
499 "theta_max(M1) = {}\n".format(theta_max) +
500 "theta = {}\n".format(theta))
501 beta = beta_from_mach_theta(M1, theta)
502 MN1 = dict()
ValueError: Detachment detected: can't solve the flow when theta > theta_max.
M1 = [2.]
theta_max(M1) = 22.97353176093536
theta = [30.]
[10]:
print_oblique_shockwave(*shockwave_solver("m1", 1.8400645259024768, "theta", 20))
M1 1.8400645259024768
Mn1 1.664726146515799
M2 0.9225790066302748
Mn2 0.64990193322869
beta 64.78435329607117
theta 20.0
p2/p1 3.066532000042231
rho2/rho1 2.1396485447978377
t2/t1 1.433194254027345
p02/p01 0.8701212937216544
Again, we can insert different parameter to solve for the shock. For example, let’s say I know the pressure ratio across the shock, the deflection angle, and I want to solve for the *weak shock solution*. I can do:
[11]:
result = shockwave_solver("pressure", 5.211572502219574, 'theta', 20)
print_oblique_shockwave(*result)
M1 nan
Mn1 2.147072259523833
M2 nan
Mn2 0.5543701693902555
beta nan
theta 20.0
p2/p1 5.211572502219574
rho2/rho1 2.8782256018884964
t2/t1 1.8106893701453053
p02/p01 0.6524015014542756
/home/davide/Documents/Development/pygasflow/pygasflow/solvers/shockwave.py:194: UserWarning: Undetermined case. Setting M1 = beta = M2 = NaN
warnings.warn("Undetermined case. Setting M1 = beta = M2 = NaN")
Comparing with the previous results, we see that the ratios are correct, the normal Mach numbers are correct, but the shock wave angle \(\beta\) and thus the Mach numbers upstream and downstream of the shock are not determined. This is to be expected: given a ratio, we can compute only the normal Mach number across the shock wave corresponsing to the weak solution, but we are unable to uniquely determine the shock wave angle \(\beta\) and the Mach number.
Therefore, if we would like to compute the *strong shock solution* giving a ratio and the deflection angle :math:`theta`, we will get the wrong results:
[12]:
result = shockwave_solver("pressure", 5.211572502219574, 'theta', 20, gamma=1.4, flag='strong')
print_oblique_shockwave(*result)
M1 nan
Mn1 2.147072259523833
M2 nan
Mn2 0.5543701693902555
beta nan
theta 20.0
p2/p1 5.211572502219574
rho2/rho1 2.8782256018884964
t2/t1 1.8106893701453053
p02/p01 0.6524015014542756
Even by specify the flag='strong'
, at the moment of writing this tutorial, it is not possible to compute the Normal Mach number corresponding to strong solution of the input ration, and it is not possible to uniquely determine the shock wave angle \(\beta\) and thus computing the correct results.
We can solve a shock wave by knowing both the shock wave angle \(\beta\) and the deflection angle \(\theta\). Following the previus example, by chosing the shock wave angle corresponding to the weak solution we get:
[14]:
r1 = shockwave_solver("beta", 32.46389685027039, 'theta', 20)
r2 = shockwave_solver('theta', 20, "beta", 32.46389685027039)
print_oblique_shockwave(*r1)
print()
print_oblique_shockwave(*r2)
M1 4.000000000000003
Mn1 2.1470722595238345
M2 2.5686168890322807
Mn2 0.5543701693902553
beta 32.46389685027039
theta 20.000000000000004
p2/p1 5.211572502219582
rho2/rho1 2.8782256018884977
t2/t1 1.8106893701453068
p02/p01 0.6524015014542744
M1 4.000000000000003
Mn1 2.1470722595238345
M2 2.5686168890322807
Mn2 0.5543701693902553
beta 32.46389685027039
theta 20.000000000000004
p2/p1 5.211572502219582
rho2/rho1 2.8782256018884977
t2/t1 1.8106893701453068
p02/p01 0.6524015014542744
Note that we do not need to specify the flag
arguments, since for each \((\beta, \theta)\) corresponds only one Mach number.
By chosing the shock wave angle corresponding to the strong solution we get:
[15]:
r1 = shockwave_solver("beta", 83.85418932598304, 'theta', 20)
r2 = shockwave_solver('theta', 20, "beta", 83.85418932598304)
print_oblique_shockwave(*r1)
print_oblique_shockwave(*r2)
M1 3.9999999999999862
Mn1 3.9770106527393994
M2 0.48523272499938463
Mn2 0.4355815468235271
beta 83.85418932598304
theta 19.99999999999999
p2/p1 18.286049354003108
rho2/rho1 4.558843412947653
t2/t1 4.011115912002717
p02/p01 0.14147889026890847
M1 3.9999999999999862
Mn1 3.9770106527393994
M2 0.48523272499938463
Mn2 0.4355815468235271
beta 83.85418932598304
theta 19.99999999999999
p2/p1 18.286049354003108
rho2/rho1 4.558843412947653
t2/t1 4.011115912002717
p02/p01 0.14147889026890847
Finally, the solver should be able to determine if a solution doesn’t exist for the current choice of parameters. For example (see Oblique Shock Diagram):
[16]:
print_oblique_shockwave(*shockwave_solver("beta", 88, "theta", 20))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [16], in <module>
----> 1 print_oblique_shockwave(*shockwave_solver("beta", 88, "theta", 20))
File ~/Documents/Development/pygasflow/pygasflow/utils/decorators.py:206, in as_array.<locals>.decorator.<locals>.wrapper_function(*args, **kwargs)
204 if i < len(args):
205 args[i] = convert_to_ndarray(args[i])
--> 206 return original_function(*args, **kwargs)
File ~/Documents/Development/pygasflow/pygasflow/utils/decorators.py:121, in check_shockwave.<locals>.decorator.<locals>.wrapper_function(*args, **kwargs)
118 if "flag" in all_param.keys() and len(args) == len(all_param.keys()):
119 args[-1] = _check_flag_shockwave(all_param["flag"])
--> 121 res = original_function(*args, **kwargs)
122 return ret_correct_vals(res)
File ~/Documents/Development/pygasflow/pygasflow/solvers/shockwave.py:150, in shockwave_solver(p1_name, p1_value, p2_name, p2_value, gamma, flag)
148 if not isinstance(theta, np.ndarray):
149 theta = theta * np.ones_like(beta)
--> 150 M1 = mach_from_theta_beta.__no_check(theta, beta)
151 else: # 'm2'
152 # TODO:
153 # Is it even possible to solve it knowing only M2, beta or M2, theta?????
154 raise NotImplementedError("Solving a shock wave with a given M2 is not yet implemented.")
File ~/Documents/Development/pygasflow/pygasflow/utils/decorators.py:125, in check_shockwave.<locals>.decorator.<locals>.no_check_function(*args, **kwargs)
124 def no_check_function(*args, **kwargs):
--> 125 res = original_function(*args, **kwargs)
126 return ret_correct_vals(res)
File ~/Documents/Development/pygasflow/pygasflow/shockwave.py:800, in mach_from_theta_beta(theta, beta, gamma)
798 theta_max[i] = theta_from_mach_beta(100000, b, gamma)
799 if np.any(theta > theta_max):
--> 800 raise ValueError("There is no solution for the current choice of" +
801 " parameters. Please check the Oblique Shock diagram with the following"
802 " parameters:\n" +
803 "beta = {}\n".format(beta) +
804 "theta = {}\n".format(theta))
805 # case beta == 90 and theta == 0, which leaves M to be indeterminate, NaN
806 idx0 = np.bitwise_and(beta == 90, theta == 0)
ValueError: There is no solution for the current choice of parameters. Please check the Oblique Shock diagram with the following parameters:
beta = [88.]
theta = [20.]
conical_shockwave_solver
Let’s look at the documentation for this function to see how it works:
[17]:
help(conical_shockwave_solver)
Help on function conical_shockwave_solver in module pygasflow.solvers.shockwave:
conical_shockwave_solver(M1, param_name, param_value, gamma=1.4, flag='weak')
Try to compute all the ratios, angles and mach numbers across the conical shock wave.
Parameters
----------
M1 : float
Upstream Mach number. Must be M1 > 1.
param_name : string
Name of the parameter given in input. Can be either one of:
* ``'mc'``: Mach number at the cone's surface.
* ``'theta_c'``: Half cone angle.
* ``'beta'``: shock wave angle.
param_value : float
Actual value of the parameter. Requirements:
* Mc >= 0
* 0 < beta <= 90
* 0 < theta_c < 90
gamma : float, optional
Specific heats ratio. Default to 1.4. Must be > 1.
flag : string, optional
Can be either ``'weak'`` or ``'strong'``. Default to ``'weak'``
(in conical shockwaves, the strong solution is rarely encountered).
Returns
-------
M : float
Upstream Mach number.
Mc : float
Mach number at the surface of the cone.
theta_c : float
Half cone angle.
beta : float
Shock wave angle.
delta : float
Flow deflection angle.
pr : float
Pressure ratio across the shock wave.
dr : float
Density ratio across the shock wave.
tr : float
Temperature ratio across the shock wave.
tpr : float
Total Pressure ratio across the shock wave.
pc_p1 : float
Pressure ratio between the cone's surface and the upstream condition.
rhoc_rho1 : float
Density ratio between the cone's surface and the upstream condition.
Tc_T1 : float
Temperature ratio between the cone's surface and the upstream condition.
[18]:
def print_conical_shockwave(M1, Mc, theta_c, beta, delta, pr, dr, tr, tpr, pc_p1, rhoc_rho1, Tc_T1):
print("M1 \t\t {}".format(M1))
print("Mc \t\t {}".format(Mc))
print("theta_c \t {}".format(theta_c))
print("beta \t\t {}".format(beta))
print("delta \t\t {}".format(delta))
print("p2/p1 \t\t {}".format(pr))
print("rho2/rho1 \t {}".format(dr))
print("t2/t1 \t\t {}".format(tr))
print("p02/p01 \t {}".format(tpr))
print("pc/p1 \t\t {}".format(pc_p1))
print("rho_c/rho1 \t {}".format(rhoc_rho1))
print("tc/t1 \t\t {}".format(Tc_T1))
[19]:
result = conical_shockwave_solver(4, 'beta', 20)
print_conical_shockwave(*result)
M1 4.0
Mc 3.3494441585129917
theta_c 12.923342940926778
beta 20
delta 7.444220294251439
p2/p1 2.0169185308895377
rho2/rho1 1.6342327959123613
t2/t1 1.2341684342245318
p02/p01 0.965779172840477
pc/p1 2.385514639007803
rho_c/rho1 1.8423870467954182
tc/t1 1.2947955985454198
[20]:
result = conical_shockwave_solver(3, 'theta_c', 26.377485151514648)
print_conical_shockwave(*result)
M1 3.0
Mc 2.000000000000039
theta_c 26.377485151514648
beta 35.90847523748602
delta 18.392639366690542
p2/p1 3.44505054944179
rho2/rho1 2.294355459847854
t2/t1 1.5015330491423686
p02/p01 0.8304690737856829
pc/p1 3.898726823356718
rho_c/rho1 2.506324386443648
tc/t1 1.5555555555555283
[21]:
result = conical_shockwave_solver(3, 'mc', 2)
print_conical_shockwave(*result)
M1 3.0
Mc 2.0
theta_c 26.377485151514648
beta 35.90847523748602
delta 18.392639366690542
p2/p1 3.44505054944179
rho2/rho1 2.294355459847854
t2/t1 1.5015330491423686
p02/p01 0.8304690737856829
pc/p1 3.8987268233569545
rho_c/rho1 2.5063243864437568
tc/t1 1.5555555555555554
[22]:
result = conical_shockwave_solver(3, 'beta', 35.90847523748602)
print_conical_shockwave(*result)
M1 3.0
Mc 2.000000000000039
theta_c 26.377485151514648
beta 35.90847523748602
delta 18.392639366690542
p2/p1 3.44505054944179
rho2/rho1 2.294355459847854
t2/t1 1.5015330491423686
p02/p01 0.8304690737856829
pc/p1 3.898726823356718
rho_c/rho1 2.506324386443648
tc/t1 1.5555555555555283
The solver should be able to detect detachment:
[23]:
result = conical_shockwave_solver(2, 'theta_c', 45)
print_conical_shockwave(*result)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [23], in <module>
----> 1 result = conical_shockwave_solver(2, 'theta_c', 45)
2 print_conical_shockwave(*result)
File ~/Documents/Development/pygasflow/pygasflow/utils/decorators.py:206, in as_array.<locals>.decorator.<locals>.wrapper_function(*args, **kwargs)
204 if i < len(args):
205 args[i] = convert_to_ndarray(args[i])
--> 206 return original_function(*args, **kwargs)
File ~/Documents/Development/pygasflow/pygasflow/utils/decorators.py:121, in check_shockwave.<locals>.decorator.<locals>.wrapper_function(*args, **kwargs)
118 if "flag" in all_param.keys() and len(args) == len(all_param.keys()):
119 args[-1] = _check_flag_shockwave(all_param["flag"])
--> 121 res = original_function(*args, **kwargs)
122 return ret_correct_vals(res)
File ~/Documents/Development/pygasflow/pygasflow/solvers/shockwave.py:285, in conical_shockwave_solver(M1, param_name, param_value, gamma, flag)
283 Mc, theta_c = mach_cone_angle_from_shock_angle(M1, beta, gamma)
284 elif theta_c:
--> 285 Mc, _, beta = shock_angle_from_mach_cone_angle(M1, theta_c, gamma, flag)
287 # compute the ratios across the shockwave
288 MN1 = M1 * np.sin(np.deg2rad(beta))
File ~/Documents/Development/pygasflow/pygasflow/utils/decorators.py:206, in as_array.<locals>.decorator.<locals>.wrapper_function(*args, **kwargs)
204 if i < len(args):
205 args[i] = convert_to_ndarray(args[i])
--> 206 return original_function(*args, **kwargs)
File ~/Documents/Development/pygasflow/pygasflow/utils/decorators.py:121, in check_shockwave.<locals>.decorator.<locals>.wrapper_function(*args, **kwargs)
118 if "flag" in all_param.keys() and len(args) == len(all_param.keys()):
119 args[-1] = _check_flag_shockwave(all_param["flag"])
--> 121 res = original_function(*args, **kwargs)
122 return ret_correct_vals(res)
File ~/Documents/Development/pygasflow/pygasflow/shockwave.py:1161, in shock_angle_from_mach_cone_angle(M1, theta_c, gamma, flag)
1159 Mc = np.zeros_like(M1)
1160 for i, m in enumerate(M1):
-> 1161 Mc[i], theta_c_comp[i], beta[i] = function(m)
1162 return ret_correct_vals(Mc), ret_correct_vals(theta_c_comp), ret_correct_vals(beta)
1163 return function(M1)
File ~/Documents/Development/pygasflow/pygasflow/shockwave.py:1135, in shock_angle_from_mach_cone_angle.<locals>.function(M)
1133 Mc, tcmax, bmax = max_theta_c_from_mach(M)
1134 if theta_c > tcmax:
-> 1135 raise ValueError("Detachment detected: can't solve the flow when theta_c > theta_c_max.\n" +
1136 "M1 = {}\n".format(M1) +
1137 "theta_c_max(M1) = {}\n".format(tcmax) +
1138 "theta_c = {}\n".format(theta_c))
1140 # need to add a small offset otherwise mach_cone_angle_from_shock_angle
1141 # could crash
1142 bmin = np.rad2deg(np.arcsin(1 / M)) + 1e-08
ValueError: Detachment detected: can't solve the flow when theta_c > theta_c_max.
M1 = [2.]
theta_c_max(M1) = 40.688476890932144
theta_c = 45
[ ]: