SciVis 2017 Project 5: "tensr"
Assigned March 8; Due Wed March 15 at 11:59pm
For this project, you will implement 2-D symmetric field convolution, integration along eigenvectors, and Line Integral Convolution (LIC).
Logistics
The usual ...Like in p4vectr, if you want to compile your code without the -O2 optimization, you can:
Compiling without optimization may produce an executable that is easier to debug.export DASHO=-O0 make clean; makeLike in earlier projects, there is a tnsVerbose global variable that you should use to control the printing of any debugging messages. tnsVerbose is set from the value of environment variable TNS_VERBOSE by the tensr as soon as it starts. Grading will be done with TNS_VERBOSE unset.
What to do
Run "./rtensr" to review the commands available, and run "./rtensr about" to see what needs to be implemented. The convolution code (for tnsConvoEval) will be nearly identical to what was done for p4vectr: we again need 2-D convolution, but now in a tensor field rather than a vector field, but that just means 3 values instead of 2 need to be reconstru. Reading through and understanding the header file tns.h is essential. The tnsMath.h macro collection will be familiar.The handling of these lines
is the same as in previous assignments. There are detailed notes in the comments preceeding these blocks detailing what has to be done./* 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 */Just like p4vectr, 33710 students have two additional things to implement:
- Runge-Kutta Fourth-order integration along streamlines: the "-iintg rk4" option for "tensr sline" and "tensr lic", which determines the value of the intg variable passed to tnsSlineTrace() and tnsLIC, respectively.
- In tnsLIC, if the rndLinterp argument is nonzero, do bilinear interpolation into the given noise texture, instead of nearest-neighbor interplation.
Example tensr/rtensr commands to try
The commands here use "./rrendr"; you should make sure that you get the exactly same results by running "./rendr". To an unfortunate extent the commands are intended to be executed in the order shown: later commands assume the presence of files created by running earlier commands.
- Always make sure your code builds cleanly with "make"
- See if a 2-D eignsystem can be computed:
The three values given are the unique Txx, Txy, Tyy elements of a symmetric 2D matrix. When two eigenvalues are equal, or very nearly equal (as with the last example), the is no single stable correct answer for what the eigenvectors should be. What matter is that Tv=Lv, or Tv-Lv=0, for eigenvector v and eignevalue L; that is what is tested in the tensr esysoutput../rtensr esys 1 2 3 ./rtensr esys 1 0 1 ./rtensr esys 1 0.1 1 ./rtensr esys 1 0.0000000000001 1- Make a little tensor dataset, and try convolution. This one has a constantly rotating eigensystem, and a region of higher anisotropy in a ring around the origin. The highest anisotropy also varies as a function of position, from highest anisotropy on the right, to lowest anisotropy on the left.
You should try other kernels, too (see tensr klist). Many students seem to ignore the odd-support bspln2 kernel../rtensr sdg -w 1 -o circ.nrrd ./rtensr ceval -i circ.nrrd -w 0.6 0.3 -k bspln3 -pe ./rtensr ceval -i circ.nrrd -w 0.1 0.1 -k bspln3 -pe- Try some streamlines along eigenvectors. The trick with these is that with eigenvectors not having a meaningful sign, "upstream" and "upstream" no longer have instrinsic meaning, and yet the streamline has to depart from the seed point in two opposite directions, and trace the locally-computed eigenvector as it goes.
To get a view of these; we make a background image that outlines where in world-space the data is:for I in euler rk2; do for E in 0 1; do ./rtensr sline -i circ.nrrd -k bspln2 -s 0.5 0.3 -h 0.15 -l 70 -intg $I -we $E -o sln${E}-$I.txt done doneAnd then we can show the single streamlines:unu slice -i circ.nrrd -a 0 -p 0 | # scalar image unu crop -min 1 1 -max M-1 M-1 | # cropped by one unu 1op 1 | # all values are 1 unu pad -min -1 -1 -max M+1 M+1 -b pad -v 0 | # border of 0s unu quantize -b 8 -o background.png(You can force Preview to display all the files with the same size by clicking on one of the thumbnails on the left, typing Command-a and then Command-0). One way to follow the path of the principle eigenvector (associated with the larger eigenvalue) all the way around the circle, as opposed to having the path double back on itself, is to make sure that the sign of the eigenvector (the one being integrated) is such that it has a positive dot product with the incoming direction (the prior direction along the path).for WUT in sln0-euler sln0-rk2 sln1-euler sln1-rk2; do ./rtensr eps -i background.png -s $WUT.txt -th 0.007 -o $WUT.eps done open sln{0,1}-{euler,rk2}.eps- 33710 students should also be implementing RK4 integration:
for I in euler rk2 rk4; do for E in 0 1; do ./rtensr sline -i circ.nrrd -k bspln2 -s 0.5 0.3 -h 0.15 -l 70 -intg $I -we $E -o sln${E}-$I.txt done done for WUT in sln0-euler sln0-rk2 sln0-rk4 sln1-euler sln1-rk2 sln1-rk4; do ./rtensr eps -i background.png -s $WUT.txt -th 0.007 -o $WUT.eps done open sln{0,1}-{euler,rk2,rk4}.eps- While vector streamlines can continue until they hit the field boundary, tensor eigenvector streamlines can stop when the anisotropy falls below some threshold:
In sln0-at0.eps the paths are stopped by the low anisotropy on the left side of the domain, whereas in sln0-at6.eps the field anisotropy is always above the anisotropy threshold, so the path can continue around../rtensr sline -i circ.nrrd -k bspln2 -s 0.5 0.3 -h 0.1 -l 70 -intg euler -we 0 -at 0.00001 -o sln0-at6.txt ./rtensr sline -i circ.nrrd -k bspln2 -s 0.5 0.3 -h 0.1 -l 70 -intg euler -we 0 -at 0.1 -o sln0-at1.txt for T in 6 1; do ./rtensr eps -i background.png -s sln0-at${T}.txt -th 0.01 -o sln0-at${T}.eps done open sln0-at{6,1}.eps- On to LIC. First make a noise texture:
Then compute some LICs:unu slice -i circ.nrrd -a 0 -p 0 | # get scalar image with same orientation unu crop -min 1 1 -max M-1 M-1 | # crop to get away from edges of tensor field unu resample -s x4 x4 | # noise is 4x resolution of vector data unu 1op nrand -s 42 | # generate noise unu resample -s x1 x1 -k hann:1.6,7 | # blur a bit (to help anti-alias LIC) unu flip -a 1 -o noise.nrrd # so standard raster display looks correct ./rtensr info noise.nrrd unu quantize -b 8 -i noise.nrrd -min 0.1% -max 0.1% -o noise.png open noise.pngThis shows the direction of the first (lic0.png) and second (lic1.png) eigenvector, as well as the field anisotropy (aniso.png).LPARM="-i circ.nrrd -r noise.nrrd -k tent " QPARM="-b 8 -min 0.1% -max 0.1%" ./rtensr lic $LPARM -h 0.003 -l 150 -we 0 -ao aniso.nrrd -o lic0.nrrd ./rtensr lic $LPARM -h 0.003 -l 150 -we 1 -o lic1.nrrd unu 2op x aniso.nrrd lic0.nrrd | unu quantize $QPARM -o lic0.png unu 2op x aniso.nrrd lic1.nrrd | unu quantize $QPARM -o lic1.png unu quantize -b 8 -i aniso.nrrd -o aniso.png open lic0.png lic1.png aniso.png- 33710 students should implement the linear interpolation into the noise texture triggered by the -rlin option to the lic command (exactly as in p4vectr):
LPARM="-i circ.nrrd -r noise.nrrd -k tent " QPARM="-b 8 -min 0.1% -max 0.1%" ./rtensr lic $LPARM -h 0.003 -l 150 -we 0 -rlin -o lic0-rlin.nrrd ./rtensr lic $LPARM -h 0.003 -l 150 -we 1 -rlin -o lic1-rlin.nrrd unu 2op x aniso.nrrd lic0-rlin.nrrd | unu quantize $QPARM -o lic0-rlin.png unu 2op x aniso.nrrd lic1-rlin.nrrd | unu quantize $QPARM -o lic1-rlin.png open lic0-rlin.png lic1-rlin.png- One big source of confusion or bugs with p4vectr was how to handle when when the streamline leaves the domain of the vector field, and how samples along the streamline should be weighted; this test highlights that. First make the tensor field right.nrrd and the "noise" texture noise.nrrd.
In the right.nrrd, the streamlines along the principle eigenvector go left-right (the principle eigenvector is (1,0) or (-1,0)), which allows you to predict somewhat how LIC should produce a horizontal blurring of the edge image. Do LIC and compare with reference:./rtensr sdg -sz 151 201 -l 151 201 -p 1 0 0 0 0 0 5 0 0 1 0 0 -o right.nrrd unu slice -i right.nrrd -a 0 -p 2 | # scalar image unu grid -i - | # array of sample locations unu reshape -s 2 151 201 | # put back in shape unu dice -a 0 -o ./ # extract X and Y coords unu 2op gt 0.nrrd 1.nrrd -o edge.nrrd # make edge image unu slice -i right.nrrd -a 0 -p 2 | # scalar image w/ orientation unu 1op 0 | unu 2op + - edge.nrrd | # insert edge image unu crop -min 1 1 -max M-1 M-1 -o edge.nrrd # crop out edge unu quantize -b 8 -i edge.nrrd -o edge.png # look at it open edge.pngThe order in compare-edge-lic.png is: reference, your result, difference. Solid gray is good; anything markedly significantly different from solid gray indicates a bug. The difference image may also show (subtly, with faint bars on the left and right sides) a more minor difference: whether, when you are testing whether a streamline vertex is inside the noise texture, you do that test based on the floating-point index-space coordinates (just after conversion from world-space), or whether you do it after rounding those the index-space coordinate to integers. The directions never specified which is correct, so no deductions are made based on this. The reference implementation first rounds index-space positions to integers, and then tests whether they are valid indices into the noise texture.for W in ./r ./; do ${W}tensr lic -i right.nrrd -k tent -r edge.nrrd -h 0.21 -l 101 -lk box -o ${W}edge-lic.nrrd unu quantize -b 8 -i ${W}edge-lic.nrrd -min -0.03 -max 1.03 -o ${W}edge-lic.png done unu 2op - {,r}edge-lic.nrrd | unu quantize -b 8 -min -0.125 -max 0.125 -o diff.png unu join -a 0 -i {r,}edge-lic.png diff.png -o compare-edge-lic.png open compare-edge-lic.png rm -f 0.nrrd 1.nrrd right.nrrd edge.nrrd {r,}edge-lic.{png,nrrd} diff.pngGrading
The grade will be based on style (10%) and correctness (90%), similar to previous projects. The style points will be the same as for Project 2: new functions are "static", convolution uses 2*S not S^2 kernel evaluations, the code compiles without warnings, and there are no memory leaks (though how this is tested may be more rigorous than it was for Project 2). Also, points will be deducted if there are extraneous debugging messages.. The correctness points will be based on the commands above or some slight modifications.