This file is indexed.

/usr/include/teem/ten.h is in libteem-dev 1.11.0~svn6057-1ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
/*
  Teem: Tools to process and visualize scientific data and images             .
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public License
  (LGPL) as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  The terms of redistributing and/or modifying this software also
  include exceptions to the LGPL that facilitate static linking.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with this library; if not, write to Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef TEN_HAS_BEEN_INCLUDED
#define TEN_HAS_BEEN_INCLUDED

#include <math.h>

#include <teem/air.h>
#include <teem/biff.h>
#include <teem/ell.h>
#include <teem/nrrd.h>
#include <teem/unrrdu.h>
#include <teem/dye.h>
#include <teem/gage.h>
#include <teem/limn.h>
#include <teem/echo.h>

#include "tenMacros.h"

#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(TEEM_STATIC)
#  if defined(TEEM_BUILD) || defined(ten_EXPORTS) || defined(teem_EXPORTS)
#    define TEN_EXPORT extern __declspec(dllexport)
#  else
#    define TEN_EXPORT extern __declspec(dllimport)
#  endif
#else /* TEEM_STATIC || UNIX */
#  define TEN_EXPORT extern
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define TEN tenBiffKey

/*
****** tenAniso* enum
**
** the different scalar values that can describe a tensor.  Nearly
** all of these are anisotropy metrics, but with time this has become
** a convenient way to present any scalar invariant (such as trace),
** and even the individual eigenvalues
**
** keep in sync:
** aniso.c: _tenAnisoEval_X_f(), _tenAnisoEval_f[]
** aniso.c: _tenAnisoTen_X_d(), _tenAnisoTen_d[]
** aniso.c: tenAnisoCalc_f()
** enumsTen.c: tenAniso
*/
enum {
  tenAnisoUnknown,  /*  0: nobody knows */
  tenAniso_Conf,    /*  1: not an anisotropy, but enables some useful hacks */
  tenAniso_Cl1,     /*  2: Westin's linear (first version) */
  tenAniso_Cp1,     /*  3: Westin's planar (first version) */
  tenAniso_Ca1,     /*  4: Westin's linear + planar (first version) */
  tenAniso_Clpmin1, /*  5: minimum of Cl and Cp (first version) */
  tenAniso_Cs1,     /*  6: Westin's spherical (first version) */
  tenAniso_Ct1,     /*  7: gk's anisotropy type (first version) */
  tenAniso_Cl2,     /*  8: Westin's linear (second version) */
  tenAniso_Cp2,     /*  9: Westin's planar (second version) */
  tenAniso_Ca2,     /* 10: Westin's linear + planar (second version) */
  tenAniso_Clpmin2, /* 11: minimum of Cl and Cp (second version) */
  tenAniso_Cs2,     /* 12: Westin's spherical (second version) */
  tenAniso_Ct2,     /* 13: gk's anisotropy type (second version) */
  tenAniso_RA,      /* 14: Bass+Pier's relative anisotropy */
  tenAniso_FA,      /* 15: (Bass+Pier's fractional anisotropy)/sqrt(2) */
  tenAniso_VF,      /* 16: volume fraction = 1-(Bass+Pier's volume ratio) */
  tenAniso_B,       /* 17: linear term in cubic characteristic polynomial */
  tenAniso_Q,       /* 18: radius of root circle is 2*sqrt(Q) */
  tenAniso_R,       /* 19: half of third moment of eigenvalues */
  tenAniso_S,       /* 20: frobenius norm, squared */
  tenAniso_Skew,    /* 21: R/sqrt(2*Q^3) */
  tenAniso_Mode,    /* 22: 3*sqrt(6)*det(dev)/norm(dev) = sqrt(2)*skew */
  tenAniso_Th,      /* 23: acos(sqrt(2)*skew)/3 */
  tenAniso_Omega,   /* 24: FA*(1+mode)/2 */
  tenAniso_Det,     /* 25: plain old determinant */
  tenAniso_Tr,      /* 26: plain old trace */
  tenAniso_eval0,   /* 27: largest eigenvalue */
  tenAniso_eval1,   /* 28: middle eigenvalue */
  tenAniso_eval2,   /* 29: smallest eigenvalue */
  tenAnisoLast
};
#define TEN_ANISO_MAX  29

/*
******** tenInterpType* enum
**
** different kinds of interpolations paths between tensors
*/
enum {
  tenInterpTypeUnknown,         /*  0: nobody knows */
  tenInterpTypeLinear,          /*  1: simple per-coefficient linear */
  tenInterpTypeLogLinear,       /*  2: linear on logs (Log-Euclidean) */
  tenInterpTypeAffineInvariant, /*  3: Riemannian approach of many authors */
  tenInterpTypeWang,            /*  4: affine-invariant of Z Wang & B Vemuri */
  tenInterpTypeGeoLoxK,         /*  5: geodesic-loxodrome on K_i invariants */
  tenInterpTypeGeoLoxR,         /*  6: geodesic-loxodrome on R_i invariants */
  tenInterpTypeLoxK,            /*  7: total loxodrome on K_i invariants */
  tenInterpTypeLoxR,            /*  8: total loxodrome on R_i invariants */
  tenInterpTypeQuatGeoLoxK,     /*  9: geodesic-loxodrome on K_i invariants */
  tenInterpTypeQuatGeoLoxR,     /* 10: geodesic-loxodrome on R_i invariants */
  tenInterpTypeRThetaPhiLinear, /* 11: linear interpolation of (R,theta,phi),
                                   oriented by eigensystem of linear avg */
  tenInterpTypeLast
};
#define TEN_INTERP_TYPE_MAX        11

/*
******** tenGlyphType* enum
**
** the different types of glyphs that may be used for tensor viz
*/
enum {
  tenGlyphTypeUnknown,    /* 0: nobody knows */
  tenGlyphTypeBox,        /* 1 */
  tenGlyphTypeSphere,     /* 2 */
  tenGlyphTypeCylinder,   /* 3 */
  tenGlyphTypeSuperquad,  /* 4 */
  tenGlyphTypeBetterquad, /* 5: for T Schultz, GL Kindlmann.
                             Superquadric Glyphs for Symmetric
                             Second-Order Tensors. IEEE TVCG
                             Nov/Dec 2010, 16(6):1595-1604 */
  tenGlyphTypePolarPlot,  /* 6 */
  tenGlyphTypeLast
};
#define TEN_GLYPH_TYPE_MAX   6

/*
******** tenGlyphParm struct
**
** all input parameters to tenGlyphGen
*/
typedef struct {
  int verbose;

  /* glyphs will be shown at samples that have confidence >= confThresh,
     and anisotropy anisoType >= anisoThresh, and if nmask is non-NULL,
     then the corresponding mask value must be >= maskThresh.  If
     onlyPositive, then samples with a non-positive eigenvalue will
     be skipped, regardless of their purported anisotropy */
  Nrrd *nmask;
  int anisoType, onlyPositive;
  float confThresh, anisoThresh, maskThresh;

  /* glyphs have shape glyphType and size glyphScale. Superquadrics
     are tuned by sqdSharp, and things that must polygonalize do so
     according to facetRes.  Postscript rendering of glyph edges is
     governed by edgeWidth[] */
  int glyphType, facetRes;
  float glyphScale, sqdSharp;
  float edgeWidth[5];  /* 0: contour, 1: front crease, 2: front non-crease */

  /* glyphs are colored by eigenvector colEvec with the standard XYZ-RGB
     colormapping, with maximal saturation colMaxSat (use 0.0 to turn off
     coloring).  Saturation is modulated by anisotropy colAnisoType, to a
     degree controlled by colAnisoModulate (if 0, saturation is not at all
     modulated by anistropy).  Post-saturation, there is a per-channel
     gamma of colGamma. */
  int colEvec, colAnisoType;
  float colMaxSat, colIsoGray, colGamma, colAnisoModulate, ADSP[4];

  /* if doSlice, a slice of anisotropy sliceAnisoType will be depicted
     in grayscale as a sheet of grayscale squares, one per sample. As
     with glyphs, these are thresholded by confThresh and maskThresh
     (but not anisoThresh).  Things can be lightened up with a
     sliceGamma > 1, after the slice's gray values have been mapped from
     [0,1] to [sliceBias,1]. The squares will be at their corresponding
     sample locations, but offset by sliceOffset */
  unsigned int sliceAxis;
  size_t slicePos;
  int doSlice, sliceAnisoType;
  float sliceOffset, sliceBias, sliceGamma;
} tenGlyphParm;

#define TEN_ANISO_DESC \
  "All the Westin metrics come in two versions.  Currently supported:\n " \
  "\b\bo \"cl1\", \"cl2\": Westin's linear\n " \
  "\b\bo \"cp1\", \"cp2\": Westin's planar\n " \
  "\b\bo \"ca1\", \"ca2\": Westin's linear + planar\n " \
  "\b\bo \"cs1\", \"cs2\": Westin's spherical (1-ca)\n " \
  "\b\bo \"ct1\", \"ct2\": GK's anisotropy type (cp/ca)\n " \
  "\b\bo \"ra\": Basser/Pierpaoli relative anisotropy/sqrt(2)\n " \
  "\b\bo \"fa\": Basser/Pierpaoli fractional anisotropy\n " \
  "\b\bo \"vf\": volume fraction = 1-(Basser/Pierpaoli volume ratio)\n " \
  "\b\bo \"tr\": trace"

/*
******** tenGage* enum
**
** all the possible queries supported in the tenGage gage kind
** various properties of the quantities below (eigenvalues = v1, v2, v3):
** eigenvalue cubic equation: v^3 + A*v^2 + B*v + C = 0
** Trace = v1 + v2 + v3 = -A
** B = v1*v2 + v1*v3 + v2*v3
** Det = v1*v2*v3 = -C
** S = v1*v1 + v2*v2 + v3*v3
** Q = (S-B)/9 = variance({v1,v2,v3})/2 = (RootRadius/2)^2
** FA = 3*sqrt(Q/S)
** R = (9*A*B - 2*A^3 - 27*C)/54
     = (5*A*B - 2*A*S - 27*C)/54 = thirdmoment({v1,v2,v3})/2
** P = arccos(R/sqrt(Q)^3)/3 = phase angle of cubic solution
**
** NOTE: currently tenGage knows *nothing* about nrrd->measurementFrame!
** You probably want to call tenMeasurementFrameReduce() first.
**
** Hey- the problem with adding the RGB eigenvector coloring to the
** capability of tenGage is that because this is visualization, you
** can't easily control whether the measurement frame is applied, if
** known- in that sense the RGB info is uniquely different from the
** other vector and tensor items that can be queried . . . so after a
** brief appearance here the RGB evec coloring was removed.  The
** gagePerVolume->data field that it motivated has rightly remained.
**
** !!! Changes to this list need to be propogated to:
** !!! tenGage.c: _tenGageTable[], _tenGageAnswer(),
** !!! enumsTen.c: tenGage airEnum.
**
*/
enum {
  tenGageUnknown,          /*   0: nobody knows */

  tenGageTensor,           /*   1: "t", the reconstructed tensor: [7] */
  tenGageConfidence,       /*   2: "c", first of seven tensor values: [1] */
  tenGageTrace,            /*   3: "tr", trace of tensor: [1] */
  tenGageNorm,             /*   4: "n", frobenius norm  of tensor: [1] */
  tenGageB,                /*   5: "b": [1] */
  tenGageDet,              /*   6: "det", determinant of tensor: [1] */
  tenGageS,                /*   7: "s", square of frobenius norm: [1] */
  tenGageQ,                /*   8: "q", (S - B)/9: [1] */
  tenGageFA,               /*   9: "fa", fractional anisotropy: [1] */
  tenGageR,                /*  10: "r", 9*A*B - 2*A^3 - 27*C: [1] */
  tenGageMode,             /*  11: "mode", sqrt(2)*R/sqrt(Q^3): [1] */
  tenGageTheta,            /*  12: "th", arccos(-mode)/AIR_PI: [1] */
  tenGageModeWarp,         /*  13: "modew", mode warped for better contrast:
                                   cos((1-m)*pi/2): [1] */
  tenGageOmega,            /*  14: "om", fa*(mode+1)/2: [1] */

  tenGageEval,             /*  15: "eval", all eigenvals of tensor : [3] */
  tenGageEval0,            /*  16: "eval0", major eigenval of tensor : [1] */
  tenGageEval1,            /*  17: "eval1", medium eigenval of tensor : [1] */
  tenGageEval2,            /*  18: "eval2", minor eigenval of tensor : [1] */
  tenGageEvec,             /*  19: "evec", major eigenvects of tensor: [9] */
  tenGageEvec0,            /*  20: "evec0", major eigenvect of tensor: [3] */
  tenGageEvec1,            /*  21: "evec1", medium eigenvect of tensor: [3] */
  tenGageEvec2,            /*  22: "evec2", minor eigenvect of tensor: [3] */

  tenGageDelNormK2,        /*  23: "delnk2": normalized gradient tensor of
                                   K2 = eval variance: [7] */
  tenGageDelNormK3,        /*  24: "delnk3": normal gradient tensor of
                                   K3 = R3 = eval skewness: [7] */
  tenGageDelNormR1,        /*  25: "delnr1": normalized gradient tensor of
                                   R1 = tensor norm: [7] */
  tenGageDelNormR2,        /*  26: "delnr2": normalized gradient tensor of
                                   R2 = FA: [7] */
  tenGageDelNormPhi1,      /*  27: "delnphi1": normalized rotation tangent
                                    around principal evector: [7] */
  tenGageDelNormPhi2,      /*  28: "delnphi2": normalized rotation tangent
                                    rotation around medium evector: [7] */
  tenGageDelNormPhi3,      /*  29: "delnphi3": normalized rotation tangent
                                    rotation around minor evector: [7] */

  tenGageTensorGrad,       /*  30: "tg", all tensor component gradients,
                                   starting with confidence gradient: [21] */
  tenGageTensorGradMag,    /*  31: "tgm", actually a 3-vector of tensor
                                   gradient norms, one for each axis: [3] */
  tenGageTensorGradMagMag, /*  32: "tgmm", single scalar magnitude: [1] */

  tenGageTraceGradVec,     /*  33: "trgv": gradient (vector) of trace: [3] */
  tenGageTraceGradMag,     /*  34: "trgm": gradient magnitude of trace: [1] */
  tenGageTraceNormal,      /*  35: "trn": normal of trace: [3] */

  tenGageNormGradVec,      /*  36: "ngv", gradient (vector) of norm: [3] */
  tenGageNormGradMag,      /*  37: "ngm", gradient magnitude of norm: [1] */
  tenGageNormNormal,       /*  38: "nn", normal of norm: [3] */

  tenGageBGradVec,         /*  39: "bgv", gradient (vector) of B: [3] */
  tenGageBGradMag,         /*  40: "bgm", gradient magnitude of B: [1] */
  tenGageBNormal,          /*  41: "bn", normal of B: [3] */

  tenGageDetGradVec,       /*  42: "detgv", gradient (vector) of Det: [3] */
  tenGageDetGradMag,       /*  43: "detgm", gradient magnitude of Det: [1] */
  tenGageDetNormal,        /*  44: "detn", normal of Det: [3] */

  tenGageSGradVec,         /*  45: "sgv", gradient (vector) of S: [3] */
  tenGageSGradMag,         /*  46: "sgm", gradient magnitude of S: [1] */
  tenGageSNormal,          /*  47: "sn", normal of S: [3] */

  tenGageQGradVec,         /*  48: "qgv", gradient vector of Q: [3] */
  tenGageQGradMag,         /*  49: "qgm", gradient magnitude of Q: [1] */
  tenGageQNormal,          /*  50: "qn", normalized gradient of Q: [3] */

  tenGageFAGradVec,        /*  51: "fagv", gradient vector of FA: [3] */
  tenGageFAGradMag,        /*  52: "fagm", gradient magnitude of FA: [1] */
  tenGageFANormal,         /*  53: "fan", normalized gradient of FA: [3] */

  tenGageRGradVec,         /*  54: "rgv", gradient vector of Q: [3] */
  tenGageRGradMag,         /*  55: "rgm", gradient magnitude of Q: [1] */
  tenGageRNormal,          /*  56: "rn", normalized gradient of Q: [3] */

  tenGageModeGradVec,      /*  57: "mgv", gradient vector of Mode: [3] */
  tenGageModeGradMag,      /*  58: "mgm", gradient magnitude of Mode: [1] */
  tenGageModeNormal,       /*  59: "mn", normalized gradient of Mode: [3] */

  tenGageThetaGradVec,     /*  60: "thgv", gradient vector of Th: [3] */
  tenGageThetaGradMag,     /*  61: "thgm", gradient magnitude of Th: [1] */
  tenGageThetaNormal,      /*  62: "thn", normalized gradient of Th: [3] */

  tenGageOmegaGradVec,     /*  63: "omgv", gradient vector of Omega: [3] */
  tenGageOmegaGradMag,     /*  64: "omgm", gradient magnitude of Omega: [1] */
  tenGageOmegaNormal,      /*  65: "omn", normalized gradient of Omega: [3] */

  tenGageInvarKGrads,      /*  66: "ikgs", projections of tensor gradient onto
                                  the normalized shape gradients: eval mean,
                                  variance, skew, in that order: [9]  */
  tenGageInvarKGradMags,   /*  67: "ikgms", vector magnitude of the spatial
                                  invariant gradients (above): [3] */
  tenGageInvarRGrads,      /*  68: "irgs", projections of tensor gradient onto
                                  the normalized shape gradients: eval mean,
                                  variance, skew, in that order: [9]  */
  tenGageInvarRGradMags,   /*  69: "irgms", vector magnitude of the spatial
                                  invariant gradients (above): [3] */
  tenGageRotTans,          /*  70: "rts", projections of the tensor grad onto
                                   *normalized* rotation tangents: [9] */
  tenGageRotTanMags,       /*  71: "rtms", mags of vectors above: [3] */
  tenGageEvalGrads,        /*  72: "evgs", projections of tensor gradient onto
                                   gradients of eigenvalues: [9] */
  tenGageCl1,              /*  73: same as tenAniso_Cl1, but faster */
  tenGageCp1,              /*  74: same as tenAniso_Cp1, but faster */
  tenGageCa1,              /*  75: same as tenAniso_Ca1, but faster */
  tenGageClpmin1,          /*  76: min(cl1,cp1) */
  tenGageCl2,              /*  77: same as tenAniso_Cl2, but faster */
  tenGageCp2,              /*  78: same as tenAniso_Cp2, but faster */
  tenGageCa2,              /*  79: same as tenAniso_Ca2, but faster */
  tenGageClpmin2,          /*  80: min(cl2,cp2) */

  tenGageHessian,          /*  81: "hess", all hessians of tensor
                                   components: [63] */
  tenGageTraceHessian,     /*  82: "trhess", hessian(trace): [9] */
  tenGageTraceHessianEval,  /*  83 */
  tenGageTraceHessianEval0, /*  84 */
  tenGageTraceHessianEval1, /*  85 */
  tenGageTraceHessianEval2, /*  86 */
  tenGageTraceHessianEvec,  /*  87 */
  tenGageTraceHessianEvec0, /*  88 */
  tenGageTraceHessianEvec1, /*  89 */
  tenGageTraceHessianEvec2, /*  90 */
  tenGageTraceHessianFrob,  /*  91 */
  tenGageBHessian,         /*  92: "bhess": [9] */
  tenGageDetHessian,       /*  93: "dethess": [9] */
  tenGageSHessian,         /*  94: "shess": [9] */
  tenGageQHessian,         /*  95: "qhess": [9] */

  tenGageFAHessian,        /*  96: "fahess": [9] */
  tenGageFAHessianEval,    /*  97: "fahesseval": [3] */
  tenGageFAHessianEval0,   /*  98: "fahesseval0": [1] */
  tenGageFAHessianEval1,   /*  99: "fahesseval1": [1] */
  tenGageFAHessianEval2,   /* 100: "fahesseval2": [1] */
  tenGageFAHessianEvec,    /* 101: "fahessevec": [9] */
  tenGageFAHessianEvec0,   /* 102: "fahessevec0": [3] */
  tenGageFAHessianEvec1,   /* 103: "fahessevec1": [3] */
  tenGageFAHessianEvec2,   /* 104: "fahessevec2": [3] */
  tenGageFAHessianFrob,    /* 105 */
  tenGageFARidgeSurfaceStrength,  /* 106: "farsurfstrn": [1] */
  tenGageFAValleySurfaceStrength, /* 107: "favsurfstrn": [1] */
  tenGageFALaplacian,      /* 108: "falapl": [1] */
  tenGageFAHessianEvalMode,/* 109: "fahessevalmode": [1] */
  tenGageFARidgeLineAlignment,    /* 110: "farlinealn": [1] */
  tenGageFARidgeSurfaceAlignment, /* 111: "farsurfaln": [1] */
  tenGageFA2ndDD,          /* 112: "fa2d": [1] */

  tenGageFAGeomTens,       /* 113: "fagten", sym. matx w/ evals {0, K1, K2}
                                   and evecs {grad, cdir0, cdir1}: [9] */
  tenGageFAKappa1,         /* 114: "fak1", 1st princ curv: [1] */
  tenGageFAKappa2,         /* 115: "fak2", 2nd princ curv (k2 <= k1): [1] */
  tenGageFATotalCurv,      /* 116: "fatc", L2 norm(K1,K2): [1] */
  tenGageFAShapeIndex,     /* 117: "fasi", Koen.'s shape index, ("S"): [1] */
  tenGageFAMeanCurv,       /* 118: "famc", mean curvature (K1 + K2)/2: [1] */
  tenGageFAGaussCurv,      /* 119: "fagc", gaussian curvature K1*K2: [1] */
  tenGageFACurvDir1,       /* 120: "facdir1", 1st princ curv direction: [3] */
  tenGageFACurvDir2,       /* 121: "facdir2", 2nd princ curv direction: [3] */
  tenGageFAFlowlineCurv,   /* 122: "fafc", curv of normal streamline: [1] */

  tenGageRHessian,         /* 123: "rhess": [9] */

  tenGageModeHessian,      /* 124: "mhess": [9] */
  tenGageModeHessianEval,  /* 125: "mhesseval": [3] */
  tenGageModeHessianEval0, /* 126: "mhesseval0": [1] */
  tenGageModeHessianEval1, /* 127: "mhesseval1": [1] */
  tenGageModeHessianEval2, /* 128: "mhesseval2": [1] */
  tenGageModeHessianEvec,  /* 129: "mhessevec": [9] */
  tenGageModeHessianEvec0, /* 130: "mhessevec0": [3] */
  tenGageModeHessianEvec1, /* 131: "mhessevec1": [3] */
  tenGageModeHessianEvec2, /* 132: "mhessevec2": [3] */
  tenGageModeHessianFrob,  /* 133 */

  tenGageOmegaHessian,     /* 134: "omhess": [9] */
  tenGageOmegaHessianEval, /* 135: "omhesseval": [3] */
  tenGageOmegaHessianEval0,/* 136: "omhesseval0": [1] */
  tenGageOmegaHessianEval1,/* 137: "omhesseval1": [1] */
  tenGageOmegaHessianEval2,/* 138: "omhesseval2": [1] */
  tenGageOmegaHessianEvec, /* 139: "omhessevec": [9] */
  tenGageOmegaHessianEvec0,/* 140: "omhessevec0": [3] */
  tenGageOmegaHessianEvec1,/* 141: "omhessevec1": [3] */
  tenGageOmegaHessianEvec2,/* 142: "omhessevec2": [3] */
  tenGageOmegaLaplacian,   /* 143: "omlapl": [1] */
  tenGageOmega2ndDD,       /* 144: "om2d": [1] */
  tenGageOmegaHessianContrTenEvec0, /* 145: "omhesscte0": [1] */
  tenGageOmegaHessianContrTenEvec1, /* 146: "omhesscte1": [1] */
  tenGageOmegaHessianContrTenEvec2, /* 147: "omhesscte2": [1] */

  tenGageTraceGradVecDotEvec0,   /* 148: "trgvdotevec0": [1] */
  tenGageTraceDiffusionAlign,    /* 149: "datr": [1] */
  tenGageTraceDiffusionFraction, /* 150: "dftr": [1] */
  tenGageFAGradVecDotEvec0,      /* 151: "fagvdotevec0": [1] */
  tenGageFADiffusionAlign,       /* 152: "dafa": [1] */
  tenGageFADiffusionFraction,    /* 153: "dffa": [1] */
  tenGageOmegaGradVecDotEvec0,   /* 154: "omgvdotevec0": [1] */
  tenGageOmegaDiffusionAlign,    /* 155: "daom": [1] */
  tenGageOmegaDiffusionFraction, /* 156: "dfom": [1] */
  tenGageConfGradVecDotEvec0,    /* 157: "confgvdotevec0": [1] */
  tenGageConfDiffusionAlign,     /* 158: "daconf": [1] */
  tenGageConfDiffusionFraction,  /* 159: "dfconf": [1] */

  tenGageCovariance, /* 160: "cov" 4rth order covariance tensor: [21]
                        in order of appearance:
                        0:xxxx  1:xxxy  2:xxxz  3:xxyy  4:xxyz  5:xxzz
                                6:xyxy  7:xyxz  8:xyyy  9:xyyz 10:xyzz
                                       11:xzxz 12:xzyy 13:xzyz 14:xzzz
                                               15:yyyy 16:yyyz 17:yyzz
                                                       18:yzyz 19:yzzz
                                                               20:zzzz */
  tenGageCovarianceRGRT, /* 161: "covr" covariance tensor expressed in frame
                            of R invariant gradients and rotation tangents */
  tenGageCovarianceKGRT, /* 162: "covk" covariance tensor expressed in frame
                            of K invariant gradients and rotation tangents */
  tenGageTensorLogEuclidean,     /* 163: "logeuc" log-euclidean interp */
  tenGageTensorQuatGeoLoxK,      /* 164: "qglk" QGL-K interpolation */
  tenGageTensorQuatGeoLoxR,      /* 165: "qglr" QGL-R interpolation */
  tenGageTensorRThetaPhiLinear,  /* 166: "rtpl" RThetaPhiLinear interp */

  tenGageCl1GradVec,       /* 167: "cl1gv" gradient vector of cl1: [3] */
  tenGageCl1GradMag,       /* 168: "cl1gm" gradient magnitude of cl1: [1] */
  tenGageCl1Normal,        /* 169: "cl1gn" normal of cl1: [3] */
  tenGageCp1GradVec,       /* 170: "cp1gv" gradient vector of cp1: [3] */
  tenGageCp1GradMag,       /* 171: "cp1gm" gradient magnitude of cp1: [1] */
  tenGageCp1Normal,        /* 172: "cl1gn" normal of cp1: [3] */
  tenGageCa1GradVec,       /* 173: "ca1gv" gradient vector of ca1: [3] */
  tenGageCa1GradMag,       /* 174: "ca1gm" gradient magnitude of ca1: [1] */
  tenGageCa1Normal,        /* 175: "cl1gn" normal of ca1: [3] */
  tenGageTensorGradRotE,   /* 176: "tgrote" all tensor component gradients,
                              starting with confidence gradient.
                              Rotated such that eigenvalue
                              derivatives are on the diagonal: [21] */
  tenGageEvalHessian,    /* 177: "evalhess" Hessian of the eigenvalues: [27] */
  tenGageCl1Hessian,     /* 178: "cl1hess" Hessian of cl1: [9] */
  tenGageCl1HessianEval, /* 179: "cl1hesseval" Hessian evals of cl1: [3] */
  tenGageCl1HessianEval0,/* 180: "cl1hesseval0" First Hess eval of cl1: [1] */
  tenGageCl1HessianEval1,/* 181: "cl1hesseval1" Second Hess eval of cl1: [1] */
  tenGageCl1HessianEval2,/* 182: "cl1hesseval2" Third Hess eval of cl1: [1] */
  tenGageCl1HessianEvec, /* 183: "cl1hessevec" Hessian evecs of cl1: [9] */
  tenGageCl1HessianEvec0,/* 184: "cl1hessevec0" First Hess evec of cl1: [3] */
  tenGageCl1HessianEvec1,/* 185: "cl1hessevec1" Second Hess evec of cl1: [3] */
  tenGageCl1HessianEvec2,/* 186: "cl1hessevec2" Third Hess evec of cl1: [3] */
  tenGageCp1Hessian,     /* 187: "cp1hess" Hessian of cp1: [9] */
  tenGageCp1HessianEval, /* 188: "cp1hesseval" Hessian evals of cp1: [3] */
  tenGageCp1HessianEval0,/* 189: "cp1hesseval0" First Hess eval of cp1: [1] */
  tenGageCp1HessianEval1,/* 190: "cp1hesseval1" Second Hess eval of cp1: [1] */
  tenGageCp1HessianEval2,/* 191: "cp1hesseval2" Third Hess eval of cp1: [1] */
  tenGageCp1HessianEvec, /* 192: "cp1hessevec" Hessian evecs of cp1: [9] */
  tenGageCp1HessianEvec0,/* 193: "cp1hessevec0" First Hess evec of cp1: [3] */
  tenGageCp1HessianEvec1,/* 194: "cp1hessevec1" Second Hess evec of cp1: [3] */
  tenGageCp1HessianEvec2,/* 195: "cp1hessevec2" Third Hess evec of cp1: [3] */
  tenGageCa1Hessian,     /* 196: "ca1hess" Hessian of ca1: [9] */
  tenGageCa1HessianEval, /* 197: "ca1hesseval" Hessian evals of ca1: [3] */
  tenGageCa1HessianEval0,/* 198: "ca1hesseval0" First Hess eval of ca1: [1] */
  tenGageCa1HessianEval1,/* 199: "ca1hesseval1" Second Hess eval of ca1: [1] */
  tenGageCa1HessianEval2,/* 200: "ca1hesseval2" Third Hess eval of ca1: [1] */
  tenGageCa1HessianEvec, /* 201: "ca1hessevec" Hessian evecs of ca1: [9] */
  tenGageCa1HessianEvec0,/* 202: "ca1hessevec0" First Hess evec of ca1: [3] */
  tenGageCa1HessianEvec1,/* 203: "ca1hessevec1" Second Hess evec of ca1: [3] */
  tenGageCa1HessianEvec2,/* 204: "ca1hessevec2" Third Hess evec of ca1: [3] */
  tenGageFiberCurving,   /* 205: "fibcurv" Savadjiev et al. fiber curving */
  tenGageFiberDispersion,/* 206: "fibdisp" Savadjiev et al. fiber dispersion */
  tenGageAniso,          /* 207: "an", all anisos: [TEN_ANISO_MAX+1] */
  tenGageLast
};
#define TEN_GAGE_ITEM_MAX     207

/*
******** tenDwiGage* enum
**
** all things that can be measured in the diffusion weighted images that
** underly diffusion tensor imaging
*/
enum {
  tenDwiGageUnknown,        /* 0: nobody knows */

  /*  1: "all", all the measured values, both baseline and diffusion
      weighted: [N], where N is the number of DWIs */
  tenDwiGageAll,

  /*  2: "b0", the non-Dwi image value, either by direct measurement
      or by estimation: [1]
      HEY: currently a hack, because it assumes a single known B0 */
  tenDwiGageB0,

  /*  3: "jdwi", just the DWIs, no B0: [N-1] (HEY same hack) */
  tenDwiGageJustDWI,

  /*  4: "adc", ADCs from the DWIs: [N-1] (HEY same hack) */
  tenDwiGageADC,

  /*  5: "mdwi", the average Dwi image value, which is thresholded to
      create the confidence mask: [1] */
  tenDwiGageMeanDWIValue,

  /*  6: "tlls": [7],
      7: "tllserr": [1],
      8: "tllserrlog": [1],
      9: "tllslike": [1],
     linear least squares fit of tensor value to log(Dwi)s */
  tenDwiGageTensorLLS,
  tenDwiGageTensorLLSError,      /* RMS error w/ Dwis */
  tenDwiGageTensorLLSErrorLog,   /* RMS error w/ log(Dwi)s */
  tenDwiGageTensorLLSLikelihood,

  /* 10: "twls": [7],
     11: "twlserr": [1],
     12: "twlserrlog": [1],
     13: "twlslike": [1],
     weighted least squares fit of tensor value to log(Dwi)s */
  tenDwiGageTensorWLS,
  tenDwiGageTensorWLSError,
  tenDwiGageTensorWLSErrorLog,
  tenDwiGageTensorWLSLikelihood,

  /* 14: "tnls": [7],
     15: "tnlserr": [1],
     16: "tnlserrlog": [1],
     17: "tnlslike": [1],
     non-linear least squares fit of tensor value to Dwis (not log) */
  tenDwiGageTensorNLS,
  tenDwiGageTensorNLSError,
  tenDwiGageTensorNLSErrorLog,
  tenDwiGageTensorNLSLikelihood,

  /* 18: "tmle": [7],
     19: "tmleerr": [1],
     20: "tmleerrlog": [1],
     21: "tmlelike": [1],
     maximum-likelihood fit of tensor value to Dwis */
  tenDwiGageTensorMLE,
  tenDwiGageTensorMLEError,
  tenDwiGageTensorMLEErrorLog,
  tenDwiGageTensorMLELikelihood,

  /* 22: "t": [7],
     23: "terr": [1],
     24: "terrlog": [1],
     25: "tlike": [1],
     one of the above tensors and its errors, depending on settings */
  tenDwiGageTensor,
  tenDwiGageTensorError,
  tenDwiGageTensorErrorLog,
  tenDwiGageTensorLikelihood,

  /* 26: "c", first of seven tensor values: [1] */
  tenDwiGageConfidence,

  /* 27: "fa", FA computed from the single tensor: [1] */
  tenDwiGageFA,

  /* 28: "adwie", all errors between measured and predicted DWIs
     [N-1] (HEY same hack) */
  tenDwiGageTensorAllDWIError,

  /* 29: "2qserr": [1]
     30: "2qs", two tensor fitting by q-ball segmentation: [14]
     31: "2qsnerr": [15] */
  tenDwiGage2TensorQSeg,
  tenDwiGage2TensorQSegError,
  tenDwiGage2TensorQSegAndError,

  /* 32: "2pelederr": [1]
     33: "2peled", two tensor fitting by q-ball segmentation: [14]
     34: "2pelednerr": [15] */
  tenDwiGage2TensorPeled,
  tenDwiGage2TensorPeledError,
  tenDwiGage2TensorPeledAndError,

  /* 35: "2peledlminfo", levmar output info vector: [9]
     note: length 9 being correct is checked in _tenDwiGagePvlDataNew() */
  tenDwiGage2TensorPeledLevmarInfo,

  tenDwiGageLast
};
#define TEN_DWI_GAGE_ITEM_MAX 35

/*
******** tenEstimate1Method* enum
**
** the different ways of doing single tensor estimation
*/
enum {
  tenEstimate1MethodUnknown,   /* 0 */
  tenEstimate1MethodLLS,       /* 1 */
  tenEstimate1MethodWLS,       /* 2 */
  tenEstimate1MethodNLS,       /* 3 */
  tenEstimate1MethodMLE,       /* 4 */
  tenEstimate1MethodLast
};
#define TEN_ESTIMATE_1_METHOD_MAX 4

/*
******** tenEstimate2Method* enum
**
** the different ways of doing two-tensor estimation
*/
enum {
  tenEstimate2MethodUnknown,   /* 0 */
  tenEstimate2MethodQSegLLS,   /* 1 */
  tenEstimate2MethodPeled,     /* 2 */
  tenEstimate2MethodLast
};
#define TEN_ESTIMATE_2_METHOD_MAX 2

/*
******** tenEvecRGBParm struct
**
** dumb little bag for the parameters relating to how to do the
** eigenvector -> RGB mapping, since its needed by various things in
** various contexts.  Note that you may need two of these, one for
** doing rgb(evec0) (the linear part) and one for doing rgb(evec2)
** (the planar part).  This used to have "aniso0" and "aniso2", but
** the associated methods were clumsy and redundant.
*/
typedef struct {
  unsigned int which; /* when the eigenvector hasn't already been computed,
                         which eigenvector to map:
                         0 for linear, 2 or planar, 1 for orthotropic */
  int aniso;          /* which anisotropy metric modulates saturation */
  double confThresh,  /* confidence threshold */
    anisoGamma,       /* gamma on aniso, pre-mapping */
    gamma,            /* per RGB component gamma, post-mapping */
    bgGray,           /* gray-value for low confidence samples */
    isoGray,          /* gray-value for isotropic samples */
    maxSat;           /* maximum saturation */
  int typeOut,        /* when output type is flexible, and if this is
                         nrrdTypeUChar or nrrdTypeUShort, then output will
                         be quantized to those types (range [0,255] and
                         [0,65535] respectively); otherwise values are
                         copied directly to output */
    genAlpha;         /* when output value set is flexible, create RGBA
                         values instead of just RGB */
} tenEvecRGBParm;

/*
******** tenFiberType* enum
**
** the different kinds of fiber tractography that we do
*/
enum {
  tenFiberTypeUnknown,    /* 0: nobody knows */
  tenFiberTypeEvec0,      /* 1: standard following of principal eigenvector */
  tenFiberTypeEvec1,      /* 2: following medium eigenvector */
  tenFiberTypeEvec2,      /* 3: following minor eigenvector */
  tenFiberTypeTensorLine, /* 4: Weinstein-Kindlmann tensorlines */
  tenFiberTypePureLine,   /* 5: "pure" tensorlines- multiplication only */
  tenFiberTypeZhukov,     /* 6: Zhukov's oriented tensor reconstruction */
  tenFiberTypeLast
};
#define TEN_FIBER_TYPE_MAX   6

/*
******** tenDwiFiberType* enum
**
** how tractography is done in DWI volumes.  This is orthogonal to
** how single- or two-tensor estimation is done; it describes what we
** do with the model(s) once estimated
*/
enum {
  tenDwiFiberTypeUnknown,      /* 0: nobody knows */
  tenDwiFiberType1Evec0,       /* 1: like old-fashioned tractography */
  tenDwiFiberType2Evec0,       /* 2: only using 2-tensor fits */
  tenDwiFiberType12BlendEvec0, /* 3: blend between 1- and 2-ten evec0 methods,
                                  based on something else */
  tenDwiFiberTypeLast
};
#define TEN_DWI_FIBER_TYPE_MAX    3

/*
******** tenFiberIntg* enum
**
** the different integration styles supported.  Obviously, this is more
** general purpose than fiber tracking, so this will be moved (elsewhere
** in Teem) as needed
*/
enum {
  tenFiberIntgUnknown,   /* 0: nobody knows */
  tenFiberIntgEuler,     /* 1: dumb but fast */
  tenFiberIntgMidpoint,  /* 2: 2nd order Runge-Kutta */
  tenFiberIntgRK4,       /* 3: 4rth order Runge-Kutta */
  tenFiberIntgLast
};
#define TEN_FIBER_INTG_MAX  3

/*
******** tenFiberStop* enum
**
** the different reasons why fibers stop going (as stored in
** tenFiberSingle->whyStop[]), or never got started
** (tenFiberSingle->whyNowhere), or never went far enough (also
** tenFiberSingle->whyNowhere).
**
** The addition of tenFiberStopMinLength and tenFiberStopMinNumSteps
** really stretch the meaningfulness of "tenFiberStop", but its the
** only logical place for such constraints to go.
** NOTE: tenFiberStopMinLength and tenFiberStopMinNumSteps only make
** sense as a value for whyNowhere, not whyStop, despite the name.
*/
enum {
  tenFiberStopUnknown,     /*  0: nobody knows,
                                  or, for tfx->whyNowhere: no, actually,
                                  we *did* get somewhere with this fiber */
  tenFiberStopAniso,       /*  1: specified aniso got below specified level */
  tenFiberStopLength,      /*  2: fiber length in world space got too long */
  tenFiberStopNumSteps,    /*  3: took too many steps along fiber */
  tenFiberStopConfidence,  /*  4: tensor "confidence" value went too low */
  tenFiberStopRadius,      /*  5: radius of curvature got too small */
  tenFiberStopBounds,      /*  6: fiber position stepped outside volume */
  tenFiberStopFraction,    /*  7: during multi-tensor tracking, fractional
                                  constituency of the tracked tensor got
                                  too small */
  tenFiberStopStub,        /*  8: treat single vertex fibers as non-starters */
  tenFiberStopMinLength,   /*  9: fibers with total (both halves) small length
                                  are discarded */
  tenFiberStopMinNumSteps, /* 10: fibers with total (both halves) small # steps
                                  are discarded (more general-purpose than
                                  tenFiberStopStub) */
  tenFiberStopLast
};
#define TEN_FIBER_STOP_MAX    10

/*
******** #define TEN_FIBER_NUM_STEPS_MAX
**
** whatever the stop criteria are for fiber tracing, no fiber half can
** have more points than this- a useful sanity check against fibers
** done amok.
*/
#define TEN_FIBER_NUM_STEPS_MAX 10240

enum {
  tenFiberParmUnknown,         /* 0: nobody knows */
  tenFiberParmStepSize,        /* 1: base step size */
  tenFiberParmUseIndexSpace,   /* 2: non-zero iff output of fiber should be
                                  seeded in and output in index space,
                                  instead of default world */
  tenFiberParmWPunct,          /* 3: tensor-line parameter */
  tenFiberParmVerbose,         /* 4: verbosity */
  tenFiberParmLast
};
#define TEN_FIBER_PARM_MAX        4

enum {
  tenTripleTypeUnknown,    /* 0: nobody knows */
  tenTripleTypeEigenvalue, /* 1: eigenvalues sorted in descending order */
  tenTripleTypeMoment,     /* 2: (mu1,mu2,mu3) */
  tenTripleTypeXYZ,        /* 3: eval rotation, after Bahn'99 JMR:141(68-77) */
  tenTripleTypeRThetaZ,    /* 4: cylindrical coords of rotated evals */
  tenTripleTypeRThetaPhi,  /* 5: spherical coords of rotated evals */
  tenTripleTypeJ,          /* 6: (J1,J2,J3) principal invariants */
  tenTripleTypeK,          /* 7: (K1,K2,K3) cylindrical invariants */
  tenTripleTypeR,          /* 8: (R1,R2,R3) spherical invariants */
  tenTripleTypeWheelParm,  /* 9: eigenvalue wheel (center,radius,angle) */
  tenTripleTypeLast
};
#define TEN_TRIPLE_TYPE_MAX   9

/*
******** tenFiberContext
**
** catch-all for input, state, and output of fiber tracing.  Luckily, like
** in a gageContext, NOTHING in here is set directly by the user; everything
** should be through the tenFiber* calls
*/
typedef struct {
  /* ---- input -------- */
  const Nrrd *nin;      /* the tensor OR DWI volume being analyzed */
  NrrdKernelSpec *ksp;  /* reconstruction kernel for tensors or DWIs */
  int useDwi,           /* we're working in a DWI, not a tensor, volume */
    fiberType,          /* from tenFiberType* OR tenDwiFiberType* enum */
    fiberProbeItem,     /* item to probe along fiber and possibly save in
                           tenFiberSingle->nval */
    intg,               /* from tenFiberIntg* enum */
    anisoStopType,      /* which aniso we do a threshold on */
    anisoSpeedType,     /* base step size is function of this anisotropy */
    stop,               /* BITFLAG for different reasons to stop a fiber */
    useIndexSpace,      /* output in index space, not world space */
    verbose;            /* blah blah blah */
  double anisoThresh,   /* anisotropy threshold */
    anisoSpeedFunc[3];  /* parameters of mapping aniso to speed */
  unsigned int maxNumSteps, /* max # steps allowed on one fiber *half* */
    minNumSteps;        /* min signficiant # steps on *whole* fiber */
  double stepSize,      /* step size in world space */
    maxHalfLen,         /* longest propagation (forward or backward) allowed
                           from midpoint */
    minWholeLen,        /* minimum significant length of whole fiber */
    confThresh,         /* confidence threshold */
    minRadius,          /* minimum radius of curvature of path */
    minFraction;        /* minimum fractional constituency in multi-tensor */
  double wPunct;        /* knob for tensor lines */
  unsigned int ten2Which;  /* which path to follow in 2-tensor tracking */
  /* ---- internal ----- */
  gageQuery query;      /* query we'll send to gageQuerySet */
  int halfIdx,          /* current fiber half being computed (0 or 1) */
    mframeUse;          /* need to use mframe[] and mframeT[] */
  double mframe[9],     /* measurement frame in normal matrix lay-out */
    mframeT[9],         /* transpose of mframe[] */
    wPos[3],            /* current world space location */
    wDir[3],            /* difference between this and last world space pos */
    lastDir[3],         /* previous value of wDir */
    seedEvec[3];        /* principal eigenvector first found at seed point */
  int lastDirSet,       /* lastDir[] is usefully set */
    lastTenSet;         /* lastTen[] is usefully set */
  unsigned int ten2Use; /* which of the 2-tensors was last used */
  gageContext *gtx;     /* wrapped around pvl */
  gagePerVolume *pvl;   /* wrapped around dtvol */

  const double *gageTen,    /* gageAnswerPointer(pvl, tenGageTensor) */
    *gageEval,              /* gageAnswerPointer(pvl, tenGageEval) */
    *gageEvec,              /* gageAnswerPointer(pvl, tenGageEvec) */
    *gageAnisoStop,         /* gageAnswerPointer(pvl, tenGage<anisoStop>) */
    *gageAnisoSpeed,        /* gageAnswerPointer(pvl, tenGage<anisoSpeed>) */
    *gageTen2;              /* gageAnswerPointer(pvl, tenDwiGage..2Tensor..) */
  double ten2AnisoStop;
  double fiberTen[7], fiberEval[3], fiberEvec[9],
    fiberAnisoStop, fiberAnisoSpeed;
  double radius;        /* current radius of curvature */
  /* ---- output ------- */
  double halfLen[2];    /* length of each fiber half in world space */
  unsigned int numSteps[2]; /* how many samples are used for each fiber half */
  int whyStop[2],       /* why backward/forward (0/1) tracing stopped
                           (from tenFiberStop* enum) */
    whyNowhere;         /* why fiber never got started (from tenFiberStop*) */

} tenFiberContext;

/*
******** tenFiberSingle
**
** experimental struct for holding results from a single tracing
*/
typedef struct {
  /* ------- available for recording for reference, not used by ten */
  double seedPos[3];    /* where was the seed point */
  unsigned int dirIdx;  /* which direction at seedpoint to follow */
  unsigned int dirNum;  /* how many directions at seedpnt could be followed */
  /* ------- output ------- */
  Nrrd *nvert;          /* locations of tract vertices */
  double halfLen[2];    /* (same as in tenFiberContext) */
  unsigned int seedIdx, /* which index in nvert is for seedpoint */
    stepNum[2];         /* (same as in tenFiberContext) */
  int whyStop[2],       /* (same as in tenFiberContext) */
    whyNowhere;         /* (same as in tenFiberContext) */
  Nrrd *nval;           /* results of probing at vertices */
  double measr[NRRD_MEASURE_MAX+1];  /* a controlled mess */
} tenFiberSingle;

/*
******** tenFiberMulti
**
** container for multiple fibers
*/
typedef struct {
  tenFiberSingle *fiber;
  unsigned int fiberNum;
  airArray *fiberArr;
} tenFiberMulti;

/*
******** struct tenEmBimodalParm
**
** input and output parameters for tenEMBimodal (for fitting two
** gaussians to a histogram).  Currently, all fields are directly
** set/read; no API help here.
**
** "fraction" means prior probability
**
** In the output, material #1 is the one with the lower mean
*/
typedef struct {
  /* ----- input -------- */
  double minProb,        /* threshold for negligible posterior prob. values */
    minProb2,            /* minProb for 2nd stage fitting */
    minDelta,            /* convergence test for maximization */
    minFraction,         /* smallest fraction (in 0.0 to 1.0) that material
                            1 or 2 can legitimately have */
    minConfidence,       /* smallest confidence value that the model fitting
                            is allowed to have */
    twoStage,            /* wacky two-stage fitting */
    verbose;             /* output messages and/or progress images */
  unsigned int maxIteration; /* cap on # of non-convergent iters allowed */
  /* ----- internal ----- */
  double *histo,         /* double version of histogram */
    *pp1, *pp2,          /* pre-computed posterior probabilities for the
                            current iteration */
    vmin, vmax,          /* value range represented by histogram. This is
                            saved from given histogram, and used to inform
                            final output values, but it is not used for
                            any intermediate histogram calculations, all of
                            which are done entirely in index space */
    delta;               /* some measure of model change between iters */
  int N,                 /* number of bins in histogram */
    stage;               /* current stage (1 or 2) */
  unsigned int iteration;  /* current iteration */
  /* ----- output ------- */
  double mean1, stdv1,   /* material 1 mean and  standard dev */
    mean2, stdv2,        /* same for material 2 */
    fraction1,           /* fraction of material 1 (== 1 - fraction2) */
    confidence,          /* (mean2 - mean1)/(stdv1 + stdv2) */
    threshold;           /* minimum-error threshold */
} tenEMBimodalParm;

/*
******** struct tenGradientParm
**
** all parameters for repulsion-based generation of gradient directions
**
** the old physics-based point-repulsion code (RK2 integration of
** equations of motion, with drag force) is gone; this is only the
** fast gradient descent with some strategies for adaptive step size
*/
typedef struct {
  /* ----------------------- INPUT */
  double initStep,        /* initial step size for gradient descent */
    jitter,               /* amount by which distribution is jittered
                             when starting with a given input set, as
                             a fraction of the ideal edge length */
    minVelocity,          /* minimum mean gradient velocity that signifies
                             end of first distribution phase */
    minPotentialChange,   /* minimum change in potential that signifies
                             end of first distribution phase */
    minMean,              /* mean gradient length that signifies end of
                             secondary balancing phase */
    minMeanImprovement;   /* magnitude of improvement (reduction) of mean
                             gradient length that signifies end of
                             secondary balancing phase */
  int single,             /* distribute single points, instead of
                             anti-podal pairs of points */
    insertZeroVec,        /* when computing output in
                             tenGradientDistribute (and only there, though
                             this is called by tenGradientGenerate), insert
                             the zero vector at the beginning of the list,
                             corresponding to a non-DWI B0 image */
    verbose;              /* verbosity level; 0 turns off everything */
  unsigned int snap,      /* interval of interations at which to save
                             snapshats of distribution */
    report,               /* interval of interations at which to report
                             on progress */
    expo,                 /* the exponent N that defines the potential
                             energy profile 1/r^N (coulomb: N=1) */
    seed,                 /* seed value for random number generator */
    maxEdgeShrink,        /* max number of times we try to compute
                             an update with smaller edge normalization */
    minIteration,         /* run for at least this many iterations,
                             which can be useful for high exponents,
                             for which potential measurements can
                             easily go to infinity */
    maxIteration;         /* bail if we haven't converged by this number
                             of iterations */
  double expo_d;          /* floating point exponent.  If expo is zero,
                             this is the value that matters */
  /* ----------------------- INTERNAL */
  double step,            /* actual current step size (adjusted during
                             the algorithm depending on progress) */
    nudge;                /* how to increase realDT with each iteration */
  /* ----------------------- OUTPUT */
  unsigned int itersUsed; /* total number of iterations */
  double potential,       /* potential, without edge normalization */
    potentialNorm,        /* potential, with edge normalization */
    angle,                /* minimum angle */
    edge;                 /* minimum edge length */
} tenGradientParm;

/*
******** struct tenEstimateContext
**
** for handling estimation of diffusion models
*/
typedef struct {
  /* input ----------- */
  double bValue,           /* scalar b value */
    valueMin,              /* smallest sensible for input Dwi value,
                              must be > 0.0 (for taking log) */
    sigma,                 /* noise parameter */
    dwiConfThresh,         /* mean Dwi threshold for confidence mask */
    dwiConfSoft;           /* softness in confidence mask */
                           /* NOTE: for both _ngrad and _nbmat:
                              1) only one can be non-NULL, and axis[1].size
                              is the total # values, both Dwi and non-Dwi
                              2) NO additional re-normalization is done on
                              the grads/bmats, UNLIKE the normalization
                              performed by tenDWMRIKeyValueParse(). */
  const Nrrd *_ngrad,      /* caller's 3-by-allNum gradient list */
    *_nbmat;               /* caller's 6-by-allNum B-matrix list,
                              off-diagonals are *NOT* pre-multiplied by 2 */
  unsigned int *skipList;  /* list of value indices that we are to skip */
  airArray *skipListArr;   /* airArray around skipList */
  const float *all_f;      /* caller's list of all values (length allNum) */
  const double *all_d;     /* caller's list of all values (length allNum) */
  int simulate,            /* if non-zero, we're being used for simulation,
                              not estimation: be tolerant of unset parms */
    estimate1Method,       /* what kind of single-tensor estimation to do */
    estimateB0,            /* if non-zero, B0 should be estimated along with
                              rest of model. Otherwise, B0 is found by simply
                              taking average of non-Dwi images */
    recordTime,            /* if non-zero, record estimation time */
    recordErrorDwi,
    recordErrorLogDwi,
    recordLikelihoodDwi,
    verbose,               /* blah blah blah */
    negEvalShift,          /* if non-zero, shift eigenvalues upwards so that
                              smallest one is non-negative */
    progress;              /* progress indication for volume processing */
  unsigned int WLSIterNum; /* number of iterations for WLS */
  /* internal -------- */
  /* a "dwi" in here is basically any value (diffusion-weighted or not)
     that varies as a function of the model parameters being estimated */
  int flag[128];           /* flags for state management */
  unsigned int allNum,     /* total number of images (Dwi and non-Dwi) */
    dwiNum;                /* number of Dwis */
  Nrrd *nbmat,             /* B-matrices (dwiNum of them) for the Dwis, with
                              off-diagonals (*YES*) pre-multiplied by 2,
                              and with a 7th column of -1.0 if estimateB0 */
    *nwght,                /* dwiNum x dwiNum matrix of weights */
    *nemat;                /* pseudo-inverse of nbmat */
  double knownB0,          /* B0 known from DWI, only if !estimateB0 */
    *all,                  /* (copy of) vector of input values,
                              allocated for allNum */
    *bnorm,                /* frob norm of B-matrix, allocated for allNum */
    *allTmp, *dwiTmp,      /* for storing intermediate values,
                              allocated for allNum and dwiNum respectively */
    *dwi;                  /* the Dwi values, allocated for dwiNum */
  unsigned char *skipLut;  /* skipLut[i] non-zero if we should ignore all[i],
                              allocated for allNum */
  /* output ---------- */
  double estimatedB0,      /* estimated non-Dwi value, only if estimateB0 */
    ten[7],                /* the estimated single tensor */
    conf,                  /* the "confidence" mask value (i.e. ten[0]) */
    mdwi,                  /* mean Dwi value (used for conf mask calc) */
    time,                  /* time required for estimation */
    errorDwi,              /* error in Dwi of estimate */
    errorLogDwi,           /* error in log(Dwi) of estimate */
    likelihoodDwi;         /* the maximized likelihood */
} tenEstimateContext;

/*
******** struct tenDwiGageKindData
**
** the kind data has static info that is set by the user
** and then not altered-- or else it wouldn't really be per-kind,
** and it wouldn't be thread-safe
*/
typedef struct {
  Nrrd *ngrad, *nbmat;       /* owned by us */
  double thresh, soft, bval, valueMin;
  int est1Method, est2Method;
  unsigned int randSeed;
} tenDwiGageKindData;

/*
******** struct tenDwiGagePvlData
**
** the pvl data is the dynamic stuff (buffers, mostly)
** that is potentially modified per query.
** being part of the pvl, such modifications are thread-safe
**
** the reason for having two tenEstimateContexts is that within
** one volume you will sometimes want to measure both one and
** two tensors, and it would be crazy to incur the overhead of
** switching between the two *per-query*.
*/
typedef struct {
  tenEstimateContext *tec1, /* for estimating single tensors */
    *tec2;                  /* for estimating two-tensors */
  double *vbuf;
  unsigned int *wght;
  double *qvals;
  double *qpoints;
  double *dists;
  double *weights;
  Nrrd *nten1EigenGrads;
  airRandMTState *randState;
  unsigned int randSeed;
  double ten1[7], ten1Evec[9], ten1Eval[3];
  int levmarUseFastExp;
  unsigned int levmarMaxIter;
  double levmarTau, levmarEps1, levmarEps2, levmarEps3,
    levmarDelta, levmarMinCp;
  double levmarInfo[9]; /* output */
} tenDwiGagePvlData;

typedef struct {
  /* input ------------- */
  int verbose;
  double convStep, minNorm, convEps, wghtSumEps;
  int enableRecurse;
  unsigned int maxIter, numSteps;
  int lengthFancy;
  /* internal ------------ */
  unsigned int allocLen;
  double *eval, *evec, *rtIn, *rtLog, *qIn, *qBuff, *qInter;
  /* output ------------ */
  unsigned int numIter;
  double convFinal;
  double lengthShape, lengthOrient;
} tenInterpParm;

/* the idea is that there should be a uniform way of describing
   DWI experiments, and as a result of calling one of the Set()
   functions below, the information is set in tenExperSpec so that
   combined with a diffusion model spec, DWIs can be simulated */
typedef struct {
  int set;               /* has been set */
  unsigned imgNum;       /* total number of images, dwi or not */
  double *bval,          /* all b values: imgNum doubles.
                            NOTE: if dwi[i] is to be considered a "b0" value
                            (for the various functions that have a knownB0 or
                            similarly named flag), bval[i] must be 0.0;
                            regardless of the gradient length */
  /* *wght,                 all weights, but not yet used */
    *grad;               /* all gradients: 3 x imgNum doubles */
} tenExperSpec;

/* description of *one* parameter in the parameter vector that
   defines one instance of a given model */
typedef struct {
  char name[AIR_STRLEN_SMALL]; /* name */
  double min, max;             /* bounds */
  int cyclic;                  /* non-zero if effectively min == max */
  int vec3;                    /* non-zero if this is a coefficient
                                  of a UNIT-LENGTH 3-vector */
  unsigned int vecIdx;         /* *if* this param is part of vector,
                                  the index into it, i.e. 0, 1, or 2 */
} tenModelParmDesc;

#define TEN_MODEL_B0_MAX 65500    /* HEY: fairly arbitrary, but is set to be
                                     a little below the max storable value
                                     of the unsigned short in which DWI
                                     values might be saved */
#define TEN_MODEL_DIFF_MAX 0.006  /* in units of mm^2/sec; diffusivity of
                                     water is about 0.003 mm^2/sec */
#define TEN_MODEL_PARM_GRAD_EPS 0.000005 /* for gradient calculations */

/*
******** struct tenModel
**
** Container for *information* about how DWI values arise (i.e. model
** parameters), with functions that help in fitting and evaluating
** models.  A tenModel does not contain any vector of model parameter
** values, it is only a description of those values (especially its
** tenModelParmDesc vector), and utilities for computing with those
** parameter values.
**
** NOTE: the current convention is to *always* have the non-DW T2
** image value ("B0") be the first value in the parameter vector that
** a tenModel is used to do describe.  The B0 value will be found either
** by trivial means (i.e copied from the image data), or by a different
** method than the rest of the model parameters, but it is stored along with
** the parameters because
** (1) its very handy to have in one place all the information that, when
** combined with the tenExperSpec, gives you a DWI value, and
** (2) sometimes B0 does have to be estimated at the same time as the rest
** of the model, so we thereby avoid doubling the number of models
** to be able to support this.
** On the other hand, the B0 value may not be stored along with the rest of
** the parm vec in the case of saving out whole nrrd of parm vecs.
** The "parmNum" field below therefore always includes the B0 value
*/
typedef struct tenModel_t {
  char name[AIR_STRLEN_SMALL];
  unsigned int parmNum;
  const tenModelParmDesc *parmDesc;
  /* noise free simulation */
  void (*simulate)(double *dwiSim, const double *parm,
                   const tenExperSpec *espec);
  /* parameter vector operations */
  char *(*sprint)(char str[AIR_STRLEN_MED], const double *parm);
  double *(*alloc)(void);
  void (*rand)(double *parm, airRandMTState *rng, int knownB0);
  void (*step)(double *parm1, const double scl,
               const double *grad, const double *parm0);
  double (*dist)(const double *parmA, const double *parmB);
  void (*copy)(double *parmA, const double *parmB);
  int (*convert)(double *parmDst, const double *parmSrc,
                 const struct tenModel_t *modelSrc);

  /* "sqe" == squared error in DWI values */
  double (*sqe)(const double *parm, const tenExperSpec *espec,
                double *dwiBuff, const double *dwiMeas, int knownB0);
  void (*sqeGrad)(double *grad, const double *parm,
                  const tenExperSpec *espec,
                  double *dwiBuff, const double *dwiMeas,
                  int knownB0);
  double (*sqeFit)(double *parm, double *convFrac, unsigned int *itersTaken,
                   const tenExperSpec *espec,
                   double *dwiBuff, const double *dwiMeas,
                   const double *parmInit, int knownB0,
                   unsigned int minIter, unsigned int maxIter,
                   double convEps, int verbose);
  /* "nll" == negative log likelihood */
  double (*nll)(const double *parm, const tenExperSpec *espec,
                double *dwiBuff, const double *dwiMeas,
                int rician, double sigma, int knownB0);
  void (*nllGrad)(double *grad, const double *parm,
                  const tenExperSpec *espec,
                  double *dwiBuff, const double *dwiMeas,
                  int rician, double sigma);
  double (*nllFit)(double *parm, const tenExperSpec *espec,
                   const double *dwiMeas, const double *parmInit,
                   int rician, double sigma, int knownB0);
} tenModel;

/* defaultsTen.c */
TEN_EXPORT const int tenPresent;
TEN_EXPORT const char *tenBiffKey;
TEN_EXPORT const char tenDefFiberKernel[];
TEN_EXPORT double tenDefFiberStepSize;
TEN_EXPORT int tenDefFiberUseIndexSpace;
TEN_EXPORT int tenDefFiberMaxNumSteps;
TEN_EXPORT double tenDefFiberMaxHalfLen;
TEN_EXPORT int tenDefFiberAnisoStopType;
TEN_EXPORT double tenDefFiberAnisoThresh;
TEN_EXPORT int tenDefFiberIntg;
TEN_EXPORT double tenDefFiberWPunct;

/* triple.c */
TEN_EXPORT void tenTripleConvertSingle_d(double dst[3],
                                         int dstType,
                                         const double src[3],
                                         const int srcType);
TEN_EXPORT void tenTripleConvertSingle_f(float dst[3],
                                         int dstType,
                                         const float src[3],
                                         const int srcType);
TEN_EXPORT void tenTripleCalcSingle_d(double dst[3],
                                      int ttype, double ten[7]);
TEN_EXPORT void tenTripleCalcSingle_f(float dst[3],
                                      int ttype, float ten[7]);
TEN_EXPORT int tenTripleCalc(Nrrd *nout, int ttype, const Nrrd *nten);
TEN_EXPORT int tenTripleConvert(Nrrd *nout, int dstType,
                                const Nrrd *nin, int srcType);

/* grads.c */
TEN_EXPORT tenGradientParm *tenGradientParmNew(void);
TEN_EXPORT tenGradientParm *tenGradientParmNix(tenGradientParm *tgparm);
TEN_EXPORT int tenGradientCheck(const Nrrd *ngrad, int type,
                                unsigned int minnum);
TEN_EXPORT int tenGradientRandom(Nrrd *ngrad, unsigned int num,
                                 unsigned int seed);
TEN_EXPORT double tenGradientIdealEdge(unsigned int N, int single);
TEN_EXPORT int tenGradientJitter(Nrrd *nout, const Nrrd *nin, double dist);
TEN_EXPORT int tenGradientBalance(Nrrd *nout, const Nrrd *nin,
                                  tenGradientParm *tgparm);
TEN_EXPORT void tenGradientMeasure(double *pot, double *minAngle,
                                   double *minEdge,
                                   const Nrrd *npos, tenGradientParm *tgparm,
                                   int edgeNormalize);
TEN_EXPORT int tenGradientDistribute(Nrrd *nout, const Nrrd *nin,
                                     tenGradientParm *tgparm);
TEN_EXPORT int tenGradientGenerate(Nrrd *nout, unsigned int num,
                                   tenGradientParm *tgparm);

/* enumsTen.c */
TEN_EXPORT const airEnum *const tenAniso;
TEN_EXPORT const airEnum *const tenInterpType;
TEN_EXPORT const airEnum _tenGage;
TEN_EXPORT const airEnum *const tenGage;
TEN_EXPORT const airEnum *const tenFiberType;
TEN_EXPORT const airEnum *const tenDwiFiberType;
TEN_EXPORT const airEnum *const tenFiberStop;
TEN_EXPORT const airEnum *const tenFiberIntg;
TEN_EXPORT const airEnum *const tenGlyphType;
TEN_EXPORT const airEnum *const tenEstimate1Method;
TEN_EXPORT const airEnum *const tenEstimate2Method;
TEN_EXPORT const airEnum *const tenTripleType;

/* path.c */
TEN_EXPORT tenInterpParm *tenInterpParmNew(void);
TEN_EXPORT tenInterpParm *tenInterpParmCopy(tenInterpParm *tip);
TEN_EXPORT int tenInterpParmBufferAlloc(tenInterpParm *tip,
                                        unsigned int num);
TEN_EXPORT tenInterpParm *tenInterpParmNix(tenInterpParm *tip);
TEN_EXPORT void tenInterpTwo_d(double oten[7],
                               const double tenA[7],
                               const double tenB[7],
                               int ptype, double aa,
                               tenInterpParm *tip);
TEN_EXPORT int tenInterpN_d(double tenOut[7],
                            const double *tenIn,
                            const double *wght,
                            unsigned int num, int ptype, tenInterpParm *tip);
TEN_EXPORT double tenInterpPathLength(Nrrd *npath, int doubleVerts,
                                      int fancy, int shape);
TEN_EXPORT int tenInterpTwoDiscrete_d(Nrrd *nout,
                                      const double tenA[7],
                                      const double tenB[7],
                                      int ptype, unsigned int num,
                                      tenInterpParm *tip);
TEN_EXPORT double tenInterpDistanceTwo_d(const double tenA[7],
                                         const double tenB[7],
                                         int ptype, tenInterpParm *tip);
TEN_EXPORT int tenInterpMulti3D(Nrrd *nout, const Nrrd *const *nin,
                                const double *wght,
                                unsigned int ninNum,
                                int ptype, tenInterpParm *tip);

/* glyph.c */
TEN_EXPORT tenGlyphParm *tenGlyphParmNew(void);
TEN_EXPORT tenGlyphParm *tenGlyphParmNix(tenGlyphParm *parm);
TEN_EXPORT int tenGlyphParmCheck(tenGlyphParm *parm,
                                 const Nrrd *nten, const Nrrd *npos,
                                 const Nrrd *nslc);
TEN_EXPORT int tenGlyphGen(limnObject *glyphs, echoScene *scene,
                           tenGlyphParm *parm,
                           const Nrrd *nten, const Nrrd *npos,
                           const Nrrd *nslc);
TEN_EXPORT unsigned int tenGlyphBqdZoneEval(const double eval[3]);
TEN_EXPORT void tenGlyphBqdUvEval(double uv[2], const double eval[3]);
TEN_EXPORT void tenGlyphBqdEvalUv(double eval[3], const double uv[2]);
TEN_EXPORT unsigned int tenGlyphBqdZoneUv(const double uv[2]);
TEN_EXPORT void tenGlyphBqdAbcUv(double abc[3], const double uv[2],
                                 double betaMax);

/* tensor.c */
TEN_EXPORT int tenVerbose;
TEN_EXPORT void tenRotateSingle_f(float tenOut[7],
                                  const float rot[9], const float tenIn[7]);
TEN_EXPORT int tenTensorCheck(const Nrrd *nin,
                              int wantType, int want4D, int useBiff);
TEN_EXPORT int tenMeasurementFrameReduce(Nrrd *nout, const Nrrd *nin);
TEN_EXPORT int tenExpand2D(Nrrd *nout, const Nrrd *nin,
                           double scale, double thresh);
TEN_EXPORT int tenExpand(Nrrd *tnine, const Nrrd *tseven,
                         double scale, double thresh);
TEN_EXPORT int tenShrink(Nrrd *tseven, const Nrrd *nconf, const Nrrd *tnine);
TEN_EXPORT int tenEigensolve_f(float eval[3], float evec[9],
                               const float ten[7]);
TEN_EXPORT int tenEigensolve_d(double eval[3], double evec[9],
                               const double ten[7]);
TEN_EXPORT void tenMakeSingle_f(float ten[7],
                                float conf, const float eval[3],
                                const float evec[9]);
TEN_EXPORT void tenMakeSingle_d(double ten[7],
                                double conf, const double eval[3],
                                const double evec[9]);
TEN_EXPORT int tenMake(Nrrd *nout, const Nrrd *nconf,
                       const Nrrd *neval, const Nrrd *nevec);
TEN_EXPORT int tenSlice(Nrrd *nout, const Nrrd *nten,
                        unsigned int axis, size_t pos, unsigned int dim);
TEN_EXPORT void tenInvariantGradientsK_d(double K1[7],
                                         double K2[7],
                                         double K3[7],
                                         const double ten[7],
                                         const double minnorm);
TEN_EXPORT void tenInvariantGradientsR_d(double R1[7],
                                         double R2[7],
                                         double R3[7],
                                         const double ten[7],
                                         const double minnorm);
TEN_EXPORT void tenRotationTangents_d(double phi1[7],
                                      double phi2[7],
                                      double phi3[7],
                                      const double evec[9]);
TEN_EXPORT void tenLogSingle_d(double logten[7], const double ten[7]);
TEN_EXPORT void tenLogSingle_f(float logten[7], const float ten[7]);
TEN_EXPORT void tenExpSingle_d(double expten[7], const double ten[7]);
TEN_EXPORT void tenExpSingle_f(float expten[7], const float ten[7]);
TEN_EXPORT void tenSqrtSingle_d(double sqrtten[7], const double ten[7]);
TEN_EXPORT void tenSqrtSingle_f(float sqrtten[7], const float ten[7]);
TEN_EXPORT void tenPowSingle_d(double powten[7], const double ten[7],
                               double power);
TEN_EXPORT void tenPowSingle_f(float powten[7], const float ten[7],
                               float power);
/* should rename to tenInvSingle_x */
TEN_EXPORT void tenInv_f(float inv[7], const float ten[7]);
TEN_EXPORT void tenInv_d(double inv[7], const double ten[7]);
TEN_EXPORT double tenDoubleContract_d(double a[7], double T[21], double b[7]);

/* chan.c */
/* old tenCalc* functions superceded/deprecated by new tenEstimate* code */
TEN_EXPORT const char *tenDWMRIModalityKey;
TEN_EXPORT const char *tenDWMRIModalityVal;
TEN_EXPORT const char *tenDWMRINAVal;
TEN_EXPORT const char *tenDWMRIBValueKey;
TEN_EXPORT const char *tenDWMRIGradKeyFmt;
TEN_EXPORT const char *tenDWMRIBmatKeyFmt;
TEN_EXPORT const char *tenDWMRINexKeyFmt;
TEN_EXPORT const char *tenDWMRISkipKeyFmt;
TEN_EXPORT int tenDWMRIKeyValueParse(Nrrd **ngradP, Nrrd **nbmatP, double *bP,
                                     unsigned int **skip,
                                     unsigned int *skipNum,
                                     const Nrrd *ndwi);
TEN_EXPORT int tenBMatrixCalc(Nrrd *nbmat, const Nrrd *ngrad);
TEN_EXPORT int tenEMatrixCalc(Nrrd *nemat, const Nrrd *nbmat, int knownB0);
TEN_EXPORT void tenEstimateLinearSingle_f(float *ten, float *B0P,
                                          const float *dwi, const double *emat,
                                          double *vbuf, unsigned int DD,
                                          int knownB0, float thresh,
                                          float soft, float b);
TEN_EXPORT void tenEstimateLinearSingle_d(double *ten, double *B0P,
                                          const double *dwi, const double*emat,
                                          double *vbuf, unsigned int DD,
                                          int knownB0, double thresh,
                                          double soft, double b);
TEN_EXPORT int tenEstimateLinear3D(Nrrd *nten, Nrrd **nterrP, Nrrd **nB0P,
                                   const Nrrd *const *ndwi,
                                   unsigned int dwiLen,
                                   const Nrrd *nbmat, int knownB0,
                                   double thresh, double soft, double b);
TEN_EXPORT int tenEstimateLinear4D(Nrrd *nten, Nrrd **nterrP, Nrrd **nB0P,
                                   const Nrrd *ndwi, const Nrrd *_nbmat,
                                   int knownB0,
                                   double thresh, double soft, double b);
TEN_EXPORT void tenSimulateSingle_f(float *dwi, float B0, const float *ten,
                                    const double *bmat, unsigned int DD,
                                    float b);
TEN_EXPORT int tenSimulate(Nrrd *ndwi, const Nrrd *nT2, const Nrrd *nten,
                           const Nrrd *nbmat, double b);

/* estimate.c */
TEN_EXPORT tenEstimateContext *tenEstimateContextNew(void);
TEN_EXPORT void tenEstimateVerboseSet(tenEstimateContext *tec,
                                      int verbose);
TEN_EXPORT void tenEstimateNegEvalShiftSet(tenEstimateContext *tec,
                                           int doit);
TEN_EXPORT int tenEstimateMethodSet(tenEstimateContext *tec,
                                    int estMethod);
TEN_EXPORT int tenEstimateSigmaSet(tenEstimateContext *tec,
                                   double sigma);
TEN_EXPORT int tenEstimateValueMinSet(tenEstimateContext *tec,
                                      double valueMin);
TEN_EXPORT int tenEstimateGradientsSet(tenEstimateContext *tec,
                                       const Nrrd *ngrad,
                                       double bValue, int estimateB0);
TEN_EXPORT int tenEstimateBMatricesSet(tenEstimateContext *tec,
                                       const Nrrd *nbmat,
                                       double bValue, int estimateB0);
TEN_EXPORT int tenEstimateSkipSet(tenEstimateContext *tec,
                                  unsigned int valIdx,
                                  int doSkip);
TEN_EXPORT int tenEstimateSkipReset(tenEstimateContext *tec);
TEN_EXPORT int tenEstimateThresholdSet(tenEstimateContext *tec,
                                       double thresh, double soft);
TEN_EXPORT int tenEstimateUpdate(tenEstimateContext *tec);
TEN_EXPORT int tenEstimate1TensorSimulateSingle_f(tenEstimateContext *tec,
                                                  float *simval,
                                                  float sigma,
                                                  float bValue, float B0,
                                                  const float _ten[7]);
TEN_EXPORT int tenEstimate1TensorSimulateSingle_d(tenEstimateContext *tec,
                                                  double *simval,
                                                  double sigma,
                                                  double bValue, double B0,
                                                  const double ten[7]);
TEN_EXPORT int tenEstimate1TensorSimulateVolume(tenEstimateContext *tec,
                                                Nrrd *ndwi,
                                                double sigma, double bValue,
                                                const Nrrd *nB0,
                                                const Nrrd *nten,
                                                int outType,
                                                int keyValueSet);
TEN_EXPORT int tenEstimate1TensorSingle_f(tenEstimateContext *tec,
                                          float ten[7], const float *all);
TEN_EXPORT int tenEstimate1TensorSingle_d(tenEstimateContext *tec,
                                          double ten[7], const double *all);
TEN_EXPORT int tenEstimate1TensorVolume4D(tenEstimateContext *tec,
                                          Nrrd *nten,
                                          Nrrd **nB0P, Nrrd **nterrP,
                                          const Nrrd *ndwi, int outType);
TEN_EXPORT tenEstimateContext *tenEstimateContextNix(tenEstimateContext *tec);

/* aniso.c */
TEN_EXPORT float (*_tenAnisoEval_f[TEN_ANISO_MAX+1])(const float eval[3]);
TEN_EXPORT float tenAnisoEval_f(const float eval[3], int aniso);
TEN_EXPORT double (*_tenAnisoEval_d[TEN_ANISO_MAX+1])(const double eval[3]);
TEN_EXPORT double tenAnisoEval_d(const double eval[3], int aniso);

TEN_EXPORT float (*_tenAnisoTen_f[TEN_ANISO_MAX+1])(const float ten[7]);
TEN_EXPORT float tenAnisoTen_f(const float ten[7], int aniso);
TEN_EXPORT double (*_tenAnisoTen_d[TEN_ANISO_MAX+1])(const double ten[7]);
TEN_EXPORT double tenAnisoTen_d(const double ten[7], int aniso);

TEN_EXPORT int tenAnisoPlot(Nrrd *nout, int aniso, unsigned int res,
                            int hflip, int whole, int nanout);
TEN_EXPORT int tenAnisoVolume(Nrrd *nout, const Nrrd *nin,
                              int aniso, double confThresh);
TEN_EXPORT int tenAnisoHistogram(Nrrd *nout, const Nrrd *nin,
                                 const Nrrd *nwght, int right,
                                 int version, unsigned int resolution);
TEN_EXPORT tenEvecRGBParm *tenEvecRGBParmNew(void);
TEN_EXPORT tenEvecRGBParm *tenEvecRGBParmNix(tenEvecRGBParm *rgbp);
TEN_EXPORT int tenEvecRGBParmCheck(const tenEvecRGBParm *rgbp);
TEN_EXPORT void tenEvecRGBSingle_f(float RGB[3], float conf,
                                   const float eval[3], const float evec[3],
                                   const tenEvecRGBParm *rgbp);
TEN_EXPORT void tenEvecRGBSingle_d(double RGB[3], double conf,
                                   const double eval[3], const double evec[3],
                                   const tenEvecRGBParm *rgbp);

/* miscTen.c */
TEN_EXPORT int tenEvecRGB(Nrrd *nout, const Nrrd *nin,
                          const tenEvecRGBParm *rgbp);
TEN_EXPORT short tenEvqSingle_f(float vec[3], float scl);
TEN_EXPORT int tenEvqVolume(Nrrd *nout, const Nrrd *nin, int which,
                            int aniso, int scaleByAniso);
TEN_EXPORT int tenBMatrixCheck(const Nrrd *nbmat,
                               int type, unsigned int minnum);
TEN_EXPORT int _tenFindValley(double *valP, const Nrrd *nhist,
                              double tweak, int save);

/* fiberMethods.c */
TEN_EXPORT void tenFiberSingleInit(tenFiberSingle *tfbs);
TEN_EXPORT void tenFiberSingleDone(tenFiberSingle *tfbs);
TEN_EXPORT tenFiberSingle *tenFiberSingleNew(void);
TEN_EXPORT tenFiberSingle *tenFiberSingleNix(tenFiberSingle *tfbs);
TEN_EXPORT tenFiberContext *tenFiberContextNew(const Nrrd *dtvol);
TEN_EXPORT tenFiberContext *tenFiberContextDwiNew(const Nrrd *dwivol,
                                                  double thresh,
                                                  double soft,
                                                  double valueMin,
                                                  int ten1method,
                                                  int ten2method);
TEN_EXPORT void tenFiberVerboseSet(tenFiberContext *tfx, int verbose);
TEN_EXPORT int tenFiberTypeSet(tenFiberContext *tfx, int type);
TEN_EXPORT int tenFiberKernelSet(tenFiberContext *tfx,
                                 const NrrdKernel *kern,
                                 const double parm[NRRD_KERNEL_PARMS_NUM]);
TEN_EXPORT int tenFiberProbeItemSet(tenFiberContext *tfx, int item);
TEN_EXPORT int tenFiberIntgSet(tenFiberContext *tfx, int intg);
TEN_EXPORT int tenFiberStopSet(tenFiberContext *tfx, int stop, ...);
TEN_EXPORT int tenFiberStopAnisoSet(tenFiberContext *tfx,
                                    int anisoType, double anisoThresh);
TEN_EXPORT int tenFiberStopDoubleSet(tenFiberContext *tfx,
                                     int stop, double val);
TEN_EXPORT int tenFiberStopUIntSet(tenFiberContext *tfx,
                                   int stop, unsigned int val);
TEN_EXPORT void tenFiberStopOn(tenFiberContext *tfx, int stop);
TEN_EXPORT void tenFiberStopOff(tenFiberContext *tfx, int stop);
TEN_EXPORT void tenFiberStopReset(tenFiberContext *tfx);
TEN_EXPORT int tenFiberAnisoSpeedSet(tenFiberContext *tfx, int aniso,
                                     double lerp, double thresh, double soft);
TEN_EXPORT int tenFiberAnisoSpeedReset(tenFiberContext *tfx);
TEN_EXPORT int tenFiberParmSet(tenFiberContext *tfx, int parm, double val);
TEN_EXPORT int tenFiberUpdate(tenFiberContext *tfx);
TEN_EXPORT tenFiberContext *tenFiberContextCopy(tenFiberContext *tfx);
TEN_EXPORT tenFiberContext *tenFiberContextNix(tenFiberContext *tfx);

/* fiber.c */
TEN_EXPORT int tenFiberTraceSet(tenFiberContext *tfx, Nrrd *nfiber,
                                double *buff, unsigned int halfBuffLen,
                                unsigned int *startIdxP, unsigned int *endIdxP,
                                double seed[3]);
TEN_EXPORT int tenFiberTrace(tenFiberContext *tfx,
                             Nrrd *nfiber, double seed[3]);
TEN_EXPORT unsigned int tenFiberDirectionNumber(tenFiberContext *tfx,
                                                double seed[3]);
TEN_EXPORT int tenFiberSingleTrace(tenFiberContext *tfx, tenFiberSingle *tfbs,
                                   double seed[3], unsigned int which);
TEN_EXPORT tenFiberMulti *tenFiberMultiNew(void);
TEN_EXPORT tenFiberMulti *tenFiberMultiNix(tenFiberMulti *tfm);
TEN_EXPORT int tenFiberMultiTrace(tenFiberContext *tfx, tenFiberMulti *tfml,
                                  const Nrrd *nseed);
TEN_EXPORT int tenFiberMultiPolyData(tenFiberContext *tfx,
                                     limnPolyData *lpld, tenFiberMulti *tfml);
TEN_EXPORT int tenFiberMultiProbeVals(tenFiberContext *tfx,
                                      Nrrd *nval, tenFiberMulti *tfml);

/* epireg.c */
TEN_EXPORT int _tenEpiRegThresholdFind(double *DWthrP, Nrrd **nin,
                                       int ninLen, int save, double expo);
TEN_EXPORT int tenEpiRegister3D(Nrrd **nout, Nrrd **ndwi,
                                unsigned int dwiLen, Nrrd *ngrad,
                                int reference,
                                double bwX, double bwY,
                                double fitFrac, double DWthr,
                                int doCC,
                                const NrrdKernel *kern, double *kparm,
                                int progress, int verbose);
TEN_EXPORT int tenEpiRegister4D(Nrrd *nout, Nrrd *nin, Nrrd *ngrad,
                                int reference,
                                double bwX, double bwY,
                                double fitFrac, double DWthr,
                                int doCC,
                                const NrrdKernel *kern, double *kparm,
                                int progress, int verbose);

/* experSpec.c */
TEN_EXPORT tenExperSpec* tenExperSpecNew(void);
TEN_EXPORT int tenExperSpecGradSingleBValSet(tenExperSpec *espec,
                                             int insertB0,
                                             double bval,
                                             const double *grad,
                                             unsigned int gradNum);
TEN_EXPORT int tenExperSpecGradBValSet(tenExperSpec *espec,
                                       int insertB0,
                                       const double *bval,
                                       const double *grad,
                                       unsigned int bgNum);
/*
TEN_EXPORT int tenExperSpecGradBValWghtSet(tenExperSpec *espec,
                                           int insertB0,
                                           const double *bval,
                                           const double *grad,
                                           const double *wght,
                                           unsigned int bgwNum);
*/
TEN_EXPORT int tenExperSpecFromKeyValueSet(tenExperSpec *espec,
                                           const Nrrd *ndwi);
TEN_EXPORT tenExperSpec* tenExperSpecNix(tenExperSpec *espec);
TEN_EXPORT double tenExperSpecKnownB0Get(const tenExperSpec *espec,
                                         const double *dwi);
TEN_EXPORT double tenExperSpecMaxBGet(const tenExperSpec *espec);
TEN_EXPORT int tenDWMRIKeyValueFromExperSpecSet(Nrrd *ndwi,
                                                const tenExperSpec *espec);

/* tenModel.c */
TEN_EXPORT const char *tenModelPrefixStr;
TEN_EXPORT int tenModelParse(const tenModel **model, int *plusB0,
                             int requirePrefix, const char *str);
TEN_EXPORT int tenModelFromAxisLearnPossible(const NrrdAxisInfo *axinfo);
TEN_EXPORT int tenModelFromAxisLearn(const tenModel **model, int *plusB0,
                                     const NrrdAxisInfo *axinfo);
TEN_EXPORT int tenModelSimulate(Nrrd *ndwi, int typeOut,
                                tenExperSpec *espec,
                                const tenModel *model,
                                const Nrrd *nB0, /* maybe NULL */
                                const Nrrd *nparm,
                                int keyValueSet);
TEN_EXPORT int tenModelSqeFit(Nrrd *nparm,
                              Nrrd **nsqeP, Nrrd **nconvP, Nrrd **niterP,
                              const tenModel *model,
                              const tenExperSpec *espec, const Nrrd *ndwi,
                              int knownB0, int saveB0, int typeOut,
                              unsigned int minIter, unsigned int maxIter,
                              unsigned int starts, double convEps,
                              airRandMTState *rng,
                              int verbose);
TEN_EXPORT int tenModelNllFit(Nrrd *nparm, Nrrd **nnllP,
                              const tenModel *model,
                              const tenExperSpec *espec, const Nrrd *ndwi,
                              int rician, double sigma, int knownB0);
TEN_EXPORT int tenModelConvert(Nrrd *nparmDst, int *convRet,
                               const tenModel *modelDst,
                               const Nrrd *nparmSrc,
                               const tenModel *modelSrc);

/*
** Have to keep this list of model declarations in sync with:
** * tenModel.c/str2model()
** * all model*.c/parmConvert()  (fallen behind here)
** * sources.cmake, GNUmakefile
**
** Note that the TEN_MODEL_STR_* strings should be all lowercase,
** as long as we want the model parsing to be case insensitive, and
** as long as the logic in tenModel.c/str2model() is so simplistic
*/
/* modelZero.c */
#define TEN_MODEL_STR_ZERO "zero"
TEN_EXPORT const tenModel *const tenModelZero;
/* modelB0.c */
#define TEN_MODEL_STR_B0 "b0"
TEN_EXPORT const tenModel *const tenModelB0;
/* modelBall.c */
#define TEN_MODEL_STR_BALL "ball"
TEN_EXPORT const tenModel *const tenModelBall;
/* model1Vector2D.c */
#define TEN_MODEL_STR_1VECTOR2D "1vector2d"
TEN_EXPORT const tenModel *const tenModel1Vector2D;
/* model1Unit2D.c */
#define TEN_MODEL_STR_1UNIT2D "1unit2d"
TEN_EXPORT const tenModel *const tenModel1Unit2D;
/* model2Unit2D.c */
#define TEN_MODEL_STR_2UNIT2D "2unit2d"
TEN_EXPORT const tenModel *const tenModel2Unit2D;
/* model1Stick.c */
#define TEN_MODEL_STR_1STICK "1stick"
TEN_EXPORT const tenModel *const tenModel1Stick;
/* modelBall1StickEMD.c */
#define TEN_MODEL_STR_BALL1STICKEMD "ball1stickemd"
TEN_EXPORT const tenModel *const tenModelBall1StickEMD;
/* modelBall1Stick.c */
#define TEN_MODEL_STR_BALL1STICK "ball1stick"
TEN_EXPORT const tenModel *const tenModelBall1Stick;
/* modelBall1Cylinder.c */
#define TEN_MODEL_STR_BALL1CYLINDER "ball1cylinder"
TEN_EXPORT const tenModel *const tenModelBall1Cylinder;
/* model1Cylinder.c */
#define TEN_MODEL_STR_1CYLINDER "1cylinder"
TEN_EXPORT const tenModel *const tenModel1Cylinder;
/* model1Tensor2.c: 2nd-order tensor (one of them), not two-tensor */
#define TEN_MODEL_STR_1TENSOR2 "1tensor2"
TEN_EXPORT const tenModel *const tenModel1Tensor2;

/* mod.c */
TEN_EXPORT int tenSizeNormalize(Nrrd *nout, const Nrrd *nin, double weight[3],
                                double amount, double target);
TEN_EXPORT int tenSizeScale(Nrrd *nout, const Nrrd *nin, double amount);
TEN_EXPORT int tenAnisoScale(Nrrd *nout, const Nrrd *nin, double scale,
                             int fixDet, int makePositive);
TEN_EXPORT int tenEigenvaluePower(Nrrd *nout, const Nrrd *nin, double expo);
TEN_EXPORT int tenEigenvalueClamp(Nrrd *nout, const Nrrd *nin,
                                  double min, double max);
TEN_EXPORT int tenEigenvalueAdd(Nrrd *nout, const Nrrd *nin, double val);
TEN_EXPORT int tenEigenvalueMultiply(Nrrd *nout, const Nrrd *nin, double val);
TEN_EXPORT int tenLog(Nrrd *nout, const Nrrd *nin);
TEN_EXPORT int tenExp(Nrrd *nout, const Nrrd *nin);

/* bvec.c */
TEN_EXPORT int tenBVecNonLinearFit(Nrrd *nout, const Nrrd *nin,
                                   double *bb, double *ww,
                                   int iterMax, double eps);

/* tenGage.c */
TEN_EXPORT gageKind *tenGageKind;

/* tenDwiGage.c */
/* we can't declare or define a tenDwiGageKind->name (analogous to
   tenGageKind->name or gageSclKind->name) because the DWI kind is
   dynamically allocated, but at least we can declare a cannonical
   name (HEY: ugly) */
#define TEN_DWI_GAGE_KIND_NAME "dwi"
TEN_EXPORT const airEnum _tenDwiGage;
TEN_EXPORT const airEnum *const tenDwiGage;
TEN_EXPORT gageKind *tenDwiGageKindNew(void);
TEN_EXPORT gageKind *tenDwiGageKindNix(gageKind *dwiKind);
/* warning: this function will likely change its arguments in the future */
TEN_EXPORT int tenDwiGageKindSet(gageKind *dwiKind,
                                 double thresh, double soft,
                                 double bval, double valueMin,
                                 const Nrrd *ngrad,
                                 const Nrrd *nbmat,
                                 int emethod1, int emethod2,
                                 unsigned int randSeed);
TEN_EXPORT int tenDwiGageKindCheck(const gageKind *kind);

/* bimod.c */
TEN_EXPORT tenEMBimodalParm* tenEMBimodalParmNew(void);
TEN_EXPORT tenEMBimodalParm* tenEMBimodalParmNix(tenEMBimodalParm *biparm);
TEN_EXPORT int tenEMBimodal(tenEMBimodalParm *biparm, const Nrrd *nhisto);

/* tend{Flotsam,Anplot,Anvol,Evec,Eval,. . .}.c */
#define TEND_DECLARE(C) TEN_EXPORT unrrduCmd tend_##C##Cmd;
#define TEND_LIST(C) &tend_##C##Cmd,
/* removed from below (superseded by estim): F(calc) \ */
#define TEND_MAP(F) \
F(about) \
F(grads) \
F(epireg) \
F(bmat) \
F(estim) \
F(sim) \
F(mfit) \
F(mconv) \
F(msim) \
F(make) \
F(avg) \
F(helix) \
F(sten) \
F(glyph) \
F(ellipse) \
F(anplot) \
F(anvol) \
F(anscale) \
F(anhist) \
F(triple) \
F(tconv) \
F(point) \
F(slice) \
F(norm) \
F(fiber) \
F(eval) \
F(evalpow) \
F(evalclamp) \
F(evaladd) \
F(evalmult) \
F(log) \
F(exp) \
F(evec) \
F(evecrgb) \
F(evq) \
F(unmf) \
F(expand) \
F(shrink) \
F(bfit) \
F(satin)
TEND_MAP(TEND_DECLARE)
TEN_EXPORT unrrduCmd *tendCmdList[];
TEN_EXPORT hestCB *tendFiberStopCB;
TEN_EXPORT const char *tendTitle;

#ifdef __cplusplus
}
#endif

#endif /* TEN_HAS_BEEN_INCLUDED */