```python
def f(a,b,c,d): return a*2+b*3+c*4+d*5
```

```python
def intersect(seq1, seq2):
    res = []
    for x in seq1:
        if x in seq2:
            res.append(x)
    return res
```

```python
def Predict(x,y):
    from sklearn import linear_model
    clf = linear_model.ARDRegression()
    l = input("请输入训练集的x,y值：")
    m = input("请输入训练集的z值：")
    clf.fit(eval(l),eval(m))
    def 笑死我了(x,y):
        from sklearn import linear_model
        clf = linear_model.ARDRegression()
        l = input("请输入训练集的x,y值：")
        m = input("请输入训练集的z值：")
        clf.fit(eval(l),eval(m))
        return clf.predict([[x,y]])
    return clf.predict([[x,y]])
```

```python
Predict
```

    <function __main__.Predict(x, y)>

```python
Predict(4,4)
```

    请输入训练集的x,y值： [[0,0],[1,1],[2,2]]
    请输入训练集的z值： [0,1,2]

    array([4.00061158])

```python
def 笑死我了(x,y):
    from sklearn import linear_model
    clf = linear_model.ARDRegression()
    l = input("请输入训练集的x,y值：")
    m = input("请输入训练集的z值：")
    clf.fit(eval(l),eval(m))
    return clf.predict([[x,y]]), 鱼水情
```

```python
笑死我了(6,6)
```

    请输入训练集的x,y值： [[0,0],[1,1],[2,2]]
    请输入训练集的z值： [0,1,2]

    (array([6.0010193]), 'sfak')

```python
鱼水情 = 'sfak'
```

```python
type(鱼水情)
```

    str

```python
鱼水情 = Predict
```

```python
鱼水情
```

    <function __main__.Predict(x, y)>

```python
X = 99 # 全局变量
```

```python
def func():
    Y = 88
    Y += 1
    return Y, X
```

```python
func() #Y是func的本地变量
```

    (89, 99)

```python
def func1():
    Y = 881111111
    Y += 1
    return Y, X
```

```python
func(), func1() #每一个函数都是独立的程序单元
```

    ((89, 99), (881111112, 99))

```python
import script1
```

```python
script1.square
```

    <function script1.square(x)>

```python
script1.spam
```

    40

```python
y1 = lambda 函数, 新人: 函数 + 新人
```

```python
def y2(函数, 新人):
    return 函数 + 新人
```

```python
y1(333,444), y2(333,444)
```

    (777, 777)

```python
y3 = [lambda 函数, 新人: 函数 + 新人 for 函数, 新人 in zip('abc','def')]
```

```python
y3
```

    [<function __main__.<listcomp>.<lambda>(函数, 新人)>,
     <function __main__.<listcomp>.<lambda>(函数, 新人)>,
     <function __main__.<listcomp>.<lambda>(函数, 新人)>]

```python
# [def y4(函数, 新人): return 函数 + 新人 for 函数, 新人 in zip('abc','def')]
```

```python
from sympy import factorial, symbols, init_session
n = symbols('n', Integer=True)
init_session()
```

    IPython console for SymPy 1.4 (Python 3.7.4-64-bit) (ground types: python)

    These commands were executed:
    >>> from __future__ import division
    >>> from sympy import *
    >>> x, y, z, t = symbols('x y z t')
    >>> k, m, n = symbols('k m n', integer=True)
    >>> f, g, h = symbols('f g h', cls=Function)
    >>> init_printing()

    Documentation can be found at https://docs.sympy.org/1.4/

```python
factorial(100)
```

```python
import functools, operator
m = functools.reduce(operator.mul,list(range(1,101)))
```

```python
m
```

```python
def 无厘头():
    j = i = 0
    if i < 100:
        j = 无厘头().j + 1
    i += 1
    return j
```

```python
# 无厘头() RecursionError: maximum recursion depth exceeded in comparison
```

```python
funct= lambda x, *y: x*y
```

```python
funct(1,100)
```

```python
def SUM(a,b,c):
    global d
    d = 4
    return a+b+c+d
```

```python
SUM(1,2,3), d
```

    (10, 4)

```python
def SUM(a,b,c):
    global d
    d = 4
    e = 2
    def SUBS():
        nonlocal a,b,c,e
        print(a+b+c+e-d)
    SUBS()
    return a+b+c+d+e
```

```python
SUM(4,5,6)
```

    13

    21

```python
def fib(n):
    return 1 if n < 2 else fib(n-1) + fib(n-2)
```

```python
for i in range(20):
    print('fibonacci %d -> ' % i, fib(i))
```

    fibonacci 0 ->  1
    fibonacci 1 ->  1
    fibonacci 2 ->  2
    fibonacci 3 ->  3
    fibonacci 4 ->  5
    fibonacci 5 ->  8
    fibonacci 6 ->  13
    fibonacci 7 ->  21
    fibonacci 8 ->  34
    fibonacci 9 ->  55
    fibonacci 10 ->  89
    fibonacci 11 ->  144
    fibonacci 12 ->  233
    fibonacci 13 ->  377
    fibonacci 14 ->  610
    fibonacci 15 ->  987
    fibonacci 16 ->  1597
    fibonacci 17 ->  2584
    fibonacci 18 ->  4181
    fibonacci 19 ->  6765

```python
def 数列(n):
    return 1 if n < 2 else fib(n-1) + fib(n-2)
```

```python
from sympy import cos, sin, init_session, pi, Sum, Rational
init_session()
```

    IPython console for SymPy 1.5.1 (Python 3.7.7-64-bit) (ground types: python)

    These commands were executed:
    >>> from __future__ import division
    >>> from sympy import *
    >>> x, y, z, t = symbols('x y z t')
    >>> k, m, n = symbols('k m n', integer=True)
    >>> f, g, h = symbols('f g h', cls=Function)
    >>> init_printing()

    Documentation can be found at https://docs.sympy.org/1.5.1/

```python
def fib(n):
    if n == 1:
        return 1
    if n == 2:
        return 2
    if n > 2:
        return (1+cos(n*pi/2)**2).doit()*fib(n-2)+(sin(n*pi/2)**2).doit()
```

```python
SUM = 0
for i in range(1,22,1):
    SUM = SUM + fib(i)
```

```python
print(SUM)
```

    2112

```python
def shulie(n):
    了 = '石头'
    return Rational(4,3) if n < 2 else shulie(n-1)**2 - shulie(n-1) + 1
```

```python
SUM = 0
for i in range(1,20,1):
    SUM = SUM + Rational(1,shulie(i))
print(SUM.evalf())
```

    3.00000000000000

```python
def SUM(a,b,c):
    global d
    d = 4
    e = 2
    def SUBS():
        nonlocal a,b,c,e
        print(a+b+c+e-d)
    SUBS()
    return a+b+c+d+e
```

```python
# %load script1.py

spam = 40

def square(x):
    return x*2, spam

class Employee:
    def sqirell(x):
        return spam
    pass

class Text():
    def PLUS(x,y):
        return str(x)+str(y), spam
    def SUBS(x,y):
        return str(x-y)

print(square(54))
print(square.__doc__)
```

```python
import script1
```

    (108, 40)
    None

```python
script1.spam
```

    40

```python
import __main__
```

```python
dir(__main__)
```

    ['In',
     'Out',
     'SUM',
     '_',
     '_3',
     '__',
     '___',
     '__builtin__',
     '__builtins__',
     '__doc__',
     '__loader__',
     '__main__',
     '__name__',
     '__package__',
     '__spec__',
     '_dh',
     '_i',
     '_i1',
     '_i10',
     '_i11',
     '_i12',
     '_i13',
     '_i14',
     '_i2',
     '_i3',
     '_i4',
     '_i5',
     '_i6',
     '_i7',
     '_i8',
     '_i9',
     '_ih',
     '_ii',
     '_iii',
     '_oh',
     'exit',
     'get_ipython',
     'quit',
     'script1']

```python
L = []
def fibonacci(n):
    L.append(n)
    return 1 if n < 2 else fibonacci(n-2)+fibonacci(n-1)
```

* L是局部变量还是全局变量？

```python
print(fibonacci(10), L, end=' ')
```

    89 [10, 8, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 9, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 8, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 10, 8, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 9, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 8, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 10, 8, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 9, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 8, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 10, 8, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 9, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 8, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 7, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1, 6, 4, 2, 0, 1, 3, 1, 2, 0, 1, 5, 3, 1, 2, 0, 1, 4, 2, 0, 1, 3, 1, 2, 0, 1]

```python
L = []
def fibonacci(n):
    M = []
    M.append(n)
    print(M,end=' ')
    return 1 if n < 2 else fibonacci(n-2)+fibonacci(n-1)
```

```python
print(fibonacci(10), L, end=' ')
```

    [10] [8] [6] [4] [2] [0] [1] [3] [1] [2] [0] [1] [5] [3] [1] [2] [0] [1] [4] [2] [0] [1] [3] [1] [2] [0] [1] [7] [5] [3] [1] [2] [0] [1] [4] [2] [0] [1] [3] [1] [2] [0] [1] [6] [4] [2] [0] [1] [3] [1] [2] [0] [1] [5] [3] [1] [2] [0] [1] [4] [2] [0] [1] [3] [1] [2] [0] [1] [9] [7] [5] [3] [1] [2] [0] [1] [4] [2] [0] [1] [3] [1] [2] [0] [1] [6] [4] [2] [0] [1] [3] [1] [2] [0] [1] [5] [3] [1] [2] [0] [1] [4] [2] [0] [1] [3] [1] [2] [0] [1] [8] [6] [4] [2] [0] [1] [3] [1] [2] [0] [1] [5] [3] [1] [2] [0] [1] [4] [2] [0] [1] [3] [1] [2] [0] [1] [7] [5] [3] [1] [2] [0] [1] [4] [2] [0] [1] [3] [1] [2] [0] [1] [6] [4] [2] [0] [1] [3] [1] [2] [0] [1] [5] [3] [1] [2] [0] [1] [4] [2] [0] [1] [3] [1] [2] [0] [1] 89 []

```python
zip = 2 # lambda, def都是python保留的关键词
```

```python
# zip('abc','def')
```

```python
del zip
```

```python
zip('abc','def')
```

    <zip at 0x21dbd5ff748>

```python
def fibonacci(n):
    global m
    m = 1
    def shulie():
        m = 2
        return m
    print(shulie(), m)
    return 1 if n < 2 else fibonacci(n-2)+fibonacci(n-1)
```

```python
fibonacci(2)
```

    2 1
    2 1
    2 1

    2

```python
def fibonacci(n):
    m = 1
    def shulie():
        return m
    print(shulie(), m)
    return 1 if n < 2 else fibonacci(n-2)+fibonacci(n-1)
```

```python
fibonacci(2)
```

    1 1
    1 1
    1 1

    2

```python
m = 3
def fibonacci(n):
    def shulie():
        return m
    print(shulie(), m)
    return 1 if n < 2 else fibonacci(n-2)+fibonacci(n-1)
```

```python
fibonacci(2)
```

    3 3
    3 3
    3 3

    2

```python
from math import tau, pi
```

```python
def fibonacci(n):
    def shulie():
        return tau
    print(shulie(), pi)
    return 1 if n < 2 else fibonacci(n-2)+fibonacci(n-1)
```

```python
fibonacci(2)
```

    6.283185307179586 3.141592653589793
    6.283185307179586 3.141592653589793
    6.283185307179586 3.141592653589793

    2

```python
from sympy import init_session, solve
init_session()
```

    IPython console for SymPy 1.5.1 (Python 3.7.7-64-bit) (ground types: python)

    These commands were executed:
    >>> from __future__ import division
    >>> from sympy import *
    >>> x, y, z, t = symbols('x y z t')
    >>> k, m, n = symbols('k m n', integer=True)
    >>> f, g, h = symbols('f g h', cls=Function)
    >>> init_printing()

    Documentation can be found at https://docs.sympy.org/1.5.1/

```python
a1, a2 = symbols('a1,a2')
```

```python
def an(n):
    if n == 1:
        return a1
    if n == 2:
        return a2
    if n > 2:
        return (n*2**n-a1+2*a2)/2**(n-1)
```

```python
def an(n):
    return (n*2**n-(n-1)*2**(n-1))/2**(n-1)
```

```python
an(1),an(2)
```

```python
SUM = 0
for i in range(1,2020,1):
    SUM = SUM + an(i)
print(SUM/2019)
```

    1011.0

```python
def an(n):
    zip = 2
    def fib():
        nonlocal n
        return 1 if n < 2 else an(n-1).fib() + an(n-2).fib()
    return (n*2**n-(n-1)*2**(n-1))/2**(n-1), fib()
```

```python
list(zip('abc','def'))
```

    [('a', 'd'), ('b', 'e'), ('c', 'f')]

```python
an(2)
```

    (3.0, 2)

```python
list(zip('abc','def'))
```

    [('a', 'd'), ('b', 'e'), ('c', 'f')]

```python
zip  = 2
```

```python
zip; del zip
```

```python
def an(n):
    def fibonacci():
        nonlocal n
        return 1 if n < 2 else an(n-2) + an(n-1)
    print((n*2**n-(n-1)*2**(n-1))/2**(n-1))
    return fibonacci()
```

```python
print(an(4), end=' ')
```

    5.0
    3.0
    1.0
    2.0
    4.0
    2.0
    3.0
    1.0
    2.0
    5

```python
m = 3
def fibonacci(n):
    print(m, end=' ')
    return 1 if n < 2 else fibonacci(n-2) + fibonacci(n-1)
```

```python
fibonacci(6)
```

    3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3

    13

* The local scope is superior to the local scopes of any enclosing defs statement (or lambda expressions)

```python
def fibonacci(n):
    m = n
    def even(m):
        m = 0
        return 0 if m < 1 else even(m-1) + 2
    print(m, even(m), end = ', ')
    return 1 if n < 2 else fibonacci(n-1) + fibonacci(n-2)
```

```python
print(fibonacci(8), end = ' ')
```

    8 0, 7 0, 6 0, 5 0, 4 0, 3 0, 2 0, 1 0, 0 0, 1 0, 2 0, 1 0, 0 0, 3 0, 2 0, 1 0, 0 0, 1 0, 4 0, 3 0, 2 0, 1 0, 0 0, 1 0, 2 0, 1 0, 0 0, 5 0, 4 0, 3 0, 2 0, 1 0, 0 0, 1 0, 2 0, 1 0, 0 0, 3 0, 2 0, 1 0, 0 0, 1 0, 6 0, 5 0, 4 0, 3 0, 2 0, 1 0, 0 0, 1 0, 2 0, 1 0, 0 0, 3 0, 2 0, 1 0, 0 0, 1 0, 4 0, 3 0, 2 0, 1 0, 0 0, 1 0, 2 0, 1 0, 0 0, 34

* The local scopes of any enclosing(E) defs and lambdas are superior to the global scope. (E>G)

```python
m = 2
def fibonacci(n):
    m = 6
    print(m,end =' ')
    return (1, n) if n < 2 else (fibonacci(n-1)+fibonacci(n-2), n)
```

```python
fibonacci(4)
```

    6 6 6 6 6 6 6 6 6

    (((((1, 1, 1, 0), 2, 1, 1), 3, (1, 1, 1, 0), 2), 4), 2)

```python
m
```

    2

* The global (G) scope is prior to the built-in scope

```python
zip = 4
```

```python
zip
```

    4

```python
del zip
```

```python
list(zip('abc','def'))
```

    [('a', 'd'), ('b', 'e'), ('c', 'f')]

```python
L = []
M = []
def rampage(m):
    L.append(zip('abc','def'))
    M = list(zip('abc','def'))
    return L, M
```

```python
L,M
```

    ([], [])

```python
rampage(4)
```

    ([<zip at 0x1d3c44f14c8>], [('a', 'd'), ('b', 'e'), ('c', 'f')])

```python
x = zip('abc','def')
list(x)
```

    [('a', 'd'), ('b', 'e'), ('c', 'f')]

```python
L =zip(*(x))
```

```python
s1 = 'abc'; s2 = 'def'
```

```python
x,y,z = zip(s1,s2)
```

```python
x, y, z
```

    (('a', 'd'), ('b', 'e'), ('c', 'f'))

```python
L = zip(*(x,y,z))
```

```python
l = list(L)
```

```python
''.join(l[0]), ''.join(l[1])
```

    ('abc', 'def')

```python
l
```

    [('a', 'b', 'c'), ('d', 'e', 'f')]

```python
Z = zip((1,2,3),(10,20,30))
```

```python
list(Z)
```

    [(1, 10), (2, 20), (3, 30)]

```python
x,y,z = zip((1,2,3),(10,20,30))
```

```python
t1 = zip(*(x,y,z))
```

```python
list(t1)
```

    [(1, 2, 3), (10, 20, 30)]

```python
list(t1) # 为什么第二次运行的时候会返回空的列表
```

    []

```python
t1 = 'South Korea Telecom'
```

```python
def f(a,b,c,d,club):
    #global IG
    FPX = 'Funplus Pheonix'
    def Versus(t):
        global IG
        IG = 'Invitcus Gaming'
        return IG + ' vs %s' % t, '%s vs %s' % (t, FPX)
    print(Versus(club))
    return ord(a)+ord(b)+ord(c)+ord(d), IG
```

```python
f('s','e','x','y',"Dragon X")
```

    ('Invitcus Gaming vs Dragon X', 'Dragon X vs Funplus Pheonix')

    (457, 'Invitcus Gaming')

```python
def fib(n):

    def f(a,b,c,d,club):
        #global IG
        FPX = 'Funplus Pheonix'
        def Versus(t):
            global IG
            IG = 'Invitcus Gaming'
            return IG + ' vs %s' % t, '%s vs %s' % (t, FPX)
        print(Versus(club))
        return ord(a)+ord(b)+ord(c)+ord(d), IG

    return IG if n < 2 else fib(n-2)+fib(n-1)
```

```python
fib(1)
```

    'Invitcus Gaming'

```python
def f(a,b,c,d):
    x,y,z = zip((1,2,3),(10,20,30))
    def unzip():
        x = (1,5)
        return zip(*(x,y,z))
    print(list(unzip()))
    return ord(a)+ord(b)+ord(c)+ord(d)
```

```python
f('a','b','c','d')
```

    [(1, 2, 3), (5, 20, 30)]

    394

```python
def tester(start):
    state = start
    check = start
    def nested(label):
        print(label,check)
        print(label,state)
        state = state + 1
        #print(state)
    return nested
```

```python
F = tester(0)
```

```python
def tester(start):
    state = start
    def nested(label):
        print(label,state)
    return nested
```

```python
F = tester(0)
```

```python
F('spam')
```

    spam 0

```python
def f(a,b,c,d):
    #global IG
    FPX = 'Funplus Pheonix'
    def Versus(t):
        global IG
        IG = 'Invitcus Gaming'
        return IG + ' vs %s' % t, '%s vs %s' % (t, FPX)

    return Versus
```

```python
f('a','b','c','d')("Top Esports")
```

    ('Invitcus Gaming vs Top Esports', 'Top Esports vs Funplus Pheonix')

```python
def tester(start):
    state = start
    check = start
    def nested(label):
        nonlocal state
        print(label,check)
        print(label,state)
        state = state + 1
        #print(state)
    return nested
```

```python
nested = tester(9)
```

```python
nested("TES")
```

    TES 9
    TES 9

```python
from sympy import Rational
```

```python
class teacher():
    def fibonacci(n):
        return 1 if n < 2 else fibonacci(n-2) + fibonacci(n-1)
    def shulie(n):
        return Rational(1,2) if n < 1 else Rational(shulie(n-1)**2,2018) + shulie(n-1)
```

```python
def 数列(n):
    return 1/2 if n < 2 else 数列(n-1)**2/2018 + 数列(n-1)
```

```python
数列(1); 数列(2); 数列(3);数列(4);数列(10);
```

    0.5011171794666097

```python
X = 99
def func(Y):
    X = 3
    Z = X + Y
    return Z
func(1)
```

    4

```python
X
```

    99

```python
import builtins
```

```python
print(dir(builtins), end=' ')
```

    ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__IPYTHON__', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'display', 'divmod', 'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'get_ipython', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']

```python
import script1
builtins.memoryview(bytes('example', encoding='utf8')).tolist()
```

    [101, 120, 97, 109, 112, 108, 101]

```python
bytes('example', encoding='utf8')
```

    b'example'

```python
ord('e')
```

    101

```python
zip = 24
```

* None = 24; True = 'str'; False = zip； def = 2; del = 10; global # 这四个单词都是python自动保留单词

```python
del zip
```

```python
list(zip('abc','def'))
```

    [('a', 'd'), ('b', 'e'), ('c', 'f')]

```python
open = 8; del open
```

```python
def hider():
    open = 'spam'
    open('script1.py').read()
```

```python
builtins.copyright()
```

    Copyright (c) 2001-2020 Python Software Foundation.
    All Rights Reserved.

    Copyright (c) 2000 BeOpen.com.
    All Rights Reserved.

    Copyright (c) 1995-2001 Corporation for National Research Initiatives.
    All Rights Reserved.

    Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
    All Rights Reserved.

```python
import operator
X = 88
def func():
    global x
    x = 99
    return operator.add(X,x)
```

```python
func()
```

    187

```python
X, x
```

    (88, 99)

* __builtin__ (2.6) === builtins (3.0)

```python
print(dir(__builtins__), end = ' ')
```

    ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__IPYTHON__', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'display', 'divmod', 'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'get_ipython', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']

```python
__builtins__ is builtins, __builtins__ is __builtin__
```

    (True, True)

```python
1 == 1.0
```

    True

```python
S = "This technique can be useful"
L = S.split()
```

```python
print(list(reversed(L)), end = ' ')
```

    ['useful', 'be', 'can', 'technique', 'This']

```python
X = 88
def func():
    global X
    X = 99
func()
print(X)
```

    99

```python
X = 99
def func1():
    global X
    X = 88
def func2():
    global X
    X = 77
```

```python
func1(), func2(), func1(), X
```

    (None, None, None, 88)

# 最小化全局变量的使用

```python
X
```

    99

```python
func1(), X, func2(), X, func1(), X
```

    (None, 88, None, 77, None, 88)

```python
S = "The net effect is that to understand this code, you have to trace the flow of control through the entire program."
L = S.split()
I=iter(L)
def func3():
    return next(I)
```

```python
func3()
```

    'to'

```python
f = open("script1.py"); f.readline()
```

    '\n'

```python
f.readline()
```

    'class Employee:\n'

```python
def func4():
    yield next(I)
```

```python
for i in func4():
    print(i)
```

    the

```python
next(func4())
```

    'the'

```python
def gensquares(N):
    for i in range(N):
        yield i**2
```

```python
for i in gensquares(6):
    print(i, end = ' squared is : ')
```

    0 squared is : 1 squared is : 4 squared is : 9 squared is : 16 squared is : 25 squared is :

```python
func4().send(None)
```

    'entire'

```python
F = func4()
next(F)
```

    'The'

```python
def gen():
    for i in range(10):
        X = yield i
        print(X)
```

```python
G = gen()
```

```python
next(G)
```

    0

```python
G.send(99)
```

    99

    2

# Minimize Cross-File Changes

```python
import script1
```

    (108, 40)
    None

```python
script1.spam = 100
```

```python
# %load script1.py

spam = 40

def square(x):
    return x*2, spam

class Employee:
    pass

class Text():
    def PLUS(x,y):
        return str(x)+str(y), spam
    def SUBS(x,y):
        return str(x-y)

print(square(54))
print(square.__doc__)
```

```python
script1.square(2)
```

    (4, 100)

```python
script1.spam = 100
```

```python
script1.spam
```

    100

```python
del script1
```

```python
from script1 import scr
```

```python
del script1
```

```python
from imp import reload
reload(script1)
```

    (108, 40)
    None

    <module 'script1' from 'C:\\Users\\NickC\\script1.py'>

* import script1 # import无法更新导入的模块,必须要用reload

```python
# %load script1.py

spam = 40
X = 99

def square(x):
    return x*2, spam

def setX(new):
    global X
    X = new

class Employee:
    pass

class Text():
    def PLUS(x,y):
        return str(x)+str(y), spam
    def SUBS(x,y):
        return str(x-y)

print(square(54))
print(square.__doc__)
```

```python
script1.setX(88)
```

```python
X
```

    99

```python
script1.X
```

    88

```python
f = open('thismod.py','w')
f.writelines('var = 99')
f.writelines('\n')
```

```python
f.writelines('def local(): var = 0')
f.writelines('\n')
```

```python
f.writelines('def glob1(): global var; var += 1')
f.writelines('\n')
f.writelines('def glob2(): var = 0; import thismod; thismod.var += 1')
f.writelines('\n')
```

```python
f.writelines("def glob3(): var = 0; import sys; glob = sys.modules['thismod']; glob.var += 1")
f.writelines('\n')
```

```python
f.writelines('def test(): print(var); local(); glob1();glob2();glob3(); print(var)')
f.writelines('\n')
```

```python
f.close()
```

```python
import os
os.remove('thismod.py')
```

```python
# %load thismod.py
var = 99
def local(): var = 0
def glob1(): global var; var += 1
def glob2(): var = 0; import thismod; thismod.var += 1
def glob3(): var = 0; import sys; glob = sys.modules['thismod']; glob.var += 1
def test(): print(var); local(); glob1();glob2();glob3(); print(var)

```

```python
import thismod
```

```python
thismod.test()
```

    99
    102

```python
thismod.var
```

    102

```python
thismod.glob1()
```

```python
thismod.test()
```

    103
    106

```python
def local():
    var = 0   #这个就是一个函数，不用分号，有缩进 或者更高级一点用上面这个语句就行
```

## Nested Scope Examples

```python
X = 99
def f1():
    X = 88
    def f2():
        print(X)
    f2()
f1()
```

    88

```python
X = 99
def f1():
    X = 77
    def f2():
        print(X)
    return f2
```

```python
f1()()
```

    77

```python
k = 98

def f1(x):
    y = x

    def f2():
        nonlocal y
        print(y, x, 'the first print !')
        y = y + 1
        print(y, 'the second print !')

        def f3(n):
            l = 32
            def f4():
                def f5():
                    global m, k, l
                    k = 49.0
                    m = 4
                    l = 56.01
                    print(m, n, y, k, 'the third print !')
                print(l, 'To prove that the E scope is prior to G scope')
                return f5
            return f4

        print(y, m, 'the fourth print !')
        return f3

    n = 1.4
    m = 3.14
    print(y, x,m, n, 'the fifth print !')
    return f2
```

```python
f1(4.32)()(8.9)()(), m, k
```

    4.32 4.32 3.14 1.4 the fifth print !
    4.32 4.32 the first print !
    5.32 the second print !
    5.32 3.14 the fourth print !
    32 To prove that the E scope is prior to G scope
    4 8.9 5.32 49.0 the third print !

    (None, 4, 49.0)

```python
X = 99
def f1():
    X = 88
    def f2():
        print(X)
    return f2
```

```python
f1()
```

    <function __main__.f1.<locals>.f2()>

# Factory Functions

```python
def maker(N):
    def action(X):
        return X**N
    return action
```

```python
f = maker(2)
```

```python
f
```

    <function __main__.maker.<locals>.action(X)>

```python
f(3)
```

    9

```python
class Firstclass:
    def setdata(self, value):
        self.data = value
    def display(self):
        print(self.data)
```

```python
x = Firstclass()
y = Firstclass()
```

```python
x.setdata("King Arthur")
y.setdata(3.1415992654)
```

```python
x.display()
y.display()
```

    King Arthur
    3.1415992654

```python
x.data = "New value"
```

```python
x.display()
```

    New value

```python
f(3), f(4)
```

    (9, 16)

```python
def maker(N):
    def action(X):
        return X**N
    return action
```

```python
f = maker(2)
```

```python
f(3)
```

    9

```python
g = maker(3)
```

```python
g(3)
```

    27

```python
f(3)
```

    9

```python
def maker(N):
    return lambda X : X**N
```

```python
f = maker(2)
f(3)
g = maker(3)
g(3)
```

    27

```python
class Firstclass:
    def setdata(self, value):
        self.data = value
    def display(self):
        print(self.data)
```

```python
def f1():
    x = 88
    def f2(x=x):
        print(x)
    f2()
```

```python
f1()
```

    88

```python
def f1():
    x = 88
    def f2(x=x):
        print(x)
    return f2()
```

```python
f1()
```

    88

```python
def f1():
    x = 88
    def f2():
        print(x)
    f2()
```

```python
f1()
```

    88

```python
def f1():
    x = 88
    def f2(x=x):
        print(x)
    return f2
```

```python
f1()(),f1()(23.4)
```

    88
    23.4

    (None, None)

```python
def step():
    x = 88
    def into(x=x):
        print(x,'the firts print')
       # x = x
        print(x,'the second print')
    return into
```

```python
step()()
```

    88 the firts print
    88 the second print

```python
def f1():
    x = 88
    y = 22
    def f2(y=x):
        #x = 23
        print(x,y)
    return f2
```

```python
f1()()
```

    88

```python
def f1():
    x  = 88
    return f2
```

```python
def f2(y=x):
    print(y)
```

```python
f1()(2)
```

    2

```python
def f1():
    def f2():
        print("hello world")
    return f2
```

```python
def func():
    x = 4
    y = 5
    z = 6.02
    action = (lambda n: x ** n + y **(x+z) + z*n*(y**2+x**3))
    return action
```

```python
def func():
    x = 4
    y = 5
    z = 6.02
    action = (lambda n,x=x,y=y,z=z: x ** n + y **(x+z) + z*n*(y**2+x**3))
    return action
```

```python
func()(2)
```

    10086169.785551196

```python
func()(2,3,4,5)
```

    65975

```python
def func1():
    x = 4
    y = 5
    z = 6.02
    action = (lambda n,x=x,y=y,z=z: x ** n + y **(x+z) + z*n*(y**2+x**3))
    return action
```

# Scopes versus defaults with loop variables

```python
def makeActions():
    acts = []
    for i in range(5):
        acts.append(lambda x: i ** x)
    return acts
```

```python
acts = makeActions()
```

```python
acts[0]
```

    <function __main__.makeActions.<locals>.<lambda>(x)>

```python
acts
```

    [<function __main__.makeActions.<locals>.<lambda>(x)>,
     <function __main__.makeActions.<locals>.<lambda>(x)>,
     <function __main__.makeActions.<locals>.<lambda>(x)>,
     <function __main__.makeActions.<locals>.<lambda>(x)>,
     <function __main__.makeActions.<locals>.<lambda>(x)>]

```python
acts[0](2), acts[1](2), acts[2](2), acts[3](2), acts[4](2)
```

    (16, 16, 16, 16, 16)

```python
actions = []
for i in range(5):
    actions.append(lambda x: i ** x)
```

```python
actions
```

    [<function __main__.<lambda>(x)>,
     <function __main__.<lambda>(x)>,
     <function __main__.<lambda>(x)>,
     <function __main__.<lambda>(x)>,
     <function __main__.<lambda>(x)>]

```python
i
```

    4

```python
[actions[i](2) for i in range(5)]
```

    [16, 16, 16, 16, 16]

```python
def makeActions():
    acts = []
    for i in range(5):
        acts.append(lambda x, i = i : i ** x)
    return acts
```

```python
acts = makeActions()
[acts[i](2) for i in range(5)]
```

    [0, 1, 4, 9, 16]

# The nonlocal statement

```python
def outer():
    X = 1
    def inner():
        nonlocal X
        print(X, 'This is the output of the first print!')
        X = X + 1
        print(X, "This is the output of the second print!")
    inner()
    print(X, "This is the output of the third print function!")
    return inner
```

```python
outer()
```

    <function __main__.outer.<locals>.inner1()>

```python
def outer():
    def inner1():
        def inner2():
            def inner3():
                def inner4():
                    global y
                    y = 3
                return inner4
            return inner3
        return inner2
    return inner1
```

```python
outer()()()()(), y
```

    (None, 3)

```python
del x,y,z
```

```python
print(k, m, n)
print(f, g, h)
```

    k m n
    f g h

```python
del k, m, n
del f, g, h
```

```python
def outer():
    y = 3
    def inner():
        nonlocal y
        print(y)
    return inner
```

```python
def outer(start):
    state = start
    def inner(string):
        nonlocal state
        print(string, state)
        state += 1
    return inner
```

```python
out = outer(0)
```

```python
type(out)
```

    function

```python
out('apple'), out('watermelon'), out('orange'), out("pineapple"), out('banana'), \
out('grape')
```

    apple 0
    watermelon 1
    orange 2
    pineapple 3
    banana 4
    grape 5

    (None, None, None, None, None, None)

```python
list(enumerate(['apple','watermelon', 'orange', 'pineapple','banana','grape']))
```

    [(0, 'apple'),
     (1, 'watermelon'),
     (2, 'orange'),
     (3, 'pineapple'),
     (4, 'banana'),
     (5, 'grape')]

```python
class fruitscounter():
    def __init__(self, start):
        self.state = start
    def __call__(self, string):
        print(string, self.state)
        self.state += 1
```

```python
fruitc = fruitscounter(0)
```

```python
import builtins
```

```python
isinstance(fruitc, fruitscounter)
```

    True

```python
fruitc.state
```

    0

```python
fruitc('apple'), fruitc('watermelon'), fruitc('orange'), fruitc('pineapple'), \
fruitc('banana'),fruitc('grape')
```

    apple 0
    watermelon 1
    orange 2
    pineapple 3
    banana 4
    grape 5

    (None, None, None, None, None, None)

```python
def FruitsCounter(start):
    def inner(string):
        print(string, inner.state)
        inner.state += 1
    inner.state = start
    return inner
```

```python
FC = FruitsCounter(0)
```

```python
FC('apple'), FC('watermelon'), FC('orange'), FC('pineapple'), FC('banana'), FC('grape')
```

    apple 0
    watermelon 1
    orange 2
    pineapple 3
    banana 4
    grape 5

    (None, None, None, None, None, None)

```python
def outer():
    y = 4
    def inner1():
        def inner2():
            y = 2
            def inner3():
                def inner4():
                    nonlocal y
                    print(y)
                return inner4
            return inner3
        return inner2
    return inner1
```

```python
from math import tau
```

```python
outer()()()()()
```

    2

```python

```


```python
# This cell is mandatory in all Dymos documentation notebooks.
missing_packages = []
try:
    import openmdao.api as om
except ImportError:
    if 'google.colab' in str(get_ipython()):
        !python -m pip install openmdao[notebooks]
    else:
        missing_packages.append('openmdao')
try:
    import dymos as dm
except ImportError:
    if 'google.colab' in str(get_ipython()):
        !python -m pip install dymos
    else:
        missing_packages.append('dymos')
try:
    import pyoptsparse
except ImportError:
    if 'google.colab' in str(get_ipython()):
        !pip install -q condacolab
        import condacolab
        condacolab.install_miniconda()
        !conda install -c conda-forge pyoptsparse
    else:
        missing_packages.append('pyoptsparse')
if missing_packages:
    raise EnvironmentError('This notebook requires the following packages '
                           'please install them and restart this notebook\'s runtime: {",".join(missing_packages)}')
```

(examples:bryson_denham)=
# The Bryson-Denham Problem

The Bryson-Denham problem is a variation of the double integrator problem {cite}`bryson1975applied`. It can be stated as:

Minimize the control effort required to reverse the direction of motion of a frictionless sliding block such that the reversal happens with some limited amount of displacement.

## State and control variables

This system has two state variables, the position ($x$) and velocity ($v$) of the sliding block.

This system has a single control variable ($u$), the acceleration of the block.

The dynamics of the system are governed by

\begin{align}
  \dot{x} &= v \\
  \dot{v} &= u
\end{align}

## Problem Definition

We seek to minimize the time required to exit the well in the positive direction.

\begin{align}
    \mathrm{Minimize} \, J &= 0.5 \int_0^1 u^2 dt
\end{align}

Subject to the initial conditions

\begin{align}
    x_0 &= 0.0 \\
    v_0 &= 1.0
\end{align}

and the terminal constraints

\begin{align}
    x_f &= 0.0 \\
    v_f &= -1.0
\end{align}

In addition, $x$ is consrained to remain below a displacement of 1/9.

\begin{align}
    x &\le 1/9
\end{align}

## Dealing with integral costs in Dymos

In classic optimal control, the objective is often broken into the terminal component (the Mayer term) and the integral component (the Lagrange term).
Dymos does not distinguish between the two.
In this case, since the objective $J$ is an integrated quantity, we add a term to the ODE

\begin{align}
\dot{J} &= 0.5 u^2
\end{align}

## Defining the ODE

The following code implements the equations of motion for the mountain car problem.
Since the rate of $x$ is given by another state ($v$), and the rate of $v$ is given by a control ($u$), there is no need to compute their rates in the ODE.
Dymos can pull their values from those other states and controls.
The ODE, therefore, only needs to compute the rate of change of $J$.

A few things to note:

1. By providing the tag `dymos.state_rate_source:{name}`, we're letting Dymos know what states need to be integrated, there's no need to specify a rate source when using this ODE in our Phase.
2. Pairing the above tag with `dymos.state_units:{units}` means we don't have to specify units when setting properties for the state in our run script.

```python
import numpy as np
import openmdao.api as om

class BrysonDenhamODE(om.ExplicitComponent):

    def initialize(self):
        self.options.declare('num_nodes', types=int)

    def setup(self):
        nn = self.options['num_nodes']

        self.add_input('x', shape=(nn,), units='m')
        self.add_input('v', shape=(nn,), units='m/s')
        self.add_input('u', shape=(nn,), units='m/s**2')

        self.add_output('J_dot', shape=(nn,), units='m**2/s**4',
                        tags=['dymos.state_rate_source:J',
                              'dymos.state_units:m**2/s**3'])

        ar = np.arange(nn, dtype=int)

        self.declare_partials(of='J_dot', wrt='u', rows=ar, cols=ar)

    def compute(self, inputs, outputs):
        u = inputs['u']
        outputs['J_dot'] = 0.5 * u**2

    def compute_partials(self, inputs, partials):
        partials['J_dot', 'u'] = inputs['u']

```

## Solving the Bryson-Denham problem with Dymos

The following script solves the minimum-time mountain car problem with Dymos.
This problem is pretty trivial and can be solved using the SLSQP optimizer in scipy.

To begin, import the packages we require:

```python
import dymos as dm
import matplotlib.pyplot as plt
```

We then instantiate an OpenMDAO problem and set the optimizer and its options.

The call to `declare_coloring` tells the optimizer to attempt to find a sparsity pattern that minimizes the work required to compute the derivatives across the model.

SLSQP does not internally use this sparsity information to reduce memory and improve performance as some other optimizers do, but the performance due to the increased efficiency in computing derivatives still makes it worthwhile.

```python
#
# Initialize the Problem and the optimization driver
#
p = om.Problem()

p.driver = om.ScipyOptimizeDriver()
p.driver.declare_coloring()
```

Next, we add a Dymos Trajectory group to the problem's model and add a phase to it.

In this case we're using the Radau pseudospectral transcription to solve the problem.

```python
#
# Create a trajectory and add a phase to it
#
traj = p.model.add_subsystem('traj', dm.Trajectory())
tx = transcription=dm.Radau(num_segments=24)
phase = traj.add_phase('phase0', dm.Phase(ode_class=BrysonDenhamODE, transcription=tx))
```

At this point, we set the options on the main variables used in a Dymos phase.

In addition to `time`, we have three states (`x`, `v`, and `J`) and a single control (`u`).

Here we use bounds on the states themselves to constrain the initial and final value of `x` and1 `v`, and the initial value of `J`.
From an optimization perspective, this means that we are removing the first and last values in the state histories of $x$ and $v$ from the vector of design variables.
Their initial and final values will remain unchanged throughout the optimization process.

On the other hand, we could specify `fix_initial=False, fix_final=False` for these values, and Dymos would be free to change them.
We would then need to put a boundary constraint in place to enforce their final values.
Feel free to experiment with different ways of enforcing the boundary constraints on this problem and see how it affects performance.

The scaler values (`ref`) are all set to 1 here.

Bounds on time duration are guesses, and the bounds on the states and controls come from the implementation in the references.

Also, we don't need to specify targets for any of the variables here because their names _are_ the targets in the top-level of the model.
The rate source and units for the states are obtained from the tags in the ODE component we previously defined.

```python
#
# Set the variables
#
phase.set_time_options(fix_initial=True, fix_duration=True)

phase.add_state('x', fix_initial=True, fix_final=True, rate_source='v')
phase.add_state('v', fix_initial=True, fix_final=True, rate_source='u')
phase.add_state('J', fix_initial=True, fix_final=False) # Rate source obtained from tags on the ODE outputs
phase.add_control('u', continuity=True, rate_continuity=False)
```

```python
#
# Minimize time at the end of the phase
#
phase.add_objective('J', loc='final', ref=1)
phase.add_path_constraint('x', upper=1/9)

#
# Setup the Problem
#
p.setup()
```

We then set the initial guesses for the variables in the problem and solve it.

We're using the phase `interp` method to provide initial guesses for the states and controls.
In this case, by giving it two values, it is linearly interpolating from the first value to the second value, and then returning the interpolated value at the input nodes for the given variable.

Finally, we use the `dymos.run_problem` method to execute the problem.
This interface allows us to do some things that the standard OpenMDAO `problem.run_driver` interface does not.
It will automatically record the final solution achieved by the optimizer in case named `'final'` in a file called `dymos_solution.db`.
By specifying `simulate=True`, it will automatically follow the solution with an explicit integration using `scipy.solve_ivp`.
The results of the simulation are stored in a case named `final` in the file `dymos_simulation.db`.
This explicit simulation demonstrates how the system evolved with the given controls, and serves as a check that we're using a dense enough grid (enough segments and segments of sufficient order) to accurately represent the solution.

If those two solution didn't agree reasonably well, we could rerun the problem with a more dense grid.
Instead, we're asking Dymos to automatically change the grid if necessary by specifying `refine_method='ph'`.
This will attempt to repeatedly solve the problem and change the number of segments and segment orders until the solution is in reasonable agreement.

```python
#
# Set the initial values
#
p['traj.phase0.t_initial'] = 0.0
p['traj.phase0.t_duration'] = 1.0

p.set_val('traj.phase0.states:x', phase.interp('x', ys=[0, 0]))
p.set_val('traj.phase0.states:v', phase.interp('v', ys=[1, -1]))
p.set_val('traj.phase0.states:J', phase.interp('J', ys=[0, 1]))
p.set_val('traj.phase0.controls:u', np.sin(phase.interp('u', ys=[0, 0])))

#
# Solve for the optimal trajectory
#
dm.run_problem(p, run_driver=True, simulate=True)

```

## Plotting the solution

The recommended practice is to obtain values from the recorded cases.
While the problem object can also be queried for values, building plotting scripts that use the case recorder files as the data source means that the problem doesn't need to be solved just to change a plot.
Here we load values of various variables from the solution and simulation for use in the animation to follow.

```python
sol = om.CaseReader('dymos_solution.db').get_case('final')
sim = om.CaseReader('dymos_simulation.db').get_case('final')

t = sol.get_val('traj.phase0.timeseries.time')
x = sol.get_val('traj.phase0.timeseries.states:x')
v = sol.get_val('traj.phase0.timeseries.states:v')
J = sol.get_val('traj.phase0.timeseries.states:J')
u = sol.get_val('traj.phase0.timeseries.controls:u')
h = np.sin(3 * x) / 3

t_sim = sim.get_val('traj.phase0.timeseries.time')
x_sim = sim.get_val('traj.phase0.timeseries.states:x')
v_sim = sim.get_val('traj.phase0.timeseries.states:v')
J_sim = sim.get_val('traj.phase0.timeseries.states:J')
u_sim = sim.get_val('traj.phase0.timeseries.controls:u')
h_sim = np.sin(3 * x_sim) / 3

fig = plt.figure(constrained_layout=True, figsize=(12, 4))
gs = fig.add_gridspec(2, 2)

x_ax = fig.add_subplot(gs[0, 0])
v_ax = fig.add_subplot(gs[1, 0])
J_ax = fig.add_subplot(gs[0, 1])
u_ax = fig.add_subplot(gs[1, 1])

x_ax.set_ylabel('x ($m$)')
v_ax.set_ylabel('v ($m/s$)')
J_ax.set_ylabel('J ($m^2$/s^3$)')
u_ax.set_ylabel('u ($m/s^2$)')
v_ax.set_xlabel('t (s)')
u_ax.set_xlabel('t (s)')

x_sol_handle, = x_ax.plot(t, x, 'o', ms=1)
v_ax.plot(t, v, 'o', ms=1)
J_ax.plot(t, J, 'o', ms=1)
u_ax.plot(t, u, 'o', ms=1)

x_sim_handle, = x_ax.plot(t_sim, x_sim, '-', ms=1)
v_ax.plot(t_sim, v_sim, '-', ms=1)
J_ax.plot(t_sim, J_sim, '-', ms=1)
u_ax.plot(t_sim, u_sim, '-', ms=1)

for ax in [x_ax, v_ax, J_ax, u_ax]:
    ax.grid(True, alpha=0.2)

plt.figlegend([x_sol_handle, x_sim_handle], ['solution', 'simulation'], ncol=2, loc='lower center');

```

```python
from openmdao.utils.assert_utils import assert_near_equal

assert_near_equal(J[-1, 0], 4.0, tolerance=1.0E-3)
```

## Animating the Solution

The collapsed code cell below contains the code used to produce an animation of the mountain car solution using Matplotlib.

The green area represents the hilly terrain the car is traversing.  The black circle is the center of the car, and the orange arrow is the applied control.

The applied control _generally_ has the same sign as the velocity and is 'bang-bang', that is, it wants to be at its maximum possible magnitude.  Interestingly, the sign of the control flips shortly before the sign of the velocity changes.

```python
import matplotlib as mpl
from matplotlib import animation

BLOCK_SIZE = 0.02
X_EXTENTS = (-0.025, 0.175)

fig = plt.figure(constrained_layout=True, figsize=(12, 6))
gs = fig.add_gridspec(3, 2)

anim_ax = fig.add_subplot(gs[:, 0])
anim_ax.set_aspect('equal')

x_ax = fig.add_subplot(gs[0, 1:])
v_ax = fig.add_subplot(gs[1, 1:])
u_ax = fig.add_subplot(gs[2, 1:])

x_ax.set_ylabel('x')
v_ax.set_ylabel('v')
u_ax.set_ylabel('u')
u_ax.set_xlabel('t')

# set up the subplots as needed
anim_ax.set_xlim(X_EXTENTS);
y_extents = [-np.diff(X_EXTENTS) / 2, np.diff(X_EXTENTS) / 2]
anim_ax.set_ylim(y_extents);
anim_ax.set_xlabel('x');
anim_ax.set_yticks([])
time_text = anim_ax.text(0.05, 0.9, 't = 0.000 s', fontsize=16, transform=anim_ax.transAxes)

x_sol_line, = x_ax.plot(t, x, 'o', ms=1, label='solution', color='k')
v_ax.plot(t, v, 'o', ms=1, color='k')
u_ax.plot(t, u, 'o', ms=1, color='k')

x_sim_line, = x_ax.plot([], [], '-', linewidth=3, label='simulation', color='tab:blue')
v_sim_line, = v_ax.plot([], [], '-', linewidth=3, color='tab:red')
u_sim_line, = u_ax.plot([], [], '-', linewidth=3, color='tab:orange')

plt.figlegend(ncol=2, handles=[x_sol_line, x_sim_line], loc='upper center',
              bbox_to_anchor=(0.78,0.98))

x_ax.grid(alpha=0.2)
txt_x = x_ax.text(0.8, 0.1, f'x = {x_sim[0, 0]:6.3f}', horizontalalignment='left',
                  verticalalignment='center', transform=x_ax.transAxes)

v_ax.grid(alpha=0.2)
txt_v = v_ax.text(0.8, 0.1, f'v = {v_sim[0, 0]:6.3f}', horizontalalignment='left',
                  verticalalignment='center', transform=v_ax.transAxes)

u_ax.grid(alpha=0.2)
txt_u = u_ax.text(0.8, 0.1, f'u = {u_sim[0, 0]:6.3f}', horizontalalignment='left',
                  verticalalignment='center', transform=u_ax.transAxes)

x_terrain = np.linspace(-0.025, 0.175, 2);
h_terrain = 0 * x_terrain
terrain_line, = anim_ax.plot(x_terrain, h_terrain, '-', color='tab:gray', lw=2);
terrain = anim_ax.fill_between(x_terrain, h_terrain, h_terrain-1, color='tab:green');
wall = mpl.patches.Rectangle(xy=(1/9 + BLOCK_SIZE, 0), width=BLOCK_SIZE, height=3*BLOCK_SIZE, color='tab:gray')
anim_ax.add_patch(wall)
block = mpl.patches.Rectangle(xy=(0, 0), width=BLOCK_SIZE, height=BLOCK_SIZE, alpha=0.5)
anim_ax.add_patch(block)
v_vec = anim_ax.quiver(x_sim[0,0] + BLOCK_SIZE / 2, BLOCK_SIZE * 0.25, v_sim[0,0], [0], scale=10, angles='xy', color='tab:red')
u_vec = anim_ax.quiver(x_sim[0,0] + BLOCK_SIZE / 2, BLOCK_SIZE * 0.75, u_sim[0,0], [0], scale=50, angles='xy', color='tab:orange')

# See https://brushingupscience.com/2019/08/01/elaborate-matplotlib-animations/ for quiver animation

ANIM_DURATION = 3
PRE_PAUSE_DURATION = 1
POST_PAUSE_DURATION = 0.5
ANIM_FPS = 20

num_points = t_sim.size
num_frames = int(ANIM_DURATION * ANIM_FPS)
pre_pause_frames = int(PRE_PAUSE_DURATION * ANIM_FPS)
post_pause_frames = int(POST_PAUSE_DURATION * ANIM_FPS)

idx_from_frame_num = np.linspace(0, num_points-1, num_frames, dtype=int)

def drawframe(n):

    if n < pre_pause_frames:
        idx = 0
    elif n - pre_pause_frames >= idx_from_frame_num.size:
        idx = num_points - 1
    else:
        idx = idx_from_frame_num[n - pre_pause_frames]

    x = x_sim[idx]
    v = v_sim[idx]
    u = u_sim[idx]
    t = t_sim[idx]
    h = 0
    block.set_xy((x[0], h))

    v_vec.set_offsets((x[0] + BLOCK_SIZE/2, BLOCK_SIZE * 0.25))
    v_vec.set_UVC(v, 0)

    u_vec.set_offsets((x[0] + BLOCK_SIZE/2, BLOCK_SIZE * 0.75))
    u_vec.set_UVC(u, 0)

    x_sim_line.set_data(t_sim[:idx], x_sim[:idx])
    v_sim_line.set_data(t_sim[:idx], v_sim[:idx])
    u_sim_line.set_data(t_sim[:idx], u_sim[:idx])

    txt_x.set_text(f'x = {x[0]:6.3f}')
    txt_v.set_text(f'v = {v[0]:6.3f}')
    txt_u.set_text(f'u = {u[0]:6.3f}')

    time_text.set_text(f't = {t[0]:6.3f}')

    return block, u_vec, v_vec, x_sim_line, v_sim_line, u_sim_line, time_text

# # blit=True re-draws only the parts that have changed.
# # repeat_delay has no effect when using to_jshtml, so pad drawframe to show the final frame for PAUSE_FRAMES extra frames.
anim = animation.FuncAnimation(fig, drawframe, frames=pre_pause_frames + num_frames + post_pause_frames, interval=1000/ANIM_FPS, blit=True);
plt.close()  # Don't let jupyter display the un-animated plot

from IPython.display import HTML
with open('anim.html', 'w') as f:
    f.write(anim.to_jshtml())
HTML('anim.html')
```

## References

```{bibliography}
:filter: docname in docnames
```


We start with...

```C#
Console.WriteLine("Hello World!");
```

    Hello World!

Then we do a plot with Plotly, following the [Plotting with XPlot](https://github.com/dotnet/interactive/blob/master/NotebookExamples/csharp/Docs/Plotting%20with%20Xplot.ipynb) example from `dotnet/interactive`:

```C#
using XPlot.Plotly;

var bar = new Graph.Bar
{
    name = "Bar",
    x = new[] {'A', 'B', 'C'},
    y = new[] {1, 3, 2}
};

var chart = Chart.Plot(new[] {bar});
chart.WithTitle("A bar plot");
display(chart);
```

We also test the math outputs as in the [Math and Latex](https://github.com/dotnet/interactive/blob/master/NotebookExamples/csharp/Docs/Math%20and%20LaTeX.ipynb) example:

```C#
(LaTeXString)@"\begin{align} e^{i \pi} = -1\end{align}"
```

\begin{align} e^{i \pi} = -1\end{align}

```C#
(MathString)@"e^{i \pi} = -1"
```

$$e^{i \pi} = -1$$


# Tutorial-IllinoisGRMHD: harm_u2p_util.c

## Authors: Leo Werneck & Zach Etienne

**This module is currently under development**

## In this tutorial module we explain the utility functions needed by the conservative-to-primitive algorithm used by `HARM`. This module will likely be absorbed by another one once we finish documenting the code.

### Required and recommended citations:

* **(Required)** Etienne, Z. B., Paschalidis, V., Haas R., Mösta P., and Shapiro, S. L. IllinoisGRMHD: an open-source, user-friendly GRMHD code for dynamical spacetimes. Class. Quantum Grav. 32 (2015) 175009. ([arxiv:1501.07276](http://arxiv.org/abs/1501.07276)).
* **(Required)** Noble, S. C., Gammie, C. F., McKinney, J. C., Del Zanna, L. Primitive Variable Solvers for Conservative General Relativistic Magnetohydrodynamics. Astrophysical Journal, 641, 626 (2006) ([astro-ph/0512420](https://arxiv.org/abs/astro-ph/0512420)).
* **(Recommended)** Del Zanna, L., Bucciantini N., Londrillo, P. An efficient shock-capturing central-type scheme for multidimensional relativistic flows - II. Magnetohydrodynamics. A&A 400 (2) 397-413 (2003). DOI: 10.1051/0004-6361:20021641 ([astro-ph/0210618](https://arxiv.org/abs/astro-ph/0210618)).

# Table of Contents
$$\label{toc}$$

This module is organized as follows

0. [Step 0](#src_dir): **Source directory creation**
1. [Step 1](#introduction): **Introduction**
1. [Step 2](#harm_utoprim_2d__c__eos_indep): **EOS independent routines**
    1. [Step 2.a](#raise_g): *The `raise_g()` function*
    1. [Step 2.b](#lower_g): *The `lower_g()` function*
    1. [Step 2.c](#ncov_calc): *The `ncov_calc()` function*
1. [Step 3](#harm_utoprim_2d__c__eos_dep): **EOS dependent routines**
    1. [Step 3.a](#pressure_rho0_u): *The `pressure_rho0_u()` function*
    1. [Step 3.b](#pressure_rho0_w): *The `pressure_rho0_w()` function*
1. [Step n-1](#code_validation): **Code validation**
1. [Step n](#latex_pdf_output): **Output this notebook to $\LaTeX$-formatted PDF file**

# Step 0: Source directory creation \[Back to [top](#toc)\]
$$\label{src_dir}$$

We will now use the [cmdline_helper.py NRPy+ module](Tutorial-Tutorial-cmdline_helper.ipynb) to create the source directory within the `IllinoisGRMHD` NRPy+ directory, if it does not exist yet.

```python
# Step 0: Creation of the IllinoisGRMHD source directory
# Step 0a: Add NRPy's directory to the path
# https://stackoverflow.com/questions/16780014/import-file-from-parent-directory
import os,sys
nrpy_dir_path = os.path.join("..","..")
if nrpy_dir_path not in sys.path:
    sys.path.append(nrpy_dir_path)

# Step 0b: Load up cmdline_helper and create the directory
import cmdline_helper as cmd
IGM_src_dir_path = os.path.join("..","src")
cmd.mkdir(IGM_src_dir_path)

# Step 0c: Create the output file path
outfile_path__harm_u2p_util__c = os.path.join(IGM_src_dir_path,"harm_u2p_util.c")
```

# Step 1: Introduction \[Back to [top](#toc)\]
$$\label{introduction}$$

# Step 2: EOS independent routines` \[Back to [top](#toc)\]
$$\label{harm_utoprim_2d__c__eos_indep}$$

```python
%%writefile $outfile_path__harm_u2p_util__c
#ifndef __HARM_U2P_UTIL__C__
#define __HARM_U2P_UTIL__C__
/*
  -------------------------------------------------------------------------------
  Copyright 2005 Scott C. Noble, Charles F. Gammie,
  Jonathan C. McKinney, and Luca Del Zanna

  This file is part of PVS-GRMHD.

  PVS-GRMHD is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  PVS-GRMHD is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with PVS-GRMHD; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  -------------------------------------------------------------------------------
*/

// Function prototypes for this file:
static void raise_g(CCTK_REAL vcov[NDIM], CCTK_REAL gcon[NDIM][NDIM], CCTK_REAL vcon[NDIM]);
static void lower_g(CCTK_REAL vcon[NDIM], CCTK_REAL gcov[NDIM][NDIM], CCTK_REAL vcov[NDIM]);
static void ncov_calc(CCTK_REAL gcon[NDIM][NDIM],CCTK_REAL ncov[NDIM]);
static CCTK_REAL pressure_rho0_u(eos_struct eos, CCTK_REAL rho0, CCTK_REAL u);
static CCTK_REAL pressure_rho0_w(eos_struct eos, CCTK_REAL rho0, CCTK_REAL w);

// Inlined function used by this file
static inline void compute_P_cold__eps_cold(eos_struct eos,CCTK_REAL rho_in, CCTK_REAL &P_cold,CCTK_REAL &eps_cold);
```

    Writing ../src/harm_u2p_util.c

## Step 2.a: The `raise_g()` function \[Back to [top](#toc)\]
$$\label{raise_g}$$

This is a simple function, used to *raise* the indices of a *covariant vector* using an inverse metric, $g^{\mu\nu}$. Usually the vector is 4-dimensional and $g^{\mu\nu}$ is the inverse physical ADM 4-metric, but the function can be used with arbitrary vectors and metrics. In other words, given a vector $v_{\mu}$ and an inverse metric $g^{\mu\nu}$ the function outputs

$$
\boxed{v^{\mu} = g^{\mu\nu}v_{\nu}}\ .
$$

```python
%%writefile -a $outfile_path__harm_u2p_util__c

/**********************************************************************
    raise_g():

         -- calculates the contravariant form of a covariant tensor,
            using the inverse of the metric;
***********************************************************************/
static void raise_g(CCTK_REAL vcov[NDIM], CCTK_REAL gcon[NDIM][NDIM], CCTK_REAL vcon[NDIM])
{
  int i,j;

  for(i=0;i<NDIM;i++) {
    vcon[i] = 0. ;
    for(j=0;j<NDIM;j++)
      vcon[i] += gcon[i][j]*vcov[j] ;
  }

  return ;
}
```

    Appending to ../src/harm_u2p_util.c

## Step 2.b: The `lower_g()` function \[Back to [top](#toc)\]
$$\label{lower_g}$$

This is a simple function, used to *lower* the indices of a *contravariant vector* using a metric, $g_{\mu\nu}$. Usually the vector is 4-dimensional and $g_{\mu\nu}$ is the physical ADM 4-metric, but the function can be used with arbitrary vectors and metrics. In other words, given a vector $v^{\mu}$ and a metric $g_{\mu\nu}$ the function outputs

$$
\boxed{v_{\mu} = g_{\mu\nu}v^{\nu}}\ .
$$

```python
%%writefile -a $outfile_path__harm_u2p_util__c

/**********************************************************************
     lower_g():

          -- calculates the ocvariant form of a contravariant tensor
             using the metric;
***********************************************************************/
static void lower_g(CCTK_REAL vcon[NDIM], CCTK_REAL gcov[NDIM][NDIM], CCTK_REAL vcov[NDIM])
{
  int i,j;

  for(i=0;i<NDIM;i++) {
    vcov[i] = 0. ;
    for(j=0;j<NDIM;j++)
      vcov[i] += gcov[i][j]*vcon[j] ;
  }

  return ;
}
```

    Appending to ../src/harm_u2p_util.c

## Step 2.c: The `ncov_calc()` function \[Back to [top](#toc)\]
$$\label{ncov_calc}$$

This simple function sets the covariant normal vector $n_{\mu} = \left(-\alpha,0,0,0\right)$.

```python
%%writefile -a $outfile_path__harm_u2p_util__c

/**********************************************************************
     ncov_calc():

         -- calculates the covariant form of the normal vector to our
            spacelike hypersurfaces ala the ADM formalism.

         -- requires the inverse metric;
***********************************************************************/
static void ncov_calc(CCTK_REAL gcon[NDIM][NDIM],CCTK_REAL ncov[NDIM])
{
  CCTK_REAL lapse ;
  int i;

  lapse = sqrt(-1./gcon[0][0]) ;

  ncov[0] = -lapse ;
  for( i = 1; i < NDIM; i++) {
    ncov[i] = 0. ;
  }

  return ;
}
```

    Appending to ../src/harm_u2p_util.c

# Step 3: EOS dependent routines
$$\label{harm_utoprim_2d__c__eos_dep}$$

## Step 3.a: The `pressure_rho0_u()` function \[Back to [top](#toc)\]
$$\label{pressure_rho0_u}$$

The $\Gamma$-law EOS implemented in `HARM` is

$$
p_{\Gamma}\left(\rho_{b},u\right) = \left(\Gamma-1\right)u\ ,
$$

where

$$
u = \rho_{b}\epsilon\ .
$$

Thus, the pre-PPEOS Patch version of this function was

```c
/**************************************************
  The following functions assume a Gamma-law EOS:
***************************************************/

/*
   pressure as a function of rho0 and u
   this is used by primtoU and Utoprim_?D
*/
static CCTK_REAL pressure_rho0_u(CCTK_REAL rho0, CCTK_REAL u)
{
  return((GAMMA  - 1.)*u) ;
}
```

In the case of a hybrid EOS, however, we have $p_{\rm hybrid}=p_{\rm hybrid}\left(\rho_{b},\epsilon\right)$. To obtain $p_{\rm hybrid}\left(\rho_{b},u\right)$ we use:

$$
p_{\rm hybrid} = P_{\rm cold}\left(\rho_{b}\right) + \left(\Gamma_{\rm th}-1\right)\rho_{b}\left[\epsilon - \epsilon_{\rm cold}\left(\rho_{b}\right)\right]
\implies
\boxed{
p_{\rm hybrid}\left(\rho_{b},u\right) = P_{\rm cold}\left(\rho_{b}\right) + \left(\Gamma_{\rm th}-1\right)\left[u - \rho_{b}\epsilon_{\rm cold}\left(\rho_{b}\right)\right]\ ,
}
$$

where

$$
\left\{
\begin{align}
P_{\rm cold}\left(\rho_{b}\right) = K_{\rm poly}\rho_{b}^{\Gamma_{\rm poly}}\ ,\\
\epsilon_{\rm cold}\left(\rho_{b}\right) = C + \frac{P_{\rm cold}}{\rho_{b}\left(\Gamma_{\rm poly}-1\right)}\ ,
\end{align}
\right.
$$

where $C$ is a precomputed integration constant which guarantees the continuity of $\epsilon_{\rm cold}\left(\rho_{b}\right)$ and the subscript "poly" indicates the local polytropic EOS quantity.

```python
%%writefile -a $outfile_path__harm_u2p_util__c

/**************************************************
  The following functions assume a Gamma-law EOS:
***************************************************/

/*
pressure as a function of rho0 and u
this is used by primtoU and Utoprim_?D
*/
static CCTK_REAL pressure_rho0_u(eos_struct eos, CCTK_REAL rho0, CCTK_REAL u)
{

  // Set up Gamma_th:
#ifndef ENABLE_STANDALONE_IGM_C2P_SOLVER
  DECLARE_CCTK_PARAMETERS;
#endif

  // Compute P_cold, eps_cold
  CCTK_REAL P_cold, eps_cold;
  compute_P_cold__eps_cold(eos,rho0, P_cold,eps_cold);

  /* Compute the pressure as a function of rho_b (rho0) and
   * u = rho_b * eps, using our hybrid EOS:
   * .-------------------------------------------------------------.
   * | p(rho_b,u) = P_cold + (Gamma_th - 1)*(u - rho_b * eps_cold) |
   * .-------------------------------------------------------------.
   */
  return( P_cold + (Gamma_th - 1.0)*(u - rho0*eps_cold) );

}
```

    Appending to ../src/harm_u2p_util.c

## Step 3.2: The `pressure_rho0_w()` function \[Back to [top](#toc)\]
$$\label{pressure_rho0_w}$$

The $\Gamma$-law EOS implemented in `HARM` is

$$
p_{\Gamma} = \left(\Gamma-1\right)u\ .
$$

We want now to obtain $p_{\Gamma}\left(\rho_{b},w\right)$, where

$$
w = u + \rho_{b} + p\ .
$$

Then

$$
p_{\Gamma} = \left(\Gamma-1\right)\left(w - \rho_{b} - p_{\Gamma}\right)
\implies
\boxed{
p_{\Gamma}\left(\rho_{b},w\right) = \frac{\left(\Gamma-1\right)}{\Gamma}\left(w-\rho_{b}\right)
}\ .
$$

Thus, the pre-PPEOS Patch version of this function was

```c
/*
   pressure as a function of rho0 and w = rho0 + u + p
   this is used by primtoU and Utoprim_1D
*/
static CCTK_REAL pressure_rho0_w(CCTK_REAL rho0, CCTK_REAL w)
{
  return((GAMMA-1.)*(w - rho0)/GAMMA) ;
}
```

For our hybrid EOS, we have

$$
\begin{align}
p_{\rm hybrid} &= P_{\rm cold} + \left(\Gamma_{\rm th}-1\right)\rho_{b}\left[\epsilon - \epsilon_{\rm cold}\right]\\
&= P_{\rm cold} + \left(\Gamma_{\rm th}-1\right)\left[u - \rho_{b}\epsilon_{\rm cold}\right]\\
&= P_{\rm cold} + \left(\Gamma_{\rm th}-1\right)\left[w-\rho_{b}-p_{\rm hybrid} - \rho_{b}\epsilon_{\rm cold}\right]\\
&= P_{\rm cold} + \left(\Gamma_{\rm th}-1\right)\left[w - \rho_{b}\left(1+\epsilon_{\rm cold}\right)\right]- \left(\Gamma_{\rm th}-1\right)p_{\rm hybrid}\\
\implies
&\boxed{
p_{\rm hybrid}\left(\rho_{b},w\right) = \frac{P_{\rm cold}}{\Gamma_{\rm th}} + \frac{\left(\Gamma_{\rm th}-1\right)}{\Gamma_{\rm th}}\left[w - \rho_{b}\left(1+\epsilon_{\rm cold}\right)\right]
}
\end{align}
$$

```python
%%writefile -a $outfile_path__harm_u2p_util__c

/*
   pressure as a function of rho0 and w = rho0 + u + p
   this is used by primtoU and Utoprim_1D
*/
static CCTK_REAL pressure_rho0_w(eos_struct eos, CCTK_REAL rho0, CCTK_REAL w)
{

  // Set up Gamma_th:
#ifndef ENABLE_STANDALONE_IGM_C2P_SOLVER
  DECLARE_CCTK_PARAMETERS;
#endif

  // Compute P_cold, eps_cold
  CCTK_REAL P_cold, eps_cold;
  compute_P_cold__eps_cold(eos,rho0, P_cold,eps_cold);

  /* Compute the pressure as a function of rho_b (rho0) and
   * w = u + rho_b + p, using our hybrid EOS:
   *  ----------------------------------------------------------------------------
   * | p(rho_b,w) = ( P_cold + (Gamma_th-1)*( w - rho_b*(1+eps_cold) ) )/Gamma_th |
   *  ----------------------------------------------------------------------------
   */
  return( (P_cold + (Gamma_th-1.0)*( w - rho0*(1.0+eps_cold) ) )/Gamma_th );
}
#endif
```

    Appending to ../src/harm_u2p_util.c

# Step 4: Code validation \[Back to [top](#toc)\]
$$\label{code_validation}$$

First we download the original `IllinoisGRMHD` source code and then compare it to the source code generated by this tutorial notebook.

```python
# Verify if the code generated by this tutorial module
# matches the original IllinoisGRMHD source code

# First download the original IllinoisGRMHD source code
import urllib
from os import path

original_IGM_file_url  = "https://bitbucket.org/zach_etienne/wvuthorns/raw/5611b2f0b17135538c9d9d17c7da062abe0401b6/IllinoisGRMHD/src/harm_u2p_util.c"
original_IGM_file_name = "harm_u2p_util-original.c"
original_IGM_file_path = os.path.join(IGM_src_dir_path,original_IGM_file_name)

# Then download the original IllinoisGRMHD source code
# We try it here in a couple of ways in an attempt to keep
# the code more portable
try:
    original_IGM_file_code = urllib.request.urlopen(original_IGM_file_url).read().decode("utf-8")
    # Write down the file the original IllinoisGRMHD source code
    with open(original_IGM_file_path,"w") as file:
        file.write(original_IGM_file_code)
except:
    try:
        original_IGM_file_code = urllib.urlopen(original_IGM_file_url).read().decode("utf-8")
        # Write down the file the original IllinoisGRMHD source code
        with open(original_IGM_file_path,"w") as file:
            file.write(original_IGM_file_code)
    except:
        # If all else fails, hope wget does the job
        !wget -O $original_IGM_file_path $original_IGM_file_url

# Perform validation
Validation__harm_u2p_util__c  = !diff $original_IGM_file_path $outfile_path__harm_u2p_util__c

if Validation__harm_u2p_util__c == []:
    # If the validation passes, we do not need to store the original IGM source code file
    !rm $original_IGM_file_path
    print("Validation test for harm_u2p_util.c: PASSED!")
else:
    # If the validation fails, we keep the original IGM source code file
    print("Validation test for harm_u2p_util.c: FAILED!")
    # We also print out the difference between the code generated
    # in this tutorial module and the original IGM source code
    print("Diff:")
    for diff_line in Validation__harm_u2p_util__c:
        print(diff_line)
```

    Validation test for harm_u2p_util.c: FAILED!
    Diff:
    1c1,2
    <
    ---
    > #ifndef __HARM_U2P_UTIL__C__
    > #define __HARM_U2P_UTIL__C__
    28,154c29,33
    < void primtoU_g( CCTK_REAL prim[], CCTK_REAL gcov[][NDIM], CCTK_REAL gcon[][NDIM], CCTK_REAL gdet,  CCTK_REAL U[] );
    < static void ucon_calc_g(CCTK_REAL prim[],CCTK_REAL gcov[][NDIM],CCTK_REAL gcon[][NDIM],CCTK_REAL ucon[]);
    < static void raise_g(CCTK_REAL vcov[], CCTK_REAL gcon[][NDIM], CCTK_REAL vcon[]);
    < static void lower_g(CCTK_REAL vcon[], CCTK_REAL gcov[][NDIM], CCTK_REAL vcov[]);
    < static void ncov_calc(CCTK_REAL gcon[][NDIM],CCTK_REAL ncov[]) ;
    < static void bcon_calc_g(CCTK_REAL prim[],CCTK_REAL ucon[],CCTK_REAL ucov[],CCTK_REAL ncov[],CCTK_REAL bcon[]);
    < static CCTK_REAL pressure_rho0_u(CCTK_REAL rho0, CCTK_REAL u);
    < static CCTK_REAL pressure_rho0_w(CCTK_REAL rho0, CCTK_REAL w);
    < int gamma_calc_g(CCTK_REAL *pr, CCTK_REAL gcov[NDIM][NDIM], CCTK_REAL *gamma);
    <
    < /**********************************************************************
    <    primtoU_g():
    <
    <        -- calculates the conserved variables from the primitive variables
    <             and the metric;
    <        -- assumes that the conserved and primitive variables are defined ala HARM:
    <
    <               /  rho u^t           \
    <          U =  |  T^t_\mu + rho u^t |  sqrt(-det(g_{\mu\nu}))
    <               \   B^i              /
    <
    <              /    rho        \
    <      P = |    uu         |
    <              | \tilde{u}^i   |
    <              \   B^i         /
    <
    < **************************************************************************/
    <
    <
    < void primtoU_g(
    <                CCTK_REAL prim[NPR],       /* primitive variables */
    <                CCTK_REAL gcov[NDIM][NDIM],    /* covariant (index dn) form of metric */
    <                CCTK_REAL gcon[NDIM][NDIM],    /* contravariant (index up) form of metric */
    <                CCTK_REAL gdet,                /* sqrt of -1 times det(g_{\mu \nu}) */
    <                CCTK_REAL U[NPR]           /* matrix of derivatives */
    <                ) {
    <   int i ;
    <   CCTK_REAL rho0 ;
    <   static CCTK_REAL ucon[NDIM],ucov[NDIM],bcon[NDIM],bcov[NDIM],ncov[NDIM] ;
    <   CCTK_REAL gamma,n_dot_b,bsq,u,p,w, alpha ;
    <
    <
    <   /* Calculate auxiliary quantities: */
    <   alpha = 1.0/sqrt(-gcon[0][0]);
    <
    <   ucon_calc_g(prim,gcov,gcon,ucon) ;
    <   lower_g(ucon,gcov,ucov) ;
    <   ncov_calc(gcon,ncov) ;
    <
    <   gamma = -ncov[0]*ucon[0] ;
    <
    <   bcon_calc_g(prim,ucon,ucov,ncov,bcon) ;
    <   lower_g(bcon,gcov,bcov) ;
    <
    <   n_dot_b = 0. ;
    <   for(i=0;i<4;i++) n_dot_b += ncov[i]*bcon[i] ;
    <   bsq = 0. ;
    <   for(i=0;i<4;i++) bsq += bcov[i]*bcon[i] ;
    <
    <   rho0 = prim[RHO] ;
    <   u = prim[UU] ;
    <   p = pressure_rho0_u(rho0,u) ;
    <   w = rho0 + u + p ;
    <
    <   // Now set the conserved variables themselves, using HARM's definition:
    <   U[RHO] = ucon[0]*rho0 ;
    <
    <   for( i = 0; i < 4; i++) {
    <     U[QCOV0+i] = gamma*(w + bsq)*ucov[i]
    <       - (p + bsq/2.)*ncov[i]
    <       + n_dot_b*bcov[i] ;
    <
    <     U[QCOV0+i] /= alpha;
    <   }
    <
    <   U[QCOV0] = U[QCOV0] + U[RHO];
    <   U[BCON1] = prim[BCON1] ;
    <   U[BCON2] = prim[BCON2] ;
    <   U[BCON3] = prim[BCON3] ;
    <
    <   for(i = 0; i < NPR; i++ ) {
    <     U[i] *= gdet;
    <   }
    <
    <   return ;
    < }
    <
    < /**********************************************************************
    <   ucon_calc_g():
    <
    <        -- calculates the contravariant (up) components of the four-velocity
    <           given the primitive variables, of which the velocity is
    <           \tilde{u}^i = \gamma v^j  where v^j is the velocity of the
    <           flow w.r.t a normal observer to the coordinates;
    <
    <        -- also requires the metric and inverse metric;
    <
    <        -- assumes:
    <
    <              /    rho        \
    <      P = |    uu         |
    <              | \tilde{u}^i   |
    <              \   B^i         /
    <
    < ******************************************************************/
    < static void ucon_calc_g(CCTK_REAL prim[NPR],CCTK_REAL gcov[NDIM][NDIM],CCTK_REAL gcon[NDIM][NDIM],
    <                  CCTK_REAL ucon[NDIM])
    < {
    <   CCTK_REAL u_tilde_con[4] ;
    <   CCTK_REAL u_tilde_sq ;
    <   CCTK_REAL gamma,lapse ;
    <   int i,j;
    <
    <   u_tilde_con[0] = 0. ;
    <   u_tilde_con[1] = prim[UTCON1] ;
    <   u_tilde_con[2] = prim[UTCON2] ;
    <   u_tilde_con[3] = prim[UTCON3] ;
    <
    <   u_tilde_sq = 0. ;
    <   for(i=0;i<NDIM;i++)
    <     for(j=0;j<NDIM;j++)
    <       u_tilde_sq += gcov[i][j]*u_tilde_con[i]*u_tilde_con[j] ;
    <   u_tilde_sq = fabs(u_tilde_sq) ;
    <
    <   gamma = sqrt(1. + u_tilde_sq) ;
    <
    <   lapse = sqrt(-1./gcon[0][0]) ;
    ---
    > static void raise_g(CCTK_REAL vcov[NDIM], CCTK_REAL gcon[NDIM][NDIM], CCTK_REAL vcon[NDIM]);
    > static void lower_g(CCTK_REAL vcon[NDIM], CCTK_REAL gcov[NDIM][NDIM], CCTK_REAL vcov[NDIM]);
    > static void ncov_calc(CCTK_REAL gcon[NDIM][NDIM],CCTK_REAL ncov[NDIM]);
    > static CCTK_REAL pressure_rho0_u(eos_struct eos, CCTK_REAL rho0, CCTK_REAL u);
    > static CCTK_REAL pressure_rho0_w(eos_struct eos, CCTK_REAL rho0, CCTK_REAL w);
    156c35,36
    <   for(i=0;i<NDIM;i++) ucon[i] = u_tilde_con[i] - lapse*gamma*gcon[0][i] ;
    ---
    > // Inlined function used by this file
    > static inline void compute_P_cold__eps_cold(eos_struct eos,CCTK_REAL rho_in, CCTK_REAL &P_cold,CCTK_REAL &eps_cold);
    158,159d37
    <   return ;
    < }
    166c44
    < ******************************************************************/
    ---
    > ***********************************************************************/
    179a58
    >
    185c64
    < ******************************************************************/
    ---
    > ***********************************************************************/
    198a78
    >
    206c86
    < ******************************************************************/
    ---
    > ***********************************************************************/
    222,292d101
    < /**********************************************************************
    <     bcon_calc_g():
    <
    <         -- using the primitive variables, contra-/co-variant 4-vel.,
    <            and covariant normal vector, calculate the contravariant
    <            form of the magnetic 4-vector b^\mu (the small "b" in HARM);
    <        -- assumes:
    <
    <              /    rho        \
    <      P = |    uu         |
    <              | \tilde{u}^i   |
    <              \   B^i         /
    < ******************************************************************/
    < static void bcon_calc_g(CCTK_REAL prim[NPR],CCTK_REAL ucon[NDIM],CCTK_REAL ucov[NDIM],
    <                  CCTK_REAL ncov[NDIM],CCTK_REAL bcon[NDIM])
    < {
    <   static CCTK_REAL Bcon[NDIM] ;
    <   CCTK_REAL u_dot_B ;
    <   CCTK_REAL gamma ;
    <   int i ;
    <
    <   // Bcon = \mathcal{B}^\mu  of the paper:
    <   Bcon[0] = 0. ;
    <   for(i=1;i<NDIM;i++) Bcon[i] = -ncov[0] * prim[BCON1+i-1] ;
    <
    <   u_dot_B = 0. ;
    <   for(i=0;i<NDIM;i++) u_dot_B += ucov[i]*Bcon[i] ;
    <
    <   gamma = -ucon[0]*ncov[0] ;
    <   for(i=0;i<NDIM;i++) bcon[i] = (Bcon[i] + ucon[i]*u_dot_B)/gamma ;
    < }
    <
    <
    < /**********************************************************************
    <     gamma_calc_g():
    <
    <         -- using the primitive variables, contra-/co-variant 4-vel.,
    <            and covariant normal vector, calculate the contravariant
    <            form of the magnetic 4-vector b^\mu (the small "b" in HARM);
    <
    <        -- assumes:
    <
    <              /    rho        \
    <      P = |    uu         |
    <              | \tilde{u}^i   |
    <              \   B^i         /
    < ******************************************************************/
    < int gamma_calc_g(CCTK_REAL *pr, CCTK_REAL gcov[NDIM][NDIM], CCTK_REAL *gamma)
    < {
    <   CCTK_REAL utsq ;
    <
    <   utsq =    gcov[1][1]*pr[UTCON1]*pr[UTCON1]
    <     + gcov[2][2]*pr[UTCON2]*pr[UTCON2]
    <     + gcov[3][3]*pr[UTCON3]*pr[UTCON3]
    <     + 2.*(  gcov[1][2]*pr[UTCON1]*pr[UTCON2]
    <             + gcov[1][3]*pr[UTCON1]*pr[UTCON3]
    <             + gcov[2][3]*pr[UTCON2]*pr[UTCON3]) ;
    <
    <   if(utsq<0.0){
    <     if(fabs(utsq)>1E-10){ // then assume not just machine precision
    <       return (1);
    <     }
    <     else utsq=1E-10; // set floor
    <   }
    <
    <   *gamma = sqrt(1. + utsq) ;
    <
    <   return(0) ;
    < }
    <
    <
    298,299c107,108
    <    pressure as a function of rho0 and u
    <    this is used by primtoU and Utoprim_?D
    ---
    > pressure as a function of rho0 and u
    > this is used by primtoU and Utoprim_?D
    301c110
    < static CCTK_REAL pressure_rho0_u(CCTK_REAL rho0, CCTK_REAL u)
    ---
    > static CCTK_REAL pressure_rho0_u(eos_struct eos, CCTK_REAL rho0, CCTK_REAL u)
    302a112,114
    >
    >   // Set up Gamma_th:
    > #ifndef ENABLE_STANDALONE_IGM_C2P_SOLVER
    304c116,129
    <   return((gamma_th /* <- Should be local polytropic Gamma factor */  - 1.)*u) ;
    ---
    > #endif
    >
    >   // Compute P_cold, eps_cold
    >   CCTK_REAL P_cold, eps_cold;
    >   compute_P_cold__eps_cold(eos,rho0, P_cold,eps_cold);
    >
    >   /* Compute the pressure as a function of rho_b (rho0) and
    >    * u = rho_b * eps, using our hybrid EOS:
    >    * .-------------------------------------------------------------.
    >    * | p(rho_b,u) = P_cold + (Gamma_th - 1)*(u - rho_b * eps_cold) |
    >    * .-------------------------------------------------------------.
    >    */
    >   return( P_cold + (Gamma_th - 1.0)*(u - rho0*eps_cold) );
    >
    308d132
    <
    313c137
    < static CCTK_REAL pressure_rho0_w(CCTK_REAL rho0, CCTK_REAL w)
    ---
    > static CCTK_REAL pressure_rho0_w(eos_struct eos, CCTK_REAL rho0, CCTK_REAL w)
    314a139,141
    >
    >   // Set up Gamma_th:
    > #ifndef ENABLE_STANDALONE_IGM_C2P_SOLVER
    316c143,155
    <   return((gamma_th /* <- Should be local polytropic Gamma factor */ -1.)*(w - rho0)/gamma_th /* <- Should be local polytropic Gamma factor */ ) ;
    ---
    > #endif
    >
    >   // Compute P_cold, eps_cold
    >   CCTK_REAL P_cold, eps_cold;
    >   compute_P_cold__eps_cold(eos,rho0, P_cold,eps_cold);
    >
    >   /* Compute the pressure as a function of rho_b (rho0) and
    >    * w = u + rho_b + p, using our hybrid EOS:
    >    *  ----------------------------------------------------------------------------
    >    * | p(rho_b,w) = ( P_cold + (Gamma_th-1)*( w - rho_b*(1+eps_cold) ) )/Gamma_th |
    >    *  ----------------------------------------------------------------------------
    >    */
    >   return( (P_cold + (Gamma_th-1.0)*( w - rho0*(1.0+eps_cold) ) )/Gamma_th );
    318,319c157
    <
    <
    ---
    > #endif

# Step 5: Output this notebook to $\LaTeX$-formatted PDF file \[Back to [top](#toc)\]
$$\label{latex_pdf_output}$$

The following code cell converts this Jupyter notebook into a proper, clickable $\LaTeX$-formatted PDF file. After the cell is successfully run, the generated PDF may be found in the root NRPy+ tutorial directory, with filename
[Tutorial-IllinoisGRMHD__harm_u2p_util.pdf](Tutorial-IllinoisGRMHD__harm_u2p_util.pdf) (Note that clicking on this link may not work; you may need to open the PDF file through another means).

```python
latex_nrpy_style_path = os.path.join(nrpy_dir_path,"latex_nrpy_style.tplx")
#!jupyter nbconvert --to latex --template $latex_nrpy_style_path --log-level='WARN' Tutorial-IllinoisGRMHD__harm_u2p_util.ipynb
#!pdflatex -interaction=batchmode Tutorial-IllinoisGRMHD__harm_u2p_util.tex
#!pdflatex -interaction=batchmode Tutorial-IllinoisGRMHD__harm_u2p_util.tex
#!pdflatex -interaction=batchmode Tutorial-IllinoisGRMHD__harm_u2p_util.tex
!rm -f Tut*.out Tut*.aux Tut*.log
```