SciVis 2017 Project 1: "plotr"

Assigned Jan 4; Due Thu Jan 12 9:00pm

This project involves material covered in the first week of lectures (and readings in FSV) and the first lab. The basic goal is to implement a 1-D version of a fundamental abstraction in scientific visualization: a continuous function. The function is reconstructed by convolving a continuous reconstruction kernel with discretely sampled data located somewhere in world-space. With that abstraction implemented, you can generate the simplest kind of scientific visualization: the graph of a function y=f(x). You will create a utility that plots (by making a PNG image) the convolution result, and you can view the image with any normal image viewer (including the Preview application on the Mac). Data can be synthesized by sampling polynomials. If you know how to graph a polynomial like f(x)=x^2 on paper, you can tell if your result looks correct. In this way, this project introduces a principle that future projects will build upon: the verification of an implementation by emperical comparison of results to the correct answer known from first principles. This powerful method of debugging does not require a reference implementation. Still, you are given a reference implementation to show by example how your code should work.

This project depends on the math in the assigned FSV readings. Lerp is essential (including its application to root-finding), as are node-centered vs cell-centered samples, and the the precise definition of convolution sums for even and odd kernel supports. The hardest part of finishing the plotr plot plotting utility is keeping track of the different index and world spaces involved, and correctly converting between them. You'll also need to understand the raster structure of the output image to traverse its pixels correctly. For all this functionality, however, you only need to write about 160 lines of code.

Getting started

You can work individually or in pairs for this project. Use https://work-groups.cs.uchicago.edu to pair up with another student (our class will be identified as 23710 even for 33710 students). Once the joint repository is created for your work together on a project, that project directory in your individual repository will be ignored by graders. If you are able to create a pair repo, but it is not seeded with the p1plotr files, ask a question in the p1plotr folder on Piazza. All individual CNETID-scivis-2017 directories should now be populated with a p1plotr directory containing the files for this project.

What to do

The technical information about this project is in the source files, and embedded in the rplotr executable, rather than spelled out here. To start, you should run "./rplotr" to review all the commands available, and you should then run "./rplotr about" to learn more about how plotr works, and to see the four source files you should be editing, to complete the implementation of which functions, to be tested with which plotr commands.

As indicated there, you should start by reading through plt.h to see what structs, functions, and files are involved. Note that the pltKernel kernel knows its own support and its derivative, and the pltData data container includes meta-data about where samples are located within some interval. The first code you write should be filling in the implemention of pltLerp() in util.c; this function will come in very handy. You can test your implementation with "make && ./plotr lerp", for which you supply five argments to lerp on the command-line. Compare your results with ./rplotr lerp.

Here is a prioritized listing of the source files involved:

  1. Must read and understand: plt.h
  2. Read and understand because you're adding code: util.c, poly.c, convo.c, pplot.c
  3. Should skim to understand the functions if their purpose isn't clear from plt.h: misc.c, data.c
  4. Can skim if interested (the rest of the files): plotr_about.c, plotr_ceval.c, plotr_csamp.c, plotr_delta.c, plotr_foo.c, plotr_itow.c, plotr_keval.c, plotr_klist.c, plotr_lerp.c, plotr_peval.c, plotr_plot.c, plotr_psamp.c, plotr_wtoi.c

For each of the plotr X commands corresponding to a function you need to implement (listed in the output of plotr about), you should carefully read the usage information (generated by "plotr X") to make sure you understand the purpose of the command and the meaning of its command-line options. You can also scrutinize the implementation of the command (in plotr_X.c) to see how the underlying C function is being called.

Just before the definition of the functions that you have to finish, there is a comment block that defines what the inputs and outputs to the function are; this provides the technical definition of what a correct implementation should be. The reference implementation rplotr should conform to this.

Throughout the code you will see some unfamiliar functions, like airMop for memory management, biffAdd/biffGet for error messages, and hest for command-line parsing. These functions come from Teem (scivis-2017/teem-install/lib/libteem.a). You should not to worry about them since you will not be writing any Teem-related functions to complete the required functions.

For this project there is no additional work for 33710 students to do relative to 23710 students.

Where to put your code

In the definition of functions that you have to implement, you will see lines:
/* v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v  begin student code */


/* ^'^'^'^'^'^'^'^'^'^'^'^'^'^'^'^'^'^'^  end student code */
Do not edit these lines, , or any of the lines outside the regions they delineate. You only modify lines within the indicated regions. For reference, the number of lines of code in the reference implementation is recorded per-region in a comment (e.g. /* ( 2 lines in reference implementation ) */). Feel free to remove that comment, and do not take this number too seriously. It should only be a rough indication of how many lines you should write, but you do not get points for exactly matching the number of lines in the reference implementation. Excessively long or inefficient code may lose style points. You may add new variable definitions anywhere with these code region (it will certainly be needed for the longer functions).

You should make a habit of frequently typing make to make sure that everything still compiles without problems. One of the make targets is an integrity check that verifies checksums of the files you should not be editing, and the portions outside the “student code” blocks in the files you should be editing. If you make a change outside a student code block region, make will fail with a message starting like (if you weren't supposed to modify the file at all):

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! plotr_klist.c seems to have been modified:
!!! cksum plotr_klist.c (1550491006 1697) != expected 3037869832 1696
or like (if the file should be modified):
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! util.c seems to have been modified outside a student code region:
!!! ./.strip.sh util.c | cksum result (2806917232 2430) != expected 3312319458 2429
These messages identify the file in question, how a checksum was computed (./.strip.sh is used to remove student code regions), and how it differs from the expected result.

You can use svn update -r to recover an earlier version ("revision" in svn-speak) of a file; use svn log to find the revision number of when the files were first disributed to you.

Or, if you just want to directly see what the file started as, you can see pristine copies of the distributed files in $SCIVIS/work/p1plotr. You aren't able to commit changes in the per-class scivis-2017 repository (which $SCIVIS should expand to), so "(cd $SCIVIS; svn revert --recursive .)" should fix things in scivis-2017 if you do mistakenly modify anything there.

Example plotr commands to try

For all of these examples (and for this project in general), your goal is to make your plotr program act the same as the reference implementation rplotr.

The first code you write for this project is to finish the implementation of pltLerp in util.c Then compile with make, and compare your function to the reference:

./rplotr lerp 3 7 0 1 2
./plotr lerp 3 7 0 1 2
By reading the usage information (from "./rplotr lerp"), make sure you understand why ./rplotr lerp produces this answer. All the commands below use ./rplotr, but you should be able to replace ./rplotr with ./plotr and get the same output.

A cubic polynomial f(x) = 2 - x - 2x^2 + x^3 can be sampled and reconstructed various ways to show what is needed for this project.

./rplotr psamp -mm -2 3 -p 2 -1 -2 1 -n 6 -c cell -o cubic.txt
./rplotr itow cubic.txt 0
./rplotr wtoi cubic.txt -2
./rplotr ceval -i cubic.txt -k tent -x 0.5
./rplotr ceval -i cubic.txt -k ctmr -x 0.5
./rplotr ceval -i cubic.txt -k ctmr -d 1 -x 0.5
./rplotr ceval -i cubic.txt -k c4hexic -x 0.5
./rplotr ceval -i cubic.txt -k c4hexic -d 2 -x 0.5
./rplotr plot -s 600 300 -xmm -2 3 -ymm -3 4 -p 2 -1 -2 1 -thp 15 -tha 5 -i cubic.txt -dd 30 -hz 80 -o plot.png
The synthetic data in cubic.txt is generated by sampling the polynomial. The location of the samples along the real number line can be probed with plotr itow and plotr wtoi. The different plotr ceval commands reconstruct the data (or some derivative) at the midpoint of the data with different kernels. You should confirm that c4hexic is giving the analytically correct answer p(0.5)=1.125 (since that kernel reconstructs cubic polynomials exactly). plotr plot uses the (default) tent reconstruction kernel to linearly interpolate between the sampled data points, visible in the resulting plot.png (below) as black lines connecting the gray dots showing the data points. For reference, the correct polynomial is visible underneath. The vertical green tickmarks show the (linearly interpolated) zero-crossings.

Another way to exercise the functionality in this project is to make graphs of the convolution kernels themselves, by convolving them with data that is all 0 except for a single 1 (the Kronecker delta function). We generate this synthetic data with:

./rplotr delta -mm -4 4 -n 9 -c node -o delta.txt
Then try:
./rplotr plot -i delta.txt -k box     -xmm -4.8 4.8 -ymm -0.5 1.2 -s 800 300 -thp 12 -dd 15 -o k-box.png
./rplotr plot -i delta.txt -k tent    -xmm -4.8 4.8 -ymm -0.5 1.2 -s 800 300 -thp 12 -dd 15 -o k-tent.png
./rplotr plot -i delta.txt -k bspln2  -xmm -4.8 4.8 -ymm -0.5 1.2 -s 800 300 -thp 12 -dd 15 -o k-bspln2.png
./rplotr plot -i delta.txt -k bspln3  -xmm -4.8 4.8 -ymm -0.5 1.2 -s 800 300 -thp 12 -dd 15 -o k-bspln3.png
./rplotr plot -i delta.txt -k ctmr    -xmm -4.8 4.8 -ymm -0.5 1.2 -s 800 300 -thp 12 -dd 15 -o k-ctmr.png
./rplotr plot -i delta.txt -k c4hexic -xmm -4.8 4.8 -ymm -0.5 1.2 -s 800 300 -thp 12 -dd 15 -o k-c4hexic.png
open k-*.png
Using open on PNG files should lauch the Preview program to display the images. Try adding "-d 1", or "-d 2" to all these, while adjusting the vertical range to something like "-ymm -1.9 1.9" or wider, to plot derivatives of the kernels.

The -so option indicates where the convolution kernel did not fully fit inside the data domain. Try this:

./rplotr plot -i delta.txt -k c4hexic -xmm -4.8 4.8 -ymm -0.5 1.2 -s 800 300 -thp 12 -dd 15 -so true -o k-c4hexic-so.png
open k-c4hexic*.png
Note in k-c4hexic-so.png the green colors on the X axis before and after the kernel plot, showing where the kernel was missing one or more samples.

To make sure differentiation is correctly happening in world-space, you can first sample some polynomial, like f(x) = -x + x^3, and make sure that its reconstruction agrees with the polynomial at the sample points (and that the zero-crossings show up at the right place):

./rplotr psamp -p 0 -1 0 1 -mm -1.3 1.3 -n 8 -c node -o 08.txt
./rplotr plot -i 08.txt -xmm -1.4 1.4 -ymm -1 1.5 -p 0 -1 0 1 -thp 5 -tha 4 -hz 30 -o plot08.png
and then you can plot the derivative of the reconstruction, along with the analytic derivative of the polynomial f'(x) = -1 + 3x^2, to make sure they more or less agree, for a variety of kernels
./rplotr plot -d 1 -i 08.txt -xmm -1.4 1.4 -ymm -1.2 1.5 -p -1 0 3 -thp 5 -tha 4 -o plot08d.png
./rplotr plot -d 1 -i 08.txt -xmm -1.4 1.4 -ymm -1.2 1.5 -p -1 0 3 -thp 5 -tha 4 -k bspln2 -o plot08d-bspln2.png
./rplotr plot -d 1 -i 08.txt -xmm -1.4 1.4 -ymm -1.2 1.5 -p -1 0 3 -thp 5 -tha 4 -k ctmr -o plot08d-ctmr.png
Increasing the sampling density by a factor of five (40 instead of 8 samples) should make the reconstructed world-space derivative more accurate (closer to the correct polynomial answer plotted in red):
./rplotr psamp -p 0 -1 0 1 -mm -1.3 1.3 -n 40 -c node -o 40.txt
./rplotr plot -i 40.txt -xmm -1.4 1.4 -ymm -1.2 1.5 -p 0 -1 0 1 -thp 5 -tha 4 -hz 30 -o plot40.png
./rplotr plot -d 1 -i 40.txt -xmm -1.4 1.4 -ymm -1.2 1.5 -p -1 0 3 -thp 5 -tha 4 -o plot40d.png
./rplotr plot -d 1 -i 40.txt -xmm -1.4 1.4 -ymm -1.2 1.5 -p -1 0 3 -thp 5 -tha 4 -k bspln2 -o plot40d-bspln2.png
./rplotr plot -d 1 -i 40.txt -xmm -1.4 1.4 -ymm -1.2 1.5 -p -1 0 3 -thp 5 -tha 4 -k ctmr -o plot40d-ctmr.png
You can open plot{08,40}d-ctmr.png, for example, to compare the first derivative measurements with from two different sampling resolutions.

Once you know differentiation is working correctly, you can implement plotr plot -apcoth true, which uses the derivative of the function being plotted to approximate a constant-thickness plot. Try this:

./rplotr plot -i delta.txt -k ctmr -xmm -4.8 4.8 -ymm -0.5 1.2 -s 800 300 -thp 12 -dd 15 -apcoth true -o k-ctmr-apcoth.png
open k-ctmr{,-apcoth}.png

All the files generated by the tests above can be safely removed with:

rm -f *.txt *.png
since none of your work is stored in .txt or .png files.

Grading

The grade will be based on correctness (80%) and style (20%). If your code does not compile cleanly with the provided Makefile, .integrity.sh, and .strip.sh, you will get a ZERO for correctness! Subverting the integrity checks is a terrible idea. A grading script (which will give an approximate idea of your project grade) will be distributed shortly. For the style points, keep in mind: