4 @brief Implementation of the non-iterator parts of the ParFUM-Iterators layer
9 @todo add code to generate ghost layers
10 @todo Support multiple models
11 @todo Specify element types to be used via input vector in meshModel_Create
15 #include "ParFUM_Iterators.h"
16 #include "ParFUM_Iterators.decl.h"
18 #include "ParFUM_internals.h"
21 #include <cuda_runtime.h>
34 int tetFaces
[] = {0,1,3, 0,2,1, 1,2,3, 0,3,2};
35 int cohFaces
[] = {0,1,2, 3,4,5};
38 int lib_FP_Type_Size()
40 static const int LIB_FP_TYPE_SIZE
= sizeof(FP_TYPE
);
41 return LIB_FP_TYPE_SIZE
;
45 void mesh_set_device(MeshModel
* m
, MeshDevice d
)
50 CkAssert(m
->allocatedForCUDADevice
);
56 MeshDevice
mesh_target_device(MeshModel
* m
)
58 return m
->target_device
;
62 void fillIDHash(MeshModel
* model
)
65 if(model
->nodeIDHash
== NULL
)
66 model
->nodeIDHash
= new CkHashtableT
<CkHashtableAdaptorT
<int>, int>;
68 if(model
->elemIDHash
== NULL
)
69 model
->elemIDHash
= new CkHashtableT
<CkHashtableAdaptorT
<int>, int>;
71 for(int i
=0; i
<model
->node_id_T
->size(); ++i
){
72 model
->nodeIDHash
->put((*model
->node_id_T
)(i
,0)) = i
+1;
74 for(int i
=0; i
<model
->elem_id_T
->size(); ++i
){
75 model
->elemIDHash
->put((*model
->elem_id_T
)(i
,0)) = i
+1;
80 // Set the pointers in the model to point to the data stored by the ParFUM framework.
81 // If the number of nodes or elements increases, then this function should be called
82 // because the attribute arrays may have been resized, after which the old pointers
84 void setTableReferences(MeshModel
* model
, bool recomputeHash
)
86 model
->ElemConn_T
= &((FEM_IndexAttribute
*)model
->mesh
->elem
[MESH_ELEMENT_TET4
].lookup(FEM_CONN
,""))->get();
87 model
->elem_id_T
= &((FEM_DataAttribute
*)model
->mesh
->elem
[MESH_ELEMENT_TET4
].lookup(ATT_ELEM_ID
,""))->getInt();
88 model
->n2eConn_T
= &((FEM_DataAttribute
*)model
->mesh
->elem
[MESH_ELEMENT_TET4
].lookup(ATT_ELEM_N2E_CONN
, ""))->getInt();
89 model
->node_id_T
= &((FEM_DataAttribute
*)model
->mesh
->node
.lookup(ATT_NODE_ID
,""))->getInt();
91 model
->coord_T
= &((FEM_DataAttribute
*)model
->mesh
->node
.lookup(ATT_NODE_COORD
, ""))->getFloat();
93 model
->coord_T
= &((FEM_DataAttribute
*)model
->mesh
->node
.lookup(ATT_NODE_COORD
, ""))->getDouble();
95 model
->ElemData_T
= &((FEM_DataAttribute
*)model
->mesh
->elem
[MESH_ELEMENT_TET4
].lookup(ATT_ELEM_DATA
,""))->getChar();
96 FEM_Entity
* ghost
= model
->mesh
->elem
[MESH_ELEMENT_TET4
].getGhost();
98 model
->GhostElemData_T
= &((FEM_DataAttribute
*)ghost
->lookup(ATT_ELEM_DATA
,""))->getChar();
101 model
->NodeData_T
= &((FEM_DataAttribute
*)model
->mesh
->node
.lookup(ATT_NODE_DATA
,""))->getChar();
102 ghost
= model
->mesh
->node
.getGhost();
104 model
->GhostNodeData_T
= &((FEM_DataAttribute
*)ghost
->lookup(ATT_NODE_DATA
,""))->getChar();
107 if(model
->nodeIDHash
== NULL
) {
108 model
->nodeIDHash
= new CkHashtableT
<CkHashtableAdaptorT
<int>, int>;
111 if(model
->elemIDHash
== NULL
) {
112 model
->elemIDHash
= new CkHashtableT
<CkHashtableAdaptorT
<int>, int>;
121 /** Create a model before partitioning. Given the number of nodes per element.
123 After this call, the node data and element data CANNOT be set. They can only
124 be set in the driver. If the user tries to set the attribute values, the
125 call will be ignored.
128 MeshModel
* meshModel_Create_Init(){
129 MeshModel
* model
= new MeshModel
;
130 memset((void*) model
, 0, sizeof(MeshModel
));
132 model
->nodeIDHash
= new CkHashtableT
<CkHashtableAdaptorT
<int>, int>;
133 model
->elemIDHash
= new CkHashtableT
<CkHashtableAdaptorT
<int>, int>;
135 // This only uses a single mesh
136 int which_mesh
=FEM_Mesh_default_write();
137 model
->mesh
= FEM_Mesh_lookup(which_mesh
,"meshModel_Create_Init");
139 /** @note Here we allocate the arrays with a single
140 initial node and element, which are set as
141 invalid. If no initial elements were provided.
142 the AllocTable2d's would not ever get allocated,
143 and insertNode or insertElement would fail.
145 char temp_array
[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
148 // Allocate node id array
149 FEM_Mesh_data(which_mesh
,FEM_NODE
,ATT_NODE_ID
,temp_array
, 0, 1, FEM_INT
, 1);
150 // Allocate node coords
152 FEM_Mesh_data(which_mesh
,FEM_NODE
,ATT_NODE_COORD
,temp_array
, 0, 1, FEM_FLOAT
, 3);
154 FEM_Mesh_data(which_mesh
,FEM_NODE
,ATT_NODE_COORD
,temp_array
, 0, 1, FEM_DOUBLE
, 3);
156 FEM_Mesh_data(which_mesh
,FEM_NODE
,FEM_COORD
,temp_array
, 0, 1, FEM_DOUBLE
, 3); // Needed for shared node regeneration
157 // Don't allocate the ATT_NODE_DATA array because it will be large
159 // Allocate element connectivity
160 FEM_Mesh_data(which_mesh
,FEM_ELEM
+MESH_ELEMENT_TET4
,FEM_CONN
,temp_array
, 0, 1, FEM_INDEX_0
, 4);
161 FEM_Mesh_data(which_mesh
,FEM_ELEM
+MESH_ELEMENT_COH3T3
,FEM_CONN
,temp_array
, 0, 1, FEM_INDEX_0
, 6);
163 // Allocate element id array
164 FEM_Mesh_data(which_mesh
,FEM_ELEM
+MESH_ELEMENT_TET4
,ATT_ELEM_ID
,temp_array
, 0, 1, FEM_INT
, 1);
165 FEM_Mesh_data(which_mesh
,FEM_ELEM
+MESH_ELEMENT_COH3T3
,ATT_ELEM_ID
,temp_array
, 0, 1, FEM_INT
, 1);
168 // Don't allocate the ATT_ELEM_DATA array because it will be large
170 FEM_Mesh_allocate_valid_attr(which_mesh
, FEM_NODE
);
171 FEM_Mesh_allocate_valid_attr(which_mesh
, FEM_ELEM
+MESH_ELEMENT_TET4
);
172 FEM_Mesh_allocate_valid_attr(which_mesh
, FEM_ELEM
+MESH_ELEMENT_COH3T3
);
174 FEM_set_entity_invalid(which_mesh
, FEM_NODE
, 0);
175 FEM_set_entity_invalid(which_mesh
, FEM_ELEM
+MESH_ELEMENT_TET4
, 0);
176 FEM_set_entity_invalid(which_mesh
, FEM_ELEM
+MESH_ELEMENT_COH3T3
, 0);
178 // Setup the adjacency lists
179 setTableReferences(model
, true);
183 /** Get the mesh for use in the driver. It will be partitioned already.
185 In the driver routine, after getting the model from this function,
186 the input data file should be reread to fill in the node and element
187 data values which were not done in init.
190 void meshModel_Create_Driver(MeshDevice target_device
, int elem_attr_sz
,
191 int node_attr_sz
, int model_attr_sz
, void *mAtt
, MeshModel
&model
) {
193 CkAssert(ATT_NODE_ID
!= FEM_COORD
);
194 CkAssert(ATT_NODE_DATA
!= FEM_COORD
);
196 int partition
= FEM_My_partition();
197 if(haveConfigurableCPUGPUMap()){
198 if(isPartitionCPU(partition
))
199 CkPrintf("partition %d is on CPU\n", partition
);
201 CkPrintf("partition %d is on GPU\n", partition
);
205 // This only uses a single mesh, so don't create multiple MeshModels of these
206 CkAssert(elem_attr_sz
> 0);
207 CkAssert(node_attr_sz
> 0);
208 int which_mesh
=FEM_Mesh_default_read();
210 memset((void *) &model
, 0, sizeof(MeshModel
));
212 model
.target_device
= target_device
;
213 model
.elem_attr_size
= elem_attr_sz
;
214 model
.node_attr_size
= node_attr_sz
;
215 model
.model_attr_size
= model_attr_sz
;
217 model
.mesh
= FEM_Mesh_lookup(which_mesh
,"meshModel_Create_Driver");
220 model
.num_local_elem
= model
.mesh
->elem
[MESH_ELEMENT_TET4
].size();
221 model
.num_local_node
= model
.mesh
->node
.size();
223 // Allocate user model attributes
224 FEM_Mesh_become_set(which_mesh
);
225 char* temp_array
= (char*) malloc(model
.num_local_elem
* model
.elem_attr_size
);
226 FEM_Mesh_data(which_mesh
,FEM_ELEM
+MESH_ELEMENT_TET4
,ATT_ELEM_DATA
,temp_array
,0,model
.num_local_elem
,FEM_BYTE
,model
.elem_attr_size
);
229 temp_array
= (char*) malloc(model
.num_local_node
* model
.node_attr_size
);
230 FEM_Mesh_data(which_mesh
,FEM_NODE
,ATT_NODE_DATA
,temp_array
,0,model
.num_local_node
,FEM_BYTE
,model
.node_attr_size
);
234 const int connSize
= model
.mesh
->elem
[MESH_ELEMENT_TET4
].getConn().width();
235 temp_array
= (char*) malloc(model
.num_local_node
* connSize
);
236 FEM_Mesh_data(which_mesh
,FEM_ELEM
+MESH_ELEMENT_TET4
,ATT_ELEM_N2E_CONN
,temp_array
, 0, 1, FEM_INT
, connSize
);
239 setTableReferences(&model
, true);
241 // Setup the adjacencies
242 int nodesPerTuple
= 3;
243 int tuplesPerTet
= 4;
244 int tuplesPerCoh
= 2;
246 FEM_Add_elem2face_tuples(which_mesh
, MESH_ELEMENT_TET4
, nodesPerTuple
, tuplesPerTet
, tetFaces
);
247 FEM_Add_elem2face_tuples(which_mesh
, MESH_ELEMENT_COH3T3
, nodesPerTuple
, tuplesPerCoh
, cohFaces
);
249 model
.mesh
->createNodeElemAdj();
250 model
.mesh
->createNodeNodeAdj();
251 model
.mesh
->createElemElemAdj();
255 /** Create n2e connectivity array and copy to device global memory */
256 FEM_Mesh_create_node_elem_adjacency(which_mesh
);
257 FEM_Mesh
* mesh
= FEM_Mesh_lookup(which_mesh
, "meshModel_Create_Driver");
258 FEM_DataAttribute
* at
= (FEM_DataAttribute
*)
259 model
.mesh
->elem
[MESH_ELEMENT_TET4
].lookup(ATT_ELEM_N2E_CONN
,"meshModel_Create_Driver");
260 n2eTable
= at
->getInt().getData();
262 FEM_IndexAttribute
* iat
= (FEM_IndexAttribute
*)
263 model
.mesh
->elem
[MESH_ELEMENT_TET4
].lookup(FEM_CONN
,"meshModel_Create_Driver");
264 int* connTable
= iat
->get().getData();
268 for (int i
=0; i
<model
.num_local_node
; ++i
) {
269 mesh
->n2e_getAll(i
, adjElements
, size
);
270 for (int j
=0; j
<size
; ++j
) {
271 for (int k
=0; k
<connSize
+1; ++k
) {
272 if (connTable
[connSize
*adjElements
[j
]+k
] == i
) {
273 n2eTable
[connSize
*adjElements
[j
]+k
] = j
;
277 CkPrintf("Element %d cannot find node %d in its conn [%d %d %d]\n",
279 connTable
[connSize
*adjElements
[j
]+0],
280 connTable
[connSize
*adjElements
[j
]+1],
281 connTable
[connSize
*adjElements
[j
]+2]);
286 delete[] adjElements
;
290 //for (int i=0; i<model->num_local_elem*4; ++i) {
291 // printf("%d ", connTable[i]);
292 // if ((i+1)%4 == 0) printf("\n");
295 //for (int i=0; i<model->num_local_elem*4; ++i) {
296 // printf("%d ", n2eTable[i]);
297 // if ((i+1)%4 == 0) printf("\n");
299 FEM_Mesh_become_get(which_mesh
);
302 if (model
.target_device
== DeviceGPU
) {
303 allocateModelForCUDADevice(&model
);
312 // MeshDevice target_device
313 void allocateModelForCUDADevice(MeshModel
* model
){
315 CkPrintf("[%d] allocateModelForCUDADevice\n", CkMyPe() );
317 if( ! model
->allocatedForCUDADevice
) {
318 model
->allocatedForCUDADevice
= true;
320 const int connSize
= model
->mesh
->elem
[MESH_ELEMENT_TET4
].getConn().width();
321 const FEM_DataAttribute
* at
= (FEM_DataAttribute
*) model
->mesh
->elem
[MESH_ELEMENT_TET4
].lookup(ATT_ELEM_N2E_CONN
,"allocateModelForCUDADevice");
322 const int* n2eTable
= at
->getInt().getData();
325 int size
= model
->num_local_elem
* connSize
*sizeof(int);
326 cudaError_t err
= cudaMalloc((void**)&(model
->device_model
.n2eConnDevice
), size
);
327 if(err
== cudaErrorMemoryAllocation
){
328 CkPrintf("[%d] cudaMalloc FAILED with error cudaErrorMemoryAllocation model->device_model.n2eConnDevice in ParFUM_Iterators.cc size=%d: %s\n", CkMyPe(), size
, cudaGetErrorString(err
));
329 }else if(err
!= cudaSuccess
){
330 CkPrintf("[%d] cudaMalloc FAILED model->device_model.n2eConnDevice in ParFUM_Iterators.cc size=%d: %s\n", CkMyPe(), size
, cudaGetErrorString(err
));
331 CkAbort("cudaMalloc FAILED");
333 CkAssert(cudaMemcpy(model
->device_model
.n2eConnDevice
,n2eTable
,size
, cudaMemcpyHostToDevice
) == cudaSuccess
);
336 /** copy number/sizes of nodes and elements to device structure */
337 model
->device_model
.elem_attr_size
= model
->elem_attr_size
;
338 model
->device_model
.node_attr_size
= model
->node_attr_size
;
339 model
->device_model
.model_attr_size
= model
->model_attr_size
;
340 model
->device_model
.num_local_node
= model
->num_local_node
;
341 model
->device_model
.num_local_elem
= model
->num_local_elem
;
343 /** Copy element Attribute array to device global memory */
345 FEM_DataAttribute
* at
= (FEM_DataAttribute
*) model
->mesh
->elem
[MESH_ELEMENT_TET4
].lookup(ATT_ELEM_DATA
,"meshModel_Create_Driver");
346 AllocTable2d
<unsigned char> &dataTable
= at
->getChar();
347 unsigned char *ElemData
= dataTable
.getData();
348 int size
= dataTable
.size()*dataTable
.width();
349 assert(size
== model
->num_local_elem
* model
->elem_attr_size
);
350 CkAssert(cudaMalloc((void**)&(model
->device_model
.ElemDataDevice
), size
) == cudaSuccess
);
351 CkAssert(cudaMemcpy(model
->device_model
.ElemDataDevice
,ElemData
,size
,
352 cudaMemcpyHostToDevice
) == cudaSuccess
);
355 /** Copy node Attribute array to device global memory */
357 FEM_DataAttribute
* at
= (FEM_DataAttribute
*) model
->mesh
->node
.lookup(ATT_NODE_DATA
,"meshModel_Create_Driver");
358 AllocTable2d
<unsigned char> &dataTable
= at
->getChar();
359 unsigned char *NodeData
= dataTable
.getData();
360 int size
= dataTable
.size()*dataTable
.width();
361 assert(size
== model
->num_local_node
* model
->node_attr_size
);
362 CkAssert(cudaMalloc((void**)&(model
->device_model
.NodeDataDevice
), size
) == cudaSuccess
);
363 CkAssert(cudaMemcpy(model
->device_model
.NodeDataDevice
,NodeData
,size
,
364 cudaMemcpyHostToDevice
) == cudaSuccess
);
367 /** Copy elem connectivity array to device global memory */
369 FEM_IndexAttribute
* at
= (FEM_IndexAttribute
*) model
->mesh
->elem
[MESH_ELEMENT_TET4
].lookup(FEM_CONN
,"meshModel_Create_Driver");
370 AllocTable2d
<int> &dataTable
= at
->get();
371 int *data
= dataTable
.getData();
372 int size
= dataTable
.size()*dataTable
.width()*sizeof(int);
373 CkAssert(cudaMalloc((void**)&(model
->device_model
.ElemConnDevice
), size
) == cudaSuccess
);
374 CkAssert(cudaMemcpy(model
->device_model
.ElemConnDevice
,data
,size
,
375 cudaMemcpyHostToDevice
) == cudaSuccess
);
378 /** Copy model Attribute to device global memory */
380 printf("Copying model attribute of size %d\n", model
->model_attr_size
);
381 CkAssert(cudaMalloc((void**)&(model
->device_model
.mAttDevice
),
382 model
->model_attr_size
) == cudaSuccess
);
383 CkAssert(cudaMemcpy(model
->device_model
.mAttDevice
,model
->mAtt
,model
->model_attr_size
,
384 cudaMemcpyHostToDevice
) == cudaSuccess
);
390 // Copy data from GPU and deallocate its memory
391 void deallocateModelForCUDADevice(MeshModel
* model
){
393 CkPrintf("[%d] deallocateModelForCUDADevice\n", CkMyPe() );
395 if( model
->allocatedForCUDADevice
) {
396 model
->allocatedForCUDADevice
= false;
398 const int connSize
= model
->mesh
->elem
[MESH_ELEMENT_TET4
].getConn().width();
399 FEM_DataAttribute
* at
= (FEM_DataAttribute
*) model
->mesh
->elem
[MESH_ELEMENT_TET4
].lookup(ATT_ELEM_N2E_CONN
,"allocateModelForCUDADevice");
400 int* n2eTable
= at
->getInt().getData();
402 int size
= model
->num_local_elem
* connSize
*sizeof(int);
404 CkAssert(cudaMemcpy(n2eTable
,model
->device_model
.n2eConnDevice
,size
, cudaMemcpyDeviceToHost
) == cudaSuccess
);
405 CkAssert(cudaFree(model
->device_model
.n2eConnDevice
) == cudaSuccess
);
407 /** Copy element Attribute array from device global memory */
409 FEM_DataAttribute
* at
= (FEM_DataAttribute
*) model
->mesh
->elem
[MESH_ELEMENT_TET4
].lookup(ATT_ELEM_DATA
,"meshModel_Create_Driver");
410 AllocTable2d
<unsigned char> &dataTable
= at
->getChar();
411 unsigned char *ElemData
= dataTable
.getData();
412 int size
= dataTable
.size()*dataTable
.width();
413 assert(size
== model
->num_local_elem
* model
->elem_attr_size
);
414 CkAssert(cudaMemcpy(ElemData
,model
->device_model
.ElemDataDevice
,size
, cudaMemcpyDeviceToHost
) == cudaSuccess
);
415 CkAssert(cudaFree(model
->device_model
.ElemDataDevice
) == cudaSuccess
);
418 /** Copy node Attribute array from device global memory */
420 FEM_DataAttribute
* at
= (FEM_DataAttribute
*) model
->mesh
->node
.lookup(ATT_NODE_DATA
,"meshModel_Create_Driver");
421 AllocTable2d
<unsigned char> &dataTable
= at
->getChar();
422 unsigned char *NodeData
= dataTable
.getData();
423 int size
= dataTable
.size()*dataTable
.width();
424 assert(size
== model
->num_local_node
* model
->node_attr_size
);
425 CkAssert(cudaMemcpy(NodeData
,model
->device_model
.NodeDataDevice
,size
, cudaMemcpyDeviceToHost
) == cudaSuccess
);
426 CkAssert(cudaFree(model
->device_model
.NodeDataDevice
) == cudaSuccess
);
429 /** Copy elem connectivity array from device global memory */
431 FEM_IndexAttribute
* at
= (FEM_IndexAttribute
*) model
->mesh
->elem
[MESH_ELEMENT_TET4
].lookup(FEM_CONN
,"meshModel_Create_Driver");
432 AllocTable2d
<int> &dataTable
= at
->get();
433 int *data
= dataTable
.getData();
434 int size
= dataTable
.size()*dataTable
.width()*sizeof(int);
435 CkAssert(cudaMemcpy(data
,model
->device_model
.ElemConnDevice
,size
, cudaMemcpyDeviceToHost
) == cudaSuccess
);
436 CkAssert(cudaFree(model
->device_model
.ElemConnDevice
) == cudaSuccess
);
439 /** Copy model Attribute from device global memory */
441 printf("Copying model attribute of size %d\n", model
->model_attr_size
);
442 CkAssert(cudaMemcpy(model
->mAtt
,model
->device_model
.mAttDevice
,model
->model_attr_size
, cudaMemcpyDeviceToHost
) == cudaSuccess
);
443 CkAssert(cudaFree(model
->device_model
.mAttDevice
) == cudaSuccess
);
454 /** Copy node attribute array from CUDA device back to the ParFUM attribute */
455 void mesh_retrieve_node_data(MeshModel
* m
){
457 CkAssert( m
->allocatedForCUDADevice
);
458 cudaError_t status
= cudaMemcpy(m
->NodeData_T
->getData(),
459 m
->device_model
.NodeDataDevice
,
460 m
->num_local_node
* m
->node_attr_size
,
461 cudaMemcpyDeviceToHost
);
462 CkAssert(status
== cudaSuccess
);
466 /** Copy node attribute array to CUDA device from the ParFUM attribute */
467 void mesh_put_node_data(MeshModel
* m
){
469 CkAssert( m
->allocatedForCUDADevice
);
470 cudaError_t status
= cudaMemcpy(m
->device_model
.NodeDataDevice
,
471 m
->NodeData_T
->getData(),
472 m
->num_local_node
* m
->node_attr_size
,
473 cudaMemcpyHostToDevice
);
474 CkAssert(status
== cudaSuccess
);
479 /** Copy element attribute array from CUDA device back to the ParFUM attribute */
480 void mesh_retrieve_elem_data(MeshModel
* m
){
482 CkAssert( m
->allocatedForCUDADevice
);
483 cudaError_t status
= cudaMemcpy(m
->ElemData_T
->getData(),
484 m
->device_model
.ElemDataDevice
,
485 m
->num_local_elem
* m
->elem_attr_size
,
486 cudaMemcpyDeviceToHost
);
487 CkAssert(status
== cudaSuccess
);
492 /** Copy elem attribute array to CUDA device from the ParFUM attribute */
493 void mesh_put_elem_data(MeshModel
* m
) {
495 CkAssert( m
->allocatedForCUDADevice
);
496 cudaError_t status
= cudaMemcpy(m
->device_model
.ElemDataDevice
,
497 m
->ElemData_T
->getData(),
498 m
->num_local_elem
* m
->elem_attr_size
,
499 cudaMemcpyHostToDevice
);
500 CkAssert(status
== cudaSuccess
);
505 /** Copy node and elem attribute arrays to CUDA device from the ParFUM attribute */
506 void mesh_put_data(MeshModel
* m
) {
508 CkAssert( m
->allocatedForCUDADevice
);
509 mesh_put_node_data(m
);
510 mesh_put_elem_data(m
);
511 cudaError_t status
= cudaMemcpy(m
->device_model
.mAttDevice
,m
->mAtt
,m
->model_attr_size
,
512 cudaMemcpyHostToDevice
);
513 CkAssert(status
== cudaSuccess
);
518 /** Copy node and elem attribute arrays from CUDA device to the ParFUM attribute */
519 void mesh_retrieve_data(MeshModel
* m
) {
521 CkAssert( m
->allocatedForCUDADevice
);
522 mesh_retrieve_node_data(m
);
523 mesh_retrieve_elem_data(m
);
524 cudaError_t status
= cudaMemcpy(m
->mAtt
,m
->device_model
.mAttDevice
,m
->model_attr_size
,
525 cudaMemcpyDeviceToHost
);
526 CkAssert(status
== cudaSuccess
);
531 /** Cleanup a model */
532 void meshModel_Destroy(MeshModel
* m
){
534 if (m
->target_device
== DeviceGPU
) {
535 // CkAssert(cudaFree(m->device_model.mAttDevice) == cudaSuccess);
536 // CkAssert(cudaFree(m->device_model.NodeDataDevice) == cudaSuccess);
537 // CkAssert(cudaFree(m->device_model.ElemDataDevice) == cudaSuccess);
544 MeshNode
meshModel_InsertNode(MeshModel
* m
, double x
, double y
, double z
){
545 int newNode
= FEM_add_node_local(m
->mesh
,false,false,false);
546 setTableReferences(m
);
547 (*m
->coord_T
)(newNode
,0)=x
;
548 (*m
->coord_T
)(newNode
,1)=y
;
549 (*m
->coord_T
)(newNode
,2)=z
;
553 MeshNode
meshModel_InsertNode(MeshModel
* m
, float x
, float y
, float z
){
554 int newNode
= FEM_add_node_local(m
->mesh
,false,false,false);
555 setTableReferences(m
);
556 (*m
->coord_T
)(newNode
,0)=x
;
557 (*m
->coord_T
)(newNode
,1)=y
;
558 (*m
->coord_T
)(newNode
,2)=z
;
564 @todo Make this work with ghosts
566 void meshNode_SetId(MeshModel
* m
, MeshNode n
, EntityID id
){
568 (*m
->node_id_T
)(n
,0)=id
;
569 m
->nodeIDHash
->put(id
) = n
+1;
572 /** Insert an element */
573 MeshElement
meshModel_InsertElem(MeshModel
*m
, MeshElementType type
, MeshNode
* nodes
){
574 CkAssert(type
== MESH_ELEMENT_TET4
|| type
== MESH_ELEMENT_TET10
);
578 if(type
==MESH_ELEMENT_TET4
){
584 newEl
.type
= MESH_ELEMENT_TET4
;
585 newEl
.id
= FEM_add_element_local(m
->mesh
, conn
, 4, type
, 0,0);
586 } else if (type
==MESH_ELEMENT_TET10
){
598 newEl
.type
= MESH_ELEMENT_TET10
;
599 newEl
.id
= FEM_add_element_local(m
->mesh
, conn
, 10, type
, 0, 0);
602 setTableReferences(m
);
606 /** Set id of an element
607 @todo Make this work with ghosts
609 void meshElement_SetId(MeshModel
* m
, MeshElement e
, EntityID id
){
611 (*m
->elem_id_T
)(e
.id
,0)=id
;
612 m
->elemIDHash
->put(id
) = e
.id
+1;
615 /** get the number of elements in the mesh */
616 int meshModel_GetNElem (MeshModel
* m
){
617 const int numBulk
= m
->mesh
->elem
[MESH_ELEMENT_TET4
].count_valid();
618 const int numCohesive
= m
->mesh
->elem
[MESH_ELEMENT_COH3T3
].count_valid();
619 std::cout
<< " numBulk = " << numBulk
<< " numCohesive " << numCohesive
<< std::endl
;
620 return numBulk
+ numCohesive
;
624 @brief Set attribute of a node
626 The attribute passed in must be a contiguous data structure with size equal to the value node_attr_sz passed into meshModel_Create_Driver() and meshModel_Create_Init()
628 The supplied attribute will be copied into the ParFUM attribute array "ATT_NODE_DATA. Then ParFUM will own this data. The function meshNode_GetAttrib() will return a pointer to the copy owned by ParFUM. If a single material parameter attribute is used for multiple nodes, each node will get a separate copy of the array. Any subsequent modifications to the data will only be reflected at a single node.
630 The user is responsible for deallocating parameter d passed into this function.
633 void meshNode_SetAttrib(MeshModel
* m
, MeshNode n
, void* d
)
635 if(m
->NodeData_T
== NULL
){
636 CkPrintf("Ignoring call to meshNode_SetAttrib\n");
641 assert(m
->GhostNodeData_T
);
642 data
= m
->GhostNodeData_T
->getData();
643 n
= FEM_From_ghost_index(n
);
645 assert(m
->NodeData_T
);
646 data
= m
->NodeData_T
->getData();
648 memcpy(data
+ n
*m
->node_attr_size
, d
, m
->node_attr_size
);
652 /** @brief Set attribute of an element
653 See meshNode_SetAttrib() for description
655 void meshElement_SetAttrib(MeshModel
* m
, MeshElement e
, void* d
){
656 if(m
->ElemData_T
== NULL
){
657 CkPrintf("Ignoring call to meshElement_SetAttrib\n");
662 data
= m
->GhostElemData_T
->getData();
663 e
.id
= FEM_From_ghost_index(e
.id
);
665 data
= m
->ElemData_T
->getData();
667 memcpy(data
+ e
.id
*m
->elem_attr_size
, d
, m
->elem_attr_size
);
671 /** @brief Get elem attribute
672 See meshNode_SetAttrib() for description
674 void* meshElement_GetAttrib(MeshModel
* m
, MeshElement e
)
676 if(! m
->mesh
->elem
[e
.type
].is_valid_any_idx(e
.id
))
679 if (FEM_Is_ghost_index(e
.id
)) {
680 data
= m
->GhostElemData_T
->getData();
681 e
.id
= FEM_From_ghost_index(e
.id
);
683 data
= m
->ElemData_T
->getData();
685 return (data
+ e
.id
*m
->elem_attr_size
);
688 /** @brief Get nodal attribute
689 See meshNode_SetAttrib() for description
691 void* meshNode_GetAttrib(MeshModel
* m
, MeshNode n
)
693 if(!m
->mesh
->node
.is_valid_any_idx(n
))
697 if (FEM_Is_ghost_index(n
)) {
698 data
= m
->GhostNodeData_T
->getData();
699 n
= FEM_From_ghost_index(n
);
701 data
= m
->NodeData_T
->getData();
703 return (data
+ n
*m
->node_attr_size
);
710 MeshNode
meshModel_GetNodeAtId(MeshModel
* m
, EntityID id
)
712 int hashnode
= m
->nodeIDHash
->get(id
)-1;
713 if (hashnode
!= -1) return hashnode
;
715 AllocTable2d
<int>* ghostNode_id_T
= &((FEM_DataAttribute
*)m
->mesh
->
716 node
.getGhost()->lookup(ATT_NODE_ID
,""))->getInt();
717 if(ghostNode_id_T
!= NULL
){
718 for(int i
=0; i
<ghostNode_id_T
->size(); ++i
) {
719 if((*ghostNode_id_T
)(i
,0)==id
){
720 return FEM_To_ghost_index(i
);
730 Note: this will currently only work with TET4 elements
732 #ifndef INLINE_GETELEMATID
733 MeshElement
meshModel_GetElemAtId(MeshModel
*m
,EntityID id
)
736 e
.id
= m
->elemIDHash
->get(id
)-1;
737 e
.type
= MESH_ELEMENT_TET4
;
739 if (e
.id
!= -1) return e
;
741 AllocTable2d
<int>* ghostElem_id_T
= &((FEM_DataAttribute
*)m
->mesh
->
742 elem
[MESH_ELEMENT_TET4
].getGhost()->lookup(ATT_ELEM_ID
,""))->getInt();
744 if(ghostElem_id_T
!= NULL
) {
745 for(int i
=0; i
<ghostElem_id_T
->size(); ++i
) {
746 if((*ghostElem_id_T
)(i
,0)==id
){
747 e
.id
= FEM_To_ghost_index(i
);
748 e
.type
= MESH_ELEMENT_TET4
;
755 e
.type
= MESH_ELEMENT_TET4
;
761 MeshNode
meshElement_GetNode(MeshModel
* m
,MeshElement e
,int idx
){
764 CkAssert(m
->mesh
->elem
[e
.type
].getGhost());
765 const AllocTable2d
<int> &conn
= ((FEM_Elem
*)m
->mesh
->elem
[e
.type
].getGhost())->getConn();
766 CkAssert(idx
>=0 && idx
<conn
.width());
767 node
= conn(FEM_From_ghost_index(e
.id
),idx
);
769 const AllocTable2d
<int> &conn
= m
->mesh
->elem
[e
.type
].getConn();
770 CkAssert(idx
>=0 && idx
<conn
.width());
771 node
= conn(e
.id
,idx
);
777 int meshNode_GetId(MeshModel
* m
, MeshNode n
){
779 return (*m
->node_id_T
)(n
,0);
783 /** @todo handle ghost nodes as appropriate */
784 int meshModel_GetNNodes(MeshModel
*model
){
785 return model
->mesh
->node
.count_valid();
788 /** @todo How should we handle meshes with mixed elements? */
789 int meshElement_GetNNodes(MeshModel
* model
, MeshElement elem
){
790 return model
->mesh
->elem
[elem
.type
].getConn().width();
793 /** @todo make sure we are in a getting mesh */
794 void meshNode_GetPosition(MeshModel
*model
, MeshNode node
,double*x
,double*y
,double*z
){
796 AllocTable2d
<double>* table
= &((FEM_DataAttribute
*)model
->
797 mesh
->node
.getGhost()->lookup(ATT_NODE_COORD
,""))->getDouble();
798 node
= FEM_From_ghost_index(node
);
799 *x
= (*table
)(node
,0);
800 *y
= (*table
)(node
,1);
801 *z
= (*table
)(node
,2);
803 *x
= (*model
->coord_T
)(node
,0);
804 *y
= (*model
->coord_T
)(node
,1);
805 *z
= (*model
->coord_T
)(node
,2);
809 /** @todo make sure we are in a getting mesh */
810 void meshNode_GetPosition(MeshModel
*model
, MeshNode node
,float*x
,float*y
,float*z
){
812 AllocTable2d
<float>* table
= &((FEM_DataAttribute
*)model
->
813 mesh
->node
.getGhost()->lookup(ATT_NODE_COORD
,""))->getFloat();
814 node
= FEM_From_ghost_index(node
);
816 *x
= (*table
)(node
,0);
817 *y
= (*table
)(node
,1);
818 *z
= (*table
)(node
,2);
820 *x
= (*model
->coord_T
)(node
,0);
821 *y
= (*model
->coord_T
)(node
,1);
822 *z
= (*model
->coord_T
)(node
,2);
826 void meshModel_Sync(MeshModel
*m
){
827 MPI_Barrier(MPI_COMM_WORLD
);
830 /** Test the node and element iterators */
831 void meshModel_TestIterators(MeshModel
*m
){
832 CkAssert(m
->mesh
->elem
[MESH_ELEMENT_TET4
].ghost
!=NULL
);
833 CkAssert(m
->mesh
->node
.ghost
!=NULL
);
835 int expected_elem_count
= m
->mesh
->elem
[MESH_ELEMENT_TET4
].count_valid() + m
->mesh
->elem
[MESH_ELEMENT_TET4
].ghost
->count_valid();
836 int iterated_elem_count
= 0;
838 int expected_node_count
= m
->mesh
->node
.count_valid() + m
->mesh
->node
.ghost
->count_valid();
839 int iterated_node_count
= 0;
841 int myId
= FEM_My_partition();
844 MeshNodeItr
* itr
= meshModel_CreateNodeItr(m
);
845 for(meshNodeItr_Begin(itr
);meshNodeItr_IsValid(itr
);meshNodeItr_Next(itr
)){
846 iterated_node_count
++;
847 MeshNode node
= meshNodeItr_GetCurr(itr
);
848 void* na
= meshNode_GetAttrib(m
,node
);
849 CkAssert(na
!= NULL
);
852 MeshElemItr
* e_itr
= meshModel_CreateElemItr(m
);
853 for(meshElemItr_Begin(e_itr
);meshElemItr_IsValid(e_itr
);meshElemItr_Next(e_itr
)){
854 iterated_elem_count
++;
855 MeshElement elem
= meshElemItr_GetCurr(e_itr
);
856 void* ea
= meshElement_GetAttrib(m
,elem
);
857 CkAssert(ea
!= NULL
);
860 CkAssert(iterated_node_count
== expected_node_count
);
861 CkAssert(iterated_elem_count
==expected_elem_count
);
862 CkPrintf("Completed Iterator Test!\n");
866 bool meshElement_IsCohesive(MeshModel
* m
, MeshElement e
){
867 return e
.type
> MESH_ELEMENT_MIN_COHESIVE
;
871 /** currently we only support linear tets for the bulk elements */
872 int meshFacet_GetNNodes (MeshModel
* m
, MeshFacet f
){
876 MeshNode
meshFacet_GetNode (MeshModel
* m
, MeshFacet f
, int i
){
880 MeshElement
meshFacet_GetElem (MeshModel
* m
, MeshFacet f
, int i
){
884 /** I'm not quite sure the point of this function
885 * TODO figure out what this is supposed to do
887 bool meshElement_IsValid(MeshModel
* m
, MeshElement e
){
888 return m
->mesh
->elem
[e
.type
].is_valid_any_idx(e
.id
);
892 /** We will use the following to identify the original boundary nodes.
893 * These are those that are adjacent to a facet that is on the boundary(has one adjacent element).
894 * Assume vertex=node.
897 bool meshVertex_IsBoundary (MeshModel
* m
, MeshVertex v
){
898 return m
->mesh
->node
.isBoundary(v
);
902 MeshVertex
meshNode_GetVertex (MeshModel
* m
, MeshNode n
){
907 int meshElement_GetId (MeshModel
* m
, MeshElement e
) {
909 return (*m
->elem_id_T
)(e
.id
,0);
912 /** Determine if two triangles are the same, but possibly varied under
913 * rotation or mirroring */
914 bool areSameTriangle(int a1
, int a2
, int a3
, int b1
, int b2
, int b3
) {
915 if (a1
==b1
&& a2
==b2
&& a3
==b3
) return true;
916 if (a1
==b2
&& a2
==b3
&& a3
==b1
) return true;
917 if (a1
==b3
&& a2
==b1
&& a3
==b2
) return true;
918 if (a1
==b1
&& a2
==b3
&& a3
==b2
) return true;
919 if (a1
==b2
&& a2
==b1
&& a3
==b3
) return true;
920 if (a1
==b3
&& a2
==b2
&& a3
==b1
) return true;
926 MeshElement
meshModel_InsertCohesiveAtFacet (MeshModel
* m
, MeshElementType etype
, MeshFacet f
){
927 MeshElement newCohesiveElement
;
929 CkAssert(etype
== MESH_ELEMENT_COH3T3
);
931 const MeshElement firstElement
= f
.elem
[0];
932 const MeshElement secondElement
= f
.elem
[1];
934 CkAssert(firstElement
.type
!= MESH_ELEMENT_COH3T3
);
935 CkAssert(secondElement
.type
!= MESH_ELEMENT_COH3T3
);
937 CkAssert(firstElement
.id
!= -1);
938 CkAssert(secondElement
.id
!= -1);
940 // Create a new element
941 int newEl
= m
->mesh
->elem
[etype
].get_next_invalid(m
->mesh
);
942 m
->mesh
->elem
[etype
].set_valid(newEl
, false);
944 newCohesiveElement
.id
= newEl
;
945 newCohesiveElement
.type
= etype
;
948 CkPrintf("/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/ \n");
949 CkPrintf("Inserting cohesive %d of type %d at facet %d,%d,%d\n", newEl
, etype
, f
.node
[0], f
.node
[1], f
.node
[2]);
960 /// The lists of elements that can be reached from element on one side of the facet by iterating around each of the three nodes
961 std::set
<MeshElement
> reachableFromElement1
[3];
962 std::set
<MeshNode
> reachableNodeFromElement1
[3];
963 bool canReachSecond
[3];
966 // Examine each node to determine if the node should be split
967 for(int whichNode
= 0; whichNode
<3; whichNode
++){
969 CkPrintf("--------------------------------\n");
970 CkPrintf("Determining whether to split node %d\n", f
.node
[whichNode
]);
973 canReachSecond
[whichNode
]=false;
975 MeshNode theNode
= f
.node
[whichNode
];
977 // Traverse across the faces to see which elements we can get to from the first element of this facet
978 std::stack
<MeshElement
> traverseTheseElements
;
979 CkAssert(firstElement
.type
!= MESH_ELEMENT_COH3T3
);
980 traverseTheseElements
.push(firstElement
);
982 while(traverseTheseElements
.size()>0 && ! canReachSecond
[whichNode
]){
983 MeshElement traversedToElem
= traverseTheseElements
.top();
984 traverseTheseElements
.pop();
986 // We should only examine elements that we have not yet already examined
987 if(reachableFromElement1
[whichNode
].find(traversedToElem
) == reachableFromElement1
[whichNode
].end()){
988 reachableFromElement1
[whichNode
].insert(traversedToElem
);
990 CkPrintf("Can iterate from first element %d to element %d\n", firstElement
.id
, traversedToElem
.id
);
992 // keep track of which nodes the split node would be adjacent to,
993 // if we split this node
994 for (int elemNode
=0; elemNode
<4; ++elemNode
) {
995 int queryNode
= m
->mesh
->e2n_getNode(traversedToElem
.id
, elemNode
, traversedToElem
.type
);
996 if (m
->mesh
->n2n_exists(theNode
, queryNode
) &&
997 queryNode
!= f
.node
[0] &&
998 queryNode
!= f
.node
[1] &&
999 queryNode
!= f
.node
[2]) {
1000 reachableNodeFromElement1
[whichNode
].insert(queryNode
);
1004 //CkPrintf("Examining element %s,%d\n", traversedToElem.type==MESH_ELEMENT_COH3T3?"MESH_ELEMENT_COH3T3":"MESH_ELEMENT_TET4", traversedToElem.id);
1007 // Add all elements across this elements face, if they contain whichNode
1008 for(int face
=0;face
<4;face
++){
1010 MeshElement neighbor
= m
->mesh
->e2e_getElem(traversedToElem
, face
);
1011 // Only traverse to neighboring bulk elements
1012 if(neighbor
.type
== MESH_ELEMENT_TET4
){
1014 CkPrintf("element %d,%d is adjacent to bulk element %d on face %d\n", traversedToElem
.type
,traversedToElem
.id
, neighbor
.id
, face
);
1016 if(meshElement_IsValid(m
,neighbor
)) {
1017 bool containsTheNode
= false;
1018 for(int i
=0;i
<4;i
++){
1019 if(meshElement_GetNode(m
,neighbor
,i
) == theNode
){
1020 containsTheNode
= true;
1024 if(containsTheNode
){
1025 // Don't traverse across the face at which we are inserting the cohesive element
1026 if(!areSameTriangle(f
.node
[0],f
.node
[1],f
.node
[2],
1027 meshElement_GetNode(m
,traversedToElem
,tetFaces
[face
*3+0]),
1028 meshElement_GetNode(m
,traversedToElem
,tetFaces
[face
*3+1]),
1029 meshElement_GetNode(m
,traversedToElem
,tetFaces
[face
*3+2]) ) ){
1031 // If this element is the second element adjacent to the new cohesive element, we can stop
1032 if(neighbor
== secondElement
){
1033 canReachSecond
[whichNode
] = true;
1035 CkPrintf("We have traversed to the other side of the facet\n");
1038 // Otherwise, add this element to the set remaining to be examined
1039 CkAssert(neighbor
.type
!= MESH_ELEMENT_COH3T3
);
1040 traverseTheseElements
.push(neighbor
);
1042 //CkPrintf("Adding element %d,%d to list\n", neighbor.type, neighbor.id);
1046 // ignore the element because it is not adjacent to the node we are considering splitting
1053 //CkPrintf("So far we have traversed through %d elements(%d remaining)\n", reachableFromElement1[whichNode].size(), traverseTheseElements.size() );
1064 // Now do the actual splitting of the nodes
1065 int myChunk
= FEM_My_partition();
1066 for(int whichNode
= 0; whichNode
<3; whichNode
++){
1067 if(canReachSecond
[whichNode
]){
1069 CkPrintf("Node %d doesn't need to be split\n", f
.node
[whichNode
]);
1074 CkPrintf("Node %d needs to be split\n", f
.node
[whichNode
]);
1075 CkPrintf("There are %d elements that will be reassigned to the new node\n",
1076 reachableFromElement1
[whichNode
].size());
1079 // Create a new node
1080 int newNode
= m
->mesh
->node
.get_next_invalid(m
->mesh
);
1081 m
->mesh
->node
.set_valid(newNode
);
1083 // copy its coordinates
1084 // TODO: copy its other data as well
1085 (*m
->coord_T
)(newNode
,0) = (*m
->coord_T
)(conn
[whichNode
],0);
1086 (*m
->coord_T
)(newNode
,1) = (*m
->coord_T
)(conn
[whichNode
],1);
1087 (*m
->coord_T
)(newNode
,2) = (*m
->coord_T
)(conn
[whichNode
],2);
1090 CkPrintf("Splitting node %d into %d and %d\n", conn
[whichNode
], conn
[whichNode
], newNode
);
1092 // can we use nilesh's idxl aware stuff here?
1093 //FEM_add_node(m->mesh, int* adjacentNodes, int numAdjacentNodes, &myChunk, 1, 0);
1095 // relabel one node in the cohesive element to the new node
1096 conn
[whichNode
+3] = newNode
;
1098 // relabel the appropriate old node in the elements in reachableFromElement1
1099 std::set
<MeshElement
>::iterator elem
;
1100 for (elem
= reachableFromElement1
[whichNode
].begin(); elem
!= reachableFromElement1
[whichNode
].end(); ++elem
) {
1101 m
->mesh
->e2n_replace(elem
->id
, conn
[whichNode
], newNode
, elem
->type
);
1105 CkPrintf("replacing node %d with %d in elem %d\n", conn
[whichNode
], newNode
, elem
->id
);
1109 // fix node-node adjacencies
1110 std::set
<MeshNode
>::iterator node
;
1111 for (node
= reachableNodeFromElement1
[whichNode
].begin(); node
!= reachableNodeFromElement1
[whichNode
].end(); ++node
) {
1112 m
->mesh
->n2n_replace(*node
, conn
[whichNode
], newNode
);
1114 CkPrintf("node %d is now adjacent to %d instead of %d\n",
1115 *node
, newNode
, conn
[whichNode
]);
1122 m
->mesh
->e2e_printAll(firstElement
);
1123 m
->mesh
->e2e_printAll(secondElement
);
1126 // fix elem-elem adjacencies
1127 m
->mesh
->e2e_replace(firstElement
, secondElement
, newCohesiveElement
);
1128 m
->mesh
->e2e_replace(secondElement
, firstElement
, newCohesiveElement
);
1131 CkPrintf("elements %d and %d were adjacent, now both adjacent to cohesive %d instead\n",
1132 firstElement
.id
, secondElement
.id
, newEl
);
1134 m
->mesh
->e2e_printAll(firstElement
);
1135 m
->mesh
->e2e_printAll(secondElement
);
1139 // set cohesive connectivity
1140 m
->mesh
->elem
[newCohesiveElement
.type
].connIs(newEl
,conn
);
1142 CkPrintf("Setting connectivity of new cohesive %d to [%d %d %d %d %d %d]\n\n",
1143 newEl
, conn
[0], conn
[1], conn
[2], conn
[3], conn
[4], conn
[5]);
1145 return newCohesiveElement
;
1152 /// A class responsible for parsing the command line arguments for the PE
1153 /// to extract the format string passed in with +ConfigurableRRMap
1154 class ConfigurableCPUGPUMapLoader
{
1161 /// labels for states used when parsing the ConfigurableRRMap from ARGV
1168 enum loadStatus state
;
1170 ConfigurableCPUGPUMapLoader(){
1176 /// load configuration if possible, and return whether a valid configuration exists
1177 bool haveConfiguration() {
1178 if(state
== not_loaded
) {
1180 CkPrintf("[%d] loading ConfigurableCPUGPUMap configuration\n", CkMyPe());
1182 char **argv
=CkGetArgv();
1183 char *configuration
= NULL
;
1184 bool found
= CmiGetArgString(argv
, "+ConfigurableCPUGPUMap", &configuration
);
1187 CkPrintf("Couldn't find +ConfigurableCPUGPUMap command line argument\n");
1189 state
= loaded_not_found
;
1193 CkPrintf("Found +ConfigurableCPUGPUMap command line argument in %p=\"%s\"\n", configuration
, configuration
);
1195 std::istringstream
instream(configuration
);
1196 CkAssert(instream
.good());
1197 // extract first integer
1198 instream
>> objs_per_block
;
1199 instream
>> numNodes
;
1200 CkAssert(instream
.good());
1201 CkAssert(objs_per_block
> 0);
1202 locations
= new char[objs_per_block
];
1203 for(int i
=0;i
<objs_per_block
;i
++){
1204 CkAssert(instream
.good());
1205 instream
>> locations
[i
];
1206 // CkPrintf("location[%d] = '%c'\n", i, locations[i]);
1207 CkAssert(locations
[i
] == 'G' || locations
[i
] == 'C');
1209 state
= loaded_found
;
1214 CkPrintf("[%d] ConfigurableCPUGPUMap has already been loaded\n", CkMyPe());
1216 return state
== loaded_found
;
1221 CkpvDeclare(ConfigurableCPUGPUMapLoader
, myConfigGPUCPUMapLoader
);
1223 void _initConfigurableCPUGPUMap(){
1224 // CkPrintf("Initializing CPUGPU Map!\n");
1225 CkpvInitialize(ConfigurableCPUGPUMapLoader
, myConfigGPUCPUMapLoader
);
1229 /// Try to load the command line arguments for ConfigurableRRMap
1230 bool haveConfigurableCPUGPUMap(){
1231 ConfigurableCPUGPUMapLoader
&loader
= CkpvAccess(myConfigGPUCPUMapLoader
);
1232 return loader
.haveConfiguration();
1235 int configurableCPUGPUMapNumNodes(){
1236 ConfigurableCPUGPUMapLoader
&loader
= CkpvAccess(myConfigGPUCPUMapLoader
);
1237 return loader
.numNodes
;
1241 bool isPartitionCPU(int partition
){
1242 ConfigurableCPUGPUMapLoader
&loader
= CkpvAccess(myConfigGPUCPUMapLoader
);
1243 int l
= partition
% loader
.objs_per_block
;
1244 return loader
.locations
[l
] == 'C';
1247 bool isPartitionGPU(int partition
){
1248 return ! isPartitionCPU(partition
);
1251 #include "ParFUM_Iterators.def.h"