#!F-adobe-helvetica-medium-r-normal--18*
#!N 
#!CNavyBlue 
#!N  #!Rexmodp1 A Parallel Version of the AverageCell Module #!N #!EC 
#!N #!N Writing a version of AverageCell for a parallel environment 
introduces a "problem" that does not arise with the Add module: 
the implementation of parallelism by dividing Fields into spatially disjoint subsets 
called partitions. Each partition is stored as a Field inside a 
Group Object. This Group is a special subclass of Group objects 
called a "Composite Field." #!N #!N The AverageCell algorithm requires information 
about the neighbors of each cell. But for cells on a 
partition boundary, at least some of those neighbors are in another 
partition.  #!F-adobe-times-bold-r-normal--18*   DXGrow #!EF deals with this difficulty and obtains the 
needed information by "growing" the partition by a specified number of 
cells. In effect it "restores the old neighborhood." The desired operation 
can then be performed on the "grown" Field.  #!F-adobe-times-bold-r-normal--18*   DXShrink #!EF 
restores the partition to its pre-growth state by removing the extra 
cells and "cleaning up." (See  #!Lgns,dxall1120 h Growing and Shrinking Partitioned Data  #!EL  .) #!N #!N To create 
a version of Data Explorer that includes the AverageCellParallel module, copy 
the following files to the directory where you want to work: 
#!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N  #!F-adobe-times-bold-r-normal--18*   /opt/local/dx/samples/program_guide/Makefile_ #!EF  #!F-adobe-times-bold-i-normal--18*   workstation #!EF 
#!N  #!F-adobe-times-bold-r-normal--18*   /opt/local/dx/samples/program_guide/averagecell_parallel.c #!EF #!N  #!F-adobe-times-bold-r-normal--18*   /opt/local/dx/samples/program_guide/averagecellpar.mdf #!EF #!EF #!N #!N 
#!EC Now rename the makefile to  #!F-adobe-times-bold-r-normal--18*   Makefile #!EF and enter: 
make avgcell_par. #!N #!N To run this version (from the directory 
to which the files were copied), enter: #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   
#!N dx -edit -mdf ./averagecellpar.mdf -exec ./dxexec #!EF #!N #!N #!EC 
#!N #!N You can now run any visual program that uses 
the AverageCellParallel module. One such program is  #!F-adobe-times-bold-r-normal--18*   averagecell_parallel.net #!EF in 
the directory  #!F-adobe-times-bold-r-normal--18*   /opt/local/dx/samples/program_guide #!EF . #!N #!N The example AverageCellParallel 
code follows: #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 01 #include <dx/dx.h> #!N 
02 #!N 03 static Error DoAverageCell(Object); #!N 04 #!N 05 #!N 
06 #!N 07 Error m_AverageCellParallel(Object *in, Object *out) #!N 08 { 
#!N 09 Object o=NULL; #!N 10 #!N 11 if (!in[0]) { 
#!N 12 DXSetError(ERROR_BAD_PARAMETER,"missing input"); #!N 13 goto error; #!N 14 } 
#!N 15 #!N 16 o = DXCopy(in[0], COPY_STRUCTURE); #!EF #!N #!N 
#!EC #!N #!N "Grow" the Fields so that averaging can be 
performed across partition boundaries. Since it is not necessary to grow 
a Field beyond the original boundaries of the data, and since 
only the "data" component is affected, grow the partition by one 
cell. (The original components--"positions," "data," etc.--are copied into components named "original 
positions," "original data," and so on.) #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 
17 if (!DXGrow(o, 1, GROW_NONE, "data", NULL)) #!N 18 goto error; 
#!EF #!N #!N #!EC #!N #!N Create the task Group. #!CForestGreen 
#!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 19 if (!DXCreateTaskGroup()) #!N 20 goto error; 
#!EF #!N #!N #!EC #!N #!N The add tasks will be 
added in  #!F-adobe-times-bold-r-normal--18*   DoAverageCell() #!EF . #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 
21 if (!DoAverageCell(o)) { #!N 22 DXAbortTaskGroup(); #!N 23 goto error; 
#!N 24 } #!N 25 #!N 26 if (!DXExecuteTaskGroup()) #!N 27 
goto error; #!EF #!N #!N #!EC #!N #!N Do not call 
 #!F-adobe-times-bold-r-normal--18*   DXShrink #!EF to shrink the grown Field until you have 
recursively removed any "original data" component(s), assuming that you want to 
save the newly created one(s). Otherwise the new "data" component(s) will 
be replaced by the (unprocessed) "original data" components(s). Now you can 
call  #!F-adobe-times-bold-r-normal--18*   DXShrink #!EF . #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 28 
if (DXExists(o, "original data")) #!N 29 DXRemove(o,"original data"); #!N 30 if 
(!DXShrink(o)) #!N 31 goto error; #!N 32 #!N 33 out[0] = 
o; #!N 34 return OK; #!N 35 error: #!N 36 DXDelete((Object)o); 
#!N 37 return ERROR; #!N 38 } #!N 39 #!N 40 
struct arg { #!N 41 Field field; #!N 42 }; #!N 
43 #!N 44 static Error AddCellTask(Pointer p) #!N 45 { #!N 
46 struct arg *arg = (struct arg *)p; #!N 47 int 
i, j, numitems, shape, *neighbors_ptr, sum, neighbor; #!N 48 int dim, 
counts[3]; #!N 49 char *attribute; #!N 50 float *data_ptr, *newdata_ptr, dataaverage; 
#!N 51 Array connections, data, newdata=NULL, neighbors; #!N 52 Field field; 
#!N 53 #!N 54 field = arg->field; #!N 55 #!EF #!N 
#!N #!EC #!N #!N Get the connections component; determine the number 
of connections and their element type. #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 
56 #!N 57 connections = (Array)DXGetComponentValue(field,"connections"); #!N 58 if (!connections) { 
#!N 59 DXSetError(ERROR_MISSING_DATA,"input has no connections"); #!N 60 goto error; #!N 
61 } #!N 62 if (!DXGetArrayInfo(connections, &numitems, NULL, NULL, NULL, NULL)) 
{ #!N 63 goto error; #!N 64 } #!N 65 if 
(!(attribute= #!N 66 (char *)DXGetString((String)DXGetComponentAttribute(field, #!N 67 "connections", #!N 68 "element 
type")))) { #!N 69 DXSetError(ERROR_MISSING_DATA, #!N 70 "missing connection element type 
attribute"); #!N 71 goto error; #!N 72 } #!N 73 #!N 
74 #!EF #!N #!N #!EC #!N #!N Get the data component, 
and get the data dependency attribute. #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 
75 data = (Array)DXGetComponentValue(field,"data"); #!N 76 if (!data) { #!N 77 
DXSetError(ERROR_MISSING_DATA,"input has no data"); #!N 78 goto error; #!N 79 } 
#!N 80 if (!(attribute= #!N 81 (char *)DXGetString((String)DXGetComponentAttribute(field, #!N 82 "data", 
#!N 83 "dep")))) { #!N 84 DXSetError(ERROR_MISSING_DATA, #!N 85 "missing data 
dependency attribute"); #!N 86 goto error; #!N 87 } #!N 88 
#!EF #!N #!N #!EC #!N #!N In this example, the data 
must be dependent on the connections. #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 
89 if (strcmp(attribute,"connections")) { #!N 90 DXSetError(ERROR_INVALID_DATA, #!N 91 "data must 
be dependent on connections"); #!N 92 goto error; #!N 93 } 
#!N 94 #!EF #!N #!N #!EC #!N #!N For this example, 
the data must be floating-point scalar. #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 
95 if (!DXTypeCheck(data, TYPE_FLOAT, CATEGORY_REAL, 0, NULL)) { #!N 96 DXSetError(ERROR_INVALID_DATA, 
"data must be floating point scalar"); #!N 97 goto error; #!N 
98 } #!EF #!N #!N #!EC #!N #!N Get a pointer 
to the data. #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 99 data_ptr = 
(float *)DXGetArrayData(data); #!N 100 #!EF #!N #!N #!EC #!N #!N Make 
a new data component, allocate space in it, and get a 
pointer to it. #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 101 newdata = 
DXNewArray(TYPE_FLOAT,CATEGORY_REAL, 0); #!N 102 if (!DXAddArrayData(newdata, 0, numitems, NULL)) #!N 103 
goto error; #!N 104 newdata_ptr = (float *)DXGetArrayData(newdata); #!N 105 #!EF 
#!N #!N #!EC #!N #!N If the data is ungridded, use 
the neighbors component. If it is gridded, use a different method. 
#!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 106 if (!DXQueryGridConnections(connections, &dim, counts)) { 
#!N 107 #!EF #!N #!N #!EC #!N #!N Now the program 
needs the neighbors of the connections. Note that neighbors can be 
obtained only for ungridded data: for gridded data there are more 
efficient ways to determine neighbors. #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 108 
neighbors = DXNeighbors(field); #!N 109 if (!neighbors) #!N 110 goto error; 
#!N 111 neighbors_ptr = (int *)DXGetArrayData(neighbors); #!N 112 if (!DXGetArrayInfo(neighbors, NULL, 
NULL, NULL, NULL, &shape)) #!N 113 goto error; #!N 114 #!N 
115 #!N 116 for (i=0; i<numitems; i++) { #!N 117 dataaverage 
= data_ptr[i]; #!N 118 sum = 1; #!EF #!N #!N #!EC 
#!N #!N  #!F-adobe-times-bold-r-normal--18*   shape #!EF is the number of neighbors of 
a connection element. #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 119 for (j=0; 
j<shape; j++) { #!N 120 neighbor = neighbors_ptr[shape*i + j]; #!N 
121 if (neighbor != -1) { #!N 122 dataaverage = dataaverage 
+ data_ptr[neighbor]; #!N 123 sum++; #!N 124 } #!N 125 } 
#!N 126 dataaverage = dataaverage/sum; #!N 127 newdata_ptr[i] = dataaverage; #!N 
128 } #!N 129 } #!N 130 #!N 131 else { 
#!EF #!N #!N #!EC #!N #!N The connections are gridded. This 
example handles only 2-dimensional connections (quads). #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 
132 #!N 133 if (dim != 2) { #!N 134 DXSetError(ERROR_INVALID_DATA,"connections 
must be 2-dimensional"); #!N 135 goto error; #!N 136 } #!N 
137 #!N 138 for (i=0; i< numitems; i++) { #!N 139 
dataaverage = data_ptr[i]; #!N 140 sum = 1; #!EF #!N #!N 
#!EC #!N #!N  #!F-adobe-times-medium-r-normal--18*   There are as many as four (4) 
neighbors for every quad. #!EF #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 141 
if ((i % (counts[1]-1)) > 0) { #!N 142 neighbor = 
i-1; #!N 143 dataaverage = dataaverage + data_ptr[neighbor]; #!N 144 sum++; 
#!N 145 } #!EF #!N #!N #!EC #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   
#!N 146 if ((i % (counts[1]-1)) < (counts[1] - 2)) { 
#!N 147 neighbor = i+1; #!N 148 dataaverage = dataaverage + 
data_ptr[neighbor]; #!N 149 sum++; #!N 150 } #!EF #!N #!N #!EC 
#!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 151 neighbor = i-(counts[1]-1); #!N 152 
if (neighbor>=0 && neighbor<numitems) { #!N 153 dataaverage = dataaverage + 
data_ptr[neighbor]; #!N 154 sum++; #!N 155 } #!N 156 neighbor = 
i+(counts[1]-1); #!N 157 if (neighbor>=0 && neighbor<numitems) { #!N 158 dataaverage 
= dataaverage + data_ptr[neighbor]; #!N 159 sum++; #!N 160 } #!N 
161 dataaverage = dataaverage/sum; #!N 162 newdata_ptr[i] = dataaverage; #!N 163 
} #!N 164 } #!EF #!N #!N #!EC #!N #!N Place 
the new data component in the Field. #!CForestGreen #!N #!N  #!F-adobe-courier-bold-r-normal--18*   
#!N 165 DXSetComponentValue(field, "data", (Object)newdata); #!N 166 newdata=NULL; #!EF #!N #!N 
#!EC #!N #!N The data component has been changed (lines 162 
and 165) #!N #!N #!CForestGreen #!N  #!F-adobe-courier-bold-r-normal--18*   #!N 167 if (!DXChangedComponentValues(field,"data")) 
#!N 168 goto error; #!N 169 #!N 170 #!N 171 return 
OK; #!N 172 error: #!N 173 DXDelete((Object)newdata); #!N 174 return ERROR; 
#!N 175 } #!N 176 #!N 177 #!N 178 static Error 
DoAverageCell(Object object) #!N 179 { #!N 180 Object subo; #!N 181 
struct arg arg; #!N 182 int i; #!N 183 #!N 184 
switch (DXGetObjectClass(object)) { #!N 185 case (CLASS_FIELD): #!N 186 #!N 187 
arg.field = (Field)object; #!N 188 if (!DXAddTask(AddCellTask, &arg, sizeof(arg), 0.0)) #!N 
189 goto error; #!N 190 break; #!N 191 #!N 192 case 
(CLASS_GROUP): #!EF #!N #!N #!EC #!N #!N If  #!F-adobe-times-bold-r-normal--18*   object #!EF 
is a Group, recursively call  #!F-adobe-times-bold-r-normal--18*   DoAverageCell() #!EF . #!CForestGreen #!N 
#!N  #!F-adobe-courier-bold-r-normal--18*   #!N 193 for (i=0; subo=DXGetEnumeratedMember((Group)object, i, NULL); i++) { 
#!N 194 if (!DoAverageCell(subo)) #!N 195 return ERROR; #!N 196 } 
#!N 197 break; #!N 198 } #!N 199 return OK; #!N 
200 error: #!N 201 return ERROR; #!N 202 } #!EF #!N 
#!N #!EC #!N #!N #!N  #!F-adobe-times-medium-i-normal--18*   Next Topic #!EF #!N #!N 
 #!Lmtds,dxall1045 h Making a Module Work  #!EL  #!N  #!F-adobe-times-medium-i-normal--18*   #!N 
