Exercise 3¶
What this exercise is about¶
You will implement a finite difference solver for the 2D Laplace equation using pure Go. This exercise combines the programming concepts from sessions 06-09 with practical numerical methods commonly used in scientific computing and data science. We are going to work with the data generated with by the solver. The aim is for you to become more comfortable with Go and continue to use the command line.
The 2D Poisson equation:
∂²u/∂x² + ∂²u/∂y² = f(x,y)
will be solved using the 5-point finite difference stencil:
u[i,j] = (u[i+1,j] + u[i-1,j] + u[i,j+1] + u[i,j-1] + f[i,j]) / 4
General Instructions¶
All submitted work must be stored in your GitLab repository. Below it will be explained how to do that. For the repository it is important that:
- one exercise = one GitLab repository → each exercise gets its own GitLab repository
- your repository must be private
- your repository must be named exactly as specified (in the setup below); do not change the name or the upper-case/lower-case letters
- create commits frequently, at least one commit per question
- push your work frequently (this also is your backup if your laptop breaks)
- your repository must be up-to-date before the deadline
- you must double-check your repository in the web browser to make sure all your work is uploaded to the code.vt.edu server
- you must provide screenshots as proof when they are requested; screenshots are also committed to the repository
⚠️ The screenshots must be taken by you on your laptop! Not following this is an Honor Code violation.
⚠️ You must run your code yourself! Not following this is an Honor Code violation.
⚠️ You must create complete log files of all AI conversations! Not following this is an Honor Code violation.
0. Setup: Git and GitLab¶
-
Create a new repository on GitLab at code.vt.edu:
-
in the top-left corner, click the "+" icon
- in the new menu that pops up, click "New project/repository"; a new page loads
- in the new page, click the "Create black project" button; a new page loads:
- enter the "Project name":
cmda3634-ex3 - in the drop-down field "Pick a group or namespace", select your username
- the "Project slug" field should populate automatically after entering a project name; do not change the slug
- enter the "Project name":
-
for the "Visibility level", select "private" (very important!)
- for the "Project configuration", select only "Initialize repository with README"
-
Add the instructor and TA to your repository as a member with Developer access. In the web browser with your new repository open:
-
in the left sidebar, hover the mouse cursor over "Manage"
- in the menu that pops up, click "Members"; a new page loads
- on the new page, click button "Invite members"
- enter the
jrudi - select maximum role: "Developer"
- click the button "Invite"
- enter the
- repeat to invite a new member:
- enter the
jraind - select maximum role: "Developer"
- click the button "Invite"
- enter the
1. Implement and Output the Right-Hand-Side (10 points)¶
You can find the source code files for this exercise in the folder exercises/03-code
We define a function that maps two points in space to a scalar:
func f(x float64, y float64) float64 {
return 8.0 * math.Sin(2.0 * math.Pi * x) * math.Sin(2.0 * math.Pi * x)
}
Using two nested for-loops and img.Set together with the predefined functions in the skeleton code (s1.go) visualize the function above.
Save the code in the file f_png.go and explain – in your own words – what it does in your README.md file.
Tip on creating images in Go: Check out the "mandelbrot" example in our course repository.
These files should be in your solution in folder
q1:
f_png.gof.pngREADME.md
2. Simple IO formats (30 points)¶
You can find the source code files for this exercise in the folder exercises/03-code
In your solution in folder q2, create a new program (f_io.go) based on (s2.go). Now you should output the data in a csv format.
When you output the data of a matrix in stdout, follow this formatting: for example, if \(u\) is 4-by-3 matrix:
Then the output should be:
1,2,3
4,5,6
7,8,9
10,11,12
It is good to think of the output line-by-line, as oppose to the code in Q1 where we updated element by element.
Create a slice of strings (s = make([]string, Ny)) and a writer (csv.NewWriter(out)); then write one row at the time (writer.Write(s[:])).
This program should be able to output the field with stdio to the terminal and to a file called name.csv.
To redirect stdio from your program into a file you need to use command line arguments.
If an argument is provided the program should create a file using os.Create().
Tip: Look at the design of the "gif" example for inspiration.
Deliverable: With the following commands
go run f_io.go > data1.csv
go run f_io.go data2
ls -ls
data1.csv and data2.csv.
Note the two different ways your program should create output files.
Take a screenshot after running the above lines; and store the screenshot in the
folder q2.
Now create plots of your csv file in Python or MATLAB by first reading the file with either
numpy.loadtxt()orpandas.read_csv()(Python) orimport dataorreadmatrix()(MATLAB).
Write a small script that generates a surface plot (see for example MATLAB surface 3d) of the data generated from your Go program.
Save the figure as surface.png.
It is important that the axes are graded and the numbers are visible!
These files should be in your solution in folder
q2:
f_io.godata1.csvdata2.csvsurface_plot.pyorsurface_plot.msurface.pngscreenshot.png
3.1 Implement a Linear Solver (35 points)¶
You can find the source code files for this exercise in the folder exercises/03-code
A classic method for solving Poisson problems is Gauss-Seidel iteration. One iteration of Gauss-Seidel loops over all the points of the grid with a 5-point finite difference stencil.
Nx := 80 // number of grid points in x-direction
Ny := 80 // number of grid points in y-direction
for i := 1; i < Nx-1; i++ {
for j := 1; j < Ny-1; j++ {
x := float64(i)/Nx
y := float64(j)/Ny
u[i][j] = 0.25 * (u[i+1][j] + u[i-1][j] + u[i][j+1] + u[i][j-1] + h*h*f(x, y))
}
u) and the source term (f) the same way as the question above.
We call the residual a measure of the error of the solution (u). For our problem the residual (r) is \(r = f-Au\).
To track the progress to solution, we compute the norm of the residual (r).
The residual norm (res) is \(\|r\| = \|f-Au\|\)) is calculated as:
res := 0.
for i := 1; i < Nx-1; i++ {
for j := 1; j < Ny-1; j++ {
x := float64(i)/Nx
y := float64(j)/Ny
res += math.Pow(h*h*f(x, y) - (4.0*u[i][j]-u[i-1][j]-u[i+1][j]-u[i][j+1]-u[i][j-1]), 2)
}
}
res = math.Sqrt(res)
Copy s3.go to q3 and rename it to poisson.go and fill in the missing components.
Reuse the code implemented in q2 to output the solution u and generate a png-file.
Run the program and collect the solver data as:
go run Poisson.go > log
These files should be in your solution in folder
q3:
possion.gou.csvu.pnglog
3.2 Data (15 points)¶
Using your terminal skills filter the log file such that you can plot the convergence plot (number of iterations vs residual).
Tip: Find out how to use either one of these commands:
grep,sed,awk,cutor similar. And then usematplotlib.plot(Python),plot(MATLAB), orgnuplot(terminal).
Generate a figure and save it as convergence.png.
your_command log > filtered_log
These additional files should be in your solution in folder
q3:
filtered_logplot.py(if you used Python),plot.m(if you used MATLAB), orgnuplot.txt(if you used gnuplot containing your gnuplot command)convergence.png
4. Final README and reflection (10 points)¶
Update the README.md file in your submission repository. (If no file named
README.md exists in your repository, then create one.)
Add complete log files of ALL your AI conversations – just like you did in Exercise 2. Store then in the files:
q1/q1_ai_log.mdq2/q2_ai_log.mdq3/q3_ai_log.md
README content and formatting¶
Example of a README.md file (in the root folder of your repository, not in subfolders q1, q2, ...):
# Exercise 3
## Contents
1. Question: Output a discretized function

- [code](f_png.go)
- [README](q1/README.md)
- [AI log](q1/q1_ai_log.md)
2. Question: Simple I/O with CSV


- [f_io](q2/f_io.go)
- [code](q2/surface_plot.py) or [code](q2/surface_plot.m)
- [data1](q2/data1.csv)
- [data2](q2/data2.csv)
- [AI log](q2/q2_ai_log.md)
3. Question: Poisson Solver


- [code](q3/poisson.go)
- [README](q3/README.md)
- [AI log](q3/q3_ai_log.md)
## Reflection
(your reflection text here)
## AI use
(your documentation of AI use goes here)
Submission¶
Submit as before for Ex. 1 and Ex. 2.
Do not forget to submit the link in Canvas on time and do not edit the GitLab after the link has been submitted to Canvas.
Congrats! You're done! 🍪