2 Triangle Mesh Refinement (TMR) demo code.
4 Reads in a Triangle mesh.
5 Passes it to the REFINE2D subsystem.
6 Asks for refinements occasionally.
15 #include "ckvector3d.h"
16 #include "charm-api.h"
20 #include "femrefine.h"
23 //The material constants c, as computed by fortran mat_const
24 // I think the units here are Pascals (N/m^2)
25 const double matConst[4]={3.692e9, 1.292e9, 3.692e9, 1.200e9 };
27 //Material density, Kg/m^3
28 const double density=5.0*1000.0;
29 //Plate thickness, meters
30 const double thickness=0.0001;
32 //The timestep, in seconds
33 // This aught to be adjusted when the mesh changes!
34 const double dt=1.0e-12;
36 static void die(const char *str) {
37 CkError("Fatal error: %s\n",str);
42 void resize_nodes(void *data,int *len,int *max);
43 void resize_elems(void *data,int *len,int *max);
45 #define NANCHECK 1 /*Check for NaNs at each timestep*/
50 CkPrintf("init started\n");
52 const char *eleName="out.1024.ele";
53 const char *nodeName="out.1024.node";
54 int nPts=0; //Number of nodes
55 vector2d *pts=0; //Node coordinates
57 CkPrintf("Reading node coordinates from %s\n",nodeName);
58 //Open and read the node coordinate file
61 FILE *f=fopen(nodeName,"r");
62 if (f==NULL) die("Can't open node file!");
64 if (1!=sscanf(line,"%d",&nPts)) die("Can't read number of points!");
65 pts=new vector2d[nPts];
66 for (int i=0;i<nPts;i++) {
68 if (NULL==fgets(line,1024,f)) die("Can't read node input line!");
69 if (3!=sscanf(line,"%d%lf%lf",&ptNo,&pts[i].x,&pts[i].y))
70 die("Can't parse node input line!");
74 CkPrintf("Passing node coords to framework\n");
76 // Register the node entity and its data arrays that will be used later. This
77 // needs to be done so that the width of the data segments are set correctly
78 // and can be used later
79 FEM_Register_entity(FEM_Mesh_default_write(),FEM_NODE,NULL,nPts,nPts,resize_nodes);
80 for(int k=0;k<=4;k++){
82 vector2d *t = new vector2d[nPts];
83 FEM_Register_array(FEM_Mesh_default_write(),FEM_NODE,FEM_DATA+k,t,FEM_DOUBLE,2);
85 FEM_Register_array(FEM_Mesh_default_write(),FEM_NODE,FEM_DATA+k,pts,FEM_DOUBLE,2);
88 double *td = new double[nPts];
89 FEM_Register_array(FEM_Mesh_default_write(),FEM_NODE,FEM_DATA+5,td,FEM_DOUBLE,1);
90 int *validNodes = new int[nPts];
91 for(int ii=0;ii<nPts;ii++){
94 FEM_Register_array(FEM_Mesh_default_write(),FEM_NODE,FEM_VALID,validNodes,FEM_INT,1);
98 CkPrintf("Reading elements from %s\n",eleName);
99 //Open and read the element connectivity file
102 FILE *f=fopen(eleName,"r");
103 if (f==NULL) die("Can't open element file!");
105 if (1!=sscanf(line,"%d",&nEle)) die("Can't read number of elements!");
107 for (int i=0;i<nEle;i++) {
109 if (NULL==fgets(line,1024,f)) die("Can't read element input line!");
110 if (4!=sscanf(line,"%d%d%d%d",&elNo,&ele[3*i+0],&ele[3*i+1],&ele[3*i+2]))
111 die("Can't parse element input line!");
112 ele[3*i+0]--; //Fortran to C indexing
113 ele[3*i+1]--; //Fortran to C indexing
114 ele[3*i+2]--; //Fortran to C indexing
119 CkPrintf("Passing elements to framework\n");
120 // Register the Element entity and its connectivity array. Register the
121 // data arrays to set up the widths correctly at the beginning
122 FEM_Register_entity(FEM_Mesh_default_write(),FEM_ELEM,NULL,nEle,nEle,resize_elems);
123 FEM_Register_array(FEM_Mesh_default_write(),FEM_ELEM,FEM_CONN,ele,FEM_INDEX_0,3);
125 for(int k=0;k<3;k++){
126 void *t = new double[nEle];
127 FEM_Register_array(FEM_Mesh_default_write(),FEM_ELEM,FEM_DATA+k,t,FEM_DOUBLE,1);
129 int *validElem = new int[nEle];
130 for(int ii=0;ii<nEle;ii++){
133 FEM_Register_array(FEM_Mesh_default_write(),FEM_ELEM,FEM_VALID,validElem,FEM_INT,1);
135 /*Build the ghost layer for refinement border*/
136 FEM_Add_ghost_layer(2,0); /*2 nodes/tuple, do not add ghost nodes*/
137 //FEM_Add_ghost_layer(2,1); /*2 nodes/tuple, do not add ghost nodes*/
138 const static int tri2edge[6]={0,1, 1,2, 2,0};
139 FEM_Add_ghost_elem(0,3,tri2edge);
140 CkPrintf("Finished with init\n");
146 int *conn; //Element connectivity table
147 vector2d *coord; //Undeformed coordinates of each node
148 vector2d *R_net, *d, *v, *a; //Physical fields of each node
149 double *m_i; //Inverse of mass at each node
150 int m_i_fid; //Field ID for m_i
151 int *validNode,*validElem;
152 double *S11, *S22, *S12; //Stresses for each element
155 void pup_myGlobals(pup_er p,myGlobals *g)
157 FEM_Print("-------- called pup routine -------");
158 pup_int(p,&g->nnodes);
159 pup_int(p,&g->nelems);
160 pup_int(p,&g->maxelems);
161 pup_int(p,&g->maxnodes);
162 int nnodes=g->nnodes, nelems=g->nelems;
163 if (pup_isUnpacking(p)) {
164 g->coord=new vector2d[g->maxnodes];
165 g->conn=new int[3*g->maxelems];
166 g->R_net=new vector2d[g->maxnodes]; //Net force
167 g->d=new vector2d[g->maxnodes];//Node displacement
168 g->v=new vector2d[g->maxnodes];//Node velocity
169 g->a=new vector2d[g->maxnodes];
170 g->m_i=new double[g->maxnodes];
171 g->S11=new double[g->maxelems];
172 g->S22=new double[g->maxelems];
173 g->S12=new double[g->maxelems];
174 g->validNode = new int[g->maxnodes];
175 g->validElem = new int[g->maxelems];
177 pup_doubles(p,(double *)g->coord,2*nnodes);
178 pup_ints(p,(int *)g->conn,3*nelems);
179 pup_doubles(p,(double *)g->R_net,2*nnodes);
180 pup_doubles(p,(double *)g->d,2*nnodes);
181 pup_doubles(p,(double *)g->v,2*nnodes);
182 pup_doubles(p,(double *)g->a,2*nnodes);
183 pup_doubles(p,(double *)g->m_i,nnodes);
184 pup_doubles(p,(double *)g->S11,nelems);
185 pup_doubles(p,(double *)g->S22,nelems);
186 pup_doubles(p,(double *)g->S12,nelems);
187 pup_ints(p,(int *)g->validNode,nnodes);
188 pup_ints(p,(int *)g->validElem,nelems);
189 if (pup_isDeleting(p)) {
200 delete[] g->validNode;
201 delete[] g->validElem;
205 //Return the signed area of triangle i
206 double calcArea(myGlobals &g, int i)
208 int n1=g.conn[3*i+0];
209 int n2=g.conn[3*i+1];
210 int n3=g.conn[3*i+2];
211 vector2d a=g.coord[n1];
212 vector2d b=g.coord[n2];
213 vector2d c=g.coord[n3];
215 double area=0.5*(b.x*c.y-c.x*b.y);
219 // Check the quality of triangle i
220 void checkTriangle(myGlobals &g, int i)
222 double area=calcArea(g,i);
224 CkError("Triangle %d of chunk %d is inverted! (area=%g)\n",
225 i,FEM_My_partition(),area);
226 CkAbort("Inverted triangle");
229 CkError("Triangle %d of chunk %d is a sliver!\n",i,FEM_My_partition());
230 CkAbort("Sliver triangle");
234 //Compute forces on constant-strain triangles:
235 void CST_NL(const vector2d *coor,const int *lm,vector2d *R_net,
236 const vector2d *d,const double *c,
238 double *S11o,double *S22o,double *S12o);
240 //Update node position, velocity, accelleration based on net force.
241 void advanceNodes(const double dt,int nnodes,const vector2d *coord,
242 vector2d *R_net,vector2d *a,vector2d *v,vector2d *d,
243 const double *m_i,bool dampen)
245 const vector2d z(0,0);
246 const double shearForce=1.0e-11/(dt*dt);
249 for (i=0;i<nnodes;i++) {
250 vector2d R_n=R_net[i];
252 if (((R_n.x-R_n.x)!=0)) {
253 CkPrintf("R_net[%d]=NaN at (%.4f,%.4f) ",i,coord[i].x,coord[i].y);
254 CmiAbort("nan node");
257 if (fabs(d[i].x)>1.0) {
258 CkPrintf("d[%d] %f large at (%.4f,%.4f) ",i,d[i].x,coord[i].x,coord[i].y);
263 //Apply boundary conditions (HACK: hardcoded!)
265 if (coord[i].x<0.00001)
266 R_n.y+=shearForce/m_i[i]; //Bottom edge pushed hard down
267 if (coord[i].y>0.02-0.00001)
268 R_n=z; //Top edge held in place
270 //Update displacement and velocity
271 vector2d aNew=R_n*m_i[i];
272 v[i]+=(dt*0.5)*(aNew+a[i]);
273 d[i]+=dt*v[i]+(dt*dt*0.5)*aNew;
275 //if (coord[i].y>0.02-0.00001) d[i].y=0.0; //Top edge in horizontal slot
278 for (i=0;i<nnodes;i++)
279 v[i]*=0.9; //Dampen velocity slightly (prevents eventual blowup)
282 CkPrintf("Nodes all NaN!\n");
283 CkAbort("Node forces NaN!");
287 //Fill out the m_i array with the inverse of the node masses
288 void calcMasses(myGlobals &g) {
291 //Zero out node masses
292 for (i=0;i<g.nnodes;i++) m_i[i]=0.0;
293 //Add mass from surrounding triangles:
294 for (i=0;i<g.nelems;i++) {
296 int n1=g.conn[3*i+0];
297 int n2=g.conn[3*i+1];
298 int n3=g.conn[3*i+2];
299 double area=calcArea(g,i);
300 // if (1 || i%100==0) CkPrintf("Triangle %d (%d %d %d) has area %.3g\n",i,n1,n2,n3,area);
301 double mass=0.333*density*(thickness*area);
307 //Include mass from other processors
308 FEM_Update_field(g.m_i_fid,m_i);
309 //Invert masses to get m_i
310 for (i=0;i<g.nnodes;i++) {
312 if (mass<1.0e-10) m_i[i]=1.0; //Disconnected node (!)
313 else m_i[i]=1.0/mass;
317 void init_myGlobal(myGlobals *g){
318 g->coord = g->R_net = g->d = g->v = g->a = NULL;
321 g->S11 = g->S22 = g->S12 = NULL;
325 void resize_nodes(void *data,int *len,int *max){
326 printf("[%d] resize nodes called len %d max %d\n",FEM_My_partition(),*len,*max);
327 FEM_Register_entity(FEM_Mesh_default_read(),FEM_NODE,data,*len,*max,resize_nodes);
328 myGlobals *g = (myGlobals *)data;
329 vector2d *coord=g->coord,*R_net=g->R_net,*d=g->d,*v=g->v,*a=g->a;
331 int *validNode = g->validNode;
333 g->coord=new vector2d[*max];
337 g->R_net=new vector2d[g->maxnodes]; //Net force
338 g->d=new vector2d[g->maxnodes];//Node displacement
339 g->v=new vector2d[g->maxnodes];//Node velocity
340 g->a=new vector2d[g->maxnodes];//Node accelleration
341 g->m_i=new double[g->maxnodes];//Node mass
342 g->validNode = new int[g->maxnodes]; //is the node valid
345 for(int k=0;k<*len;k++){
346 printf("before resize node %d ( %.6f %.6f ) \n",k,coord[k].x,coord[k].y);
350 FEM_Register_array(FEM_Mesh_default_read(),FEM_NODE,FEM_DATA,(void *)g->coord,FEM_DOUBLE,2);
351 FEM_Register_array(FEM_Mesh_default_read(),FEM_NODE,FEM_DATA+1,(void *)g->R_net,FEM_DOUBLE,2);
352 FEM_Register_array(FEM_Mesh_default_read(),FEM_NODE,FEM_DATA+2,(void *)g->d,FEM_DOUBLE,2);
353 FEM_Register_array(FEM_Mesh_default_read(),FEM_NODE,FEM_DATA+3,(void *)g->v,FEM_DOUBLE,2);
354 FEM_Register_array(FEM_Mesh_default_read(),FEM_NODE,FEM_DATA+4,(void *)g->a,FEM_DOUBLE,2);
355 FEM_Register_array_layout(FEM_Mesh_default_read(),FEM_NODE,FEM_DATA+5,(void *)g->m_i,g->m_i_fid);
356 FEM_Register_array(FEM_Mesh_default_read(),FEM_NODE,FEM_VALID,(void *)g->validNode,FEM_INT,1);
358 for(int k=0;k<*len;k++){
359 printf("after resize node %d ( %.6f %.6f )\n",k,g->coord[k].x,g->coord[k].y);
373 void resize_elems(void *data,int *len,int *max){
374 printf("[%d] resize elems called len %d max %d\n",FEM_My_partition(),*len,*max);
375 FEM_Register_entity(FEM_Mesh_default_read(),FEM_ELEM,data,*len,*max,resize_elems);
376 myGlobals *g = (myGlobals *)data;
378 double *S11 = g->S11,*S22 = g->S22,*S12 = g->S12;
379 int *validElem = g->validElem;
381 g->conn = new int[3*(*max)];
383 g->S11=new double[g->maxelems];
384 g->S22=new double[g->maxelems];
385 g->S12=new double[g->maxelems];
386 g->validElem = new int[g->maxelems];
388 FEM_Register_array(FEM_Mesh_default_read(),FEM_ELEM,FEM_CONN,(void *)g->conn,FEM_INDEX_0,3);
389 CkPrintf("Connectivity array starts at %p \n",g->conn);
390 FEM_Register_array(FEM_Mesh_default_read(),FEM_ELEM,FEM_DATA,(void *)g->S11,FEM_DOUBLE,1);
391 FEM_Register_array(FEM_Mesh_default_read(),FEM_ELEM,FEM_DATA+1,(void *)g->S22,FEM_DOUBLE,1);
392 FEM_Register_array(FEM_Mesh_default_read(),FEM_ELEM,FEM_DATA+2,(void *)g->S12,FEM_DOUBLE,1);
393 FEM_Register_array(FEM_Mesh_default_read(),FEM_ELEM,FEM_VALID,(void *)g->validElem,FEM_INT,1);
404 void repeat_after_split(void *data){
405 myGlobals *g = (myGlobals *)data;
406 g->nelems = FEM_Mesh_get_length(FEM_Mesh_default_read(),FEM_ELEM);
407 g->nnodes = FEM_Mesh_get_length(FEM_Mesh_default_read(),FEM_NODE);
408 for(int k=0;k<g->nnodes;k++){
410 printf(" node %d ( %.6f %.6f )\n",k,g->coord[k].x,g->coord[k].y);
422 int myChunk=FEM_My_partition();
424 /*Add a refinement object to FEM array*/
425 CkPrintf("[%d] begin init\n",myChunk);
427 CkPrintf("[%d] end init\n",myChunk);
430 FEM_Register(&g,(FEM_PupFn)pup_myGlobals);
433 g.nnodes = FEM_Mesh_get_length(FEM_Mesh_default_read(),FEM_NODE);
434 int maxNodes = g.nnodes;
435 g.maxnodes=2*maxNodes;
436 g.m_i_fid=FEM_Create_field(FEM_DOUBLE,1,0,sizeof(double));
437 resize_nodes((void *)&g,&g.nnodes,&maxNodes);
439 g.nelems=FEM_Mesh_get_length(FEM_Mesh_default_read(),FEM_ELEM);
441 resize_elems((void *)&g,&g.nelems,&g.maxelems);
443 FEM_REFINE2D_Newmesh(FEM_Mesh_default_read(),FEM_NODE,FEM_ELEM);
445 //Initialize associated data
446 for (i=0;i<g.maxnodes;i++) {
447 g.R_net[i]=g.d[i]=g.v[i]=g.a[i]=vector2d(0.0);
450 //Apply a small initial perturbation to positions
451 for (i=0;i<g.nnodes;i++) {
452 const double max=1.0e-15/15.0; //Tiny perturbation
453 g.d[i].x+=max*(i&15);
454 g.d[i].y+=max*((i+5)&15);
457 int fid=FEM_Create_field(FEM_DOUBLE,2,0,sizeof(vector2d));
459 for (i=0;i<g.nelems;i++){
465 CkPrintf("Entering timeloop\n");
467 // int tSteps=0x70FF00FF;
471 double startTime=CkWallTimer();
472 double curArea=2.5e-5/1024;
474 if (1) { //Publish data to the net
475 NetFEM n=NetFEM_Begin(myChunk,t,2,NetFEM_WRITE);
477 double *vcoord = new double[2*g.nnodes];
478 double *vnodeid = new double[g.nnodes];
479 int *maptovalid = new int[g.nnodes];
480 for(int i=0;i<g.nnodes;i++){
482 vcoord[2*count] = ((double *)g.coord)[2*i];
483 vcoord[2*count+1] = ((double *)g.coord)[2*i+1];
484 maptovalid[i] = count;
485 printf("~~~~~~~ %d %d %.6lf %.6lf \n",count,i,vcoord[2*count],vcoord[2*count+1]);
490 NetFEM_Nodes(n,count,(double *)vcoord,"Position (m)");
491 NetFEM_Scalar(n,vnodeid,1,"Node ID");
492 /* NetFEM_Vector(n,(double *)g.d,"Displacement (m)");
493 NetFEM_Vector(n,(double *)g.v,"Velocity (m/s)");*/
495 int *vconn = new int[3*g.nelems];
496 double *vid = new double[3*g.nelems];
497 for(int i=0;i<g.nelems;i++){
499 vconn[3*count] = maptovalid[g.conn[3*i]];
500 vconn[3*count+1] = maptovalid[g.conn[3*i+1]];
501 vconn[3*count+2] = maptovalid[g.conn[3*i+2]];
502 printf("~~~~~~~ %d %d < %d,%d %d,%d %d,%d >\n",count,i,vconn[3*count],g.conn[3*i],vconn[3*count+1],g.conn[3*i+1],vconn[3*count+2],g.conn[3*i+2]);
507 NetFEM_Elements(n,count,3,(int *)vconn,"Triangles");
508 NetFEM_Scalar(n,vid,1,"Element ID");
509 /* NetFEM_Scalar(n,g.S22,1,"Y Stress (pure)");
510 NetFEM_Scalar(n,g.S12,1,"Shear Stress (pure)");*/
514 delete [] maptovalid;
518 for (t=1;t<=tSteps;t++) {
519 /* if (1) { //Structural mechanics
520 //Compute forces on nodes exerted by elements
521 CST_NL(g.coord,g.conn,g.R_net,g.d,matConst,g.nnodes,g.nelems,g.S11,g.S22,g.S12);
522 //Communicate net force on shared nodes
523 FEM_Update_field(fid,g.R_net);
524 //Advance node positions
525 advanceNodes(dt,g.nnodes,g.coord,g.R_net,g.a,g.v,g.d,g.m_i,(t%4)==0);
528 //Debugging/perf. output
529 double curTime=CkWallTimer();
530 double total=curTime-startTime;
532 /* if (CkMyPe()==0 && (t%64==0))
533 CkPrintf("%d %.6f sec for loop %d \n",CkNumPes(),total,t);*/
534 /* if (0 && t%16==0) {
535 CkPrintf(" Triangle 0:\n");
536 for (int j=0;j<3;j++) {
538 CkPrintf(" Node %d: coord=(%.4f,%.4f) d=(%.4g,%.4g)\n",
539 n,g.coord[n].x,g.coord[n].y,g.d[n].x,g.d[n].y);
545 double *areas=new double[g.nelems];
546 for (i=0;i<g.nelems;i++) {
547 areas[i]=1.5*calcArea(g,i);
548 // areas[i]=calcArea(g,i);
554 CkPrintf("[%d] Starting coarsening step: %d nodes, %d elements to %.3g\n", myChunk,g.nnodes,g.nelems,curArea);
555 FEM_REFINE2D_Coarsen(FEM_Mesh_default_read(),FEM_NODE,(double *)g.coord,FEM_ELEM,areas);
556 repeat_after_split((void *)&g);
557 g.nelems = FEM_Mesh_get_length(FEM_Mesh_default_read(),FEM_ELEM);
558 g.nnodes = FEM_Mesh_get_length(FEM_Mesh_default_read(),FEM_NODE);
559 CkPrintf("[%d] Done with coarsening step: %d nodes, %d elements\n",
560 myChunk,g.nnodes,g.nelems);
561 if (1) { //Publish data to the net
562 NetFEM n=NetFEM_Begin(myChunk,t,2,NetFEM_WRITE);
564 double *vcoord = new double[2*g.nnodes];
565 double *vnodeid = new double[g.nnodes];
566 int *maptovalid = new int[g.nnodes];
567 for(int i=0;i<g.nnodes;i++){
570 vcoord[2*count] = ((double *)g.coord)[2*i];
571 vcoord[2*count+1] = ((double *)g.coord)[2*i+1];
572 maptovalid[i] = count;
573 printf("node~~~~~~~ %d %d %.6lf %.6lf \n",count,i,vcoord[2*count],vcoord[2*count+1]);
578 NetFEM_Nodes(n,count,(double *)vcoord,"Position (m)");
579 NetFEM_Scalar(n,vnodeid,1,"Node ID");
580 /* NetFEM_Vector(n,(double *)g.d,"Displacement (m)");
581 NetFEM_Vector(n,(double *)g.v,"Velocity (m/s)");*/
583 int *vconn = new int[3*g.nelems];
584 double *vid = new double[3*g.nelems];
585 for(int i=0;i<g.nelems;i++){
587 vconn[3*count] = maptovalid[g.conn[3*i]];
588 vconn[3*count+1] = maptovalid[g.conn[3*i+1]];
589 vconn[3*count+2] = maptovalid[g.conn[3*i+2]];
590 printf("~~~~~~~ %d %d < %d,%d %d,%d %d,%d >\n",count,i,vconn[3*count],g.conn[3*i],vconn[3*count+1],g.conn[3*i+1],vconn[3*count+2],g.conn[3*i+2]);
595 NetFEM_Elements(n,count,3,(int *)vconn,"Triangles");
596 NetFEM_Scalar(n,vid,1,"Element ID");
597 /* NetFEM_Scalar(n,g.S22,1,"Y Stress (pure)");
598 NetFEM_Scalar(n,g.S12,1,"Shear Stress (pure)");*/
602 delete [] maptovalid;
608 CkPrintf("Driver finished\n");