Practical Session 3 – ARRAYS & MODULESIn this session, we will be looking at how a Python uses the Numpy package to store andmanipulate arrays (vectors and matrices). This is, of course, very important when you are solvingengineering problems. We will also practice creating our own functions and modules to improvecode structure and modularity.You should be able to complete the lab sheet and answer the assessed question within theallotted lab time (and are strongly encouraged to do so).Part A: Arrays (vectors & matrices) in Python1. Defining Matrices and Simple Operations with Numpy: https://numpy.org/The Numpy package contains many useful commands and functions for manipulating arrays andsolving linear systems (like Ax=b). However, Numpy requires arrays to be defined in quite a specificway. For example, to define the matrix ???? = ()34 1 2 we need to input the following:import numpy as npA = np.array([[1,2],[3,4]])A few points to note from above:1. We of course had to import the Numpy library – which we have renamed as np in our code(for convenience).2. There are mulitple square brackets to take extra care with: the inner most designateindividual rows, the outermost square brackets enclose the whole matrix.3. The np.array( ) function is then needed so that Python knows this object is to be treatedas a matrix/vector, not as a Python list.With a matrix A defined as above and numpy imported, we can now use a range of commands andnumpy functions to study/operate on this matrix to do some very useful things. Some of thefunctions of use to us for linear systems can be found in Numpy’s linalg sub-library only. Hencesome function calls will need to be prefixed with np.linalg., not just np. (as we will see below).Exercise:For the matrices/vectors???? = (1 3 2 4) , ???? = (11 5 ) , ???? = (1 4 2 5 3 6)by using Python with Numpy, determine the purpose of the following functions/commands, andprovide their output.1. A[0,0] Returns value 1: first element of array2. C[1,2] Returns 6: 2nd row, 3rd column3. C[0,:] Returns 1st row: array([1, 2, 3])4. A.shape Returns shape of A array, (2,2)5. C.size Returns number of elements in C: 66. A.T Returns A transposed: array([[1, 3],[2, 4]])7. b.T b transposed: array([[ 5, 11]])8. A.dot(C) Matrix multiply of A with C:array([[ 9, 12, 15],[19, 26, 33]])9. A*C Error: this is element-wise multiplication (not correct matrixmultiplication) and the matrices are not the same size10. [email protected] Another symbol for matrix multiplication (as dot)11. np.linalg.inv(A) Inverse of matrix A:array([[-2. , 1. ],[ 1.5, -0.5]])12. np.linalg.det(A)Determinant of A: -213. np.linalg.solve(A, b) Finds solution of Ax=b, where x is array([[1.],[2.]])14. [email protected](2) A multiplied by the 2×2 identity matrix2. Arrays for Solving Partial Differential Equations (PDEs)Consider the very important advection equation???????????????? + ???????????????????? = 0which may describe the flow of pollutant concentration, c, down a river at speed U (the sign of Ugives the direction of the flow; if U>0, then the flow is in the positive x direction). Theoretically, thePDE perfectly transports a quantity (e.g. c) at speed U without change (see Figure below).We’ve learnt how to derive finite difference approximations to solve the above equation (see verysimilar Q14 on examples sheet). For example:????????,????+1 = ????????,???? –????????ℎ (????????+1,???? – ????????,????)Notice how our finite difference notation corresponds nicely to that used for Python arrays, i.e.????????,????+1 looks like c(M,N+1). We can use arrays to store the solution of our partial differentialequation, c, for all x (spatial) points, m, and time steps, n.The following code (advection.py) solves the advection equation using finite differences. You’llnotice a couple of new Numpy functions:np.linspace(0, 1, num=(NUM_X+1)): This provides an array of NUM_X+1 evenly-spacedpoints positioned between 0 and 1 inclusive. These are our x-axis values.np.zeros((NUM_X+1, NUM_T+1)): This provides an array full of zeros, with NUM_X+1 rowsand NUM_T+1 columns. Often useful to initialise arrays quickly.You’ll also notice use of the matplotlib library and its sub-library pyplot to enable simple plotsto be created. Again, this is very useful and you’ll see the commands for this library are quite selfexplanatory. More information can be found here: https://matplotlib.org/index.htmlRead through the code below and try to understand each line. Complete comments are in the onlinefile and should aid your understanding. You may want to re-read your notes on PDEs.(Note: you are not expected to be able to reproduce this code – only modify it!)import numpy as np # importing the Numpy package for arraysimport matplotlib.pyplot as plt #importing matplotlib for graph plottingNUM_X = 10 # The number of segments in our x domain (so NUM+1 points)NUM_T = 1000 # The number of time steps forward we want to takeH = 0.1 # The space (x) step length or segment sizeK = 0.01 # The time (t) step lengthU = -0.1 # The speed of the flowX = np.linspace(0, 1, num=(NUM_X+1))C = np.zeros((NUM_X+1, NUM_T+1))for M in range(NUM_X+1):if X[M] > 0.75 and X[M]