Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

plug_reorder_parseMap.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002    Major portions of this software are copyrighted by the Medical College
00003    of Wisconsin, 1994-2000, and are released under the Gnu General Public
00004    License, Version 2.  See the file README.Copyright for details.
00005 ******************************************************************************/
00006 
00007 #ifndef __PLUGIN_REORDER_PARSEMAP_C__
00008 #define __PLUGIN_REORDER_PARSEMAP_C__
00009 
00010 #ifndef MAIN_PLUGIN_REORDER
00011 #define MAIN_PLUGIN_REORDER_PARSEMAP /* compile parseMap for command line testing */
00012 #define DEBUG_PLUGIN_REORDER_PARSEMAP
00013 #endif
00014 
00015 /*
00016     Function:   REORDER_parseMap
00017 
00018     Author:     Jay Brian Kummer/Medical College Of WI/Neitz & DeYoe Labs
00019 
00020     Date:       April 21, 1997
00021 
00022     Purpose:
00023 
00024                 AFNI 'reorder' plugin routine that parses the epoch map file
00025                 for a requested shuffling of a 3D+Time dataSet. This function
00026                 will return an array of indices representing the new (reorderd)
00027                 position of time-course values. The caller will then apply this
00028                 order to all voxels in the dataSet.
00029 
00030                 This version of the parseMap function, 'parseMap', 'collates'
00031                 duplicated classes in the map file in the order that they appear
00032                 (e.g., given a sequence of classes [ D C A B A ], the reorderd
00033                 order returned will be indices for [ A1 A2 B C D ]).
00034                 
00035                 The "epoch map" is a series of entries (given in a text file)
00036                 which indicates the classification and, implicitly, the target
00037                 order of epochs of a time-course. These maps are companions to
00038                 dataSets arising from specific sequences of stimulus presentation
00039                 and, therefore, should have a one-to-one correspondence to those
00040                 dataSets (i.e., they have the same time length).
00041 
00042                 The expected format of the epoch map file is as follows:
00043 
00044                         # Comment lines begin with a '#' and persist to the end of the line.
00045                         [ <EpochClass><PointNumberInClass> | - ]
00046                         ...one entry for each TR in the stimulus presentation...
00047 
00048                 Each entry is either an 'EpochClass' or a '-'. The latter excludes the
00049                 point from the resulting reordering. 'EpochClass' is a single letter,
00050                 [a-zA-Z], which classifies the current epoch; the contatenated number
00051                 is an increasing value from 1 to the epoch length and is used mainly
00052                 to delimit contiguous instances of the same class. 
00053 
00054                 For example:
00055 
00056                         # This map is a companion to a dataSet acquired during visual
00057                         # presentation of sequence of different size rings:
00058                         #
00059                         #   RingSize |__A__
00060                         #            |    |          __D__
00061                         #            |    |__B__    |
00062                         #            |         |    |
00063                         #            |         |__C__
00064                         #            |_____________________
00065                         #            1                   20 (TR)
00066                         #
00067                         # 5 scans per presentation, total of 20 scans, 4 epochs.
00068                         #
00069                         # User expects response amplitudes to be proportional
00070                         # to ring sizes; this will be much easier to analyze if
00071                         # epochs are ordered corresponding to an increasing
00072                         # trend in ring size, so reorder the epochs:
00073                         C1
00074                         C2
00075                         C3
00076                         C4
00077                         C5
00078                         B1
00079                         B2
00080                         B3
00081                         B4
00082                         B5
00083                         D1
00084                         D2
00085                         D3
00086                         D4
00087                         D5
00088                         A1
00089                         A2
00090                         A3
00091                         A4
00092                         A5
00093                         # Resulting order:
00094                         #   RingSize |               __A__
00095                         #            |          __D__|
00096                         #            |     __B__|
00097                         #            |    |     
00098                         #            |__C_|    
00099                         #            |_____________________
00100                         #            1                   20 (TR)
00101                         #
00102 
00103                 The TR number of each entry is, implicitly, the line number of the
00104                 entry; therefore, the number of lines in the map file (except for
00105                 comment lines) should equal the number of TRs in the companion
00106                 dataSet.
00107 
00108     Usage:
00109 
00110                 char *myFile = "QQ_epoch.map";  /  epoch map for a given experiment  /
00111                 int length = npts;                              /  number of time-course points in  /
00112                                                                                 /  the dataSet  /
00113                 ClassInfo *classKRH;                            /  Place to store the sequence of classes /
00114                 int classCount;                                 /  Number of classes in 'class' array /
00115                 if(NULL == REORDER_parseMap(myFile, &length, &classKRH, &classCount)) {
00116                         printf("!! error !!\n");
00117                         FreeWorkspace();
00118                         return NULL;
00119                         }
00120 
00121     Input Parameters:
00122 
00123                 myFile, char *, pointer to a NULL-terminated string, filename for an
00124                         epoch map
00125                 length, int *, pointer to a value storing the number of time-course points
00126                         in the dataSet
00127     Output Parameters:
00128 
00129                 int *, pointer to an array of length 'length' containing indices (on
00130                         the interval [0, (length-1)] for the new ordering of time-course
00131                         data points. NULL is returned on any error.
00132                 By parameter:
00133                 class, ClassInfo **, address of a pointer to an array of structures
00134                         that will contain class and class length info.
00135                 classCount, integer, address of an integer to receive the length of 'class'
00136 
00137     Side Effects:
00138 
00139                 The contents of 'length' will hold the length of the 3D+time dataSet
00140                 to be processed by this plugin; on return, this will contain the length of
00141                 the array of indices returned by this function, which in turn will also be
00142                 the time-length of the reorderd 3D+time dataset. The return length can only
00143                 be altered (decreased) by excluding TR points from the reorderd dataSet (by
00144                 specifying '-' in the epoch map file). 'class' will be allocated to the
00145                 length 'classCount' if parsing is successful.
00146 
00147         Pseudo Code:
00148 
00149                 Check input parameters.
00150                 Count the number of entries in the file.
00151                 ...Pseudo code boring...losing consciousness...
00152 
00153         Code: */
00154 
00155 #include <stdio.h>
00156 #include <stdlib.h>
00157 #include <ctype.h>
00158 #include <string.h>
00159 
00160 #ifndef MAIN_PLUGIN_REORDER
00161 typedef struct {
00162         char classKRH;
00163         int length;
00164         } ClassInfo;
00165 #endif
00166 
00167 int *REORDER_parseMap(char *mapFile
00168                                         , int *length
00169                                         , ClassInfo **classKRH
00170                                         , int *classCount)
00171 {
00172 FILE *inf = NULL;
00173 char c; int icc ;
00174 char *sptr;
00175 char *classList=NULL;
00176 char cBuf[256] = {0};
00177 int i;
00178 int j;
00179 int k;
00180 int line;
00181 int excluded;
00182 int rawLength;
00183 int *index = NULL;
00184 int *classNum=NULL;
00185 int classStart;
00186 char currentClass;
00187 int currentClassPos;
00188 
00189 /* Check input parameters */
00190 if(NULL == mapFile) {
00191         printf("!! [AFNI/reorder] NULL file name !!\n");
00192         *length = *classCount = 0;
00193         return NULL;
00194         }
00195 
00196 if(0 == mapFile[0]) {
00197         printf("!! [AFNI/reorder] Empty file name !!\n");
00198         *length = *classCount = 0;
00199         return NULL;
00200         }
00201 
00202 if(NULL == (inf = fopen(mapFile, "r"))) {
00203         printf("!! [AFNI/reorder] Trouble opening '%s' for reading !!\n", mapFile);
00204         *length = *classCount = 0;
00205         return NULL;
00206         }
00207 
00208 /* Count the number of noncomment entries in the file */
00209 for(i = 0, line = 1, excluded = 0;; line++) {
00210         if(i > *length) {
00211                 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00212                 printf("[parseMap] Entry count exceeds expected\n");
00213                 #endif
00214                 printf("!! [AFNI/reorder] Number of entries in 'mapFile' exceeds expected of %d !!\n"
00215                         , *length);
00216                 *length = *classCount = 0;
00217                 return NULL;
00218                 }
00219 
00220         /* Test for EOF */
00221     c = icc = fgetc(inf);
00222         if(EOF == icc || feof(inf)) {
00223                 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00224                 printf("[parseMap] EOF detected: ");
00225                 #endif
00226                 if(i != *length) {
00227                         #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00228                         printf("Abnormal\n");
00229                         #endif
00230                         printf("!! [AFNI/reorder] Unexpected EOF at line %d !!\n", line);
00231                         *length = *classCount = 0;
00232                         return NULL;
00233                         }
00234                 else {
00235                         #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00236                         printf("Normal\n");
00237                         #endif
00238                         break;
00239                         }
00240                 }
00241         ungetc(c, inf);
00242 
00243         #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00244         printf("[parseMap] Processing line %d...\n", line);
00245         #endif
00246 
00247         /* Get the next line */
00248         fgets(cBuf, sizeof(cBuf), inf);
00249         
00250         /* Delete newline character */
00251         sptr = strchr(cBuf, '\n');
00252         if(sptr) {
00253                 *sptr = 0;
00254                 }
00255   
00256         /* Eat leading whitespace */
00257         sptr = cBuf;
00258         while(isspace(*sptr)) ++sptr;
00259 
00260         /* Skip comments and empty lines */
00261         if('#' == *sptr || 0 == *sptr) {
00262                 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00263                 printf("[parseMap] Skipping comment or empty line.\n");
00264                 #endif
00265                 continue;
00266                 }
00267 
00268         if('-' == *sptr) { /* excluded value */
00269                 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00270                 printf("[parseMap] Excluded point detected.\n");
00271                 #endif
00272                 ++i;
00273                 ++excluded;
00274                 continue;
00275                 }
00276 
00277         /* Check for valid class name */
00278         if(!isalpha(*sptr)) {
00279                 printf("!! [AFNI/reorder] Bad map entry: '%s' at line %d !!\n"
00280                         , sptr, line);
00281                 *length = *classCount = 0;
00282                 return NULL;
00283                 }
00284 
00285         if(!isdigit(*(sptr+1))) {
00286                 printf("!! [AFNI/reorder] Illformed entry '%s' at line %d !!\n"
00287                         , sptr, line);
00288                 *length = *classCount = 0;
00289                 return NULL;
00290                 }
00291 
00292         ++i;
00293         }
00294 
00295 /* Rewind the input file for reuse */
00296 rewind(inf);
00297 
00298 /* Allocate workspace */
00299 index = (int *)calloc(sizeof(int), i-excluded);
00300 if(NULL == index) {
00301         printf("!! [AFNI/reorder] Allocation error(1) !!\n");
00302         *length = *classCount = 0;
00303         return NULL;
00304         }
00305 
00306 classList = (char *)calloc(sizeof(char), i);
00307 if(NULL == classList) {
00308         printf("!! [AFNI/reorder] Allocation error(2) !!\n");
00309         free(index);
00310         *length = *classCount = 0;
00311         return NULL;
00312         }
00313 
00314 classNum = (int *)calloc(sizeof(int), i);
00315 if(NULL == classNum) {
00316         printf("!! [AFNI/reorder] Allocation error(3) !!\n");
00317         free(index);
00318         free(classList);
00319         *length = *classCount = 0;
00320         return NULL;
00321         }
00322 
00323 /* Arrays to be reallocated (initialize) */
00324 (*classKRH) = (ClassInfo *)calloc(sizeof(ClassInfo), 1);
00325 if(NULL == (*classKRH)) {
00326         printf("!! [AFNI/reorder] Allocation error(4) !!\n");
00327         free(index);
00328         free(classList);
00329         free(classNum);
00330         *length = *classCount = 0;
00331         return NULL;
00332         }
00333 
00334 /* Set return length */
00335 rawLength = i;
00336 *length = i - excluded;
00337 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00338 printf("[parseMap] Return length of array is %d elements...\n", *length);
00339 #endif
00340 
00341 /* Collect mapping information from file */
00342 currentClass = 0;
00343 *classCount = 0;
00344 for(i = 0, line = 1; i < rawLength; line++) {
00345         /* Get the next line */
00346         fgets(cBuf, sizeof(cBuf), inf);
00347 
00348         /* Delete newline character */
00349         sptr = strchr(cBuf, '\n');
00350         if(sptr) {
00351                 *sptr = 0;
00352                 }
00353   
00354         /* Eat leading whitespace */
00355         sptr = cBuf;
00356         while(isspace(*sptr)) ++sptr;
00357 
00358         /* Skip comments and empty lines */
00359         if('#' == *sptr || 0 == *sptr) {
00360                 continue;
00361                 }
00362 
00363         if('-' == *sptr) { /* excluded value */
00364                 classList[i] = classNum[i] = 0;
00365                 i++;
00366                 continue;
00367                 }
00368 
00369         #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00370         printf("[parseMap] Processing line %d [%s]...\n", line, sptr);
00371         #endif
00372 
00373         classList[i] = cBuf[0];
00374         classNum[i] = atoi(&cBuf[1]);
00375 
00376         /* Count classes and make sure they are numbered properly */
00377         if(0 == currentClass && 0 == *classCount) { /* first class */
00378                 currentClass = cBuf[0];
00379                 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00380                 printf("[parseMap] First class: %c\n", currentClass);
00381                 #endif
00382                 k = classNum[i];
00383                 if(k != 1) {
00384                         printf("!! [AFNI/reorder] Invalid class numbering at line %d [Should start at 1] {1} !!\n"
00385                                 , line); 
00386                         free(classList);
00387                         free(classNum);
00388                         free(index);
00389                         free((*classKRH));
00390                         (*classKRH) = NULL;
00391                         *length = *classCount = 0;
00392                         return NULL;
00393                         }
00394 
00395                 (*classCount)++;
00396 
00397                 /* reallocate space */
00398                 (*classKRH) = (ClassInfo *)realloc((void *)(*classKRH), (*classCount)*sizeof(ClassInfo));
00399                 if(NULL == (*classKRH)) {
00400                         printf("!! [AFNI/reorder] Allocation error(4) !!\n");
00401                         free(index);
00402                         free(classList);
00403                         free(classNum);
00404                         *length = *classCount = 0;
00405                         return NULL;
00406                         }
00407                 (*classKRH)[(*classCount)-1].classKRH = currentClass;
00408                 (*classKRH)[(*classCount)-1].length = 1;
00409                 }
00410         else if(currentClass != cBuf[0]) { /* new class */
00411                 currentClass = cBuf[0];
00412                 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00413                 printf("[parseMap] Next class: %c\n", currentClass);
00414                 #endif
00415                 k = classNum[i];
00416                 if(k != 1) {
00417                         printf("!! [AFNI/reorder] Invalid class numbering at line %d [Should start at 1] {2} !!\n"
00418                                 , line); 
00419                         free(classList);
00420                         free(classNum);
00421                         free(index);
00422                         free((*classKRH));
00423                         (*classKRH) = NULL;
00424                         *length = *classCount = 0;
00425                         return NULL;
00426                         }
00427 
00428                 (*classCount)++;
00429 
00430                 /* reallocate space */
00431                 (*classKRH) = (ClassInfo *)realloc((void *)(*classKRH), (*classCount)*sizeof(ClassInfo));
00432                 if(NULL == (*classKRH)) {
00433                         printf("!! [AFNI/reorder] Allocation error(4) !!\n");
00434                         free(index);
00435                         free(classList);
00436                         free(classNum);
00437                         *length = *classCount = 0;
00438                         return NULL;
00439                         }
00440                 (*classKRH)[(*classCount)-1].classKRH = currentClass;
00441                 (*classKRH)[(*classCount)-1].length = 1;
00442                 }
00443         else {
00444                 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00445                 printf("[parseMap] Next entry, checking class numbering...\n");
00446                 #endif
00447                 ++k;
00448                 if(1 == classNum[i]) { /* contiguous instance of current class */
00449                         #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00450                         printf("[parseMap] Contiguous class: %c\n", currentClass);
00451                         #endif
00452         
00453                         k = 1;
00454                         (*classCount)++;
00455         
00456                         /* reallocate space */
00457                         (*classKRH) = (ClassInfo *)realloc((void *)(*classKRH), (*classCount)*sizeof(ClassInfo));
00458                         if(NULL == (*classKRH)) {
00459                                 printf("!! [AFNI/reorder] Allocation error(4) !!\n");
00460                                 free(index);
00461                                 free(classList);
00462                                 free(classNum);
00463                                 *length = *classCount = 0;
00464                                 return NULL;
00465                                 }
00466                         (*classKRH)[(*classCount)-1].classKRH = currentClass;
00467                         (*classKRH)[(*classCount)-1].length = 0;
00468                         }
00469                 else if(classNum[i] != k) {
00470                         printf("!! [AFNI/reorder] Invalid class numbering at line %d {3} !!\n"
00471                                 , line); 
00472                         free(index);
00473                         free(classList);
00474                         free(classNum);
00475                         free((*classKRH));
00476                         (*classKRH) = NULL;
00477                         *length = *classCount = 0;
00478                         return NULL;
00479                         }
00480                 ++(*classKRH)[(*classCount)-1].length;
00481                 }
00482         ++i;
00483         }
00484 fclose(inf);
00485 
00486 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00487 printf("\n[parseMap] Epoch map has %d distinct classes.\n\n", *classCount);
00488 printf("[parseMap] Parsed the following:\n");
00489 for(i = 0; i < rawLength; i++) {
00490         if(classList[i]) {
00491                 printf("  [%d] Class %c %d\n", i, classList[i], classNum[i]);
00492                 }
00493         else {
00494                 printf("  [%d] Excluded.\n", i);
00495                 }
00496         }
00497 printf("\n[parseMap] Meta-sequence of classes is:\n");
00498 for(i = 0; i < *classCount; i++) {
00499         printf("  [%d] Class %c [Width %d TRs]\n", i, (*classKRH)[i].classKRH, (*classKRH)[i].length);
00500         }
00501 #endif
00502 
00503 /* Build array of indices for reordering the time-course */
00504 /* Find the first occurrence of the lowest value class [currentClass].
00505    Store the the index positions of that class sequence in the current
00506    positions available in the 'index' array.
00507 */
00508 
00509 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00510 printf("\n[parseMap] Building mapping array...\n");
00511 #endif
00512 for(i = 0, currentClass = 0; i < *length; /* quit when all indices are remapped */) {
00513         /* Get next class to remap */
00514         if(!currentClass) {
00515                 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00516                 printf("\n  Determining next class to map...\n");
00517                 #endif
00518                 j = 0;
00519                 while(j < rawLength) { /* look for next non-null class */
00520                         if(classList[j]) {
00521                                 break;
00522                                 }
00523                         ++j;
00524                         }
00525                 if(j == rawLength) {
00526                         #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00527                         printf("  << No more classes to map >>\n");
00528                         #endif
00529                         break; /* done if there is none */
00530                         }
00531 
00532                 currentClass = classList[j];    /* current epoch class to remap */
00533                 classStart = classNum[j];       /* starting number of current class */
00534                 currentClassPos = j;            /* index of current class */
00535 
00536                 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00537                 printf("  Next valid class is '%c', checking to see if there is a better one...\n"
00538                         , currentClass);
00539                 #endif
00540 
00541                 /* See if there's a better one */
00542                 for(j = 1; j < rawLength; j++) {
00543                         if(classList[j]) {
00544                                 if(classList[j] < currentClass) {
00545                                         #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00546                                         printf("    Class '%c' should be done before '%c'...\n"
00547                                                 , classList[j], currentClass);
00548                                         #endif
00549                                         currentClass = classList[j];            /* new epoch class to remap */
00550                                         classStart = classNum[j];       /* starting number of new class */
00551                                         currentClassPos = j;            /* index of new class */
00552                                         }
00553                                 }
00554                         }
00555 
00556                 #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00557                 printf("  Remapping class '%c' [starting index is %d]...\n"
00558                         , currentClass, currentClassPos);
00559                 #endif
00560                 }
00561 
00562         /* currenClassPos is the index of the start position for the current
00563            class to be remapped; remap until class changes or class number
00564            returns to 1 */
00565         /* for(k = currentClassPos; i < rawLength, k < rawLength; ) { */
00566         /* for(k = currentClassPos; i < rawLength && k < rawLength; ) { */
00567            for(k = currentClassPos; k < rawLength; ) {
00568                 if(classList[k]) {
00569                         #ifdef DEBUG_PLUGIN_REORDER_PARSEMAP
00570                         printf("    Index[%d] <-- %d [Old index]\n", i, k);
00571                         #endif
00572                         index[i] = k; /* store the position of the TR value from the old time-course */ 
00573                         classList[k] = 0; /* mark as 'done' */
00574                         ++i;
00575                         ++k;
00576                         }
00577                 else { /* stop when a 'exclusion' point is found */
00578                         break;
00579                         }
00580 
00581                 if(classList[k] != currentClass || 1 == classNum[k]) {
00582                         break;
00583                         }
00584                 }
00585         currentClass = 0;
00586         }
00587 
00588 /* Free workspace */
00589 free(classNum);
00590 
00591 return(index);
00592 }
00593 
00594 #ifdef MAIN_PLUGIN_REORDER_PARSEMAP
00595 main(int argc, char *argv[])
00596 {
00597 int *index = NULL;
00598 ClassInfo *classKRH = NULL;
00599 int classCount = 0;
00600 int length;
00601 int i;
00602 
00603 if(3 != argc) {
00604         printf("usage: parseMap <MapFile> <TargetCount>\n");
00605         exit(1);
00606         }
00607 
00608 length = atoi(argv[2]);
00609 if(length < 1) {
00610         printf("!! [Main] Invalid target count: %d !!\n", length);
00611         exit(1);
00612         }
00613 
00614 if(NULL == (index = REORDER_parseMap(argv[1], &length, &classKRH, &classCount))) {
00615         printf("!! [Main] Trouble parsing epoch map file !!\n");
00616         exit(1);
00617         }
00618 
00619 printf("\n[Main] Indices for epoch remapping:\n");
00620 for(i = 0; i < length; i++) {
00621         printf("  %d\n", index[i]);
00622         }
00623 
00624 printf("\n[Main] Meta-sequence of classes is:\n");
00625 for(i = 0; i < classCount; i++) {
00626         printf("  [%d] Class %c [Width %d TRs]\n", i, classKRH[i].classKRH, classKRH[i].length);
00627         }
00628 
00629 free(index);
00630 free(classKRH);
00631 }
00632 #endif
00633 
00634 #endif
00635 
 

Powered by Plone

This site conforms to the following standards: