Non Linear Regression Analysis

If the data shows a curvy trend, then linear regression will not produce very accurate results when compared to a non-linear regression because, as the name implies, linear regression presumes that the data is linear.
Let's learn about non linear regressions and apply an example on python. In this notebook, we fit a non-linear model to the datapoints corrensponding to China's GDP from 1960 to 2014.

Importing required libraries

```python
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
```

Though Linear regression is very good to solve many problems, it cannot be used for all datasets. First recall how linear regression, could model a dataset. It models a linear relation between a dependent variable y and independent variable x. It had a simple equation, of degree 1, for example y = $2x$ + 3.

```python
x = np.arange(-5.0, 5.0, 0.1)

##You can adjust the slope and intercept to verify the changes in the graph
y = 2*(x) + 3
y_noise = 2 * np.random.normal(size=x.size)
ydata = y + y_noise
#plt.figure(figsize=(8,6))
plt.plot(x, ydata,  'bo')
plt.plot(x,y, 'r')
plt.ylabel('Dependent Variable')
plt.xlabel('Indepdendent Variable')
plt.show()
```

Non-linear regressions are a relationship between independent variables $x$ and a dependent variable $y$ which result in a non-linear function modeled data. Essentially any relationship that is not linear can be termed as non-linear, and is usually represented by the polynomial of $k$ degrees (maximum power of $x$).

$$ \ y = a x^3 + b x^2 + c x + d \ $$

Non-linear functions can have elements like exponentials, logarithms, fractions, and others. For example: $$ y = \log(x)$$

Or even, more complicated such as :
$$ y = \log(a x^3 + b x^2 + c x + d)$$

Let's take a look at a cubic function's graph.

```python
x = np.arange(-5.0, 5.0, 0.1)

##You can adjust the slope and intercept to verify the changes in the graph
y = 1*(x**3) + 1*(x**2) + 1*x + 3
y_noise = 20 * np.random.normal(size=x.size)
ydata = y + y_noise
plt.plot(x, ydata,  'bo')
plt.plot(x,y, 'r')
plt.ylabel('Dependent Variable')
plt.xlabel('Indepdendent Variable')
plt.show()
```

As you can see, this function has $x^3$ and $x^2$ as independent variables. Also, the graphic of this function is not a straight line over the 2D plane. So this is a non-linear function.

Some other types of non-linear functions are:

### Quadratic

$$ Y = X^2 $$

```python
x = np.arange(-5.0, 5.0, 0.1)

##You can adjust the slope and intercept to verify the changes in the graph

y = np.power(x,2)
y_noise = 2 * np.random.normal(size=x.size)
ydata = y + y_noise
plt.plot(x, ydata,  'bo')
plt.plot(x,y, 'r')
plt.ylabel('Dependent Variable')
plt.xlabel('Indepdendent Variable')
plt.show()
```

### Exponential

An exponential function with base c is defined by $$ Y = a + b c^X$$ where b ≠0, c > 0 , c ≠1, and x is any real number. The base, c, is constant and the exponent, x, is a variable.

```python
X = np.arange(-5.0, 5.0, 0.1)

##You can adjust the slope and intercept to verify the changes in the graph

Y= np.exp(X)

plt.plot(X,Y)
plt.ylabel('Dependent Variable')
plt.xlabel('Indepdendent Variable')
plt.show()
```

### Logarithmic

The response $y$ is a results of applying logarithmic map from input $x$'s to output variable $y$. It is one of the simplest form of __log()__: i.e. $$ y = \log(x)$$

Please consider that instead of $x$, we can use $X$, which can be polynomial representation of the $x$'s. In general form it would be written as
\begin{equation}
y = \log(X)
\end{equation}

```python
X = np.arange(-5.0, 5.0, 0.1)

Y = np.log(X)

plt.plot(X,Y)
plt.ylabel('Dependent Variable')
plt.xlabel('Indepdendent Variable')
plt.show()
```

### Sigmoidal/Logistic

$$ Y = a + \frac{b}{1+ c^{(X-d)}}$$

```python
X = np.arange(-5.0, 5.0, 0.1)

Y = 1-4/(1+np.power(3, X-2))

plt.plot(X,Y)
plt.ylabel('Dependent Variable')
plt.xlabel('Indepdendent Variable')
plt.show()
```

# Non-Linear Regression example

For an example, we're going to try and fit a non-linear model to the datapoints corresponding to China's GDP from 1960 to 2014. We download a dataset with two columns, the first, a year between 1960 and 2014, the second, China's corresponding annual gross domestic income in US dollars for that year.

```python
import numpy as np
import pandas as pd

#downloading dataset
!wget -nv -O china_gdp.csv https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/ML0101ENv3/labs/china_gdp.csv

df = pd.read_csv("china_gdp.csv")
df.head(10)
```

    2020-06-30 17:52:25 URL:https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/ML0101ENv3/labs/china_gdp.csv [1218/1218] -> "china_gdp.csv" [1]

      Year
      Value

      0
      1960
      5.918412e+10

      1
      1961
      4.955705e+10

      2
      1962
      4.668518e+10

      3
      1963
      5.009730e+10

      4
      1964
      5.906225e+10

      5
      1965
      6.970915e+10

      6
      1966
      7.587943e+10

      7
      1967
      7.205703e+10

      8
      1968
      6.999350e+10

      9
      1969
      7.871882e+10

__Did you know?__ When it comes to Machine Learning, you will likely be working with large datasets. As a business, where can you host your data? IBM is offering a unique opportunity for businesses, with 10 Tb of IBM Cloud Object Storage: [Sign up now for free](http://cocl.us/ML0101EN-IBM-Offer-CC)

### Plotting the Dataset ###
This is what the datapoints look like. It kind of looks like an either logistic or exponential function. The growth starts off slow, then from 2005 on forward, the growth is very significant. And finally, it decelerate slightly in the 2010s.

```python
plt.figure(figsize=(8,5))
x_data, y_data = (df["Year"].values, df["Value"].values)
plt.plot(x_data, y_data, 'ro')
plt.ylabel('GDP')
plt.xlabel('Year')
plt.show()
```

### Choosing a model ###

From an initial look at the plot, we determine that the logistic function could be a good approximation,
since it has the property of starting with a slow growth, increasing growth in the middle, and then decreasing again at the end; as illustrated below:

```python
X = np.arange(-5.0, 5.0, 0.1)
Y = 1.0 / (1.0 + np.exp(-X))

plt.plot(X,Y)
plt.ylabel('Dependent Variable')
plt.xlabel('Indepdendent Variable')
plt.show()
```

The formula for the logistic function is the following:

$$ \hat{Y} = \frac1{1+e^{\beta_1(X-\beta_2)}}$$

$\beta_1$: Controls the curve's steepness,

$\beta_2$: Slides the curve on the x-axis.

### Building The Model ###
Now, let's build our regression model and initialize its parameters.

```python
def sigmoid(x, Beta_1, Beta_2):
     y = 1 / (1 + np.exp(-Beta_1*(x-Beta_2)))
     return y
```

Lets look at a sample sigmoid line that might fit with the data:

```python
beta_1 = 0.10
beta_2 = 1990.0

#logistic function
Y_pred = sigmoid(x_data, beta_1 , beta_2)

#plot initial prediction against datapoints
plt.plot(x_data, Y_pred*15000000000000.)
plt.plot(x_data, y_data, 'ro')
```

Our task here is to find the best parameters for our model. Lets first normalize our x and y:

```python
# Lets normalize our data
xdata =x_data/max(x_data)
ydata =y_data/max(y_data)
```

#### How we find the best parameters for our fit line?
we can use __curve_fit__ which uses non-linear least squares to fit our sigmoid function, to data. Optimal values for the parameters so that the sum of the squared residuals of sigmoid(xdata, *popt) - ydata is minimized.

popt are our optimized parameters.

```python
from scipy.optimize import curve_fit
popt, pcov = curve_fit(sigmoid, xdata, ydata)
#print the final parameters
print(" beta_1 = %f, beta_2 = %f" % (popt[0], popt[1]))
```

     beta_1 = 690.451710, beta_2 = 0.997207

Now we plot our resulting regression model.

```python
x = np.linspace(1960, 2015, 55)
x = x/max(x)
plt.figure(figsize=(8,5))
y = sigmoid(x, *popt)
plt.plot(xdata, ydata, 'ro', label='data')
plt.plot(x,y, linewidth=3.0, label='fit')
plt.legend(loc='best')
plt.ylabel('GDP')
plt.xlabel('Year')
plt.show()
```

## Practice
Can you calculate what is the accuracy of our model?

```python
# write your code here
x

```

    array([0.97270471, 0.97321018, 0.97371565, 0.97422112, 0.97472659,
           0.97523206, 0.97573752, 0.97624299, 0.97674846, 0.97725393,
           0.9777594 , 0.97826487, 0.97877033, 0.9792758 , 0.97978127,
           0.98028674, 0.98079221, 0.98129767, 0.98180314, 0.98230861,
           0.98281408, 0.98331955, 0.98382502, 0.98433048, 0.98483595,
           0.98534142, 0.98584689, 0.98635236, 0.98685783, 0.98736329,
           0.98786876, 0.98837423, 0.9888797 , 0.98938517, 0.98989064,
           0.9903961 , 0.99090157, 0.99140704, 0.99191251, 0.99241798,
           0.99292344, 0.99342891, 0.99393438, 0.99443985, 0.99494532,
           0.99545079, 0.99595625, 0.99646172, 0.99696719, 0.99747266,
           0.99797813, 0.9984836 , 0.99898906, 0.99949453, 1.        ])

Double-click __here__ for the solution.

Want to learn more?

IBM SPSS Modeler is a comprehensive analytics platform that has many machine learning algorithms. It has been designed to bring predictive intelligence to decisions made by individuals, by groups, by systems – by your enterprise as a whole. A free trial is available through this course, available here: SPSS Modeler

Also, you can use Watson Studio to run these notebooks faster with bigger datasets. Watson Studio is IBM's leading cloud solution for data scientists, built by data scientists. With Jupyter notebooks, RStudio, Apache Spark and popular libraries pre-packaged in the cloud, Watson Studio enables data scientists to collaborate on their projects without having to install anything. Join the fast-growing community of Watson Studio users today with a free account at Watson Studio

Thanks for completing this lesson!

Author:  Saeed Aghabozorgi

Saeed Aghabozorgi, PhD is a Data Scientist in IBM with a track record of developing enterprise level applications that substantially increases clients’ ability to turn data into actionable knowledge. He is a researcher in data mining field and expert in developing advanced analytic methods like machine learning and statistical modelling on large datasets.

Copyright © 2018 Cognitive Class. This notebook and its source code are released under the terms of the MIT License.


# CSC421 Assignment 2 - Part I  Propositional Logic (5 points) #
### Author: George Tzanetakis

This notebook is based on the supporting material for topics covered in **Chapter 7 - Logical Agents** from the book *Artificial Intelligence: A Modern Approach.* You can consult and modify the code provided in logic.py and logic.ipynb for completing the assignment questions. This part does NOT rely on the provided code so you can complete it just using basic Python.

```
Birds can fly, unless they are penguins and ostriches, or if they happen
to be dead, or have broken wings, or are confined to cages, or have their
feet stuck in cement, or have undergone experiences so dreadful as to render
them psychologically incapable of flight

Marvin Minsky
```

# Introduction - Parsing and evaluating prefix logic expressions

In this assignment your task is to incrementally create a parser and evaluator for prefix logic expressions as well as implement simple model checking. **NOTE THAT THE GRADING IN THIS ASSIGNMENT IS DIFFERENT FOR GRADUATE STUDENTS AND THEY HAVE TO DO EXTRA WORK FOR FULL MARKS**

# Question 1A (Minimum) CSC421 -  (1 point, CSC581C - 0 points)

Your first task will be to write a simple evaluator of prefix logic expressions with constants. In prefix notation the operator precedes the operands and no operands are required. For example 5+3 in prefix notation is written + 5 3 or 5 * 2 + 3 would be written + * 5 2 3 or + * 5 2 * 3 4 is equivalent to (5 * 2) + (3 * 4).

As a first step we will consider very simple expressions with one operator and two constant operands. We will use 0 for false and 1 for true. The following logical connectives should be implemented (see Figure 7.8 in your book) (notice that for now there is no negation symbol ~):

1. &    (and),
3. |    (or),
4. =>   (implication)
5. <=>  (biconditional)

Example expressions:
```
& 1 0
=> 0 1
<=> 1 1
```

Your function should take as input a string with the prefix expression and return the result of evaluating the expression (basically a 1 for true and 0 for false). You can split a string to a list using .split[' ']. For this part of the assignment you only evaluate expressions with two constant operands i.e no nested/recursive expressions.

```python
a = '& 1 0'
print(a.split(' '))
```

```python
# YOUR CODE GOES HERE
def simple_logic_evaluator(input_string):
    elements = input_string.split(' ')
    if len(elements) < 3:
        return None
    const1 = str(elements[1])
    const2 = str(elements[2])
    if elements[0] == '&':
        return int(const1 and const2)
    elif elements[0] == '|':
        return int(const1 or const2)
    elif elements[0] == '=>':
        return int((not const1) or const2)
    elif elements[0] == '<=>':
        return int((const1 and const2) or (not const1 and not const2))
    else:
        return None

expr1 = '& 1 0'
expr2 = '| 1 0'
expr3 = '=> 1 0'
expr4 = '<=> 1 0'
expr5 = '&'

output1 = simple_logic_evaluator(expr1)
print("(" + str(expr1) + '): ' + str(output1))
output2 = simple_logic_evaluator(expr2)
print("(" + str(expr2) + '): ' + str(output2))
output3 = simple_logic_evaluator(expr3)
print("(" + str(expr3) + '): ' + str(output3))
output4 = simple_logic_evaluator(expr4)
print("(" + str(expr4) + '): ' + str(output4))
output5 = simple_logic_evaluator(expr5)
print("(" + str(expr5) + '): ' + str(output5))
```

    (& 1 0): 0
    (| 1 0): 1
    (=> 1 0): 0
    (<=> 1 0): 0
    (&): None

# Question 1B (Minimum) (CSC421 - 1 point, CSC581C - 0 point)

Your next task is to implement variables and bindings for your propositional logic evaluator. In this version in addition to constants (0 and 1) you also can have variables which are strings with associated values provided in a dictionary. You still only consider two operands and one operator (no nesting). For example in the code below
the three expressions are equivalent. Your function should take as arguments the expression to be evaluated as a string and the dictionary with the variable bindings. In addition you need to add the ~ (not) operator. To do so for each variable in the dictionary add a not version. For example if 'a' in the dictionary has a value of 1 the '~a' in the dictionary should have a value of 0. Notice that the not symbol is part of the string and NOT separated by a space.

```python
d = {'foo': 0, 'b': 1}
print(d)
expr1 = '& 0 1'
expr2 = '& foo 1'
expr3 = '& foo ~b'
```

```python
# YOUR CODE GOES HERE

def propositional_logic_evaluator(input_string, d):
    # add negation elements to the dictionary
    for elem in list(d.keys()):
        if elem[0] != '~':
            d['~'+elem] = int(not d[elem])
    # add 0 and 1 to dictionary for cleaner code
    d['0'] = 0
    d['1'] = 1

    elements = input_string.split(' ')
    if len(elements) < 3:
        return None
    const1 = elements[1]
    const2 = elements[2]
    if const1 not in d or const2 not in d:
        return None
    if elements[0] == '&':
        return int(d[const1] and d[const2])
    elif elements[0] == '|':
        return int(d[const1] or d[const2])
    elif elements[0] == '=>':
        return int(not d[const1] or d[const2])
    elif elements[0] == '<=>':
        return int((d[const1] and d[const2]) or (not d[const1] and not d[const2]))
    else:
        return None

d = {'foo': 0, 'b': 1}
expr1 = '& 0 1'
expr2 = '& foo 1'
expr3 = '& foo ~b'
expr4 = '| foo ~b'
expr5 = '=> foo ~b'
expr6 = '<=> foo ~b'
expr7 = '& foo1 foo'
output = propositional_logic_evaluator(expr1, d)
print('(' + str(expr1) + '): ' + str(output))
output = propositional_logic_evaluator(expr2, d)
print('(' + str(expr2) + '): ' + str(output))
output = propositional_logic_evaluator(expr3, d)
print('(' + str(expr3) + '): ' + str(output))
output = propositional_logic_evaluator(expr4, d)
print('(' + str(expr4) + '): ' + str(output))
output = propositional_logic_evaluator(expr5, d)
print('(' + str(expr5) + '): ' + str(output))
output = propositional_logic_evaluator(expr6, d)
print('(' + str(expr6) + '): ' + str(output))
output = propositional_logic_evaluator(expr7, d)
print('(' + str(expr7) + '): ' + str(output))
```

    (& 0 1): 0
    (& foo 1): 0
    (& foo ~b): 0
    (| foo ~b): 0
    (=> foo ~b): 1
    (<=> foo ~b): 1
    (& foo1 foo): None

# Question 1C (Expected) 1 point

The following code is a recursive evaluator for prefix arithmetic expressions. It assumes that there are always two operands either an integer or a prefix expression starting with an operator (addition or multiplication). It is a good idea to go through this function carefully by hand to understand how the recursion works.

Informed by your understanding of the arithmetic recursive_eval function your task is to write function to implement a recursive prefix logic evaluator. Your evaluator should also support variables bindings using a dictionary as in the previous question.

Example expressions:
```
& 1 & 1 a
=> 0 & b ~alice
<=> foo 1
```

```python
def recursive_eval(l):
    head, tail = l[0], l[1:]
    if head in ['+', '*']:
        val1, tail = recursive_eval(tail)
        val2, tail = recursive_eval(tail)
        if head == '+':
            return (int(val1)+int(val2), tail)
        elif head == '*':
            return (int(val1)*int(val2), tail)
    # operator is a number
    else:
        return (int(head),tail)

def prefix_eval(input_str):
    input_list = input_str.split(' ')
    res, tail = recursive_eval(input_list)
    return res

print(prefix_eval('1'))
print(prefix_eval('+ 1 2'))
print(prefix_eval('+ 1 * 2 3'))
print(prefix_eval('+ * 5 2 * 3 + 1 5'))
```

```python
# YOUR CODE GOES HERE

def recursive_eval(elements,d):
    head,tail = elements[0],elements[1:]
    if head in ['&','|','=>','<=>']:  # head element is an operator
        const1,tail = recursive_eval(tail,d)
        const2,tail = recursive_eval(tail,d)
        if head == '&':
            return (str(int(d[const1] and d[const2])),tail)
        elif head == '|':
            return (str(int(d[const1] or d[const2])),tail)
        elif head == '=>':
            return (str(int(not d[const1] or d[const2])),tail)
        elif head == '<=>':
            return (str(int((d[const1] and d[const2]) or (not d[const1] and not d[const2]))),tail)
    else:  # head element is a variable
        return (str(d[head]),tail)

def prefix_eval(input_string,d):
    # add negation elements to the dictionary
    for elem in list(d.keys()):
        if elem[0] != '~':
            d['~'+elem] = int(not d[elem])
    # add 0 and 1 to dictionary for cleaner code
    d['0'] = 0
    d['1'] = 1

    elements = input_string.split(' ')
    res,tail = recursive_eval(elements,d)
    return int(res)

d = {'foo': 0, 'b': 1}
expr1 = '& 0 1' # false
expr2 = '& | b ~b | ~foo foo' # (b | ~b) & (~foo | foo) = true
expr3 = '& | 1 0 | ~foo foo' # (b | ~b) & (~foo | foo) = true
expr4 = '<=> | b ~b & 1 1'  # (1 | 0) <=> (1 & 1) = true
expr5 = '=> | 1 0 & 1 1'  # (1|0) => (1&1) = true
output = prefix_eval(expr1,d)
print('(' + str(expr1) + '): ' + str(output))
output = prefix_eval(expr2,d)
print('(' + str(expr2) + '): ' + str(output))
output = prefix_eval(expr3,d)
print('(' + str(expr3) + '): ' + str(output))
output = prefix_eval(expr4,d)
print('(' + str(expr4) + '): ' + str(output))
output = prefix_eval(expr5,d)
print('(' + str(expr5) + '): ' + str(output))
```

    (& 0 1): 0
    (& | b ~b | ~foo foo): 1
    (& | 1 0 | ~foo foo): 1
    (<=> | b ~b & 1 1): 1
    (=> | 1 0 & 1 1): 1

# QUESTION 1D (EXPECTED) 1 point

Using the recursive prefix evaluator you defined in the previous question
answer the following question (you will need to convert the exressions below
to prefix). You can use multiple string assignments to assemble more complicated
sentences into one big string:

Let A be the formula:

\begin{equation}
  (( p_{1} \rightarrow (p2 \land p_{3})) \land ((\neg p_{1})
  \rightarrow (p_{3} \land p_{4})))
\end{equation}

Let B be the formula:

\begin{equation}
  (( p_{3} \rightarrow (\neg p_{6})) \land ((\neg
  p_{3}) \rightarrow (p_{4} \rightarrow p_{1})))
\end{equation}

Let C be the formula:

\begin{equation}
  ((\neg(p2 \land p_{5})) \land (p2 \rightarrow p_{5}))
\end{equation}

Let D be the formula:

\begin{equation}
  (\neg (p_{3} \rightarrow p_{6}))
\end{equation}

Evaluate the formulate E:
\begin{equation}
  (( A \land (B \land C)) \rightarrow D)
\end{equation}

under the true assignment $I_{1}$, where $I_{1}(p_{1}) = I_{1}(p_{3}) = I_{1}(p_{5}) = false$
and $I_{1}(p2) = I_{1}(p_{4}) = I_{1}(p_{6}) = true$ as well as under the truth assignment
$I_{2}$, where $I_{2}(p_{1}) = I_{2}(p_{3}) = I_{2}(p_{5}) = true$ and
$I_{2}(p_{2})=I_{2}(p_{4})=I_{2}(p_{6}) = false$.

```python
# YOUR CODE GOES HERE

# A = ( p1=>(p2&p3) ) & ( ~p1=>(p3&p4) )
# B = (p3=>~p6) & ( ~p3=>(p4=>p1) )
# C = ~(p2&p5) & (p2=>p5)
# D = ~(p3=>p6) = ~p3 | p6
# E = (A&B&C)=>D

# I1: {p1,p3,p5} = false, {p2,p4,p6} = true
# I2: {p1,p3,p5} = true, {p2,p4,p6} = false

d1 = {'p1':0, 'p2':1, 'p3':0, 'p4':1, 'p5':0, 'p6':1}
d2 = {'p1':1, 'p2':0, 'p3':1, 'p4':0, 'p5':1, 'p6':0}

# A for case 1: 0
# A for case 2: 0
A = '& => p1 & p2 p3 => ~p1 & p3 p4'
output = prefix_eval(A,d1)
print('A for d1: ' + str(output))
output = prefix_eval(A,d2)
print('A for d2: ' + str(output))
# B for case 1: 1&(1=>(0)) = 0
# B for case 2: 1&(0=>(1)) = 1
B = '& => p3 ~p6 => ~p3 => p4 p1'
output = prefix_eval(B,d1)
print('B for d1: ' + str(output))
output = prefix_eval(B,d2)
print('B for d2: ' + str(output))
# C for case 1: 1&0 = 0
# C for case 2: 1&1 = 1
C = '& | ~p2 ~p5 => p2 p5'
output = prefix_eval(C,d1)
print('C for d1: ' + str(output))
output = prefix_eval(C,d2)
print('C for d2: ' + str(output))
# D for case 1: 1
# D for case 2: 0
D = '| ~p3 p6'
output = prefix_eval(D,d1)
print('D for d1: ' + str(output))
output = prefix_eval(D,d2)
print('D for d2: ' + str(output))

# E = (A&B&C)=>D = '=> & A & B C D'
# Case 1 should be: 1
# Case 2 should be: 1
E = '=> & ' + A + ' & ' + B + ' ' + D + ' ' + D
output = prefix_eval(E,d1)
print('E for d1: ' + str(output))
output = prefix_eval(E,d2)
print('E for d2: ' + str(output))

```

    A for d1: 0
    A for d2: 0
    B for d1: 0
    B for d2: 1
    C for d1: 0
    C for d2: 1
    D for d1: 1
    D for d2: 0
    E for d1: 1
    E for d2: 1

# QUESTION 1E (ADVANCED) 1 point

Implement inference using model-checking using your prefix recursive evaluator to decide whether a knowledge base KB entais some sentence a. To do so express the knowledge base in the prefix notation, enumerate all models for the variables in the dictionary, and check that the sentence a is true in every model in which the KB is true.

You can check the implementation to tt_entails in logic.ipynb in the aima_python repository to inform how you implement your solution. Your solution should NOT rely directly on any code in logic.py or logic.ipynb.

Check your model checking using the examples that are used in logic.ipynb to check entailment (there are a few with P and Q as variables as well as the one with A, B, C, D, E, F, G. You will need to convert these examples to prefix notation.

```python
# YOUR CODE GOES HERE

from utils import extend

def check_entails(KB,a):
    logic_symbols = ['&','|','=>','<=>']
    elements = KB.split(' ')
    kb_symbols = [x for x in elements if x not in logic_symbols and x[0]!='~'] + [x[1:] for x in elements if x[0]=='~']
    elements = a.split(' ')
    a_symbols = [x for x in elements if x not in logic_symbols and x[0]!='~'] + [x[1:] for x in elements if x[0]=='~']
    symbols = list(set(kb_symbols + a_symbols))
    return check_all_models(KB, a, symbols, {})

def check_all_models(KB,a,symbols,model):
    if not symbols:
        if prefix_eval(KB,model) == 1:
            result = prefix_eval(a,model)
            return result
        else:
            return 1
    else:
        P,rest = symbols[0],symbols[1:]
        d1 = model.copy()
        d1[P] = 0
        d2 = model.copy()
        d2[P] = 1
        o1 = check_all_models(KB,a,rest,d1)
        o2 = check_all_models(KB,a,rest,d2)
        return o1 and o2

# tt_entails(P & Q, Q) --> true
KB = '& P Q'
a = 'Q'
output = check_entails(KB,a)
print('(' + str(KB) + ') entails (' + str(a) + '): ' + str(output))

# tt_entails(P | Q, Q) --> false
KB = '| P Q'
a = 'Q'
output = check_entails(KB,a)
print('(' + str(KB) + ') entails (' + str(a) + '): ' + str(output))

# tt_entails(P | Q, P) --> false
KB = '| P Q'
a = 'P'
output = check_entails(KB,a)
print('(' + str(KB) + ') entails (' + str(a) + '): ' + str(output))

# tt_entails(A & (B | C) & D & E & ~(F | G), A & D & E & ~F & ~G) --> true
KB = '& & A & | B C D & E & ~F ~G'
a = '& & A & D E & ~F ~G'
output = check_entails(KB,a)
print('(' + str(KB) + ') entails (' + str(a) + '): ' + str(output))

```

    (& P Q) entails (Q): 1
    (| P Q) entails (Q): 0
    (| P Q) entails (P): 0
    (& & A & | B C D & E & ~F ~G) entails (& & A & D E & ~F ~G): 1

# QUESTION 1F (ADVANCED) (CSC421 - 0 points, CSC581C - 1 point)

Implement conversion of the prefix expressions to prefix conjuctive normal form (CNF) based on the recursive evaluator you have implemented.

```python
# YOUR CODE GOES HERE
```

# QUESTION 1E (ADVANCED) (CSC421 - 0 POINTS, CSC581C 1 point)

Based on the recursive evaluator you have implemented do a conversion of expressions in prefix notation to the infix notation of expressions supported by logic.ipynb. Provide 4 test cases that demonstrate the the conversion works by confirming that the result of your evaluator and the logic.ipynb evaluator are the same.

```python
# YOUR CODE GOES HERE
```


```python
%matplotlib inline

import numpy as np
import pandas as pd

import pymc3 as pm

import matplotlib.pyplot as plt
import seaborn as sns
import arviz as az

from itertools import product
from sklearn import preprocessing

import warnings
warnings.filterwarnings('ignore')
```

    WARNING (theano.tensor.blas): Using NumPy C-API based implementation for BLAS functions.

## Archimedes procedure for porous material density determination

Experimental procedure is as follow, for further detail refer to standard ISO 5017.

1. Measure temperature of liquid to determine its ($\rho_{\text{liq}}$) and find object theoretical full density ( $\rho_{\text{solid}}$ ) from datasheet
2. Measure mass of sample(s) in air ($m_1$)
3. Impregnate sample(s) in fluid (Isopropanol)
4. Measure mass of wet sample(s) suspended in fluid ($m_2$)
5. Remove sample from balance and measure mass of soaked piece ($m_3$)

\begin{equation}
    \text{bulk density}, \rho_b = \frac{m_1}{m_3-m_2}*\rho_{\text{liq}}
\end{equation}

\begin{equation}
    \text{true density}, \pi_d = \frac{ \rho_b}{\rho_{\text{solid}}} * 100
\end{equation}

Parts using two powder type are made. Parts labeled bimodal should have a higher density then parts labelled unimodal.

## Load Data from excel sheet

```python
data = pd.read_excel('./data/green_sample_benchmark.xlsx', sheet_name = 'archimedes', index_col= [0,1])
iso_density = pd.read_excel('./data/green_sample_benchmark.xlsx', sheet_name = 'arch_param', index_col= 0)
```

## Display first few row of excel sheet

```python
data.head()
```

      powder type
      dry weight
      wet coated
      coated weight
      exp
      operator

      batch
      ID

      4
      3.0
      Unimodal
      14.8038
      13.2572
      15.9512
      1
      1

      3.0
      Unimodal
      14.7935
      13.2525
      15.9485
      1
      1

      8.0
      Unimodal
      15.2090
      13.6240
      16.3252
      1
      1

      8.0
      Unimodal
      15.2038
      13.6184
      16.3211
      1
      1

      14.0
      Unimodal
      15.3370
      13.7548
      16.4814
      1
      1

## Carrier fluid density

Density of the carrier fluid ($\rho_{\text{liq}}$) is necessary for density calculation. Since the density of the fluid fluctuate depending on temperature and temperature varies from experiment to experiment, it is recorded for each experiment. For experiment 2 it was recorded at the beginning and at the end.

```python
iso_density
```

      density isopropanol

      exp

      1
      0.7842

      2
      0.7842

      2
      0.7838

```python
def plot_hist(data, b):
    fig, axes = plt.subplots(1,3, figsize = (15,5))
    axes[0].hist(data['dry weight'], bins = b, density = True)
    axes[0].set_title('dry weight')
    axes[0].set_xlabel('weight (g)')
    axes[0].set_ylabel('%')

    axes[1].hist(data['wet coated'], bins = b, density = True)
    axes[1].set_title('wet weight')
    axes[1].set_xlabel('weight (g)')
    axes[1].set_ylabel('%')

    axes[2].hist(data['coated weight'], bins = b, density = True)
    axes[2].set_title('coated weight')
    axes[2].set_xlabel('weight (g)')
    axes[2].set_ylabel('%')

    plt.tight_layout()
    plt.show()

plot_hist(data, 20)
```

## Compute density
Each sample was measured 3 times at each stage. Since we are only interested in the uncertainty in the true density ($\pi_t$), a cartesian product of each measured weights (dry, wet and coated) and liquid density is done for each sample in order to compute true density.

```python
density_df = pd.DataFrame(columns = ['batch', 'id', 'density', 'operator', 'powder'])

# density of stainless steel 316L (g/cc) taken from data sheet
den_ss316 = 8.0

unique_id = 0

# iterate over each sample to do cartesian product
for idx in data.index.unique():
    sample = data.loc[idx]

    op = int(np.unique(sample['operator']).squeeze())
    powder = str(np.unique(sample['powder type']).squeeze())
    batch = idx[0]

    d_weight = sample['dry weight'].to_numpy()
    wc_weight = sample['wet coated'].to_numpy()
    c_weight = sample['coated weight'].to_numpy()

    exp_num = sample['exp']
    # density of liquid taken from datasheet
    iso_den = iso_density.loc[exp_num].to_numpy()

    # cartesian product
    prod = product(d_weight, wc_weight, c_weight, iso_den)

    for d_w, wc_w, c_w, iso_d in prod:
        #compute true density refer to equation on top
        den = (d_w/(c_w - wc_w)*iso_d)/den_ss316*100
        new_entry = {
            'batch' : batch,
            'id' : unique_id,
            'density' : float(den.squeeze()),
            'operator' : op,
            'powder' : powder
        }

        density_df = density_df.append(new_entry, ignore_index = True)

    unique_id += 1
```

```python
ax = sns.histplot(density_df['density'])
```

```python
density_df.to_csv('./data/density_archimedes.csv', index=False)
```

```python
density_df.head()
```

      batch
      id
      density
      operator
      powder

      0
      4
      0
      53.865720
      1
      Unimodal

      1
      4
      0
      53.865720
      1
      Unimodal

      2
      4
      0
      53.919760
      1
      Unimodal

      3
      4
      0
      53.919760
      1
      Unimodal

      4
      4
      0
      53.771909
      1
      Unimodal

## Setup Model

Fitted a nested model, since samples are not reused across experiment.

\begin{equation}
    y_{ijk}  = \mu_{i} + Part_{j(i)} + \epsilon_{k(ij)}
    \label{eq:Model}
\end{equation}

Each powder type follows a global mean density $\mu_{i}$. Since the measurement is destructive, therefore the same parts cannot be measured using different methods. Consequently, $Part_{j(i)}$ represent the nesting relationship between the Fixed effect of the powder and the measurement of each part. Finally, $\epsilon_{k(ij)}$ represents the measurement error ($\sigma_{gage}$). An operator and a batch random effect were previously included in the model. Including the two effects caused the sampler to diverge. The cause of the divergence was likely due to the low number of replicates for the operator(2). As for the batch effect, the removal did not change the estimated value for $\sigma_{gage}$. Therefore, it is likely that the variance due to the batch is very low. The model is set up as follows:

\begin{align*}
    \{\mu_{i} \sim Uniform(20.0, 60.0)&: i = \{\text{Unimodal},\text{Bimodal}\}\} \\
    \text{Part}_{j(i)} &\sim N(0, \sigma_{\text{part}}) \\
    \mu &= \mu_{i} + \text{Part}_{j(i)} \\
    y_{ijk} &\sim  N(\mu, \sigma_{\text{gage}})
\end{align*}
\begin{equation}
    \sigma_{\text{part}} \sim \text{HalfCauchy}(25)
    \label{eq:model_priors_p}
\end{equation}
\begin{equation}
    \sigma_{\text{gage}} \sim \text{HalfCauchy}(25)
    \label{eq:model_priors_g}
\end{equation}

```python
basic_model = pm.Model()

n_part = unique_id

powder_mean = density_df.groupby('powder').mean()['density']

part_id = density_df['id'].to_numpy().astype(np.int32)
obs_den = density_df['density'].to_numpy().astype(np.int32)

# Relabel data to integers
powder_enc = preprocessing.LabelEncoder()
powder_enc.fit(['Unimodal','Bimodal'])
powder_data = powder_enc.transform(density_df['powder'])

#compute starting point for mean inference
test_val_mu = [powder_mean[c] for c in powder_enc.classes_]

A = 10000
with basic_model:

    # setup independent mu_i
    mu_p = pm.Uniform('muP', 20.0, 60.0, shape = 2, testval = test_val_mu)
    mu_real = pm.math.switch(powder_data, mu_p[1], mu_p[0])

    # setup prior for part variance and error variance
    sig_repeat = pm.HalfCauchy('sig_repeat', 25)
    sig_part = pm.HalfCauchy('sig_part', 25)

    # each part will vary independently (nesting relationship)
    P_t = pm.Normal('P_t', mu = 0, sigma = 1, shape = n_part)

    # setup mu
    mu = pm.Deterministic('mu', mu_real + P_t[part_id]*sig_part)

    # add error and data to model
    porosity = pm.Normal('density', mu = mu, sigma = sig_repeat, observed = obs_den)

```

## Run Inference

```python
with basic_model:
    trace = pm.sample(A, chains = 4, tune = 2000, target_accept=0.9)
    prior = pm.sample_prior_predictive()
    posterior_predictive = pm.sample_posterior_predictive(trace)
```

    Auto-assigning NUTS sampler...
    Initializing NUTS using jitter+adapt_diag...
    Multiprocess sampling (4 chains in 4 jobs)
    NUTS: [P_t, sig_part, sig_repeat, muP]
    Sampling 4 chains, 0 divergences: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 48000/48000 [02:21<00:00, 340.06draws/s]
    The number of effective samples is smaller than 10% for some parameters.
    100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 40000/40000 [00:34<00:00, 1167.65it/s]

Convert trace to arviz data format for diagnostic

```python
trace_data_az = az.from_pymc3(
    trace=trace,
    prior=prior,
    posterior_predictive=posterior_predictive,
    model=basic_model
)
```

```python
# save trace for future use
trace_data_az.to_netcdf('./data/arch_trace.nc')
```

    './data/arch_trace.nc'

## Trace plot
The sampler is exploring the probability space by sampling different values of the model input parameters ($\mu_i, \sigma_{\text{part}}, \sigma_{\text{gage}}$). The left graph shows the probability density of the sampled values. The right graph shows the sampled with respect to sample number. The left graph is computed by summing up the right graph. When the left graph looks skewed towards zero or the right graph does not resemble a thick caterpillar, this indicates a biased sampling and a lack of convergence.

```python
pm.traceplot(trace, var_names=['muP','sig_repeat','sig_part'])
plt.show()
```

## Predictive check plot

Predictive posterior plot overlays data generated by the model's posterior over the real data. This is useful to check the fitness of the model.

```python
az.plot_ppc(trace_data_az, data_pairs={"density":"density"}, kind = 'scatter')
plt.show()
```

## Forest plot

Forest plot on estimated real mean $\mu_{i}$ to check if the values make sense

```python
pm.plots.forestplot(trace, var_names=['muP'])
plt.show()
```

## Compute split $\hat{R}$

In the Markov-Chain Monte Carlo (MCMC) sampler, the sampling is done simultaneously in multiple processes (chain). The rank normalized $\hat{R}$ checks for convergence by comparing the variance between chain with the variance within chain. If convergence has been achieved then the variance should be the same ($\hat{R}=1$) (Vehtari et al). [Vehtari et al.](https://arxiv.org/pdf/1903.08008v1.pdf "vehtari") recommends a $\hat{R} < 1.01$.

```python
az.rhat(trace_data_az)
```

<svg style="position: absolute; width: 0; height: 0; overflow: hidden">
<defs>
<symbol id="icon-database" viewBox="0 0 32 32">
<path d="M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z"></path>
<path d="M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z"></path>
<path d="M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z"></path>
</symbol>
<symbol id="icon-file-text2" viewBox="0 0 32 32">
<path d="M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z"></path>
<path d="M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>
<path d="M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>
<path d="M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>
</symbol>
</defs>
</svg>

<xarray.Dataset>
Dimensions:     (P_t_dim_0: 30, muP_dim_0: 2, mu_dim_0: 720)
Coordinates:
  * P_t_dim_0   (P_t_dim_0) int32 0 1 2 3 4 5 6 7 8 ... 22 23 24 25 26 27 28 29
  * muP_dim_0   (muP_dim_0) int32 0 1
  * mu_dim_0    (mu_dim_0) int32 0 1 2 3 4 5 6 7 ... 713 714 715 716 717 718 719
Data variables:
    P_t         (P_t_dim_0) float64 1.001 1.002 1.002 ... 1.002 1.002 1.002
    muP         (muP_dim_0) float64 1.002 1.002
    sig_repeat  float64 1.001
    sig_part    float64 1.001
    mu          (mu_dim_0) float64 1.0 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0 1.0

xarray.Dataset

<input id='section-ddb6af89-6113-4ced-b7c0-e51a7a3c46ed' class='xr-section-summary-in' type='checkbox' disabled >Dimensions:

P_t_dim_0: 30

muP_dim_0: 2

mu_dim_0: 720

<input id='section-551d8c75-ae7a-41ec-99f2-a3282ae36328' class='xr-section-summary-in' type='checkbox'  checked>Coordinates: (3)

P_t_dim_0

(P_t_dim_0)

int32

0 1 2 3 4 5 6 ... 24 25 26 27 28 29
<input id='attrs-a9f5f96c-6647-4d6e-bd6b-5ffdaed6ab8b' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-a6d9533f-9a11-454f-93fb-d9539f247e02' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
       18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29])

muP_dim_0

(muP_dim_0)

int32

0 1
<input id='attrs-ce834da9-21d5-4626-84db-a9d251dfb0dc' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-ae729fe3-6feb-44bc-8934-ce0c343d121e' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([0, 1])

mu_dim_0

(mu_dim_0)

int32

0 1 2 3 4 5 ... 715 716 717 718 719
<input id='attrs-1b18e1d3-1839-48c0-92ba-969c2fe2a0c3' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-185df89e-b94f-436c-89f0-86cacde617a3' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([  0,   1,   2, ..., 717, 718, 719])

<input id='section-d10c28d0-005c-433b-b2f4-ff3c49acab4f' class='xr-section-summary-in' type='checkbox'  checked>Data variables: (5)

P_t

(P_t_dim_0)

float64

1.001 1.002 1.002 ... 1.002 1.002
<input id='attrs-a7dddf07-3b1e-4434-91e4-ee895ea07bd2' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-73049bdc-b1c8-44d8-a161-fecb53557217' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([1.00106405, 1.00198185, 1.00202936, 1.00152546, 1.00120433,
       1.00139095, 1.00108648, 1.00132872, 1.00132386, 1.00145808,
       1.0013917 , 1.001941  , 1.00204963, 1.00166754, 1.00188235,
       1.00117618, 1.0010547 , 1.00120834, 1.00109899, 1.00103799,
       1.00097731, 1.00154678, 1.00110412, 1.00221174, 1.00208114,
       1.00194915, 1.00195762, 1.00207892, 1.00182306, 1.00172912])

muP

(muP_dim_0)

float64

1.002 1.002
<input id='attrs-7dcc347d-6b53-4716-9e20-af1fb25bd419' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-84e4fda6-3db4-4034-a3ef-75ce7a028ccb' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([1.00173104, 1.00230074])

sig_repeat

()

float64

1.001
<input id='attrs-3f69efd4-3a96-48ea-9589-691ea0800c60' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-1d4ddf89-8375-4712-8332-dff78441ad43' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array(1.00050419)

sig_part

()

float64

1.001
<input id='attrs-4453645e-62e0-4ead-b257-d960d63bbfe4' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-b1dc91cb-7c56-485f-8530-1af26ecad30a' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array(1.00065328)

mu

(mu_dim_0)

float64

1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
<input id='attrs-63e9cee0-3322-4df2-a802-319f9f0012d7' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-301b5177-cc46-4472-8d93-24e79ec97147' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([0.99997272, 0.99997272, 0.99997272, 0.99997272, 0.99997272,
       0.99997272, 0.99997272, 0.99997272, 0.99997272, 0.99997272,
       0.99997272, 0.99997272, 0.99997272, 0.99997272, 0.99997272,
       0.99997272, 1.0001942 , 1.0001942 , 1.0001942 , 1.0001942 ,
       1.0001942 , 1.0001942 , 1.0001942 , 1.0001942 , 1.0001942 ,
       1.0001942 , 1.0001942 , 1.0001942 , 1.0001942 , 1.0001942 ,
       1.0001942 , 1.0001942 , 1.00002651, 1.00002651, 1.00002651,
       1.00002651, 1.00002651, 1.00002651, 1.00002651, 1.00002651,
       1.00002651, 1.00002651, 1.00002651, 1.00002651, 1.00002651,
       1.00002651, 1.00002651, 1.00002651, 1.00003062, 1.00003062,
       1.00003062, 1.00003062, 1.00003062, 1.00003062, 1.00003062,
       1.00003062, 1.00003062, 1.00003062, 1.00003062, 1.00003062,
       1.00003062, 1.00003062, 1.00003062, 1.00003062, 1.00011781,
       1.00011781, 1.00011781, 1.00011781, 1.00011781, 1.00011781,
       1.00011781, 1.00011781, 1.00011781, 1.00011781, 1.00011781,
       1.00011781, 1.00011781, 1.00011781, 1.00011781, 1.00011781,
       1.00006763, 1.00006763, 1.00006763, 1.00006763, 1.00006763,
       1.00006763, 1.00006763, 1.00006763, 1.00006763, 1.00006763,
       1.00006763, 1.00006763, 1.00006763, 1.00006763, 1.00006763,
       1.00006763, 0.99997567, 0.99997567, 0.99997567, 0.99997567,
...
       1.00006383, 1.00006383, 1.00006383, 1.00006383, 1.00011264,
       1.00011264, 1.00011264, 1.00011264, 1.00011264, 1.00011264,
       1.00011264, 1.00011264, 1.00011264, 1.00011264, 1.00011264,
       1.00011264, 1.00011264, 1.00011264, 1.00011264, 1.00011264,
       1.00011264, 1.00011264, 1.00011264, 1.00011264, 1.00011264,
       1.00011264, 1.00011264, 1.00011264, 1.00011264, 1.00011264,
       1.00011264, 1.00011264, 1.00011264, 1.00011264, 1.00011264,
       1.00011264, 1.00010856, 1.00010856, 1.00010856, 1.00010856,
       1.00010856, 1.00010856, 1.00010856, 1.00010856, 1.00010856,
       1.00010856, 1.00010856, 1.00010856, 1.00010856, 1.00010856,
       1.00010856, 1.00010856, 1.00010856, 1.00010856, 1.00010856,
       1.00010856, 1.00010856, 1.00010856, 1.00010856, 1.00010856,
       1.00010856, 1.00010856, 1.00010856, 1.00010856, 1.00010856,
       1.00010856, 1.00010856, 1.00010856, 1.00013679, 1.00013679,
       1.00013679, 1.00013679, 1.00013679, 1.00013679, 1.00013679,
       1.00013679, 1.00013679, 1.00013679, 1.00013679, 1.00013679,
       1.00013679, 1.00013679, 1.00013679, 1.00013679, 1.00013679,
       1.00013679, 1.00013679, 1.00013679, 1.00013679, 1.00013679,
       1.00013679, 1.00013679, 1.00013679, 1.00013679, 1.00013679,
       1.00013679, 1.00013679, 1.00013679, 1.00013679, 1.00013679])

<input id='section-a1a5e4e4-593b-4285-be51-d86baf107d66' class='xr-section-summary-in' type='checkbox' disabled >Attributes: (0)

## Calculate highest density interval (HDI)

Taken from [arviz doc](https://arviz-devs.github.io/arviz/api/generated/arviz.hdi.html#arviz.hdi "arviz") : The HDI is the minimum width Bayesian credible interval (BCI).

```python
hdi_data = az.hdi(trace_data_az)
hdi_data.to_netcdf('./data/arch_inference.nc')
hdi_data
```

<svg style="position: absolute; width: 0; height: 0; overflow: hidden">
<defs>
<symbol id="icon-database" viewBox="0 0 32 32">
<path d="M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z"></path>
<path d="M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z"></path>
<path d="M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z"></path>
</symbol>
<symbol id="icon-file-text2" viewBox="0 0 32 32">
<path d="M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z"></path>
<path d="M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>
<path d="M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>
<path d="M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>
</symbol>
</defs>
</svg>

<xarray.Dataset>
Dimensions:     (P_t_dim_0: 30, hdi: 2, muP_dim_0: 2, mu_dim_0: 720)
Coordinates:
  * P_t_dim_0   (P_t_dim_0) int32 0 1 2 3 4 5 6 7 8 ... 22 23 24 25 26 27 28 29
  * muP_dim_0   (muP_dim_0) int32 0 1
  * mu_dim_0    (mu_dim_0) int32 0 1 2 3 4 5 6 7 ... 713 714 715 716 717 718 719
  * hdi         (hdi) <U6 'lower' 'higher'
Data variables:
    P_t         (P_t_dim_0, hdi) float64 -2.005 -0.7537 ... -0.9807 0.06227
    muP         (muP_dim_0, hdi) float64 56.23 57.55 54.15 55.54
    sig_repeat  (hdi) float64 0.3397 0.3766
    sig_part    (hdi) float64 1.036 1.753
    mu          (mu_dim_0, hdi) float64 52.84 53.18 52.84 ... 54.37 54.13 54.37

xarray.Dataset

<input id='section-d8644620-6a8a-4b2f-b1c7-f368beabd8d8' class='xr-section-summary-in' type='checkbox' disabled >Dimensions:

P_t_dim_0: 30

hdi: 2

muP_dim_0: 2

mu_dim_0: 720

<input id='section-28dcffac-8df5-4875-b8ef-b75336d7c51f' class='xr-section-summary-in' type='checkbox'  checked>Coordinates: (4)

P_t_dim_0

(P_t_dim_0)

int32

0 1 2 3 4 5 6 ... 24 25 26 27 28 29
<input id='attrs-aae5f943-3717-4762-b654-6d85a55e7818' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-f16851ae-337a-44b8-a7b1-e2cc5ebfcdc6' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
       18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29])

muP_dim_0

(muP_dim_0)

int32

0 1
<input id='attrs-ff1a4d65-b996-425c-8b53-3840489f0f9c' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-8736cad1-cc3e-488f-8b76-d38ca7a29a70' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([0, 1])

mu_dim_0

(mu_dim_0)

int32

0 1 2 3 4 5 ... 715 716 717 718 719
<input id='attrs-19cbf3c0-f8cf-400c-b128-05d3fde4d0d3' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-59ba2f60-42fc-421e-a216-b63ab5ec6cda' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([  0,   1,   2, ..., 717, 718, 719])

hdi

(hdi)

<U6

'lower' 'higher'
<input id='attrs-eef2a8e1-b3ff-4b98-afbd-d18bafed002f' class='xr-var-attrs-in' type='checkbox' ><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-2cd176f6-685b-460a-87b5-c9501af02fa4' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

hdi_prob :

0.94

array(['lower', 'higher'], dtype='<U6')

<input id='section-478dce6b-a9b1-483d-828c-7e3deef786ec' class='xr-section-summary-in' type='checkbox'  checked>Data variables: (5)

P_t

(P_t_dim_0, hdi)

float64

-2.005 -0.7537 ... -0.9807 0.06227
<input id='attrs-f83db289-3263-4a3e-8b1a-0916ac5f7c7e' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-15cfd9fa-e169-4de2-82dd-c2b56774782a' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([[-2.0050011 , -0.75371709],
       [-0.39316539,  0.62071166],
       [-0.41654559,  0.60522166],
       [ 0.1981763 ,  1.24175487],
       [-1.17269074, -0.14472022],
       [-1.18228823, -0.15588393],
       [-1.57730292, -0.48034478],
       [-1.08451488, -0.07360121],
       [-1.18172679, -0.15361101],
       [ 0.20027738,  1.25411785],
       [-1.17737422, -0.14708917],
       [-0.77421702,  0.25565607],
       [ 0.30518748,  1.40801663],
       [-1.06746455, -0.00764365],
       [-0.2277072 ,  0.79952049],
       [ 1.07761138,  2.39676647],
       [-1.79095184, -0.65498001],
       [ 0.93054779,  2.18616893],
       [ 1.22423774,  2.60833568],
       [-1.89059472, -0.72956316],
       [-2.0508537 , -0.84989165],
       [-0.73931203,  0.22532966],
       [ 1.20626068,  2.59261904],
       [-0.04424571,  0.98373063],
       [-0.3906757 ,  0.61352449],
       [-0.39688567,  0.6066097 ],
       [-0.63543884,  0.37215591],
       [ 0.30682604,  1.39568025],
       [-0.779539  ,  0.24341936],
       [-0.98065075,  0.06226615]])

muP

(muP_dim_0, hdi)

float64

56.23 57.55 54.15 55.54
<input id='attrs-fb21ba13-445c-4c3d-a46c-94faa2d85755' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-1b005aab-b3c7-43dc-aa4d-183eb7e36328' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([[56.23074557, 57.5488388 ],
       [54.1519283 , 55.53664472]])

sig_repeat

(hdi)

float64

0.3397 0.3766
<input id='attrs-a9e89649-2b6e-443a-a68e-76292323a431' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-410061c8-8e1f-4f4f-96bb-95a1326b5810' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([0.33974872, 0.37658671])

sig_part

(hdi)

float64

1.036 1.753
<input id='attrs-e92f161d-fb46-48a7-b1b0-f56fa10a4717' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-2e876c9e-d977-4481-9dc6-1cde9dccf088' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([1.03603826, 1.75311804])

mu

(mu_dim_0, hdi)

float64

52.84 53.18 52.84 ... 54.13 54.37
<input id='attrs-977dcc18-08e8-49a2-bf9a-6dba7f77a62e' class='xr-var-attrs-in' type='checkbox' disabled><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-5198d331-6373-4e9c-ac09-aad740c6f5ec' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

array([[52.8438113 , 53.17840557],
       [52.8438113 , 53.17840557],
       [52.8438113 , 53.17840557],
       ...,
       [54.13000776, 54.36993286],
       [54.13000776, 54.36993286],
       [54.13000776, 54.36993286]])

<input id='section-1fa819bc-68e9-48c1-bfc9-743f3adb01ac' class='xr-section-summary-in' type='checkbox' disabled >Attributes: (0)


# Advection-Diffusion-Reaction Model

This notebook demonstrates how to
- Define the equation you want to solve
- Setup up and initial-boundary value problem
- Choose a particular set of numerics
- Post-process the solution

$
\newcommand{\grad}{\nabla}
$

```python
%matplotlib inline
from proteus.iproteus import *
Profiling.logLevel=7
Profiling.verbose=False
```

# Defining an equation
The equation we want to solve is
\begin{equation*}
m_t + \nabla \cdot \left(\mathbf{f} - \mathbf{a} \grad u \right) + r = 0
\end{equation*}
where $u$ is the unknown solution and the coefficients have the specific  forms
\begin{align}
m(u) &= M u \\
f(u) &= \mathbf{B} u \\
a(u) &= \mathbf{A} \\
r(u) &= C u \\
\end{align}

# Proteus template equation
\begin{equation}
\mathbf{u} = \left[ u^0,u^1,\ldots,u^{nc-1} \right]
\end{equation}
\begin{equation*}
m^i_t + \nabla \cdot \left(\mathbf{f}^i - \sum_k^{nc-1} \mathbf{a}^{i,k} \nabla \phi^k(\mathbf{u}) \right) + r^i + H^i(\nabla u^i)= 0 \qquad \mbox{for } i=0,\ldots,nc-1
\end{equation*}

- $m$ is "mass"
- $\mathbf{f}$ is advection
- $\mathbf{a}$ is diffution
- $\phi$ is potential
- $H$ is Hamiltonian
- $r$ is reaction

Example: non-conservative advection
\begin{equation}
u_t + \mathbf{v} \cdot \nabla u = 0
\end{equation}

What is $m$?
What is $f$?
What is $H$?

```python
class LADR(TransportCoefficients.TC_base):
    """
    The coefficients of the linear advection-diffusion equation
    """
    def __init__(self,M,A,B,C):
        TransportCoefficients.TC_base.__init__(self,
                                               nc=1, #number of components
                                               variableNames=['u'],
                                               mass      = {0:{0:'linear'}},
                                               advection = {0:{0:'linear'}},
                                               diffusion = {0:{0:{0:'constant'}}},
                                               potential = {0:{0:'u'}},
                                               reaction  = {0:{0:'linear'}})

        self.M=M;
        self.A=A;
        self.B=B;
        self.C=C;
    def evaluate(self,t,c):
        c[('m',0)][:]         = self.M*c[('u',0)]
        c[('dm',0,0)][:]      = self.M
        c[('f',0)][...,0]     = self.B[0]*c[('u',0)]
        c[('f',0)][...,1]     = self.B[1]*c[('u',0)]
        c[('df',0,0)][...,0]  = self.B[0]
        c[('df',0,0)][...,1]  = self.B[1]
        c[('a',0,0)][...,0,0] = self.A[0][0]
        c[('a',0,0)][...,1,1] = self.A[1][1]
        c[('r',0)][:]         = self.C*c[('u',0)]
        c[('dr',0,0)][:]      = self.C

```

# Physics

```python
from proteus import default_p as p
#physics
p.name = "ladr_2d"
p.nd = 2; #Two dimensions
p.L=(1.0,1.0);
p.T=1.0

p.coefficients=LADR(M=1.0,
                    A=[[0.001,0.0],
                       [0.0,0.001]],
                    B=[2.0,1.0],
                    C=0.0)

def getDBC(x,flag):
    if x[0] == 0.0 or x[1] == 0.0:
        return lambda x,t: 1.0
    elif x[0] == p.L[0] or x[1] == p.L[1]:
        return lambda x,t: 0.0
    else:
        return None

p.dirichletConditions = {0:getDBC}
p.advectiveFluxBoundaryConditions = {}
p.diffusiveFluxBoundaryConditions = {0:{}}
p.periodicDirichletConditions = None
class IC:
    def __init__(self):
        pass
    def uOfXT(self,x,t):
        if x[0] <= 0.0 or x[1] <= 0.0:
            return 1.0
        else:
            return 0.0

p.initialConditions  = {0:IC()}
```

# Numerics

```python
from proteus import default_n as n
import proteus as pr
n.timeIntegration = pr.TimeIntegration.BackwardEuler_cfl
n.stepController = pr.StepControl.Min_dt_cfl_controller
n.runCFL=1.0
n.femSpaces = {0:pr.FemTools.C0_AffineLinearOnSimplexWithNodalBasis}
n.elementQuadrature = pr.Quadrature.SimplexGaussQuadrature(p.nd,3)
n.elementBoundaryQuadrature = pr.Quadrature.SimplexGaussQuadrature(p.nd-1,3)
n.subgridError = pr.SubgridError.AdvectionDiffusionReaction_ASGS(p.coefficients,
                                                                 p.nd,lag=False)
n.shockCapturing = pr.ShockCapturing.ResGradQuad_SC(p.coefficients,
                                                    p.nd,
                                                    shockCapturingFactor=0.99,
                                                    lag=True)
n.numericalFluxType = pr.NumericalFlux.Advection_DiagonalUpwind_Diffusion_SIPG_exterior
n.nnx=41; n.nny=41
n.tnList=[float(i)/40.0 for i in range(11)]
n.matrix = pr.LinearAlgebraTools.SparseMatrix
n.multilevelLinearSolver = pr.LinearSolvers.KSP_petsc4py
n.l_atol_res = 1.0e-8
n.parallelPartitioningType = pr.MeshTools.MeshParallelPartitioningTypes.element
n.nLayersOfOverlapForParallel = 1
n.periodicDirichletConditions = None
```

# Operator Splitting

```python
from proteus import default_s,default_so
so = default_so
so.name = p.name
so.sList=[default_s]
so.tnList = n.tnList
#so.systemStepControllerType = SplitOperator.Sequential_FixedStep
so.systemStepControllerType = SplitOperator.Sequential_FixedStep_Simple
so.systemStepExact= False
so.dt_system_fixed= 0.01
```

# Initialize Numerical Solution Object

```python
ns = NumericalSolution.NS_base(so,[p],[n],so.sList,opts)
```

# Calculate Solution

```python
failed = ns.calculateSolution('ladr_run1')
assert(not failed)
```

```python
import pylab
x = ns.modelList[0].levelModelList[-1].mesh.nodeArray[:,0]
y = ns.modelList[0].levelModelList[-1].mesh.nodeArray[:,1]
triangles = ns.modelList[0].levelModelList[-1].mesh.elementNodesArray
u = ns.modelList[0].levelModelList[-1].u[0].dof
pylab.tricontourf(x,y,triangles,u)
pylab.show()
```

You can view the log like this:

```python
!cat proteus.log
```

    [       7] Initializing NumericalSolution for ladr_2d
     System includes:
    ladr_2d

    [       7] Setting Archiver(s)
    [       7] Setting up MultilevelMesh
    [       7] Building one multilevel mesh for all models
    [       7] Generating mesh for ladr_2d
    [       7] Building 41 x 41 rectangular mesh for ladr_2d
    [       7] Partitioning mesh among 1 processors using partitioningType = 0
    [       7] Number of Subdomain Elements Owned= 3200
    [       7] Number of Subdomain Elements = 3200
    [       7] Number of Subdomain Nodes Owned= 1681
    [       7] Number of Subdomain Nodes = 1681
    [       7] Number of Subdomain elementBoundaries Owned= 4880
    [       7] Number of Subdomain elementBoundaries = 4880
    [       7] Number of Subdomain Edges Owned= 4880
    [       7] Number of Subdomain Edges = 4880
    [       7] Finished partitioning
    [       7] *** Global ***
    Number of triangles  : 3200
    Number of edges : 4880
    Number of nodes : 1681

    *** Local ***
    Number of triangles  : 3200
    Number of edges : 4880
    Number of nodes : 1681

    [       7] Numerical Solution Sparse diffusion information key (0, 0) = (array([0, 2, 4], dtype=int32), array([0, 1, 0, 1], dtype=int32))
    [       7] Setting up MultilevelTransport for ladr_2d
    [       7] Building Transport for each mesh
    [       7] Generating Trial Space
    [       7] Generating Test Space
    [       7] Allocating u
    [       7] Allocating phi
    [       7] Setting Boundary Conditions
    [       7] Setting Boundary Conditions-1
    [       7] Setting Boundary Conditions-2
    [       7] Setting Boundary Conditions-2a
    [       7] Setting Boundary Conditions-3
    [       7] Setting Boundary Conditions-4
    [       7] Initializing OneLevelTransport
    [       7] Sparse diffusion information key (0, 0) = (array([0, 2, 4], dtype=int32), array([0, 1, 0, 1], dtype=int32))
    [       7] Shallow copy of trial shape is being used for test shape w
    [       7] Shallow copy of trial shape is being used for test shape grad(w)
    [       7] Shallow copy of trial shape is being used for test shape Hess(w)
    [       7] Shallow copy of trial shape is being used for test shape w
    [       7] Updating local to global mappings
    [       7] Building time integration object
    [       7] Calculating numerical quadrature formulas
    [       7] Element Quadrature
    [       7] Element Boundary Quadrature
    [       7] Global Exterior Element Boundary Quadrature
    [       7] Allocating residual and solution vectors
    [       7] Allocating Jacobian
    [       7] Building sparse matrix structure
    [       7] Allocating parallel storage
    [       7] Allocating ghosted parallel vectors on rank 0
    [       7] Allocating un-ghosted parallel vectors on rank 0
    [       7] Allocating matrix on rank 0
    [       7] ParMat_petsc4py comm.rank= 0 blockSize = 1 par_n= 1681 par_N=1681 par_nghost=0 par_jacobian.getSizes()= ((1681, 1681), (1681, 1681))
    [       7] Building Mesh Transfers
    [       7] Setting ladr_2d stepController to proteus.StepControl.Min_dt_cfl_controller
    [       7] Setting up MultilevelLinearSolver forladr_2d
    [       7] multilevelLinearSolverChooser type= proteus.LinearSolvers.KSP_petsc4py
    [       7] Setting up MultilevelNonLinearSolver for ladr_2d
    [       7] Finished setting up models and solvers
    [       7] Setting up SimTools for ladr_2d
    [       7] Using tnList from so = ladr_2d
    [       7] Time sequence[0.0, 0.025, 0.05, 0.075, 0.1, 0.125, 0.15, 0.175, 0.2, 0.225, 0.25]
    [       7] Setting ladr_2d systemStepController to object of type proteus.SplitOperator.Sequential_FixedStep_Simple
    [       7] Finished NumericalSolution initialization
    [       9] Setting initial conditions
    [       9] Setting initial conditions for ladr_2d
    [       9] Setting initial conditions on model ladr_2d
    [       9] Attaching models and running spin-up step if requested
    [       9] Attaching models to model ladr_2d
    [       9] Attaching models to model ladr_2d
    [       9] Archiving initial conditions
    [       9] Writing initial mesh for  model = ladr_2d
    [       9] Writing initial conditions for  model = ladr_2d
    [       9] Syncing Archive
    [       9] Gathering Archive Time step
    [       9] Done Gathering Archive Time Step
    [       9] Done Syncing Archive
    [       9] Estimating initial time derivative and initializing time history for model ladr_2d
    [       9] Choosing initial time step for model ladr_2d
    [       9] Initializing time step on model ladr_2d to dt =  2.23607e-02
    [       9] Initializing time history for model step controller
    [       9] Initializing time step on system Default System to dt =  2.50000e-02
    [       9] Initializing step sequence  for system Default System to [(0.025, <proteus.Transport.MultilevelTransport instance at 0x7f2c742afbd8>)]
    [       9] Auxiliary variable calculations for model ladr_2d
    [       9] Starting time stepping
    [       9] ==============================================================
    [       9] Solving over interval [ 0.00000e+00, 2.50000e-02]
    [       9] ==============================================================
    [       9] ===========================================================dt system orig0.025
    [       9] =========================================================dt system final0.025
    [       9] Min_dt_controller setSubsteps tList=[0.025] self.t_model=0.025 self.substeps= [0.025]
    [       9] System time step t= 2.50000e-02, dt= 2.50000e-02
    [       9] Split operator iteration 0
    [       9] Model: ladr_2d
    [       9] Fractional step  2.50000e-02 for model ladr_2d
    [       9] Step exact called for model ladr_2d
    [       9] StepControl base stepExact t_model= 0.025 tOut= 0.025 t_model_last= 0.0 dt_model= 0.025 setting to 0.025
    [       9] Min_dt_controller setSubsteps tList=[0.025] self.t_model=0.025 self.substeps= [0.025]
    [       9] Model step t= 2.50000e-02, dt= 2.50000e-02 for model ladr_2d
    [       9] Model substep t= 2.50000e-02 for model ladr_2d
    [       9] Model substep t= 2.50000e-02 for model ladr_2d model.timeIntegration.t=  2.50000e-02
    [       9]    Newton it 0 norm(r) =  5.29530e+00  		 norm(r)/(rtol*norm(r0)+atol) = 5.029 test=r
    [       9] before ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= False ksp.its= 0 ksp.norm= 0.0
    [       9] after ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= True ksp.its= 3 ksp.norm= 0.00256727364888 reason = 2
    [       9]    Newton it 1 norm(r) =  4.56251e-04  		 norm(r)/(rtol*norm(r0)+atol) =  4.33307e-04
    [       9] SO_base modelStepTaken for model= ladr_2d t_system_last= 0.0 t_model_last= 0.0  setting to t_stepSequence= 0.025
    [       9] Step Taken, t_stepSequence= 0.025 Model step t= 2.50000e-02, dt= 2.50000e-02 for model ladr_2d
    [       9] Min_dt_controller setSubsteps tList=[0.047360679774997805] self.t_model=0.047360679775 self.substeps= [0.047360679774997805]
    [       9] Step Taken, System time step t= 5.00000e-02, dt= 2.50000e-02
    [       9] Step Taken, Model step t= 5.00000e-02, dt= 2.50000e-02 for model ladr_2d
    [       9] Writing mesh header for  model = ladr_2d at time t=0.025
    [       9] Writing solution for  model = ladr_2d
    [       9] Syncing Archive
    [       9] Gathering Archive Time step
    [       9] Done Gathering Archive Time Step
    [       9] Done Syncing Archive
    [       9] ==============================================================
    [       9] Solving over interval [ 2.50000e-02, 5.00000e-02]
    [       9] ==============================================================
    [       9] ===========================================================dt system orig0.025
    [       9] =========================================================dt system final0.025
    [       9] Min_dt_controller setSubsteps tList=[0.05] self.t_model=0.05 self.substeps= [0.05]
    [       9] System time step t= 5.00000e-02, dt= 2.50000e-02
    [       9] Split operator iteration 0
    [       9] Model: ladr_2d
    [       9] Fractional step  5.00000e-02 for model ladr_2d
    [       9] Step exact called for model ladr_2d
    [       9] StepControl base stepExact t_model= 0.05 tOut= 0.05 t_model_last= 0.025 dt_model= 0.025 setting to 0.025
    [       9] Min_dt_controller setSubsteps tList=[0.05] self.t_model=0.05 self.substeps= [0.05]
    [       9] Model step t= 5.00000e-02, dt= 2.50000e-02 for model ladr_2d
    [       9] Model substep t= 5.00000e-02 for model ladr_2d
    [       9] Model substep t= 5.00000e-02 for model ladr_2d model.timeIntegration.t=  5.00000e-02
    [       9]    Newton it 0 norm(r) =  1.80921e-01  		 norm(r)/(rtol*norm(r0)+atol) = 0.180594 test=r
    [       9] before ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= False ksp.its= 3 ksp.norm= 0.00256727364888
    [       9] after ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= True ksp.its= 3 ksp.norm= 0.000174444831388 reason = 2
    [       9]    Newton it 1 norm(r) =  2.19872e-05  		 norm(r)/(rtol*norm(r0)+atol) =  2.19475e-05
    [       9] SO_base modelStepTaken for model= ladr_2d t_system_last= 0.025 t_model_last= 0.025  setting to t_stepSequence= 0.05
    [       9] Step Taken, t_stepSequence= 0.05 Model step t= 5.00000e-02, dt= 2.50000e-02 for model ladr_2d
    [       9] Min_dt_controller setSubsteps tList=[0.0723606797749978] self.t_model=0.072360679775 self.substeps= [0.0723606797749978]
    [       9] Step Taken, System time step t= 7.50000e-02, dt= 2.50000e-02
    [       9] Step Taken, Model step t= 7.50000e-02, dt= 2.50000e-02 for model ladr_2d
    [       9] Writing mesh header for  model = ladr_2d at time t=0.05
    [       9] Writing solution for  model = ladr_2d
    [       9] Syncing Archive
    [       9] Gathering Archive Time step
    [       9] Done Gathering Archive Time Step
    [       9] Done Syncing Archive
    [       9] ==============================================================
    [       9] Solving over interval [ 5.00000e-02, 7.50000e-02]
    [       9] ==============================================================
    [       9] ===========================================================dt system orig0.025
    [       9] =========================================================dt system final0.025
    [       9] Min_dt_controller setSubsteps tList=[0.075] self.t_model=0.075 self.substeps= [0.075]
    [       9] System time step t= 7.50000e-02, dt= 2.50000e-02
    [       9] Split operator iteration 0
    [       9] Model: ladr_2d
    [       9] Fractional step  7.50000e-02 for model ladr_2d
    [       9] Step exact called for model ladr_2d
    [       9] StepControl base stepExact t_model= 0.075 tOut= 0.075 t_model_last= 0.05 dt_model= 0.025 setting to 0.025
    [       9] Min_dt_controller setSubsteps tList=[0.075] self.t_model=0.075 self.substeps= [0.075]
    [       9] Model step t= 7.50000e-02, dt= 2.50000e-02 for model ladr_2d
    [       9] Model substep t= 7.50000e-02 for model ladr_2d
    [       9] Model substep t= 7.50000e-02 for model ladr_2d model.timeIntegration.t=  7.50000e-02
    [       9]    Newton it 0 norm(r) =  1.26621e-01  		 norm(r)/(rtol*norm(r0)+atol) = 0.126461 test=r
    [       9] before ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= False ksp.its= 3 ksp.norm= 0.000174444831388
    [       9] after ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= True ksp.its= 3 ksp.norm= 0.000350335458124 reason = 2
    [       9]    Newton it 1 norm(r) =  1.95297e-05  		 norm(r)/(rtol*norm(r0)+atol) =  1.95050e-05
    [       9] SO_base modelStepTaken for model= ladr_2d t_system_last= 0.05 t_model_last= 0.05  setting to t_stepSequence= 0.075
    [       9] Step Taken, t_stepSequence= 0.075 Model step t= 7.50000e-02, dt= 2.50000e-02 for model ladr_2d
    [       9] Min_dt_controller setSubsteps tList=[0.0973606797749978] self.t_model=0.097360679775 self.substeps= [0.0973606797749978]
    [       9] Step Taken, System time step t= 1.00000e-01, dt= 2.50000e-02
    [       9] Step Taken, Model step t= 1.00000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Writing mesh header for  model = ladr_2d at time t=0.075
    [       9] Writing solution for  model = ladr_2d
    [       9] Syncing Archive
    [       9] Gathering Archive Time step
    [       9] Done Gathering Archive Time Step
    [       9] Done Syncing Archive
    [       9] ==============================================================
    [       9] Solving over interval [ 7.50000e-02, 1.00000e-01]
    [       9] ==============================================================
    [       9] ===========================================================dt system orig0.025
    [       9] =========================================================dt system final0.025
    [       9] Min_dt_controller setSubsteps tList=[0.1] self.t_model=0.1 self.substeps= [0.1]
    [       9] System time step t= 1.00000e-01, dt= 2.50000e-02
    [       9] Split operator iteration 0
    [       9] Model: ladr_2d
    [       9] Fractional step  1.00000e-01 for model ladr_2d
    [       9] Step exact called for model ladr_2d
    [       9] StepControl base stepExact t_model= 0.1 tOut= 0.1 t_model_last= 0.075 dt_model= 0.025 setting to 0.025
    [       9] Min_dt_controller setSubsteps tList=[0.1] self.t_model=0.1 self.substeps= [0.1]
    [       9] Model step t= 1.00000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Model substep t= 1.00000e-01 for model ladr_2d
    [       9] Model substep t= 1.00000e-01 for model ladr_2d model.timeIntegration.t=  1.00000e-01
    [       9]    Newton it 0 norm(r) =  1.07828e-01  		 norm(r)/(rtol*norm(r0)+atol) = 0.107712 test=r
    [       9] before ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= False ksp.its= 3 ksp.norm= 0.000350335458124
    [       9] after ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= True ksp.its= 3 ksp.norm= 0.000602902136397 reason = 2
    [       9]    Newton it 1 norm(r) =  2.80092e-05  		 norm(r)/(rtol*norm(r0)+atol) =  2.79791e-05
    [       9] SO_base modelStepTaken for model= ladr_2d t_system_last= 0.075 t_model_last= 0.075  setting to t_stepSequence= 0.1
    [       9] Step Taken, t_stepSequence= 0.1 Model step t= 1.00000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Min_dt_controller setSubsteps tList=[0.1223606797749978] self.t_model=0.122360679775 self.substeps= [0.1223606797749978]
    [       9] Step Taken, System time step t= 1.25000e-01, dt= 2.50000e-02
    [       9] Step Taken, Model step t= 1.25000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Writing mesh header for  model = ladr_2d at time t=0.1
    [       9] Writing solution for  model = ladr_2d
    [       9] Syncing Archive
    [       9] Gathering Archive Time step
    [       9] Done Gathering Archive Time Step
    [       9] Done Syncing Archive
    [       9] ==============================================================
    [       9] Solving over interval [ 1.00000e-01, 1.25000e-01]
    [       9] ==============================================================
    [       9] ===========================================================dt system orig0.025
    [       9] =========================================================dt system final0.025
    [       9] Min_dt_controller setSubsteps tList=[0.125] self.t_model=0.125 self.substeps= [0.125]
    [       9] System time step t= 1.25000e-01, dt= 2.50000e-02
    [       9] Split operator iteration 0
    [       9] Model: ladr_2d
    [       9] Fractional step  1.25000e-01 for model ladr_2d
    [       9] Step exact called for model ladr_2d
    [       9] StepControl base stepExact t_model= 0.125 tOut= 0.125 t_model_last= 0.1 dt_model= 0.025 setting to 0.025
    [       9] Min_dt_controller setSubsteps tList=[0.125] self.t_model=0.125 self.substeps= [0.125]
    [       9] Model step t= 1.25000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Model substep t= 1.25000e-01 for model ladr_2d
    [       9] Model substep t= 1.25000e-01 for model ladr_2d model.timeIntegration.t=  1.25000e-01
    [       9]    Newton it 0 norm(r) =  9.66718e-02  		 norm(r)/(rtol*norm(r0)+atol) = 0.0965785 test=r
    [       9] before ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= False ksp.its= 3 ksp.norm= 0.000602902136397
    [       9] after ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= True ksp.its= 3 ksp.norm= 0.000732389038733 reason = 2
    [       9]    Newton it 1 norm(r) =  3.29678e-05  		 norm(r)/(rtol*norm(r0)+atol) =  3.29360e-05
    [       9] SO_base modelStepTaken for model= ladr_2d t_system_last= 0.1 t_model_last= 0.1  setting to t_stepSequence= 0.125
    [       9] Step Taken, t_stepSequence= 0.125 Model step t= 1.25000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Min_dt_controller setSubsteps tList=[0.1473606797749978] self.t_model=0.147360679775 self.substeps= [0.1473606797749978]
    [       9] Step Taken, System time step t= 1.50000e-01, dt= 2.50000e-02
    [       9] Step Taken, Model step t= 1.50000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Writing mesh header for  model = ladr_2d at time t=0.125
    [       9] Writing solution for  model = ladr_2d
    [       9] Syncing Archive
    [       9] Gathering Archive Time step
    [       9] Done Gathering Archive Time Step
    [       9] Done Syncing Archive
    [       9] ==============================================================
    [       9] Solving over interval [ 1.25000e-01, 1.50000e-01]
    [       9] ==============================================================
    [       9] ===========================================================dt system orig0.025
    [       9] =========================================================dt system final0.025
    [       9] Min_dt_controller setSubsteps tList=[0.15] self.t_model=0.15 self.substeps= [0.15]
    [       9] System time step t= 1.50000e-01, dt= 2.50000e-02
    [       9] Split operator iteration 0
    [       9] Model: ladr_2d
    [       9] Fractional step  1.50000e-01 for model ladr_2d
    [       9] Step exact called for model ladr_2d
    [       9] StepControl base stepExact t_model= 0.15 tOut= 0.15 t_model_last= 0.125 dt_model= 0.025 setting to 0.025
    [       9] Min_dt_controller setSubsteps tList=[0.15] self.t_model=0.15 self.substeps= [0.15]
    [       9] Model step t= 1.50000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Model substep t= 1.50000e-01 for model ladr_2d
    [       9] Model substep t= 1.50000e-01 for model ladr_2d model.timeIntegration.t=  1.50000e-01
    [       9]    Newton it 0 norm(r) =  8.86300e-02  		 norm(r)/(rtol*norm(r0)+atol) = 0.0885516 test=r
    [       9] before ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= False ksp.its= 3 ksp.norm= 0.000732389038733
    [       9] after ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= True ksp.its= 3 ksp.norm= 0.000777472508832 reason = 2
    [       9]    Newton it 1 norm(r) =  3.70134e-05  		 norm(r)/(rtol*norm(r0)+atol) =  3.69807e-05
    [       9] SO_base modelStepTaken for model= ladr_2d t_system_last= 0.125 t_model_last= 0.125  setting to t_stepSequence= 0.15
    [       9] Step Taken, t_stepSequence= 0.15 Model step t= 1.50000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Min_dt_controller setSubsteps tList=[0.1723606797749978] self.t_model=0.172360679775 self.substeps= [0.1723606797749978]
    [       9] Step Taken, System time step t= 1.75000e-01, dt= 2.50000e-02
    [       9] Step Taken, Model step t= 1.75000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Writing mesh header for  model = ladr_2d at time t=0.15
    [       9] Writing solution for  model = ladr_2d
    [       9] Syncing Archive
    [       9] Gathering Archive Time step
    [       9] Done Gathering Archive Time Step
    [       9] Done Syncing Archive
    [       9] ==============================================================
    [       9] Solving over interval [ 1.50000e-01, 1.75000e-01]
    [       9] ==============================================================
    [       9] ===========================================================dt system orig0.025
    [       9] =========================================================dt system final0.025
    [       9] Min_dt_controller setSubsteps tList=[0.175] self.t_model=0.175 self.substeps= [0.175]
    [       9] System time step t= 1.75000e-01, dt= 2.50000e-02
    [       9] Split operator iteration 0
    [       9] Model: ladr_2d
    [       9] Fractional step  1.75000e-01 for model ladr_2d
    [       9] Step exact called for model ladr_2d
    [       9] StepControl base stepExact t_model= 0.175 tOut= 0.175 t_model_last= 0.15 dt_model= 0.025 setting to 0.025
    [       9] Min_dt_controller setSubsteps tList=[0.175] self.t_model=0.175 self.substeps= [0.175]
    [       9] Model step t= 1.75000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Model substep t= 1.75000e-01 for model ladr_2d
    [       9] Model substep t= 1.75000e-01 for model ladr_2d model.timeIntegration.t=  1.75000e-01
    [       9]    Newton it 0 norm(r) =  8.23469e-02  		 norm(r)/(rtol*norm(r0)+atol) = 0.0822792 test=r
    [       9] before ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= False ksp.its= 3 ksp.norm= 0.000777472508832
    [       9] after ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= True ksp.its= 3 ksp.norm= 0.000815888860838 reason = 2
    [       9]    Newton it 1 norm(r) =  3.98207e-05  		 norm(r)/(rtol*norm(r0)+atol) =  3.97880e-05
    [       9] SO_base modelStepTaken for model= ladr_2d t_system_last= 0.15 t_model_last= 0.15  setting to t_stepSequence= 0.175
    [       9] Step Taken, t_stepSequence= 0.175 Model step t= 1.75000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Min_dt_controller setSubsteps tList=[0.1973606797749978] self.t_model=0.197360679775 self.substeps= [0.1973606797749978]
    [       9] Step Taken, System time step t= 2.00000e-01, dt= 2.50000e-02
    [       9] Step Taken, Model step t= 2.00000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Writing mesh header for  model = ladr_2d at time t=0.175
    [       9] Writing solution for  model = ladr_2d
    [       9] Syncing Archive
    [       9] Gathering Archive Time step
    [       9] Done Gathering Archive Time Step
    [       9] Done Syncing Archive
    [       9] ==============================================================
    [       9] Solving over interval [ 1.75000e-01, 2.00000e-01]
    [       9] ==============================================================
    [       9] ===========================================================dt system orig0.025
    [       9] =========================================================dt system final0.025
    [       9] Min_dt_controller setSubsteps tList=[0.2] self.t_model=0.2 self.substeps= [0.2]
    [       9] System time step t= 2.00000e-01, dt= 2.50000e-02
    [       9] Split operator iteration 0
    [       9] Model: ladr_2d
    [       9] Fractional step  2.00000e-01 for model ladr_2d
    [       9] Step exact called for model ladr_2d
    [       9] StepControl base stepExact t_model= 0.2 tOut= 0.2 t_model_last= 0.175 dt_model= 0.025 setting to 0.025
    [       9] Min_dt_controller setSubsteps tList=[0.2] self.t_model=0.2 self.substeps= [0.2]
    [       9] Model step t= 2.00000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Model substep t= 2.00000e-01 for model ladr_2d
    [       9] Model substep t= 2.00000e-01 for model ladr_2d model.timeIntegration.t=  2.00000e-01
    [       9]    Newton it 0 norm(r) =  7.71455e-02  		 norm(r)/(rtol*norm(r0)+atol) = 0.077086 test=r
    [       9] before ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= False ksp.its= 3 ksp.norm= 0.000815888860838
    [       9] after ksp.rtol= 0.001 ksp.atol= 1e-08 ksp.converged= True ksp.its= 3 ksp.norm= 0.000844346041696 reason = 2
    [       9]    Newton it 1 norm(r) =  4.14653e-05  		 norm(r)/(rtol*norm(r0)+atol) =  4.14334e-05
    [       9] SO_base modelStepTaken for model= ladr_2d t_system_last= 0.175 t_model_last= 0.175  setting to t_stepSequence= 0.2
    [       9] Step Taken, t_stepSequence= 0.2 Model step t= 2.00000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Min_dt_controller setSubsteps tList=[0.22236067977499782] self.t_model=0.222360679775 self.substeps= [0.22236067977499782]
    [       9] Step Taken, System time step t= 2.25000e-01, dt= 2.50000e-02
    [       9] Step Taken, Model step t= 2.25000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Writing mesh header for  model = ladr_2d at time t=0.2
    [       9] Writing solution for  model = ladr_2d
    [       9] Syncing Archive
    [       9] Gathering Archive Time step
    [       9] Done Gathering Archive Time Step
    [       9] Done Syncing Archive
    [       9] ==============================================================
    [       9] Solving over interval [ 2.00000e-01, 2.25000e-01]
    [       9] ==============================================================
    [       9] ===========================================================dt system orig0.025
    [       9] =========================================================dt system final0.025
    [       9] Min_dt_controller setSubsteps tList=[0.225] self.t_model=0.225 self.substeps= [0.225]
    [       9] System time step t= 2.25000e-01, dt= 2.50000e-02
    [       9] Split operator iteration 0
    [       9] Model: ladr_2d
    [       9] Fractional step  2.25000e-01 for model ladr_2d
    [       9] Step exact called for model ladr_2d
    [       9] StepControl base stepExact t_model= 0.225 tOut= 0.225 t_model_last= 0.2 dt_model= 0.025 setting to 0.025
    [       9] Min_dt_controller setSubsteps tList=[0.225] self.t_model=0.225 self.substeps= [0.225]
    [       9] Model step t= 2.25000e-01, dt= 2.50000e-02 for model ladr_2d
    [       9] Model su

```python

```

```python

```


# 1質点系の運動方程式
---
下図のように質量mの質点が減衰係数c、バネ定数kで変位uで運動する場合を考える

この場合、運動方程式は次のとおりである

$$
\begin{equation*}
m \frac{d^2}{dt^2}u(t) + c \frac{d}{dt}u(t) + ku(t) = F(t)
\end{equation*}
$$

## Sympyによる数式処理
### 準備
次の操作を実行する
1. matplotlibをjupyter上で表示できるマジックコマンド
2. numpyライブラリをnp名称でインポート
3. sympyライブラリのインポート
4. 数式表示のおまじない

```python
%matplotlib inline
import numpy as np
import sympy
sympy.init_printing()
```

### 運動方程式の定義
まずは、変数や関数を定義する。
1. 変位の関数であるu、外力の関数であるFを定義する。
2. 時間、質量、減衰係数、ばね定数、１階の積分定数C1(初期速度)、２階の積分定数C2(初期変位）を定義する

```python
u = sympy.Function("u")
F = sympy.Function("F")
t, m, c, k, C1, C2 = sympy.symbols("t m c k C1 C2")
```

次に運動方程式を定義する。

* uとFはtの関数であることを考慮する
* 運動方程式は右辺をゼロとした形で左辺をeq_moという関数としてすること
* 定義したeq_moを表示する

```python
eq_mo = m * u(t).diff(t).diff(t) + c * u(t).diff(t) + k * u(t) - F(t)
eq_mo
```

## 非減衰自由振動
---

減衰0、外力0の条件下で、初速0,初期変位1の自由振動を計算する
解くべき方程式は下記の通り。

$$
\begin{align*}
m \frac{d^2u}{dt^2}  + ku & = 0 \\
\frac{du_0}{dt} &= 0 \\
u_0 &= 1
\end{align*}
$$

m=1, k=4$\pi^2$の場合のt=0～8のu(t)を各種方法でプロットする

### Sympyによる数式処理
eq_moをそのままu(t)について解くと計算負荷が大きいので、
まずは c=0, F(t)=0を代入し非減衰自由振動方程式を作成する

非減衰自由振動方程式の左辺をeq_freeとして表示する

```python
arg_free = {c:0, F(t):0}
eq_free = eq_mo.subs(arg_free)
eq_free
```

eq_freeをu(t)について解いて表示する

```python
solu_free = sympy.dsolve(
        eq_free,
        u(t)
    )
solu_free
```

よってsolu_free（右辺）の微分よりdu/dtは

```python
dsolu_freedt = sympy.diff(solu_free.rhs,t)
dsolu_freedt
```

t=0のとき、下記の境界条件があるので

$$
\begin{align*}
\frac{du_0}{dt} &= 0 \\
u_0 &= 1
\end{align*}
$$

連立方程式を解くとC1,C2は以下の通りである

```python
dict_ci = sympy.solve(
    [solu_free.rhs.subs(t,0) - 1.,
     dsolu_freedt.subs(t,0)- 0.],
    [C1,C2])
dict_ci
```

上記で求めたC1,C2とm=1,k=4をsolu_freeに代入すると、

```python
real_react_free, img_react_free = solu_free.subs(dict_ci).subs({m:1,k:4*np.pi**2.}).rhs.as_real_imag()

sympy.plotting.plot(real_react_free, (t,0,8))
sympy.plotting.plot(img_react_free, (t,0,8))
```

虚部が消えて実部だけになっていることが確認でき、解析的に階を得られた。
また下記の通り、1Hzの固有周波数で自由振動していることがわかる。

$$
\begin{align*}
f &= \frac{1}{2\pi}\sqrt\frac{k}{m} \\
f &= 1.0  \quad [Hz]
\end{align*}
$$

### Scipyによる数値計算
scipyのodeint（常微分方程式）ソルバを用いて同様の非減衰自由振動問題を計算する。

$$
\begin{align*}
m \frac{d^2}{dt^2}u  + ku & = 0 \\
\frac{du_0}{dt} &= 0 \\
u_0 &= 1
\end{align*}
$$
まずはscipyを使う準備
1. matplotlibライブラリのpyplotモジュールをpltという名称でインポート
2. scipy.integrateモジュール内のode関数をインポート

```python
from matplotlib import pyplot as plt
from scipy.integrate import odeint
```

まずは、下記のように変数変換を考える

$$
\frac{d}{dt}u := v
$$

この関係を考慮すれば、２階の常微分方程式が１階の連立常微分方程式で表現できる

$$
\begin{align*}
\left\{
    \begin{array}{l}
        \large \frac{d}{dt} \normalsize v = - \large \frac{k}{m} \normalsize u  \\
        \large \frac{d}{dt} \normalsize u= v
     \end{array}
\right.
\end{align*}
$$

変数x(=(v,u))でまとめ、xと時間tを引数として$\large \left[ \frac{dv}{dt},\frac{du}{dt}\right]$を返す関数func_odeを定義する

```python
def funcs_ode(x,t):
    dvdt = - 4. * np.pi **2 / 1. * x[1]
    dudt = x[0]
    return [dvdt, dudt]
```

次に、初期値x0と時間ti(0から8までを801分割したベクトル)を定義する。
(変数tはsympyにて使っているので変数名はtiとすること)

```python
x0 = [0., 1.]
ti = np.linspace(0,8,801)
```

初期値x0でtiに示す時間ステップでxを計算し、変位uをプロットする。

```python
x = odeint(funcs_ode,x0, ti)
plt.plot(ti,x[:,1])
```

## 強制振動
---
m=1, k=4$\pi^2$, 減衰係数c=$0.8\pi$ (減衰比$\zeta=0.2$)、外力F(t)の条件下で
上記に示す[１質点系の強制振動](#anker1)の数値計算を行う

$$
\begin{equation*}
m \frac{d^2}{dt^2}u(t) + c \frac{d}{dt}u(t) + ku(t) = F(t)
\end{equation*}
$$

外力F(t)は下記とする。尚、sgnはシグナム関数(符号関数)である
$$
F(t) = \mbox{sgn} \hspace{1pt} sin(0.25\pi (t-1.0)) +1.0
$$

シグナム関数は正の値の場合1,負の値の場合-1を取る関数で、外力Ftは次の通りプロットできる
時間は上で定義したtiを用いる

```python
Ft = np.sign(np.sin(0.25*np.pi*(ti-1) )) +1
plt.plot(ti,Ft)
```

まずは、前項と同じように変数変換を考える

$$
\frac{d}{dt}u := v
$$

この関係を考慮すれば、前項同様に２階の常微分方程式が１階の連立常微分方程式で表現できる

$$
\begin{align*}
\left\{
    \begin{array}{l}
        \large \frac{d}{dt} \normalsize v = F(t)- \large \frac{c}{m} \normalsize v  - \large \frac{k}{m} \normalsize u  \\
        \large \frac{d}{dt} \normalsize u= v
     \end{array}
\right.
\end{align*}
$$

変数x(=(v,u))でまとめ、xと時間tを引数として$\large \left[ \frac{dv}{dt},\frac{du}{dt}\right]$を返す関数func_ode2を定義する

```python
def funcs_ode2(x,t):
    dvdt = np.sign(np.sin(0.25*np.pi*(t-1.))) +1. - 0.8 * np.pi  / 1. * x[0] - 4. * np.pi **2 / 1. * x[1]
    dudt = x[0]
    return [dvdt, dudt]
```

今回は外力の応答を見たいので、初期値は速度、変位ともに0,0とする。
時間は前項同様の変数ti(0から8までを801分割したベクトル)を再定義する。（前回定義しているなら不要）

```python
x0 = [0., 0.]
ti = np.linspace(0,8,801)
```

初期値x0でtiに示す時間ステップでxを計算し、変位uをプロットする。

```python
x = odeint(funcs_ode2,x0, ti)
plt.plot(ti,x[:,1])
```

時刻1[s]より応答変位が生じている。約4[s]地点で準静的な力のつり合い状態となっていることがわかる。

---

python4engineer by TatsuyaKatayama is licensed under a Creative Commons Attribution 4.0 International License.