# SESX 2022 - Aerofoil Lab Measurement and Data File

### Theoretical Considerations

This section will provide you with the theoretical aspects required to understand the airfoil lab (or the infinite wing lab). The main objective of these experiments is to give you an insight into  two dimensional flow dynamics. First, we must define the operating environment and the operating conditions mainly to be able to create and assess the applicability of the assumptions framework. The operating environment is a low-speed open-loop wind tunnel with 100mm by 50mm cross section. The average temperature is approximately 20-25$^{\circ}$C (you need to take a note of this from the thermometer) and the ambient pressure can be assumed as the standard sea level pressure. The operating conditions are represented by the wind tunnel's speed, which ranges from 10 to 40 m/s. There are two applicable assumptions that will be described separately: \textit{inviscid flow} and \textit{incompressible flow}. These two assumptions will greatly simplify our theoretical model.

#### Inviscid flow

There are no truly inviscid flows in nature as the phenomena of friction (viscosity), mass diffusion and thermal conduction always occur at a molecular level to a certain degree. However, in many engineering applications, these transport phenomena are mostly negligible, especially for high and finite Reynolds numbers flows. Therefore, the flow can be separated into two regions: the inviscid region and the viscous region. In the case of an aerofoil mounted in a flow at a low angle of attack, the viscous region is small and represented by the thin viscous boundary layer neighbouring the surface of the aerofoil. The inviscid region is represented by all the flow outside the boundary layer. **Given a wing chord $c=0.063m$, an upstream flow velocity $u=20 m/s$ and a kinematic viscosity $\nu= 15.11\times10^{-6} m^{2}/s$ ($Re=\frac{u\times c}{\nu}$), how well is this assumption holding? Also, can the flow still be considered inviscid when the aerofoil is at high angles of attack at which separation occurs and hence a large wake is formed downstream?}**

#### Incompressible flow

An incompressible flow is defined as a flow for which the working fluid density $\rho$ is constant. There are, of course, more advanced definitions of what compressibility is which link to thermodynamic considerations, but a good approximation is that all flows for which Mach number (M) is less than 0.3, can be considered incompressible. **Hence, what are your comments regarding the applicability of the incompressibility assumption for the current case?**

#### Bernoulli's Equation
Using the assumptions of the inviscid and the incompressible flow, Bernoulli's equation becomes applicable. The equation is:

\begin{equation}
p+\frac{1}{2}\rho u^2=const.
\label{Eqn:bernoulli1}
\end{equation}

Equation 1

Thus for an incompressible, inviscid flow, the static and dynamic pressures add up to a constant along streamlines.

#### Irrotational flow
If we consider an infinitesimal fluid element moving through the flow field, we can describe its orientation as a combination of both translation and rotation. Additionally, the fluid element may also change its shape, but this change can also be considered a combination of translation and rotation. The case on the right of Figure 1 shows on the upper streamline a fluid element where the angular velocities of its sides are zero, hence the flow is irrotational. The lower streamline of the case on the right shows a two dimensional fluid element where the angular velocities of the two intersecting sides are finite, but equal and opposite to each other and so their sum is identically zero; hence the flow is irrotational as well. **How well is this assumption holding for the current case? Explain only from a qualitative point of view**

 Figure 1 - Rotational and irrotational Flow comparison

If besides inviscid and incompressible, the flow is also irrotational, the value of the constant from Equation 1 is the same between all streamlines. Applying Bernoulli's equation far upstream:

\begin{equation}
p_{\infty}+\frac{1}{2}\rho u_{\infty}^2=p_{0}
\end{equation}

Equation 2

where $p_{0}$ is defined as the stagnation or total pressure and the subscript $\infty$ refers to the upstream conditions.

#### Pressure coefficient
The static pressures and velocities around the aerofoil differ from their upstream values. Assuming that there is a negligible variation of static pressure through the thin boundary layers on the surface of the aerofoil, Bernoulli's equation can be applied to relate the surface static pressure $p_{s}$ to the upstream conditions:

\begin{equation}
p_{0}=p_{s}+\frac{1}{2}\rho u^2=p_{\infty}+\frac{1}{2}\rho u_{\infty}^2
\label{Eqn:bernoulli3}
\end{equation}

Equation 3

where $u$ is the velocity just outside the boundary layer. By defining the surface pressure coefficient, $C_{p}$ in the usual way, from Equation 3:

\begin{equation}
C_{p}=\frac{p_{s}-p_{atm}}{\frac{1}{2}\rho u_{\infty}^2}=\frac{p_{s}-p_{atm}}{p_{0}-p_{\infty}}
\label{Eqn:pressurecoeff}
\end{equation}

Equation 4

For the airfoil, we will assume the static pressure farther away from the airfoil surface is $P_{atm}$ and the velocity is calculated from the tunnel free stream pressure and total pressure. This will be measured through the use of a manometer, where the pressure is proportional to the column height and the inclination angle of the manometer (FEEG1003 Thermofluids for revision on how to use a manometer).

The experimental setup is fitted with a number of pressure tappings on both the top and bottom surfaces that are connected to a multi-manometer; this will allow you to measure the static pressures at points around the aerofoil. A standard pitot-static probe is mounted at the inlet to the contraction and the inlet of the test section to read the stagnation pressure as well as the freestream static pressure. The coefficients of pressure around the aerofoil can be determined using these readings.

Once you have the pressure coefficents you can integrate them to calcuate lift and drag. Note that the drag you will measure is only the pressure drag and would not include the viscous contribution.

#### Force considerations
In general terms an aerofoil at a geometric angle of attack $ \alpha$.

 Figure 2 - Wing dimensions diagram and force considerations across the wing section

The objective now is to determine the lift coefficients using the readings provided by the pressure tappings. First, consider an element of unit span and length $\Delta s$ on the surface of the aerofoil (i.e. left small purple line) which is tilted by $\theta$ with respect to the aerofoil's axis (i.e. red line). The normal net force to this element is, under the aforementioned assumptions, $p_{s}\Delta s$ which in the XY Cartesian coordinate system defined by the aerofoil has the following components:

\begin{equation}
\begin{split}
& \Delta N_{a}=\pm p_{s}\cos(\theta)\Delta s=\pm p_{s}\Delta x \\
& \Delta T_{a}=\pm p_{s}\sin(\theta)\Delta s=\pm p_{s}\Delta y
\label{Eqn:force1}
\end{split}
\end{equation}

Equation 5

The $+$ elements represent the ones which create a force component in positive Y or X direction and $-$ elements represent the ones that create a force component in negative Y or X direction.

The value of the normal force (N) is the integration of all $\Delta N$ across the surface of the entire airfoil. Since in the current case the size of $\Delta s$ is not infinitesimal and has a finite determinable value, the integration becomes a summation of the normal force across the upper and lower surfaces of the airfoil. The same applies to the tangential force. Hence:
 \begin{equation}
  \begin{split}
   N &=\sum_{up} \Delta N_{a}+\sum_{up} \Delta N_{f}+\sum_{low} \Delta N_{a}+\sum_{low} \Delta N_{f}\\
   T &=\sum_{up} \Delta T_{a}+\sum_{up} \Delta T_{f}+\sum_{low} \Delta T_{a}+\sum_{low} \Delta T_{f}
  \label{Eqn:force3}
  \end{split}
 \end{equation}

Equation 6

 where N is the normal force per unit span and T is the tangential force per unit span, both relative to the XY Coordinate system belonging to the aerofoil. The above summation can be re-written as an integral and converted to a force coeffcient as follows:

  \begin{equation}
   \begin{split}
    C_{N} &=\frac{N}{\frac{1}{2}\rho u_{\infty}^2 c}=\frac{1}{c} \cdot \int_{0}^{c} (C_{p,l} - C_{p,u}) \cdot dx\\
    C_{T} &=\frac{T}{\frac{1}{2}\rho u_{\infty}^2 c}=\frac{1}{c} \cdot \int_{0}^{c} (C_{p,u} \cdot \frac{dy_{u}}{dx} - C_{p,l} \cdot \frac{dy_{l}}{dx}) \cdot dx
   \label{Eqn:force4}
   \end{split}
  \end{equation}

Equation 7

Here $\rho$ is the air density, $u_{\infty}$ is the upstream wind velocity and $c$ is the wing chord. $\frac{dy_{u}}{dx}$ and $\frac{dy_{l}}{dx}$ are slope of the aerofoil surface at the location of the tappings on the upper and lower surfaces.

These normal and tangential forces can be convered to lift and drag coefficients. Note that for very thin airfoils, the pressure drag is basically zero as the slope of the airfoil is very small.Regardless, we can determine the the coefficient of lift that can be determined as,

 \begin{equation}
      C_{l} =C_{N}\cos(\alpha)-C_{T}\sin(\alpha)
    \label{Eqn:force5}
    \end{equation}

Equation 8

For the above equation, if $\alpha$ is small, then, the normal force and the lift force will be very similar to each other.

### Thin aerofoil theory
The objective of this brief section is to refresh assumptions under which this theory is applicable and also, to refresh some of its consequences. Requirements:
* As the name states, the maximum aerofoil thickness must be small compared to the chord length. You will be using a NACA0020 airfoil section where the maximum thickness of the wing is approximately 12.6 $mm$ and the chord is 63 $mm$.
* The theory is restricted to low angles of attack.
* The flow must be both inviscid and incompressible.
* The flow must be two-dimensional.

**Given the current experimental conditions, how applicable are these assumptions?**
This theory predicts the following key points for aerofoils which respect the aforementioned requirements:
* Lift coefficient is directly proportional with AoA and the proportionality parameter is $2\pi$ (i.e. $\frac{dC_{L}}{d\alpha}=2\pi$).
* On a symmetric aerofoil - no camber - the centre of pressure is located at the quarter-chord behind LE.
* For any aerofoil - with or without camber - the aerodynamic centre is located at the quarter-chord behind LE.

Numerically, the coefficient of lift of an aerofoil within the assumptions of thin aerofoil theory is,

  \begin{equation}
       C_{l}==2\pi(\alpha-\alpha_{0})
      \label{Eqn:thinaerofoil1}
     \end{equation}

Equation 9

where $\alpha_{0}$ represents the angle of attack at zero lift and $\alpha$ represents the \textit{geometric} AoA. The value $2\pi$ is the theoretical lift curve slope and in your experiment coudl give an answer slighty different than this. The value of $\alpha_0$ represents the added effect of the camber on the coefficient of lift. For a symmetric aerofoil, the value of $\alpha_0$ is 0. Furthermore, the value of $\alpha_0$ can be either positive or negative, depending on a positive or negative camber, respectively. You are required to compare the experimental results with the theoretical expectations of the thin aerofoil theory. \\
Refer to the lecture notes for further details about the theory.

## Experiment

The objective of this experiment is to examine the pressure distribution around an aerofoil of effectively infinite span, in order to show the effects of incidence changes and to determine the lift of the aerofoil. The pressure tappings data is to be compared with CFD data which is generated during the CFD lab. Please make sure that you have followed and understood the theoretical background outlined before continuing.

## Import required modules

```python
import numpy as np
import matplotlib.pyplot as plt
from numpy import cos
from numpy import sin
import os
import pandas as pd
```

## Required functions

```python
def Aerofoil(x):
    '''This function takes the x coordinate and returns the positive y coordinate of the aerofoil'''
    t=0.20
    y = (5*t)*((0.2969*x**0.5)-(0.1260*x)-(0.3516*x**2)+(0.2843*x**3)-(0.1015*x**4))
    return(y)
```

## General Data
Enter the temperature in degrees and the Pressure in Pa in the below cell then enter a formula to calculate the Density which will be required later

```python
Temperature_deg = 20 #degrees C
Pressure= 101325 #Pa

Temperature_kelvin = Temperature_deg+273 #K

rho = Pressure/(287*Temperature_kelvin)
print (rho)

```

    1.2049446433030884

The aerofoil spans the wind tunnel's working section, thus ideally generating a two-dimensional flow. Around the aerofoil, 12 pressure tappings are fitted - small diameter holes (2.5 mm), through a 3D printed aerofoil with tapping tubes connected. These pressure tappings enable the surface static pressure $p_{s}$ to be measured at various stations. Each pressure tube is connected to a manometer. The dynamic pressure, $ q_{\infty}=\frac{1}{2}\rho u_{\infty}^2 $, can be obtained from the pressure difference, $p_{0}-p_{\infty}$, using Equation equation 3. You will read the height of the different tappings and  $P_{\infty}$ is proportional to the difference between the tapping tube height and the atm height. The pressure coefficients at various points on the aerofoil are found using Equation 4. A layout of the pressure tappings can be found below.

```python
#This is set up so if the aerofoil is turned clockwise the upper surface with have the tapping positons below otherwise
#just switch upper and lower surface around
x = [1, 2, 4.5, 7.5, 11, 14.5, 20, 26, 32.1, 38, 44, 50]
xc_upper= []
xc_lower =[]
for i in range(12):
    if i % 2 == 0:
        xc_lower.append(x[i]/63)
    if i % 2 == 1:
        xc_upper.append(x[i]/63)

plt.plot([Aerofoil(i) for i in xc_upper], xc_upper, 'ro', label= 'Upper Surface Tappings')
plt.plot([Aerofoil(i) for i in np.linspace(0,1,100)], np.linspace(0,1,100), 'g-')
plt.plot([-Aerofoil(i) for i in xc_lower], xc_lower, 'bo', label = 'Lower Surface Tappings')
plt.plot([-Aerofoil(i) for i in np.linspace(0,1,100)], np.linspace(0,1,100), 'g-')
plt.gca().invert_yaxis()
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.grid()
plt.axis('scaled')
plt.show()
```

## Data collection

### 0 degrees

Next with the aerofoil set to 0 degrees then enter the manometer readings which can be used for during data processing. A summary of the data can be seen in the summary table below. When turning the aerofoil clockwise the tappings on the left hand side will be the lower surface and therefore put them on the tappings 1-6 then upper surface will be 7 to 12.

```python

```

### 6 degrees

Next with the aerofoil set to 6 degrees, turning the aerofoil clockwise will result in the upper surface as labelled in the summary table being the upper surface, if turned anti clockwise just switch lower and upper around and adjust general data cell, the lowest numbered tapping is the leading edge. When turning the aerofoil clockwise the tappings on the left hand side will be the lower surface and therefore put them on the tappings 1-6 then upper surface will be 7 to 12.

```python

```

### 12 degrees

Next with the aerofoil set to 12 degrees, turning the aerofoil clockwise will result in the upper surface as labelled in the summary table being the upper surface, if turned anti clockwise just switch lower and upper around and adjust general data cell, the lowest numbered tapping is the leading edge.  When turning the aerofoil clockwise the tappings on the left hand side will be the lower surface and therefore put them on the tappings 1-6 then upper surface will be 7 to 12.

```python

```

## More data

If you have the time, please also take data for other angles of attack as this will allow us to compute the lift curve slope more accurately. You could take data for 3 degrees and 9 degrees. For this, you need to create new cells, which you can just cut and paste from above, rename them for the new angles and write the files in to appropriate filenames. That gives you 5 data points to fit a straight line for the lift curves slope.

Finally, set the angle of attack of the airfoil at 20 degrees (or maybe a bit more), then observe what happens to the liquid columns of the pressure tappings.
Do you see the columns moving around with time?
Why do you think this happens?

# THIS SECTION IS THE POST-PROCESSING OF THE DATA OBTAINED IN THE LAB EXPERIMENTS
## Load Data and Summary

The cell below reads the data files generate in the lab (Or as given on blackboard if you were unable to attend a lab) and outputs 3 tables. If you acquired data for more angles of attack, then, you need to expand the code below accordingly.

```python
Zero_data = pd.read_csv('C:\\Users\\erikv\\Aerodynamics\\Airfoil Lab\\Zero_deg(1).csv')
Variable,Manometer = Zero_data.columns
Variable_Zero = Zero_data[Variable]
Manometer_Zero = Zero_data[Manometer]

Six_data = pd.read_csv('C:\\Users\\erikv\\Aerodynamics\\Airfoil Lab\\Six_deg(1).csv')
Variable,Manometer = Six_data.columns
Variable_Six = Six_data[Variable]
Manometer_Six = Six_data[Manometer]

Twelve_data = pd.read_csv("C:\\Users\\erikv\\Aerodynamics\\Airfoil Lab\\Twelve_deg(1).csv")
Variable,Manometer = Twelve_data.columns
Variable_Twelve = Twelve_data[Variable]
Manometer_Twelve = Twelve_data[Manometer]

#This is just to show the data next to each other
pd.concat([Zero_data, Six_data, Twelve_data], keys=['Zero', 'Six', 'Twelve'], axis=1)
```

      Zero
      Six
      Twelve

      Variable
      Manometer Reading (mm)
      Variable
      Manometer Reading (mm)
      Variable
      Manometer Reading (mm)

      0
      P_atm
      108
      P_atm
      108
      P_atm
      108

      1
      P_tot
      132
      P_tot
      134
      P_tot
      134

      2
      P_static
      110
      P_static
      110
      P_static
      112

      3
      LWR x/c = 1
      120
      LWR x/c = 1
      132
      LWR x/c = 1
      134

      4
      LWR x/c = 4.5
      98
      LWR x/c = 4.5
      112
      LWR x/c = 4.5
      124

      5
      LWR x/c = 11
      92
      LWR x/c = 11
      106
      LWR x/c = 11
      114

      6
      LWR x/c = 20
      94
      LWR x/c = 20
      104
      LWR x/c = 20
      110

      7
      LWR x/c = 32.1
      100
      LWR x/c = 32.1
      104
      LWR x/c = 32.1
      108

      8
      LWR x/c = 44
      104
      LWR x/c = 44
      106
      LWR x/c = 44
      108

      9
      UPPER x/c = 2
      108
      UPPER x/c = 2
      82
      UPPER x/c = 2
      60

      10
      UPPER x/c = 7.5
      94
      UPPER x/c = 7.5
      78
      UPPER x/c = 7.5
      68

      11
      UPPER x/c = 14.5
      94
      UPPER x/c = 14.5
      86
      UPPER x/c = 14.5
      78

      12
      UPPER x/c = 26
      98
      UPPER x/c = 26
      94
      UPPER x/c = 26
      94

      13
      UPPER x/c = 38
      102
      UPPER x/c = 38
      100
      UPPER x/c = 38
      100

      14
      UPPER x/c = 50
      106
      UPPER x/c = 50
      106
      UPPER x/c = 50
      106

## Post Processing

If running this after the lab, run the above cells to load the data and to get it ready to be processed.

The first step is to define a function to find the velocity of the flow taking the total and static pressure as inputs.

Following this define a function to calculate the pressure coefficent taking the velocity, static pressure at the tapping and the atmospheric pressure.

Once the two above functions have been define, create a function to take the array for each angle of attack as set out above, The first 3 values can be used to calculate the velocity the flow, while the others can be used to calculate the Cp on the upper and lower surfaces. Remember that tappings 1 to 6 are the lower and 7 to 12 are the upper if you turned the aerofoil clockwise.

Remember to use the x coordinate array that we made earlier for the lower and upper surfaces. These values in terms of $x/c$ is also given in the file. Split the pressures in to two lists/arrays for the lower and upper surfaces. This will make it easy to carry out the integration and also useful for plotting.

The slope of the aerofoil will be needed and this can be calculated from the aerofoil equation for an aerofoil, the tapping locations can be found above on the plot and therefore the gradient can be calculated.

$y_t = 5 \cdot t \cdot [0.2969 \cdot \sqrt{x} - 0.1260 \cdot x -0.3516 \cdot x^2 - 0.1015 \cdot x^4]$

You can just compute the derivative analytically and then use that formula to get $dy_u/dx$ and $dy_l/dx$. This way, you can just get the values at the location of the pressure tapping.

Note that in this equation all units are non-dimensionalised with respect to chord length (so x = 1 is the trailing edge of the airfoil and t is the thickness of the airfoil in terms of chord length). In order to find $C_N$ and $C_T$, you will need to integrate the pressure distribution. This can be done by using the trapezium rule or the simpson's rule.

The arrays to be used in the data processing are defined in the summary and load data cell, the arrays are from Pandas data frames as introduced at the begining of this module.

```python
# Define a function to calculate the Velocity
def findvelocity(ptot,pstat):
    v = (2*(ptot-pstat)/rho)**0.5
    return v

# Define a function to calculate the Cp
def findcp(v,pstat,patm):
    cp = (pstat-patm)/(0.5*rho*v**2)
    return cp

# Define a function to process the array
def process(array):
    patm = array.iloc[0,1]
    ptot = array.iloc[1,1]
    pstat = array.iloc[2,1]
    LWR = array.iloc[3:9,1]
    UPPER = array.iloc[9:15,1]
    return patm,ptot,pstat,LWR,UPPER

# Define a function to find the slope of the aerofoil
def findslope(x, t):
    y = []
    for i in x:
        dy = 5*t*(0.14845*i**(-0.5) - 0.406*i**3 + 0.8529*i**2 - 0.7032*i - 0.126)
        y.append(dy)
    return y

# Define a function function to find Cl by integrating the pressure coefficient
def findcl(cpup,cplow,xup,xlow,dyu,dyl,alfa):
    Cn = np.trapz(cplow,xlow)-np.trapz(cpup,xup)
    Ct = np.trapz(cpup*dyu,xup) - np.trapz(cplow*dyl,xlow)
    Cl = Cn*np.cos(alfa) - Ct*np.sin(alfa)
    return Cl,Cn,Ct

```

In the cells below to calculate the lift coefficent of the aerofoil as well as the velocity. Then plot the pressure distribution from the data collected above (plot should follow normal convention ie negative cp on the y axis, x/c on the x-axis), it would also be good to plot the pressure distribution obtained from CFD.

### 0 Degrees

```python
# In this cell find and print the Cl and Velocity
[patm0,ptot0,pstat0,LWR0,UPPER0] = process(Zero_data)

v0 = findvelocity(ptot0,pstat0)

cp0Lower = findcp(v0,LWR0,patm0)
cp0Upper = findcp(v0,UPPER0,patm0)

slopeLower0 = findslope(xc_lower, 0.2)
slopeUpper0 = findslope(xc_upper, 0.2)

[cl0,cn0,ct0] = findcl (cp0Upper, cp0Lower,xc_upper,xc_lower,slopeUpper0,slopeLower0,0 )

print ('calculated velocity:',v0,'\ncalculated lift coeffficient:',cl0)

```

    calculated velocity: 6.042863588185915
    calculated lift coeffficient: -0.0014430014430014126

```python
# Plot the pressure distribution and also plot the CFD distribution. Remember to read in the CFD data that you wrote to file when you did the CFD simulation.

plt.plot(xc_upper,cp0Upper,label='upper')
plt.plot(xc_lower,cp0Lower,label='lower')

CFD0 = np.loadtxt('CFD 0 cp.txt', skiprows=4)
CFD0cp = CFD0[:, 1:]
CFD0position = CFD0[:, 0]*15.873

#plt.plot(CFD0position, CFD0cp, label='CFD')
plt.legend(loc='upper right')
plt.axis([-0.1,1,-3.5,1.5])
plt.xlabel('location x/c')
plt.ylabel('Pressure coefficient')
plt.title('Cp distribution for 0 degrees AoA')
plt.savefig('cp 0 degrees.png')

```

### 6 Degrees

```python
# In this cell find and print the Cl and Velocity
[patm6,ptot6,pstat6,LWR6,UPPER6] = process(Six_data)

v6 = findvelocity(ptot6,pstat6)

cp6Lower = findcp(v6,LWR6,patm6)
cp6Upper = findcp(v6,UPPER6,patm6)

slopeLower6 = findslope(xc_lower, 0.2)
slopeUpper6 = findslope(xc_upper, 0.2)

[cl6,cn6,ct6] = findcl (cp6Upper, cp6Lower,xc_upper,xc_lower,slopeUpper6,slopeLower6,6*np.pi/180 )

print ('calculated velocity:',v6,'\ncalculated lift coeffficient:',cl6)

```

    calculated velocity: 6.311565172148648
    calculated lift coeffficient: 0.45624309417319664

```python
# Plot the pressure distribution and also plot the CFD distribution. Remember to read in the CFD data that you wrote to file when you did the CFD simulation.
plt.plot(xc_upper,cp6Upper,label='upper')
plt.plot(xc_lower,cp6Lower,label='lower')

CFD6 = np.loadtxt('CFD 6 cp.txt', skiprows=4)
CFD6cp = CFD6[:, 1:]
CFD6position = CFD6[:, 0]*15.873

XFLR6 = pd.read_csv('C:\\Users\\erikv\\Aerodynamics\\Airfoil Lab\\XFLR 6 cp.csv')
xflr6loc = XFLR6.iloc[1:99,0]
xflr6cp = XFLR6.iloc[1:99,1]

plt.plot(CFD6position, CFD6cp, label='CFD')
plt.plot(xflr6loc, xflr6cp, label = 'XFLR', color = 'purple')
plt.xlabel('location x/c')
plt.ylabel('Pressure coefficient')
plt.legend(loc='upper right')
plt.title('Cp distribution for 6 degrees AoA')
plt.axis([-0.1,1,-3.5,1.5])
plt.savefig('cp 6 degrees.png')

```

### 12 Degrees

```python
# In this cell find and print the Cl and Velocity
[patm12,ptot12,pstat12,LWR12,UPPER12] = process(Twelve_data)

v12 = findvelocity(ptot12,pstat12)

cp12Lower = findcp(v12,LWR12,patm12)
cp12Upper = findcp(v12,UPPER12,patm12)

slopeLower12 = findslope(xc_lower, 0.2)
slopeUpper12 = findslope(xc_upper, 0.2)

[cl12,cn12,ct12] = findcl (cp12Upper, cp12Lower,xc_upper,xc_lower,slopeUpper12,slopeLower12,12*np.pi/180 )

print ('calculated velocity:',v12,'\ncalculated lift coeffficient:',cl12)
```

    calculated velocity: 6.042863588185915
    calculated lift coeffficient: 0.8274457709531795

```python
# Plot the pressure distribution and also plot the CFD distribution. Remember to read in the CFD data that you wrote to file when you did the CFD simulation.
plt.plot(xc_upper,cp12Upper,label='upper')
plt.plot(xc_lower,cp12Lower,label='lower')

CFD12 = np.loadtxt('CFD 12 cp.txt', skiprows=4)
CFD12cp = CFD12[:, 1:]
CFD12position = CFD12[:, 0]*15.873

XFLR12 = pd.read_csv('C:\\Users\\erikv\\Aerodynamics\\Airfoil Lab\\XFLR 12 cp.csv')
xflr12loc = XFLR12.iloc[1:99,0]
xflr12cp = XFLR12.iloc[1:99,1]

plt.plot(CFD12position, CFD12cp, label='CFD')
plt.plot(xflr12loc, xflr12cp,label='xflr',color='purple')
plt.legend(loc='upper right')
plt.axis([-0.1,1,-3.5,1.5])
plt.title('Cp distribution for 12 degrees AoA')
plt.xlabel('location x/c')
plt.ylabel('Pressure coefficient')
plt.savefig('cp 12 degrees.png')

```

# thin airfoil theory

```python
T = Temperature_kelvin
C1 = 1.458e-6
mu = C1*T**(3/2)/(T+111)
Re = 30*rho*0.063/mu

cl = [cl0,cl6,cl12]
CFDcl = [2.4600574e-05,0.47211867, 0.77710977]
xfoilcl = [0,0,0]
alp = [0,6,12]
alpha = []
for i in alp:
    d = i/180*np.pi
    alpha.append(d)

plt.plot(alpha,cl, label='practical')

a,b = np.polyfit(alpha,cl,1)

def f(x):
    f = a*x + b
    return f

x = np.linspace(0,12*np.pi/180,10 )
y = f(x)

def theory(x):
    t = 2*np.pi*x
    return t

Xflr = np.loadtxt('xflr.txt', skiprows=12)
xflra = Xflr[0:12,0]*np.pi/180
xflrcl = Xflr[0:12,1]

plt.plot(xflra,xflrcl, label='xflr',color='purple')
plt.plot(x, theory(x), label = 'thin airfoil theory')
plt.plot(alpha,CFDcl,label='CFD')
plt.plot(x,y, label = 'fit')
print ('lift curve slope: ',a)
plt.legend(loc='upper left')
plt.ylabel('Lift coefficient')
plt.xlabel('Angle of attack (radians)')
plt.savefig('cl - alpha')
print ('\nCl value comparison between experiment, CFD and Xfoil:')
print ('{0:5s} - {1:15s} - {2:15s} - {3:10s}'.format('AoA','     experiment','      CFD','   Xfoil'))
for i in range(3):
    print('{0:5n} - {1:15n} - {2:15n} - {3:5n}'.format(alp[i],cl[i], CFDcl[i],xfoilcl[i]))
print ('\nReynolds Number : ',Re)

```

```python

```

```python

```

Airfoil Lab/Infinite Wing notebook.ipynb


```python
import numpy as np
```

# 1. Human capital accumulation

Consider a worker living in **two periods**, $t \in \{1,2\}$.

In each period she decides whether to **work ($l_t = 1$) or not ($l_t = 0$)**.

She can *not* borrow or save and thus **consumes all of her income** in each period.

If she **works** her **consumption** becomes:

$$c_t = w h_t l_t\,\,\text{if}\,\,l_t=1$$

where $w$ is **the wage rate** and $h_t$ is her **human capital**.

If she does **not work** her consumption becomes:

$$c_t = b\,\,\text{if}\,\,l_t=0$$

where $b$ is the **unemployment benefits**.

Her **utility of consumption** is:

$$ \frac{c_t^{1-\rho}}{1-\rho} $$

Her **disutility of working** is:

$$ \gamma l_t $$

From period 1 to period 2, she **accumulates human capital** according to:

$$ h_2 = h_1 + l_1 +
\begin{cases}
0 & \text{with prob. }0.5 \\
\Delta & \text{with prob. }0.5
\end{cases} \\
$$

where $\Delta$ is a **stochastic experience gain**.

In the **second period** the worker thus solves:

$$
\begin{eqnarray*}
v_{2}(h_{2}) & = &\max_{l_{2}} \frac{c_2^{1-\rho}}{1-\rho} - \gamma l_2
\\ & \text{s.t.} & \\
c_{2}& = & w h_2 l_2 \\
l_{2}& \in &\{0,1\}
\end{eqnarray*}
$$

In the **first period** the worker thus solves:

$$
\begin{eqnarray*}
v_{1}(h_{1}) &=& \max_{l_{1}} \frac{c_1^{1-\rho}}{1-\rho} - \gamma l_1 + \beta\mathbb{E}_{1}\left[v_2(h_2)\right]
\\ & \text{s.t.} & \\
c_1 &=& w h_1 l_1 \\
h_2 &=& h_1 + l_1 + \begin{cases}
0 & \text{with prob. }0.5\\
\Delta & \text{with prob. }0.5
\end{cases}\\
l_{1} &\in& \{0,1\}\\
\end{eqnarray*}
$$

where $\beta$ is the **discount factor** and $\mathbb{E}_{1}\left[v_2(h_2)\right]$ is the **expected value of living in period two**.

The **parameters** of the model are:

```python
rho = 2
beta = 0.96
gamma = 0.1
w = 2
b = 1
Delta = 0.1
```

The **relevant levels of human capital** are:

```python
h_vec = np.linspace(0.1,1.5,100)
```

**Question 1:** Solve the model in period 2 and illustrate the solution (including labor supply as a function of human capital).

**Question 2:** Solve the model in period 1 and illustrate the solution (including labor supply as a function of human capital).

**Question 3:** Will the worker never work if her potential wage income is lower than the unemployment benefits she can get? Explain and illustrate why or why not.

## Question 1.1
Before we start solving the model in period 2, we import the relevant libraries we are going to need throughout this exam project:

```python
# Import libraries
from scipy import optimize,arange
import numpy as np
import ipywidgets as widgets
from ipywidgets import interact, interactive, IntSlider, Layout, interact_manual
from IPython.display import display
from scipy import linalg
from scipy import optimize
import sympy as sm
import matplotlib.pyplot as plt
import pandas as pd
```

Next we will define all the relevant symbols and make sure they are printed nicely:

Now we are ready to set up the relevant functions.

The consumption function in period 2:

```python
# Define the human capital accumulation function in period 2:
# def h2(h1,l1):
#    return h1 + l1 + 0*prob(0.5) or Delta*prob(0.5)
```

```python
# Define the consumption function:
def c(h,w):
    if l == 0:
        c = b
    elif l == 1:
        c = w*h
    return c
```

```python
#Define the utility function:
def utility(c,rho,h,l):
    c(h,l,w)**(1-rho)/(1-rho)
```

```python
# Define the disutility function
def disutility(gamma,l):
    return gamma*l
```

```python
# Define the second period problem for the worker:
def v2(h2,l2,rho,w,gamma):
    utility(rho,l2,w,h2)-disutility(gamma,l2)
```

```python
# Define the first period problem for the worker:
def v1(w,h1,l1,c1,gamma,beta,Delta):

    # a. v2 value if low income
    h2_low = h1 + l1
    v2_low = v2_interp([v2_low])[0]

    #b. v2 value, if high income
    h2_high = h1 + l1 + Delta
    v2_high = v2_interp([v2_high])[0]

    #c. expected value of v2
    v2 = 0.5*v2_low + 0.5*v2_high

    #d. total value
    return utility(rho,l1,w,h1)-disutility(gamma,l)+beta*v2
```

## Herfra er det forsøg på at løse problemmet, som ikke rigtig er lykkes.... :((((((

```python
def solve_period_2(rho,gamma,Delta,w):
    #a. grids
    h2_vec = np.linspace(0.1,1.5,100)
    v2_vec = np.empty(500)
    l2_vec = np.empty(500)

    # b. solve for each m2 in grid
    for i,h2 in enumerate(h2_vec):

        # i. objective
        obj = lambda l2: -v2(l2,h2,rho,w,gamma)

        # ii. initial value (consume half)
        x0 = h2/2

        # iii. optimizer
        result = optimize.minimize_scalar(obj,x0,method='bounded',bounds=[1e-8,h2])

        # iv. save
        v2_vec[i] = -result.fun
        l2_vec[i] = result.x

    return h2_vec,v2_vec,l2_vec

def solve_period_1(rho,beta,w,Delta,v1,v2_interp):

    # a. grids
    h1_vec = np.linspace(0.1,1.5,100)
    v1_vec = np.empty(100)
    l1_vec = np.empty(100)

    # b. solve for each m1 in grid
    for i,h1 in enumerate(h1_vec):

        # i. objective
        obj = lambda l1: -v1(l1,h1,rho,beta,w,Delta,v2_interp)

        # ii. initial guess (consume half)
        x0 = h1*1/2

        # iii. optimize
        result = optimize.minimize_scalar(obj,x0,method='bounded',bounds=[1e-8,h1])

        # iv. save
        v1_vec[i] = -result.fun
        l1_vec[i] = result.x

    return h1_vec,v1_vec,l1_vec
```

```python
import numpy as np
import scipy as sp
from scipy import linalg
from scipy import optimize
from scipy import interpolate
import sympy as sm

%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
```

```python
rho = 2
beta = 0.96
gamma = 0.1
w = 2
b = 1
Delta = 0.1
```

```python
def solve_period_2(rho,w,gamma,Delta):

    # a. grids
    h2_vec = np.linspace(1e-8,5,200)
    l2_vec = np.linspace(1e-8,5,200)
    v2_grid = np.empty((200,200))

    # b. solve for each l2 in grid
    for i,h2 in enumerate(h2_vec):
        for j,v2 in enumerate(v2_vec):

            # i. objective
            obj = lambda l2: -v2(l2,h2,rho,w,gamma)

            # ii. initial value (consume half)
            x0 = h2/2

            # iii. optimizer
            result = optimize.minimize_scalar(obj,x0,method='bounded',bounds=[1e-8,h2])

            # iv. save
            v2_grid[i,j] = -result.fun
            c2_grid[i,j] = result.x

    return h2_vec,v2_vec,l2_grid
```

```python
# a. solve
h2_vec,v2_grid,l2_grid = solve_period_2(rho,w,gamma,Delta)

# b. grids
h2_grid = np.meshgrid(h2_vec,l2_vec,indexing='ij')

# c. main
fig = plt.figure()
ax = fig.add_subplot(1,1,1,projection='3d')
cs = ax.plot_surface(h2_grid,l2_grid,cmap=cm.jet)

# d. add labels
ax.set_xlabel('$m_2$')
ax.set_ylabel('$d_2$')
ax.set_zlabel('$c_2$')

# e. invert xaxis
ax.invert_xaxis()

# f. remove background
ax.xaxis.pane.fill = False
ax.yaxis.pane.fill = False
ax.zaxis.pane.fill = False

# g. add colorbar
fig.colorbar(cs);
```

# 2. AS-AD model

Consider the following **AS-AD model**. The **goods market equilibrium** is given by

$$ y_{t} = -\alpha r_{t} + v_{t} $$

where $y_{t}$ is the **output gap**, $r_{t}$ is the **ex ante real interest** and $v_{t}$ is a **demand disturbance**.

The central bank's **Taylor rule** is

$$ i_{t} = \pi_{t+1}^{e} + h \pi_{t} + b y_{t}$$

where $i_{t}$ is the **nominal interest rate**, $\pi_{t}$ is the **inflation gap**, and $\pi_{t+1}^{e}$ is the **expected inflation gap**.

The **ex ante real interest rate** is given by

$$ r_{t} = i_{t} - \pi_{t+1}^{e} $$

Together, the above implies that the **AD-curve** is

$$ \pi_{t} = \frac{1}{h\alpha}\left[v_{t} - (1+b\alpha)y_{t}\right]$$

Further, assume that the **short-run supply curve (SRAS)** is given by

$$ \pi_{t} = \pi_{t}^{e} + \gamma y_{t} + s_{t}$$

where $s_t$ is a **supply disturbance**.

**Inflation expectations are adaptive** and given by

$$ \pi_{t}^{e} = \phi\pi_{t-1}^{e} + (1-\phi)\pi_{t-1}$$

Together, this implies that the **SRAS-curve** can also be written as

$$ \pi_{t} = \pi_{t-1} + \gamma y_{t} - \phi\gamma y_{t-1} + s_{t} - \phi s_{t-1} $$

The **parameters** of the model are:

```python
par = {}

par['alpha'] = 5.76
par['h'] = 0.5
par['b'] = 0.5
par['phi'] = 0
par['gamma'] = 0.075
```

**Question 1:** Use the ``sympy`` module to solve for the equilibrium values of output, $y_t$, and inflation, $\pi_t$, (where AD = SRAS) given the parameters ($\alpha$, $h$, $b$, $\alpha$, $\gamma$) and $y_{t-1}$ , $\pi_{t-1}$, $v_t$, $s_t$, and $s_{t-1}$.

**Question 2:** Find and illustrate the equilibrium when $y_{t-1} = \pi_{t-1} = v_t = s_t = s_{t-1} = 0$. Illustrate how the equilibrium changes when instead $v_t = 0.1$.

**Persistent disturbances:** Now, additionaly, assume that both the demand and the supply disturbances are AR(1) processes

$$ v_{t} = \delta v_{t-1} + x_{t} $$
$$ s_{t} = \omega s_{t-1} + c_{t} $$

where $x_{t}$ is a **demand shock**, and $c_t$ is a **supply shock**. The **autoregressive parameters** are:

```python
par['delta'] = 0.80
par['omega'] = 0.15
```

**Question 3:** Starting from $y_{-1} = \pi_{-1} = s_{-1} = 0$, how does the economy evolve for $x_0 = 0.1$, $x_t = 0, \forall t > 0$ and $c_t = 0, \forall t \geq 0$?

**Stochastic shocks:** Now, additionally, assume that $x_t$ and $c_t$ are stochastic and normally distributed

$$ x_{t}\sim\mathcal{N}(0,\sigma_{x}^{2}) $$
$$ c_{t}\sim\mathcal{N}(0,\sigma_{c}^{2}) $$

The **standard deviations of the shocks** are:

```python
par['sigma_x'] = 3.492
par['sigma_c'] = 0.2
```

**Question 4:** Simulate the AS-AD model for 1,000 periods. Calculate the following five statistics:

1. Variance of $y_t$, $var(y_t)$
2. Variance of $\pi_t$, $var(\pi_t)$
3. Correlation between $y_t$ and $\pi_t$, $corr(y_t,\pi_t)$
4. Auto-correlation between $y_t$ and $y_{t-1}$, $corr(y_t,y_{t-1})$
5. Auto-correlation between $\pi_t$ and $\pi_{t-1}$, $corr(\pi_t,\pi_{t-1})$

**Question 5:** Plot how the correlation between $y_t$ and $\pi_t$ changes with $\phi$. Use a numerical optimizer or root finder to choose $\phi\in(0,1)$ such that the simulated correlation between $y_t$ and $\pi_t$ comes close to 0.31.

**Quesiton 6:** Use a numerical optimizer to choose $\sigma_x>0$, $\sigma_c>0$ and $\phi\in(0,1)$ to make the simulated statistics as close as possible to US business cycle data where:

1. $var(y_t) = 1.64$
2. $var(\pi_t) = 0.21$
3. $corr(y_t,\pi_t) = 0.31$
4. $corr(y_t,y_{t-1}) = 0.84$
5. $corr(\pi_t,\pi_{t-1}) = 0.48$

# 3. Exchange economy

Consider an **exchange economy** with

1. 3 goods, $(x_1,x_2,x_3)$
2. $N$ consumers indexed by \\( j \in \{1,2,\dots,N\} \\)
3. Preferences are Cobb-Douglas with log-normally distributed coefficients

    $$ \begin{eqnarray*}
    u^{j}(x_{1},x_{2},x_{3}) &=&
    \left(x_{1}^{\beta_{1}^{j}}x_{2}^{\beta_{2}^{j}}x_{3}^{\beta_{3}^{j}}\right)^{\gamma}\\
     &  & \,\,\,\beta_{i}^{j}=\frac{\alpha_{i}^{j}}{\alpha_{1}^{j}+\alpha_{2}^{j}+\alpha_{3}^{j}} \\
     &  & \,\,\,\boldsymbol{\alpha}^{j}=(\alpha_{1}^{j},\alpha_{2}^{j},\alpha_{3}^{j}) \\
     &  & \,\,\,\log(\boldsymbol{\alpha}^j) \sim \mathcal{N}(\mu,\Sigma) \\
    \end{eqnarray*} $$

4. Endowments are exponentially distributed,

$$
\begin{eqnarray*}
\boldsymbol{e}^{j} &=& (e_{1}^{j},e_{2}^{j},e_{3}^{j}) \\
 &  & e_i^j \sim f, f(z;\zeta) =  1/\zeta \exp(-z/\zeta)
\end{eqnarray*}
$$

Let $p_3 = 1$ be the **numeraire**. The implied **demand functions** are:

$$
\begin{eqnarray*}
x_{i}^{\star j}(p_{1},p_{2},\boldsymbol{e}^{j})&=&\beta^{j}_i\frac{I^j}{p_{i}} \\
\end{eqnarray*}
$$

where consumer $j$'s income is

$$I^j = p_1 e_1^j + p_2 e_2^j +p_3 e_3^j$$

The **parameters** and **random preferences and endowments** are given by:

```python
# a. parameters
N = 50000
mu = np.array([3,2,1])
Sigma = np.array([[0.25, 0, 0], [0, 0.25, 0], [0, 0, 0.25]])
gamma = 0.8
zeta = 1

# b. random draws
seed = 1986
np.random.seed(seed)

# preferences
alphas = np.exp(np.random.multivariate_normal(mu, Sigma, size=N))
betas = alphas/np.reshape(np.sum(alphas,axis=1),(N,1))

# endowments
e1 = np.random.exponential(zeta,size=N)
e2 = np.random.exponential(zeta,size=N)
e3 = np.random.exponential(zeta,size=N)
```

**Question 1:** Plot the histograms of the budget shares for each good across agents.

Consider the **excess demand functions:**

$$ z_i(p_1,p_2) = \sum_{j=1}^N x_{i}^{\star j}(p_{1},p_{2},\boldsymbol{e}^{j}) - e_i^j$$

**Question 2:** Plot the excess demand functions.

**Quesiton 3:** Find the Walras-equilibrium prices, $(p_1,p_2)$, where both excess demands are (approximately) zero, e.g. by using the following tâtonnement process:

1. Guess on $p_1 > 0$, $p_2 > 0$ and choose tolerance $\epsilon > 0$ and adjustment aggressivity parameter, $\kappa > 0$.
2. Calculate $z_1(p_1,p_2)$ and $z_2(p_1,p_2)$.
3. If $|z_1| < \epsilon$ and $|z_2| < \epsilon$ then stop.
4. Else set $p_1 = p_1 + \kappa \frac{z_1}{N}$ and $p_2 = p_2 + \kappa \frac{z_2}{N}$ and return to step 2.

**Question 4:** Plot the distribution of utility in the Walras-equilibrium and calculate its mean and variance.

**Question 5:** Find the Walras-equilibrium prices if instead all endowments were distributed equally. Discuss the implied changes in the distribution of utility. Does the value of $\gamma$ play a role for your conclusions?


2019年度
線形代数　I　講座資料

資料番号　No.2

### [2]ベクトルの内積

####  ベクトルの内積(スカラー積)

ベクトルの $\boldsymbol{a},\boldsymbol{b}$が$\boldsymbol{O}$でないとき、ベクトルの始点を同じに取り $\boldsymbol{a},\boldsymbol{b}$のなす角を$\theta$とするとき

fig-2-0.png

$ \boldsymbol{a}\cdot \boldsymbol{b}= |\boldsymbol{a}||\boldsymbol{b}|cos\theta$を $\boldsymbol{a},\boldsymbol{b}$の内積をいう　 $0^\circ \leqq \theta \leqq 180^\circ $

fig-2-1.png
fig-2-2.png
fig-2-3.png

ベクトルが成分の時に表示される時の内積の計算

$ \boldsymbol{a}= (a_1, a_2 ), \boldsymbol{b}= (b_1, b_2 )$の時

　$ \boldsymbol{a}\cdot \boldsymbol{b}= a_1 b_1 + a_2 b_2 $

成分が多くある時には、

$ \boldsymbol{a}= (a_1, a_2 ,a_3,\ldots ), \boldsymbol{b}= (b_1, b_2 ,b_3,\ldots )$の時

$ \boldsymbol{a}\cdot \boldsymbol{b}= a_1 b_1 + a_2 b_2 + a_3 b_3 + \ldots $

内積の性質

(1)　$ \boldsymbol{a}\cdot \boldsymbol{b}=  \boldsymbol{b}\cdot \boldsymbol{a} $

(2)　$\boldsymbol{a}\cdot( \boldsymbol{b}+ \boldsymbol{c} )= \boldsymbol{a}\cdot \boldsymbol{b}+\boldsymbol{a}\cdot\boldsymbol{c} $

　　$(\boldsymbol{a}+ \boldsymbol{b}) \cdot \boldsymbol{c} = \boldsymbol{a}\cdot \boldsymbol{c}+\boldsymbol{b}\cdot\boldsymbol{c} $

(3)　$(k\boldsymbol{a}) \cdot\boldsymbol{b}=k (\boldsymbol{a} \cdot\boldsymbol{b})$,
　　　$\boldsymbol{a} \cdot (k\boldsymbol{b})=k (\boldsymbol{a} \cdot\boldsymbol{b}) $

(4)　$\boldsymbol{a}\cdot \boldsymbol{a} = |\boldsymbol{a}|^2 $

内積の式を変形して見ると
$$
cos \theta= \frac{  \boldsymbol{a}\cdot \boldsymbol{b} }{  |\boldsymbol{a}||\boldsymbol{b}| }
$$
と表せる

直交条件

ベクトルの $\boldsymbol{a},\boldsymbol{b}$が$\boldsymbol{O}$でなければ

$ \boldsymbol{a},\boldsymbol{b}$ が直交する $\Longleftrightarrow $  $\boldsymbol{a}\cdot \boldsymbol{b}=0 $

ベクトルの大きさの関係と三角不等式について

$|\boldsymbol{a} \cdot\boldsymbol{b}|\leqq  |\boldsymbol{a}||\boldsymbol{b}| $

$|\boldsymbol{a}+ \boldsymbol{b}|\leqq  |\boldsymbol{a}| + |\boldsymbol{b}| $

$|\boldsymbol{a}- \boldsymbol{b}|\geqq  |\boldsymbol{a}| - |\boldsymbol{b}| $

$|\boldsymbol{a}- \boldsymbol{c}|\leqq  |\boldsymbol{a}- \boldsymbol{b}|+  |\boldsymbol{b}- \boldsymbol{c}|$

```python
from sympy import *
init_printing()
#init_session()
```

```python
import numpy as np
from matplotlib import pyplot
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
```

```python
fig = plt.figure(figsize=(4,4))
ax = fig.add_subplot(111)

a1x=4 ;a1y=5 ;a2x=6 ;a2y=2

a1 = mpatches.Arrow(x=0,y=0,dx=a1x,dy= a1y,width=1,color='red' )
a2 = mpatches.Arrow(x=0,y=0,dx=a2x,dy= a2y,width=1,color='blue' )
ax.set_xlim([0, 10])
ax.set_ylim([0, 10])
ax.add_patch(a1)
ax.add_patch(a2)
ax.text(a1x,a1y,'a1',size=20)
ax.text(a2x,a2y,'a2',size=20)
ax.grid(linestyle='-')
plt.show()
```

```python
a, b,a1,a2,b1,b2 = symbols('a b a1 a2 b1 b2')
a = Matrix([a1, a2])
b = Matrix([b1, b2])
# a.T * b　　　　　　　　# a とｂの内積を計算している
a.dot(b)                 # a とｂの内積を計算している
```

```python
# ベクトル　a =(2,5) ,b=(6,5) での内積計算の例

a, b,a1,a2,b1,b2 = symbols('a b a1 a2 b1 b2')
a = Matrix([2, 5])
b = Matrix([6, 2])
# a.T * b　　　　　　# a とｂの内積を計算している
a.dot(b)             # a とｂの内積を計算している
```

```python
# 例題　１．３ （1）
a, b,c,t = symbols('a b c t')
a = Matrix([3, 1])
b = Matrix([1, 2])
c = Matrix([t-6, t**2])
#  (a.T * b)/(a.norm() * b.norm())
a.dot(b)/(a.norm() * b.norm())   # a ・ｂ／（|a||b|）を計算している

```

```python
# 例題　１．３ （2）のための式
a.dot(c)
```

```python
# 例題　１．３ （2）上の式=0として、ｔについて解くと
solve(a.dot(c) ,0,t)
```


# Multigrid examples

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

```python
from __future__ import print_function

import numpy as np

import mesh.boundary as bnd
import mesh.patch as patch
import multigrid.MG as MG
```

## Constant-coefficent Poisson equation

We want to solve

$$\phi_{xx} + \phi_{yy} = -2[(1-6x^2)y^2(1-y^2) + (1-6y^2)x^2(1-x^2)]$$

on

$$[0,1]\times [0,1]$$

with homogeneous Dirichlet boundary conditions (this example comes from "A Multigrid Tutorial").

This has the analytic solution
$$u(x,y) = (x^2 - x^4)(y^4 - y^2)$$

We start by setting up a multigrid object--this needs to know the number of zones our problem is defined on

```python
nx = ny = 256
mg = MG.CellCenterMG2d(nx, ny,
                       xl_BC_type="dirichlet", xr_BC_type="dirichlet",
                       yl_BC_type="dirichlet", yr_BC_type="dirichlet", verbose=1)
```

    cc data: nx = 2, ny = 2, ng = 1
             nvars = 3
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet

    cc data: nx = 4, ny = 4, ng = 1
             nvars = 3
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet

    cc data: nx = 8, ny = 8, ng = 1
             nvars = 3
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet

    cc data: nx = 16, ny = 16, ng = 1
             nvars = 3
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet

    cc data: nx = 32, ny = 32, ng = 1
             nvars = 3
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet

    cc data: nx = 64, ny = 64, ng = 1
             nvars = 3
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet

    cc data: nx = 128, ny = 128, ng = 1
             nvars = 3
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet

    cc data: nx = 256, ny = 256, ng = 1
             nvars = 3
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet

Next, we initialize the RHS.  To make life easier, the `CellCenterMG2d` object has the coordinates of the solution grid (including ghost cells) as `mg.x2d` and `mg.y2d` (these are two-dimensional arrays).

```python
def rhs(x, y):
    return -2.0*((1.0-6.0*x**2)*y**2*(1.0-y**2) + (1.0-6.0*y**2)*x**2*(1.0-x**2))

mg.init_RHS(rhs(mg.x2d, mg.y2d))
```

    Source norm =  1.09751581367

The last setup step is to initialize the solution--this is the starting point for the solve.  Usually we just want to start with all zeros, so we use the `init_zeros()` method

```python
mg.init_zeros()
```

we can now solve -- there are actually two different techniques we can do here.  We can just do pure smoothing on the solution grid using `mg.smooth(mg.nlevels-1, N)`, where `N` is the number of smoothing iterations.  To get the solution `N` will need to be large and this will take a long time.

Multigrid accelerates the smoothing.  We can do a V-cycle multigrid solution using `mg.solve()`

```python
mg.solve()
```

    source norm =  1.09751581367
    <<< beginning V-cycle (cycle 1) >>>

      level: 7, grid: 256 x 256
      before G-S, residual L2: 1.097515813669473
      after G-S, residual L2: 1.502308451578657

      level: 6, grid: 128 x 128
      before G-S, residual L2: 1.0616243965458263
      after G-S, residual L2: 1.4321452257629033

      level: 5, grid: 64 x 64
      before G-S, residual L2: 1.011366277976364
      after G-S, residual L2: 1.281872470375375

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.903531158162907
      after G-S, residual L2: 0.9607576999783505

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.6736112182020367
      after G-S, residual L2: 0.4439774050299674

      level: 2, grid: 8 x 8
      before G-S, residual L2: 0.30721142286171554
      after G-S, residual L2: 0.0727215591269748

      level: 1, grid: 4 x 4
      before G-S, residual L2: 0.04841813458618458
      after G-S, residual L2: 3.9610700301811246e-05

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 3.925006722484123e-05
      after G-S, residual L2: 1.0370099820862674e-09

      level: 2, grid: 8 x 8
      before G-S, residual L2: 0.07010129273961899
      after G-S, residual L2: 0.0008815704830693547

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.4307377377402105
      after G-S, residual L2: 0.007174899576794818

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.911086486792154
      after G-S, residual L2: 0.01618756602227813

      level: 5, grid: 64 x 64
      before G-S, residual L2: 1.1945438349788615
      after G-S, residual L2: 0.022021327892004925

      level: 6, grid: 128 x 128
      before G-S, residual L2: 1.313456560108626
      after G-S, residual L2: 0.02518650395173617

      level: 7, grid: 256 x 256
      before G-S, residual L2: 1.3618314516335004
      after G-S, residual L2: 0.026870007568672097

    cycle 1: relative err = 0.999999999999964, residual err = 0.02448256984911586

    <<< beginning V-cycle (cycle 2) >>>

      level: 7, grid: 256 x 256
      before G-S, residual L2: 0.026870007568672097
      after G-S, residual L2: 0.025790216249923552

      level: 6, grid: 128 x 128
      before G-S, residual L2: 0.018218080204017304
      after G-S, residual L2: 0.023654310121915274

      level: 5, grid: 64 x 64
      before G-S, residual L2: 0.01669077991582338
      after G-S, residual L2: 0.01977335201785163

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.013922595404814862
      after G-S, residual L2: 0.013577568890182053

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.009518306167970536
      after G-S, residual L2: 0.006115159484497302

      level: 2, grid: 8 x 8
      before G-S, residual L2: 0.004244630812032651
      after G-S, residual L2: 0.0010674120586864006

      level: 1, grid: 4 x 4
      before G-S, residual L2: 0.0007108144252738053
      after G-S, residual L2: 5.818246254772703e-07

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 5.765281065294632e-07
      after G-S, residual L2: 1.5231212503339452e-11

      level: 2, grid: 8 x 8
      before G-S, residual L2: 0.0010291471590693868
      after G-S, residual L2: 1.2950948742201083e-05

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.006239446983842889
      after G-S, residual L2: 0.00010483463130232172

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.014573363314854
      after G-S, residual L2: 0.00026233988398787004

      level: 5, grid: 64 x 64
      before G-S, residual L2: 0.021564270263952755
      after G-S, residual L2: 0.0003944827058086955

      level: 6, grid: 128 x 128
      before G-S, residual L2: 0.02579092712136628
      after G-S, residual L2: 0.00048636495715121916

      level: 7, grid: 256 x 256
      before G-S, residual L2: 0.028051324215592862
      after G-S, residual L2: 0.0005440874957950154

    cycle 2: relative err = 13.739483825281054, residual err = 0.0004957445615074047

    <<< beginning V-cycle (cycle 3) >>>

      level: 7, grid: 256 x 256
      before G-S, residual L2: 0.0005440874957950154
      after G-S, residual L2: 0.0005095844930046698

      level: 6, grid: 128 x 128
      before G-S, residual L2: 0.0003597879816772893
      after G-S, residual L2: 0.00044648485218937167

      level: 5, grid: 64 x 64
      before G-S, residual L2: 0.0003147892995472901
      after G-S, residual L2: 0.0003492541721056348

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.0002457276904804801
      after G-S, residual L2: 0.00022232862524233384

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.0001558932199490972
      after G-S, residual L2: 9.511093023364078e-05

      level: 2, grid: 8 x 8
      before G-S, residual L2: 6.616899520585456e-05
      after G-S, residual L2: 1.711006102346096e-05

      level: 1, grid: 4 x 4
      before G-S, residual L2: 1.139522901981679e-05
      after G-S, residual L2: 9.33004809910226e-09

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 9.245125097272049e-09
      after G-S, residual L2: 2.442311694447821e-13

      level: 2, grid: 8 x 8
      before G-S, residual L2: 1.64991725637487e-05
      after G-S, residual L2: 2.0771258971860784e-07

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.00010097720436460624
      after G-S, residual L2: 1.7241727900979902e-06

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.0002575410544503153
      after G-S, residual L2: 4.766282851613449e-06

      level: 5, grid: 64 x 64
      before G-S, residual L2: 0.00041133882050328275
      after G-S, residual L2: 7.600616845344458e-06

      level: 6, grid: 128 x 128
      before G-S, residual L2: 0.0005232809692242086
      after G-S, residual L2: 9.860758095018993e-06

      level: 7, grid: 256 x 256
      before G-S, residual L2: 0.0005945070122423073
      after G-S, residual L2: 1.1466134915427874e-05

    cycle 3: relative err = 34.347638624909216, residual err = 1.0447352805871284e-05

    <<< beginning V-cycle (cycle 4) >>>

      level: 7, grid: 256 x 256
      before G-S, residual L2: 1.1466134915427874e-05
      after G-S, residual L2: 1.054466722279011e-05

      level: 6, grid: 128 x 128
      before G-S, residual L2: 7.442814693866286e-06
      after G-S, residual L2: 8.955050475722099e-06

      level: 5, grid: 64 x 64
      before G-S, residual L2: 6.311313968968047e-06
      after G-S, residual L2: 6.734553609148436e-06

      level: 4, grid: 32 x 32
      before G-S, residual L2: 4.737984987500691e-06
      after G-S, residual L2: 4.091799997658277e-06

      level: 3, grid: 16 x 16
      before G-S, residual L2: 2.871028473858937e-06
      after G-S, residual L2: 1.6319551993366253e-06

      level: 2, grid: 8 x 8
      before G-S, residual L2: 1.1372178077508109e-06
      after G-S, residual L2: 2.961040430099916e-07

      level: 1, grid: 4 x 4
      before G-S, residual L2: 1.9721864323458624e-07
      after G-S, residual L2: 1.61503943872384e-10

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 1.6003411195777404e-10
      after G-S, residual L2: 4.2274326344473505e-15

      level: 2, grid: 8 x 8
      before G-S, residual L2: 2.855691101825338e-07
      after G-S, residual L2: 3.5961118754371857e-09

      level: 3, grid: 16 x 16
      before G-S, residual L2: 1.7893831203170535e-06
      after G-S, residual L2: 3.1136282101831173e-08

      level: 4, grid: 32 x 32
      before G-S, residual L2: 4.97129807196115e-06
      after G-S, residual L2: 9.544819739422644e-08

      level: 5, grid: 64 x 64
      before G-S, residual L2: 8.281644276572538e-06
      after G-S, residual L2: 1.56637783149839e-07

      level: 6, grid: 128 x 128
      before G-S, residual L2: 1.0888850082357996e-05
      after G-S, residual L2: 2.0777271327080248e-07

      level: 7, grid: 256 x 256
      before G-S, residual L2: 1.2717522622400765e-05
      after G-S, residual L2: 2.464531349025277e-07

    cycle 4: relative err = 0.17409776671446628, residual err = 2.24555429482631e-07

    <<< beginning V-cycle (cycle 5) >>>

      level: 7, grid: 256 x 256
      before G-S, residual L2: 2.464531349025277e-07
      after G-S, residual L2: 2.2491138140311698e-07

      level: 6, grid: 128 x 128
      before G-S, residual L2: 1.5874562191875262e-07
      after G-S, residual L2: 1.886249099391391e-07

      level: 5, grid: 64 x 64
      before G-S, residual L2: 1.3294481979637655e-07
      after G-S, residual L2: 1.397710191717015e-07

      level: 4, grid: 32 x 32
      before G-S, residual L2: 9.836928907527788e-08
      after G-S, residual L2: 8.269030961692836e-08

      level: 3, grid: 16 x 16
      before G-S, residual L2: 5.8062531341283565e-08
      after G-S, residual L2: 3.034725896415429e-08

      level: 2, grid: 8 x 8
      before G-S, residual L2: 2.116912379336852e-08
      after G-S, residual L2: 5.467519592468213e-09

      level: 1, grid: 4 x 4
      before G-S, residual L2: 3.6418116003284676e-09
      after G-S, residual L2: 2.982625229812215e-12

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 2.955484162036181e-12
      after G-S, residual L2: 7.806739482450516e-17

      level: 2, grid: 8 x 8
      before G-S, residual L2: 5.273610709946236e-09
      after G-S, residual L2: 6.642323465658688e-11

      level: 3, grid: 16 x 16
      before G-S, residual L2: 3.4146989205844565e-08
      after G-S, residual L2: 6.052228076583688e-10

      level: 4, grid: 32 x 32
      before G-S, residual L2: 1.031248597196911e-07
      after G-S, residual L2: 2.0541497445308587e-09

      level: 5, grid: 64 x 64
      before G-S, residual L2: 1.7585349306604133e-07
      after G-S, residual L2: 3.421022608879089e-09

      level: 6, grid: 128 x 128
      before G-S, residual L2: 2.3383756442516674e-07
      after G-S, residual L2: 4.552170797983864e-09

      level: 7, grid: 256 x 256
      before G-S, residual L2: 2.7592842790687426e-07
      after G-S, residual L2: 5.41488950707315e-09

    cycle 5: relative err = 0.005391244339065405, residual err = 4.933769007818501e-09

    <<< beginning V-cycle (cycle 6) >>>

      level: 7, grid: 256 x 256
      before G-S, residual L2: 5.41488950707315e-09
      after G-S, residual L2: 4.948141362729419e-09

      level: 6, grid: 128 x 128
      before G-S, residual L2: 3.4929583962703016e-09
      after G-S, residual L2: 4.154445183511443e-09

      level: 5, grid: 64 x 64
      before G-S, residual L2: 2.9288841397931397e-09
      after G-S, residual L2: 3.074779198797186e-09

      level: 4, grid: 32 x 32
      before G-S, residual L2: 2.164991235492634e-09
      after G-S, residual L2: 1.788028730183651e-09

      level: 3, grid: 16 x 16
      before G-S, residual L2: 1.2562223343389894e-09
      after G-S, residual L2: 6.021983813990021e-10

      level: 2, grid: 8 x 8
      before G-S, residual L2: 4.2028073688787063e-10
      after G-S, residual L2: 1.0655724637281067e-10

      level: 1, grid: 4 x 4
      before G-S, residual L2: 7.097871736854444e-11
      after G-S, residual L2: 5.813506543301849e-14

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 5.760611936011378e-14
      after G-S, residual L2: 1.521555112430923e-18

      level: 2, grid: 8 x 8
      before G-S, residual L2: 1.027891920456506e-10
      after G-S, residual L2: 1.294879454701896e-12

      level: 3, grid: 16 x 16
      before G-S, residual L2: 6.914011940773812e-10
      after G-S, residual L2: 1.2453691230551983e-11

      level: 4, grid: 32 x 32
      before G-S, residual L2: 2.2570491487662195e-09
      after G-S, residual L2: 4.639035392364569e-11

      level: 5, grid: 64 x 64
      before G-S, residual L2: 3.908967396962745e-09
      after G-S, residual L2: 7.803740782474827e-11

      level: 6, grid: 128 x 128
      before G-S, residual L2: 5.196394306272565e-09
      after G-S, residual L2: 1.033274523100204e-10

      level: 7, grid: 256 x 256
      before G-S, residual L2: 6.117636729623554e-09
      after G-S, residual L2: 1.2199402602477584e-10

    cycle 6: relative err = 7.51413991329132e-05, residual err = 1.111546863428753e-10

    <<< beginning V-cycle (cycle 7) >>>

      level: 7, grid: 256 x 256
      before G-S, residual L2: 1.2199402602477584e-10
      after G-S, residual L2: 1.121992266879251e-10

      level: 6, grid: 128 x 128
      before G-S, residual L2: 7.921861122082639e-11
      after G-S, residual L2: 9.493449600138316e-11

      level: 5, grid: 64 x 64
      before G-S, residual L2: 6.694993398453784e-11
      after G-S, residual L2: 7.050995614737483e-11

      level: 4, grid: 32 x 32
      before G-S, residual L2: 4.9666563586565975e-11
      after G-S, residual L2: 4.045094776680348e-11

      level: 3, grid: 16 x 16
      before G-S, residual L2: 2.843147343834713e-11
      after G-S, residual L2: 1.2576313722677801e-11

      level: 2, grid: 8 x 8
      before G-S, residual L2: 8.777954081387978e-12
      after G-S, residual L2: 2.170559196862902e-12

      level: 1, grid: 4 x 4
      before G-S, residual L2: 1.445876195415056e-12
      after G-S, residual L2: 1.1842925278593641e-15

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 1.1735184729034125e-15
      after G-S, residual L2: 3.0994757710835167e-20

      level: 2, grid: 8 x 8
      before G-S, residual L2: 2.094012660676073e-12
      after G-S, residual L2: 2.6382579574150587e-14

      level: 3, grid: 16 x 16
      before G-S, residual L2: 1.466147487151147e-11
      after G-S, residual L2: 2.6760553592700965e-13

      level: 4, grid: 32 x 32
      before G-S, residual L2: 5.130705216489902e-11
      after G-S, residual L2: 1.0810419626613159e-12

      level: 5, grid: 64 x 64
      before G-S, residual L2: 9.001551103280705e-11
      after G-S, residual L2: 1.8342879121275396e-12

      level: 6, grid: 128 x 128
      before G-S, residual L2: 1.1914921193827463e-10
      after G-S, residual L2: 2.4124327865487605e-12

      level: 7, grid: 256 x 256
      before G-S, residual L2: 1.3907209384461257e-10
      after G-S, residual L2: 2.8429898342353533e-12

    cycle 7: relative err = 7.062255558417692e-07, residual err = 2.590386214782638e-12

We can access the solution on the finest grid using `get_solution()`

```python
phi = mg.get_solution()
```

```python
plt.imshow(np.transpose(phi.v()), origin="lower")
```

we can also get the gradient of the solution

```python
gx, gy = mg.get_solution_gradient()
```

```python
plt.subplot(121)
plt.imshow(np.transpose(gx.v()), origin="lower")
plt.subplot(122)
plt.imshow(np.transpose(gy.v()), origin="lower")
```

## General linear elliptic equation

The `GeneralMG2d` class implements support for a general elliptic equation of the form:
$$\alpha \phi + \nabla \cdot (\beta \nabla \phi) + \gamma \cdot \nabla \phi = f$$

with inhomogeneous boundary condtions.

It subclasses the `CellCenterMG2d` class, and the basic interface is the same

We will solve the above with
\begin{align}
\alpha &= 10 \\
\beta &= xy + 1 \\
\gamma &= \hat{x} + \hat{y}
\end{align}
and
\begin{align}
f = &-\frac{\pi}{2}(x + 1)\sin\left(\frac{\pi y}{2}\right) \cos\left(\frac{\pi x}{2}\right ) \\
    &-\frac{\pi}{2}(y + 1)\sin\left(\frac{\pi x}{2}\right) \cos\left(\frac{\pi y}{2}\right ) \\
    &+\left(\frac{-\pi^2 (xy+1)}{2} + 10\right) \cos\left(\frac{\pi x}{2}\right) \cos\left(\frac{\pi y}{2}\right)
\end{align}
on $[0, 1] \times [0,1]$ with boundary conditions:
\begin{align}
\phi(x=0) &= \cos(\pi y/2) \\
\phi(x=1) &= 0 \\
\phi(y=0) &= \cos(\pi x/2) \\
\phi(y=1) &= 0
\end{align}

This has the exact solution:
$$\phi = \cos(\pi x/2) \cos(\pi y/2)$$

```python
import multigrid.general_MG as gMG
```

For reference, we'll define a function providing the analytic solution

```python
def true(x,y):
    return np.cos(np.pi*x/2.0)*np.cos(np.pi*y/2.0)
```

Now the coefficents--note that since $\gamma$ is a vector, we have a different function for each component

```python
def alpha(x,y):
    return 10.0*np.ones_like(x)

def beta(x,y):
    return x*y + 1.0

def gamma_x(x,y):
    return np.ones_like(x)

def gamma_y(x,y):
    return np.ones_like(x)
```

and the righthand side function

```python
def f(x,y):
    return -0.5*np.pi*(x + 1.0)*np.sin(np.pi*y/2.0)*np.cos(np.pi*x/2.0) - \
            0.5*np.pi*(y + 1.0)*np.sin(np.pi*x/2.0)*np.cos(np.pi*y/2.0) + \
            (-np.pi**2*(x*y+1.0)/2.0 + 10.0)*np.cos(np.pi*x/2.0)*np.cos(np.pi*y/2.0)
```

Our inhomogeneous boundary conditions require a function that can be evaluated on the boundary to give the value

```python
def xl_func(y):
    return np.cos(np.pi*y/2.0)

def yl_func(x):
    return np.cos(np.pi*x/2.0)
```

Now we can setup our grid object and the coefficients, which are stored as a `CellCenter2d` object.  Note, the coefficients do not need to have the same boundary conditions as $\phi$ (and for real problems, they may not).  The one that matters the most is $\beta$, since that will need to be averaged to the edges of the domain, so the boundary conditions on the coefficients are important.

Here we use Neumann boundary conditions

```python
import mesh.patch as patch

nx = ny = 128

g = patch.Grid2d(nx, ny, ng=1)
d = patch.CellCenterData2d(g)

bc_c = bnd.BC(xlb="neumann", xrb="neumann",
              ylb="neumann", yrb="neumann")

d.register_var("alpha", bc_c)
d.register_var("beta", bc_c)
d.register_var("gamma_x", bc_c)
d.register_var("gamma_y", bc_c)
d.create()

a = d.get_var("alpha")
a[:,:] = alpha(g.x2d, g.y2d)

b = d.get_var("beta")
b[:,:] = beta(g.x2d, g.y2d)

gx = d.get_var("gamma_x")
gx[:,:] = gamma_x(g.x2d, g.y2d)

gy = d.get_var("gamma_y")
gy[:,:] = gamma_y(g.x2d, g.y2d)
```

Now we can setup the multigrid object

```python
a = gMG.GeneralMG2d(nx, ny,
                    xl_BC_type="dirichlet", yl_BC_type="dirichlet",
                    xr_BC_type="dirichlet", yr_BC_type="dirichlet",
                    xl_BC=xl_func,
                    yl_BC=yl_func,
                    coeffs=d,
                    verbose=1, vis=0, true_function=true)
```

    cc data: nx = 2, ny = 2, ng = 1
             nvars = 7
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
               alpha: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
                beta: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_x: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_y: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann

    cc data: nx = 4, ny = 4, ng = 1
             nvars = 7
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
               alpha: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
                beta: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_x: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_y: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann

    cc data: nx = 8, ny = 8, ng = 1
             nvars = 7
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
               alpha: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
                beta: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_x: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_y: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann

    cc data: nx = 16, ny = 16, ng = 1
             nvars = 7
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
               alpha: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
                beta: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_x: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_y: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann

    cc data: nx = 32, ny = 32, ng = 1
             nvars = 7
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
               alpha: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
                beta: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_x: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_y: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann

    cc data: nx = 64, ny = 64, ng = 1
             nvars = 7
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
               alpha: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
                beta: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_x: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_y: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann

    cc data: nx = 128, ny = 128, ng = 1
             nvars = 7
             variables:
                   v: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   f: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
                   r: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: dirichlet    +x: dirichlet    -y: dirichlet    +y: dirichlet
               alpha: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
                beta: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_x: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann
             gamma_y: min:    0.0000000000    max:    0.0000000000
                      BCs: -x: neumann      +x: neumann      -y: neumann      +y: neumann

just as before, we specify the righthand side and initialize the solution

```python
a.init_zeros()
a.init_RHS(f(a.x2d, a.y2d))
```

    Source norm =  1.77518149234

and we can solve it

```python
a.solve(rtol=1.e-10)
```

    source norm =  1.77518149234
    <<< beginning V-cycle (cycle 1) >>>

      level: 6, grid: 128 x 128
      before G-S, residual L2: 1.775181492337501
      after G-S, residual L2: 188.9332667507471

      level: 5, grid: 64 x 64
      before G-S, residual L2: 129.93801550392874
      after G-S, residual L2: 56.28708770794368

      level: 4, grid: 32 x 32
      before G-S, residual L2: 38.88692621665778
      after G-S, residual L2: 18.722754099081875

      level: 3, grid: 16 x 16
      before G-S, residual L2: 12.92606814051491
      after G-S, residual L2: 6.741858401611561

      level: 2, grid: 8 x 8
      before G-S, residual L2: 4.646478379380238
      after G-S, residual L2: 2.065126154146587

      level: 1, grid: 4 x 4
      before G-S, residual L2: 1.3745334259197384
      after G-S, residual L2: 0.02244519721859215

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 0.031252520872477096
      after G-S, residual L2: 8.232822131685586e-05

      level: 2, grid: 8 x 8
      before G-S, residual L2: 2.8059768631102893
      after G-S, residual L2: 0.07481536016730024

      level: 3, grid: 16 x 16
      before G-S, residual L2: 8.772402436595382
      after G-S, residual L2: 0.24361942694526875

      level: 4, grid: 32 x 32
      before G-S, residual L2: 19.591011324351037
      after G-S, residual L2: 0.5448263647958976

      level: 5, grid: 64 x 64
      before G-S, residual L2: 50.4641088994847
      after G-S, residual L2: 1.3597629173942398

      level: 6, grid: 128 x 128
      before G-S, residual L2: 160.2131163846867
      after G-S, residual L2: 4.125142056231141

    cycle 1: relative err = 0.9999999999999981, residual err = 2.3237860883730193

    <<< beginning V-cycle (cycle 2) >>>

      level: 6, grid: 128 x 128
      before G-S, residual L2: 4.125142056231141
      after G-S, residual L2: 2.4247311846143957

      level: 5, grid: 64 x 64
      before G-S, residual L2: 1.6915411385849393
      after G-S, residual L2: 1.0486241094402862

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.7283416353571861
      after G-S, residual L2: 0.45548181093652995

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.3165327512850198
      after G-S, residual L2: 0.22128563126748008

      level: 2, grid: 8 x 8
      before G-S, residual L2: 0.15332496186655512
      after G-S, residual L2: 0.0747196881784426

      level: 1, grid: 4 x 4
      before G-S, residual L2: 0.04974939187294444
      after G-S, residual L2: 0.0008133572860410457

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 0.0011325179143730458
      after G-S, residual L2: 2.98337783917788e-06

      level: 2, grid: 8 x 8
      before G-S, residual L2: 0.10152627387884022
      after G-S, residual L2: 0.0027007047002410374

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.29814672415595245
      after G-S, residual L2: 0.00819910795226899

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.5218848114624619
      after G-S, residual L2: 0.014956130961989498

      level: 5, grid: 64 x 64
      before G-S, residual L2: 0.9910630869231989
      after G-S, residual L2: 0.028422939317571984

      level: 6, grid: 128 x 128
      before G-S, residual L2: 2.044187745817752
      after G-S, residual L2: 0.058293826018797935

    cycle 2: relative err = 0.036315310129800826, residual err = 0.032838234439926776

    <<< beginning V-cycle (cycle 3) >>>

      level: 6, grid: 128 x 128
      before G-S, residual L2: 0.058293826018797935
      after G-S, residual L2: 0.0417201187072595

      level: 5, grid: 64 x 64
      before G-S, residual L2: 0.029246699093099564
      after G-S, residual L2: 0.023356326397591495

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.016306296792818056
      after G-S, residual L2: 0.012906629461195234

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.009011110787953703
      after G-S, residual L2: 0.007315262938908486

      level: 2, grid: 8 x 8
      before G-S, residual L2: 0.005081499522859323
      after G-S, residual L2: 0.002562526517155576

      level: 1, grid: 4 x 4
      before G-S, residual L2: 0.0017064130732665692
      after G-S, residual L2: 2.7912387046731474e-05

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 3.886526925433118e-05
      after G-S, residual L2: 1.0238217009484441e-07

      level: 2, grid: 8 x 8
      before G-S, residual L2: 0.0034819145217789937
      after G-S, residual L2: 9.252096659805176e-05

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.01006499034870321
      after G-S, residual L2: 0.0002744054418255884

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.016032310448838724
      after G-S, residual L2: 0.0004558226543272663

      level: 5, grid: 64 x 64
      before G-S, residual L2: 0.024303743880186898
      after G-S, residual L2: 0.0007098551729201239

      level: 6, grid: 128 x 128
      before G-S, residual L2: 0.037775318915862
      after G-S, residual L2: 0.0011035122819927912

    cycle 3: relative err = 0.0012532978372415335, residual err = 0.0006216334987470617

    <<< beginning V-cycle (cycle 4) >>>

      level: 6, grid: 128 x 128
      before G-S, residual L2: 0.0011035122819927912
      after G-S, residual L2: 0.0008898317346917108

      level: 5, grid: 64 x 64
      before G-S, residual L2: 0.0006257398720776081
      after G-S, residual L2: 0.000607740119084607

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.00042604165447901086
      after G-S, residual L2: 0.00039767401825608673

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.0002784624522907369
      after G-S, residual L2: 0.00024268300992319052

      level: 2, grid: 8 x 8
      before G-S, residual L2: 0.0001688184030119159
      after G-S, residual L2: 8.63435239999583e-05

      level: 1, grid: 4 x 4
      before G-S, residual L2: 5.750132804390505e-05
      after G-S, residual L2: 9.407985171344554e-07

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 1.3099714803222558e-06
      after G-S, residual L2: 3.450833950914012e-09

      level: 2, grid: 8 x 8
      before G-S, residual L2: 0.00011732421042687768
      after G-S, residual L2: 3.1157531467636086e-06

      level: 3, grid: 16 x 16
      before G-S, residual L2: 0.00033850867119400885
      after G-S, residual L2: 9.17760188796962e-06

      level: 4, grid: 32 x 32
      before G-S, residual L2: 0.0005249527904418192
      after G-S, residual L2: 1.4651643230958405e-05

      level: 5, grid: 64 x 64
      before G-S, residual L2: 0.0007080871923387015
      after G-S, residual L2: 2.0290645679943462e-05

      level: 6, grid: 128 x 128
      before G-S, residual L2: 0.0009185166830535544
      after G-S, residual L2: 2.6570300453995103e-05

    cycle 4: relative err = 4.2574662963457396e-05, residual err = 1.4967652923762853e-05

    <<< beginning V-cycle (cycle 5) >>>

      level: 6, grid: 128 x 128
      before G-S, residual L2: 2.6570300453995103e-05
      after G-S, residual L2: 2.3098223923757352e-05

      level: 5, grid: 64 x 64
      before G-S, residual L2: 1.6274857395354832e-05
      after G-S, residual L2: 1.7906142642175535e-05

      level: 4, grid: 32 x 32
      before G-S, residual L2: 1.258588239896169e-05
      after G-S, residual L2: 1.2880701433730278e-05

      level: 3, grid: 16 x 16
      before G-S, residual L2: 9.035061892671461e-06
      after G-S, residual L2: 8.10300318788889e-06

      level: 2, grid: 8 x 8
      before G-S, residual L2: 5.641504287378599e-06
      after G-S, residual L2: 2.9012129063955126e-06

      level: 1, grid: 4 x 4
      before G-S, residual L2: 1.932169517574082e-06
      after G-S, residual L2: 3.161675601835735e-08

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 4.4023320992879136e-08
      after G-S, residual L2: 1.1596974313938014e-10

      level: 2, grid: 8 x 8
      before G-S, residual L2: 3.9422658747144435e-06
      after G-S, residual L2: 1.0466257645445924e-07

      level: 3, grid: 16 x 16
      before G-S, residual L2: 1.1405869020431955e-05
      after G-S, residual L2: 3.0819546585464564e-07

      level: 4, grid: 32 x 32
      before G-S, residual L2: 1.7696025211842327e-05
      after G-S, residual L2: 4.853326074858634e-07

      level: 5, grid: 64 x 64
      before G-S, residual L2: 2.281722184794443e-05
      after G-S, residual L2: 6.339093026629609e-07

      level: 6, grid: 128 x 128
      before G-S, residual L2: 2.7204506586512792e-05
      after G-S, residual L2: 7.61736677407384e-07

    cycle 5: relative err = 1.4372233555992132e-06, residual err = 4.2910354839513e-07

    <<< beginning V-cycle (cycle 6) >>>

      level: 6, grid: 128 x 128
      before G-S, residual L2: 7.61736677407384e-07
      after G-S, residual L2: 6.887955287148536e-07

      level: 5, grid: 64 x 64
      before G-S, residual L2: 4.858303580829294e-07
      after G-S, residual L2: 5.698844682533653e-07

      level: 4, grid: 32 x 32
      before G-S, residual L2: 4.011448592273346e-07
      after G-S, residual L2: 4.2887305175998083e-07

      level: 3, grid: 16 x 16
      before G-S, residual L2: 3.011320287970724e-07
      after G-S, residual L2: 2.7229135972437344e-07

      level: 2, grid: 8 x 8
      before G-S, residual L2: 1.8967555884605451e-07
      after G-S, residual L2: 9.770491553515245e-08

      level: 1, grid: 4 x 4
      before G-S, residual L2: 6.507167357899105e-08
      after G-S, residual L2: 1.0648579116334552e-09

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 1.4827137294363792e-09
      after G-S, residual L2: 3.9058805523605475e-12

      level: 2, grid: 8 x 8
      before G-S, residual L2: 1.3276705475319977e-07
      after G-S, residual L2: 3.524245793876337e-09

      level: 3, grid: 16 x 16
      before G-S, residual L2: 3.8563144896921417e-07
      after G-S, residual L2: 1.0398885077513769e-08

      level: 4, grid: 32 x 32
      before G-S, residual L2: 6.038836850187365e-07
      after G-S, residual L2: 1.6338312481157817e-08

      level: 5, grid: 64 x 64
      before G-S, residual L2: 7.682416346530921e-07
      after G-S, residual L2: 2.0772116210685317e-08

      level: 6, grid: 128 x 128
      before G-S, residual L2: 8.865086230602598e-07
      after G-S, residual L2: 2.401923227919822e-08

    cycle 6: relative err = 4.8492598977484135e-08, residual err = 1.353057835656594e-08

    <<< beginning V-cycle (cycle 7) >>>

      level: 6, grid: 128 x 128
      before G-S, residual L2: 2.401923227919822e-08
      after G-S, residual L2: 2.2125290070425652e-08

      level: 5, grid: 64 x 64
      before G-S, residual L2: 1.5613809613835955e-08
      after G-S, residual L2: 1.8869606239963252e-08

      level: 4, grid: 32 x 32
      before G-S, residual L2: 1.3292687837677291e-08
      after G-S, residual L2: 1.4485742520315527e-08

      level: 3, grid: 16 x 16
      before G-S, residual L2: 1.0177212111802273e-08
      after G-S, residual L2: 9.198083791538658e-09

      level: 2, grid: 8 x 8
      before G-S, residual L2: 6.409467335640698e-09
      after G-S, residual L2: 3.3018379633629456e-09

      level: 1, grid: 4 x 4
      before G-S, residual L2: 2.1990607567876347e-09
      after G-S, residual L2: 3.598750197454369e-11

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 5.010919630110133e-11
      after G-S, residual L2: 1.3200151156453123e-13

      level: 2, grid: 8 x 8
      before G-S, residual L2: 4.48679228107323e-09
      after G-S, residual L2: 1.1908945622999935e-10

      level: 3, grid: 16 x 16
      before G-S, residual L2: 1.3081162779667808e-08
      after G-S, residual L2: 3.522982496836639e-10

      level: 4, grid: 32 x 32
      before G-S, residual L2: 2.0705037621548675e-08
      after G-S, residual L2: 5.546643639307605e-10

      level: 5, grid: 64 x 64
      before G-S, residual L2: 2.6280822057541362e-08
      after G-S, residual L2: 6.964954384251476e-10

      level: 6, grid: 128 x 128
      before G-S, residual L2: 2.994449911367404e-08
      after G-S, residual L2: 7.914383325620475e-10

    cycle 7: relative err = 1.6392150533299687e-09, residual err = 4.4583516444840087e-10

    <<< beginning V-cycle (cycle 8) >>>

      level: 6, grid: 128 x 128
      before G-S, residual L2: 7.914383325620475e-10
      after G-S, residual L2: 7.355629304356289e-10

      level: 5, grid: 64 x 64
      before G-S, residual L2: 5.19218220597571e-10
      after G-S, residual L2: 6.364663261794707e-10

      level: 4, grid: 32 x 32
      before G-S, residual L2: 4.485504928535875e-10
      after G-S, residual L2: 4.928237246176745e-10

      level: 3, grid: 16 x 16
      before G-S, residual L2: 3.4637122000064977e-10
      after G-S, residual L2: 3.1194162913950586e-10

      level: 2, grid: 8 x 8
      before G-S, residual L2: 2.174181615639314e-10
      after G-S, residual L2: 1.1194514367241423e-10

      level: 1, grid: 4 x 4
      before G-S, residual L2: 7.455734323986808e-11
      after G-S, residual L2: 1.2201499216239134e-12

      bottom solve:
      level: 0, grid: 2 x 2

      level: 1, grid: 4 x 4
      before G-S, residual L2: 1.6989436916357301e-12
      after G-S, residual L2: 4.475487188247986e-15

      level: 2, grid: 8 x 8
      before G-S, residual L2: 1.521214490284944e-10
      after G-S, residual L2: 4.037434677870943e-12

      level: 3, grid: 16 x 16
      before G-S, residual L2: 4.4491498629640967e-10
      after G-S, residual L2: 1.197248120085576e-11

      level: 4, grid: 32 x 32
      before G-S, residual L2: 7.109792371905777e-10
      after G-S, residual L2: 1.8912335700376235e-11

      level: 5, grid: 64 x 64
      before G-S, residual L2: 9.034017109357381e-10
      after G-S, residual L2: 2.3606466325271617e-11

      level: 6, grid: 128 x 128
      before G-S, residual L2: 1.0238349148814258e-09
      after G-S, residual L2: 2.678477889744364e-11

    cycle 8: relative err = 5.555107077431201e-11, residual err = 1.5088473495842003e-11

We can compare to the true solution

```python
v = a.get_solution()
b = true(a.x2d, a.y2d)
e = v - b
```

The norm of the error is

```python
e.norm()
```

    1.6719344048744095e-05

```python

```