MINCCALC(1)

๐ŸŒธ MINCCALC(1) โ€” straight from the MINC User's Guide ๐Ÿ’–

hiii bestie, welcome to the minccalc page, part one of two. grab a snack, this one is a whole journey and we're doing it together. โœจ


โœจ NAME โœจ

minccalc โ€” perform complex math operations on minc files ๐Ÿงฎ๐Ÿฆ‹


๐ŸŒˆ SYNOPSIS ๐ŸŒˆ

mincalc [<options>] <in1>.mnc [<in2>.mnc...] <out>.mnc
yes the synopsis literally says mincalc, not minccalc, and we are NOT fixing it, we are respecting the original fr fr ๐Ÿ’…

๐Ÿ’œ DESCRIPTION ๐Ÿ’œ

okay so here's the vibe. minccalc does complex, voxel-by-voxel math operations on one or more minc files, and those files have to be the same shape and have the same coordinate sampling, and out the other end comes a single output file. iconic.

the operations you want are handed over using the -expression argument (go peek at EXPRESSIONS, that's where the fun is ๐Ÿ‘€).

by default, the output file is the last non-option argument. that's the default, that's the rule, that's the law.

BUT โ€” and this is the plot twist โ€” if you use the -outfile option, then all non-option arguments are considered input files, and the output file names come from the -outfile options instead. and bestie, there can be more than one of those. multiple outputs. main character energy. ๐Ÿ‘‘


๐ŸŽ€ OPTIONS ๐ŸŽ€

little housekeeping first, and it's important:

  • options can be specified in abbreviated form (as long as they're unique, so don't get cute and ambiguous)
  • options can be given anywhere on the command line. anywhere. go wild.

now, the list. all of it. no skips. ๐Ÿซถ

  • -2 โ€” create MINC 2.0 format output files. โœŒ๏ธ
  • -help โ€” print a summary of the command-line options and exit. the "bestie I forgot" button.
  • -version โ€” print the program's version number and exit.
  • -clobber โ€” overwrite an existing file. ruthless. ๐Ÿ’€
  • -noclobber โ€” don't overwrite an existing file. this is the default.
  • -no_clobber โ€” synonym for -noclobber. same energy, different spelling.
  • -verbose โ€” print out progress information for each chunk of data copied. this is the default. it's chatty, we love her. ๐Ÿ’ฌ
  • -quiet โ€” do not print out progress information. silence. ๐Ÿคซ
  • -debug โ€” print out debugging information. for when you need to know everything.
  • -copy_header โ€” copy all of the header information from the first input file. this is the default when you have one input file.
  • -nocopy_header โ€” do not copy all of the header from the first input file; copy only coordinate information. this is the default when you have more than one input file.
  • -filetype โ€” create an output file with the same type as the first input file. default behaviour, she's chill like that.
  • -byte โ€” store output voxels in 8-bit integer format.
  • -short โ€” store output voxels in 16-bit integer format.
  • -int โ€” store output voxels in 32-bit integer format.
  • -long โ€” superseded by -int. she's retired, respect the legacy. ๐Ÿซก
  • -float โ€” store output voxels in 32-bit floating point format.
  • -double โ€” store output voxels in 64-bit floating point format. double the bits, double the drama.
  • -signed โ€” use signed, two's complement integer format. only applies if the output voxel type is specified to be an integer type โ€” that's one of -byte, -short, -int or -long.
  • -unsigned โ€” use unsigned integer format. same deal: only applies if the output voxel type is an integer type โ€” one of -byte, -short, -int or -long.
  • -range min max โ€” restrict the valid range of integer data. only applies if one of the -byte, -short, -int or -long options is specified.
  • -max_buffer_size_in_kb size โ€” specify the maximum size of the internal buffers, in kbytes. default is 4096 (that's 4MB, do the math).
  • -dimension dimname โ€” specify a dimension along which we wish to perform a cumulative operation.
  • -check_dimensions โ€” check that all input files have matching sampling in world dimensions. default. the responsible choice. ๐Ÿงš
  • -nocheck_dimensions โ€” ignore any differences in world dimensions sampling for input files. yolo mode, proceed with awareness.
  • -propagate_nan โ€” for cumulative vector operations (that's sum, prod and avg), invalid data (Not-A-Number, aka NaN) in any element of the vector will produce invalid data in the result. this is the default.
  • -ignore_nan โ€” for cumulative vector operations, invalid data (NaN) in the vector is ignored, i.e. treated as though it is not present. out of sight, out of the math. ๐Ÿ™ˆ
  • -nan โ€” when an illegal operation is attempted at a voxel (think divide by zero), the result is invalid data (NaN). this is the default. also: having no valid input data for a cumulative operation is also considered an illegal operation when -ignore_nan is used.
  • -zero โ€” when an illegal operation is attempted at a voxel (like divide by zero), the result is value zero.
  • -illegal_value value โ€” when an illegal operation is attempted at a voxel (again, divide by zero is the classic), the result is the value specified by this option.
  • -expression string โ€” specify the expression to evaluate at each voxel (see EXPRESSIONS). โญ
  • -expfile filename โ€” specify a file containing an expression to evaluate at each voxel (see EXPRESSIONS). if filename is given as `-`, then the expression is read from stdin. the only difference from command-line expressions is that comments can be given in the file. a comment line is specified by placing a `#` as the first non-whitespace character of the line. and check this out โ€” you can make minccalc scripts by setting the first line to:
#! /usr/local/mni/bin/minccalc -expfile
  • -outfile symbol output-file โ€” specify that output should be written to the specified file, taking values from the symbol which should be created in the expression (see the EXAMPLES section). if this option is given, then all non-option arguments are taken as input files. this option can be used multiple times for multiple output files. ๐Ÿ”ฅ
  • -eval_width value โ€” specify the number of voxels to process in parallel. default is 200.

๐Ÿฆ‹ EXPRESSIONS ๐Ÿฆ‹

okay bestie this is the part where it gets GOOD. the -expression argument is a single string that describes the function to evaluate. the function expression is typically written in terms of the vector A. ๐Ÿ’ซ

for example, this expression will sum the first two input files together:

A[0] + A[1]

multiple expressions can be given, separated by semicolons, and in that case only the value of the last expression is used. these expression lists can be used with assignment expressions to make the syntax very C-like:

ratio = A[0]/A[1]; A[2]*exp(-ratio)

an expression list in curly brackets is a valid expression and returns the value of the last expression in the list. this is particularly useful in for and if expressions (see below ๐Ÿ‘‡).

there are two types of values in the language: vectors and scalars. scalar literals are floating point numbers, or they may appear as symbols whose name starts with a lowercase letter.

besides normal scalar operators such as +, -, * and /, the expression language also supports:

  • the infix exponentiation operator ^
  • the usual relational operators <, <=, >, >=, ==, !=
  • the boolean operators && (and), || (or) and ! (not)
โš ๏ธ note that the && and || boolean operators always evaluate both operands, unlike C. no short-circuiting here, she does the whole job every time.

scalar mathematical functions include abs, sqrt, exp, log, sin, cos, tan, asin, acos and atan.

there are also some specialized functions:

isnan(v) - 1 if v is invalid and 0 otherwise
clamp(v1,v2,v3) - v1 bounded by [v2, v3]
segment(v1,v2,v3) - tests if v1 is in [v2, v3]

the scalar constant NaN is defined such that isnan(NaN) returns 1.


๐ŸŒŸ vectors, the extensional way

vectors can be written in the following extensional form:

[ value1, value2, ... ]

or by using the following range-generating notations:

[ a : b ]     generates {a, a+1, ..., b-1, b}
[ a : b )     generates {a, a+1, ..., b-1}
( a : b ]     generates {a+1, ..., b-1, b}
( a : b )     generates {a+1, ..., b-1}

or be generated, by intension. the following intension expression generates the vector {3,2,1}:

{ i in [1:3] | 4 - i }

vectors may also appear as symbols whose name starts with an uppercase letter.


๐Ÿ’– vector operators

in addition to the scalar operators, the following vector operators are supplied:

avg  - the average value of the scalars in vector
len  - the length of
sum  - the sum of the elements of
prod - the product of the elements of
max  - the maximum value of
min  - the minimum value of
imax - the index of the maximum value of
imin - the index of the minimum value of
V[s] - the s'th element of vector V with origin 0.

๐ŸŽ€ symbols and assignment

symbol names are introduced into a global symbol table by assignment expressions of the form:

a = A[2] * log(2)

symbols starting with a lowercase letter represent scalars, while those starting with an uppercase letter represent vectors.

and because = is an operator, its result can be used in an expression (just like in C). slay. ๐Ÿ’…


โœจ control constructs

a few control constructs are provided, bestie:

for loops can be created to loop over a vector, assigning each value to a symbol and then evaluating an expression. this is done with expressions of the form:

total=0; for{i in [0:len(A))} total=total+A[i]; total

which is equivalent to sum(A). note that this is similar to using:

total=0; len{i in [0:len(A)) | total=total+A[i]}; total

since the for construct is actually an operator (although it is usually only used for changing symbol values). also note that without the final total, the expression would not be very useful, since it would only return the length of the vector. ๐Ÿ’€

as in C, a list of expressions can be specified in curlies:

total=total2 = 0;
for {i in [0:len(A))} {
   total  = total  + A[i];
   total2 = total2 + A[i]^2
}

there are also a few forms of the if-then-else construct:

A[0]<0 ? 0 : A[0]

if (A[0]<0) result=0 else result=A[0]

the else is optional. again, the if construct is an operator, and the then or else expressions can be expression lists in curlies, in which case the value of the last expression is returned. if the else expression is missing, then the value 0 is returned when the test expression is 0 (false).

โš ๏ธ the principal oddity with the for and if constructs is that unlike C statements, they must be separated from the next expression by a semicolon even when an expression list in curlies is used:
for i in [0:len(A)) {total=total+A[i]} ; total/len(A)
if (A[i]>0) {result=2;} else {result=1} ; result*5

๐Ÿงš let-expressions

an alternative way to introduce symbol names is through let-expressions. for example, the following expression will always evaluate to 3:

let a = 1, b = 2 in a + b

these were originally designed to create variables only within the evaluated expression, but modifications have been made so that the global symbol table is changed. plot twist. ๐Ÿ™ˆ


more of this page is coming in part 2, bestie โ€” don't go anywhere ๐Ÿ’œ

โœจ EXAMPLES โœจ

okay bestie, let's get into the examples because this is where it gets fun. ๐Ÿ’–

Here's an expression for calculating standard deviation, and it even takes into account the possibility of invalid input data โ€” which gets ignored, as it should. ๐Ÿ‘‘

            s0 = s1 = s2 = 0;

            for { i in [0:len(A)) } {
               v=A[i];
               if (!isnan(v)) {
                  s0 = s0 + 1;
                  s1 = s1 + v;
                  s2 = s2 + v*v;
               }
            };

            if (s0 > 1) {
               sqrt((s2 - s1*s1/s0) / (s0-1));
            }
            else {
               NaN;
            };

The last if could be changed to return 0 if s0 is > 0 but <= 1. We also drop the curly brackets, but then there must not be a ; between the if and the else ๐Ÿซถ

            if (s0 > 1)
               sqrt((s2 - s1*s1/s0) / (s0-1))
            else if (s0 > 0)
               0
            else
               NaN

If we want both the mean and the standard deviation, we can use the -outfile option, invoking the command with ๐ŸŒธ

            minccalc -expfile stdev \
               -outfile mean mean.mnc \
               -outfile stdev stdev.mnc \
               infile1.mnc infile2.mnc ...

And using the expression file (with yet another form of if expression): ๐Ÿฆ‹

            s0 = s1 = s2 = 0;

            for {i in [0:len(A))} {
               v=A[i];
               if (!isnan(v)) {
                  s0 = s0 + 1;
                  s1 = s1 + v;
                  s2 = s2 + v*v;
               }
            };

            stdev = (s0 > 1) ? sqrt((s2 - s1*s1/s0) / (s0-1)) :
                                 (s0 > 0) ? 0 : NaN ;
            mean  = (s0 > 0) ? s1 / s0 : NaN ;

๐Ÿ’€ CAVEATS ๐Ÿ’€

A few things you should remember... no cap:

  • Vector variables must start with an uppercase letter. ๐Ÿ” 
  • Vector variable names must not be one of the function keywords, sum, len, prod, ... etc. ๐Ÿšซ
  • For loops and if expressions always need to be separated from the next expression by a semicolon. ; is literally the moment. ๐Ÿ’…
  • The symbol table is global. ๐ŸŒ
  • Boolean operators && and || always evaluate both operands. Both. Always. ๐Ÿ‘€
  • A note on parallelism: For efficiency reasons, evaluations are done on many voxels at once (the number of voxels is referred to as the width of the evaluation and is changed with the -eval_width option). An odd consequence of this is that both sides of an if-else statement are always evaluated (unless all voxels give the same test result), but statements within each consequent are only evaluated on the appropriate voxels. In particular, entries in the symbol table are only modified according to a voxel mask. A side-effect of this is that any vector symbol set in an if-else consequent must not change the length of the symbol (although it can create it) and both sides of the consequent must agree on the length of any vector symbols that they both modify. If this is not clear, just try it - the program will complain if it is not happy. ๐Ÿ˜ญ

๐Ÿ‘‘ AUTHOR ๐Ÿ‘‘

Andrew Janke - a.janke@gmail.com ๐Ÿ’Œ


๐Ÿ“œ COPYRIGHTS ๐Ÿ“œ

Copyright ยฉ 2000 by Andrew Janke ๐ŸŽ€


๐Ÿ”— SEE ALSO ๐Ÿ”—

mincmath(1) โœจ


okay that's the whole vibe, bestie. this page is from MINCCALC(1) and the date on it is $Date: 2008-01-11 04:24:16 $. periodt. ๐Ÿ’–๐Ÿ‘‘

๐Ÿ“ฆ where this page comes from