267 lines
5.7 KiB
C++
267 lines
5.7 KiB
C++
// does Cuthill-McKee algorithm as described in Hoole;
|
|
|
|
#include<stdafx.h>
|
|
#include<afxtempl.h>
|
|
#include<stdio.h>
|
|
#include<math.h>
|
|
#include "belasolv.h"
|
|
#include "belasolvDlg.h"
|
|
#include "mesh.h"
|
|
#include "spars.h"
|
|
#include "FemmeDocCore.h"
|
|
|
|
#define muo 1.2566370614359173e-6
|
|
|
|
BOOL CFemmeDocCore::SortElements()
|
|
{
|
|
// Comb Sort -- see http://en.wikipedia.org/wiki/Comb_sort
|
|
int *Score;
|
|
int i,j,k,gap;
|
|
CElement e;
|
|
|
|
Score=(int*)calloc(NumEls,sizeof(int));
|
|
|
|
for(k=0;k<NumEls;k++)
|
|
{
|
|
Score[k]=meshele[k].p[0]+meshele[k].p[1]+meshele[k].p[2];
|
|
}
|
|
|
|
gap = NumEls;
|
|
|
|
do{
|
|
//update the gap value for a next comb
|
|
if (gap > 1)
|
|
{
|
|
gap=(gap*10)/13;
|
|
if ((gap==10) || (gap==9)) gap=11;
|
|
|
|
}
|
|
|
|
//a single "comb" over the input list
|
|
for(j=0,i=0;(j+gap)<NumEls;j++)
|
|
{
|
|
if (Score[j]>Score[j+gap])
|
|
{
|
|
k=j+gap;
|
|
i=Score[k];Score[k]=Score[j];Score[j]=i;
|
|
e=meshele[k];meshele[k]=meshele[j];meshele[j]=e;
|
|
i=1;
|
|
}
|
|
}
|
|
}while((gap>1)&&(i>0));
|
|
|
|
|
|
free(Score);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CFemmeDocCore::Cuthill()
|
|
{
|
|
|
|
FILE *fp;
|
|
int i,j,k,n0,n1,n;
|
|
int newwide,*newnum,**ocon;
|
|
int *numcon,*nxtnum;
|
|
CNode swap;
|
|
char infile[256];
|
|
|
|
// allocate storage
|
|
nxtnum=(int *)calloc(NumNodes,sizeof(int));
|
|
newnum=(int *)calloc(NumNodes,sizeof(int));
|
|
numcon=(int *)calloc(NumNodes,sizeof(int));
|
|
ocon=(int **)calloc(NumNodes,sizeof(int *));
|
|
// initialize node array;
|
|
for(i=0;i<NumNodes;i++) newnum[i]= -1;
|
|
|
|
// read in connectivity from nodefile
|
|
sprintf(infile,"%s.edge",PathName);
|
|
if((fp=fopen(infile,"rt"))==NULL)
|
|
{
|
|
fprintf(stderr,"Couldn't open %s",infile);
|
|
return FALSE;
|
|
}
|
|
fscanf(fp,"%i",&k); // read in number of lines
|
|
fscanf(fp,"%i",&j); // read in boundarymarker flag;
|
|
|
|
// allocate space for connections;
|
|
ocon[0]=(int *)calloc(2*k,sizeof(int));
|
|
|
|
// with first pass, figure out how many connections
|
|
// there are for each node;
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fscanf(fp,"%i",&j);
|
|
fscanf(fp,"%i",&n0);
|
|
fscanf(fp,"%i",&n1);
|
|
fscanf(fp,"%i",&j);
|
|
|
|
numcon[n0]++;
|
|
numcon[n1]++;
|
|
}
|
|
|
|
// mete out connection storage space;
|
|
for(i=1,n=0;i<NumNodes;i++)
|
|
{
|
|
n+=numcon[i-1];
|
|
ocon[i]=ocon[0]+n;
|
|
}
|
|
|
|
// on second pass through file, store connections;
|
|
rewind(fp);
|
|
fscanf(fp,"%li",&k); // read in number of lines
|
|
fscanf(fp,"%li",&j); // read in boundarymarker flag;
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fscanf(fp,"%i",&j);
|
|
fscanf(fp,"%i",&n0);
|
|
fscanf(fp,"%i",&n1);
|
|
fscanf(fp,"%i",&j);
|
|
|
|
ocon[n0][nxtnum[n0]]=n1; nxtnum[n0]++;
|
|
ocon[n1][nxtnum[n1]]=n0; nxtnum[n1]++;
|
|
}
|
|
fclose(fp);
|
|
DeleteFile(infile);
|
|
|
|
// sort connections in order of increasing connectivity;
|
|
// I'm lazy, so I'm doing a bubble sort;
|
|
for(n0=0;n0<NumNodes;n0++)
|
|
{
|
|
for(i=1;i<numcon[n0];i++)
|
|
for(j=1;j<numcon[n0];j++)
|
|
if(numcon[ocon[n0][j]]<numcon[ocon[n0][j-1]])
|
|
{
|
|
n1=ocon[n0][j];
|
|
ocon[n0][j]=ocon[n0][j-1];
|
|
ocon[n0][j-1]=n1;
|
|
}
|
|
}
|
|
|
|
|
|
// search for a node to start with;
|
|
j=numcon[0]; n0=0;
|
|
for(i=1;i<NumNodes;i++){
|
|
if(numcon[i]<j){
|
|
j=numcon[i];
|
|
n0=i;
|
|
}
|
|
if(j==2) i=k; // break out if j==2,
|
|
// because this is the best we can do
|
|
}
|
|
|
|
// do renumbering algorithm;
|
|
for(i=0;i<NumNodes;i++) nxtnum[i]=-1;
|
|
newnum[n0]=0; n=1; nxtnum[0]=n0;
|
|
|
|
do{
|
|
// renumber in order of increasing number of connections;
|
|
|
|
for(i=0;i<numcon[n0];i++)
|
|
{
|
|
if (newnum[ocon[n0][i]]<0)
|
|
{
|
|
newnum[ocon[n0][i]]=n;
|
|
nxtnum[n]=ocon[n0][i];
|
|
n++;
|
|
}
|
|
}
|
|
|
|
// need to catch case in which problem is multiply
|
|
// connected and still renumber right.
|
|
if(nxtnum[newnum[n0]+1]<0){
|
|
// MsgBox("Multiply Connected!");
|
|
// exit(0);
|
|
|
|
// first, get a node that hasn't been visited yet;
|
|
for(i=0;i<NumNodes;i++)
|
|
if(newnum[i]<0){
|
|
j=numcon[i];
|
|
n0=i;
|
|
i=NumNodes;
|
|
}
|
|
|
|
|
|
// now, get a new starting node;
|
|
for(i=0;i<NumNodes;i++)
|
|
{
|
|
if((newnum[i]<0) && (numcon[i]<j))
|
|
{
|
|
j=numcon[i];
|
|
n0=i;
|
|
}
|
|
if(j==2) i=NumNodes; // break out if j==2,
|
|
// because this is the
|
|
// best we can do
|
|
}
|
|
|
|
// now, set things to restart;
|
|
newnum[n0]=n;
|
|
nxtnum[n]=n0;
|
|
n++;
|
|
}
|
|
else n0=nxtnum[newnum[n0]+1];
|
|
|
|
|
|
} while(n<NumNodes);
|
|
|
|
// remap connectivities;
|
|
for(i=0;i<NumNodes;i++)
|
|
for(j=0;j<numcon[i];j++)
|
|
ocon[i][j]=newnum[ocon[i][j]];
|
|
|
|
// remap (anti)periodic boundary points
|
|
for(i=0;i<NumPBCs;i++)
|
|
{
|
|
pbclist[i].x=newnum[pbclist[i].x];
|
|
pbclist[i].y=newnum[pbclist[i].y];
|
|
}
|
|
|
|
// find new bandwidth;
|
|
|
|
// PBCs fuck up the banding, som could have to do
|
|
// something like:
|
|
// if(NumPBCs!=0) BandWidth=0;
|
|
// else{
|
|
// but if we apply the PCBs the last thing before the
|
|
// solver is called, we can take advantage of banding
|
|
// speed optimizations without messing things up.
|
|
for(n0=0,newwide=0;n0<NumNodes;n0++)
|
|
{
|
|
for(i=0;i<numcon[n0];i++)
|
|
if(abs(newnum[n0]-ocon[n0][i])>newwide)
|
|
{
|
|
newwide=abs(newnum[n0]-ocon[n0][i]);
|
|
}
|
|
}
|
|
|
|
BandWidth=newwide+1;
|
|
// }
|
|
|
|
// free up the variables that we needed during the routine....
|
|
free(numcon);
|
|
free(nxtnum);
|
|
free(ocon[0]);
|
|
free(ocon);
|
|
|
|
// new mapping remains in newnum;
|
|
// apply this mapping to elements first.
|
|
for(i=0;i<NumEls;i++)
|
|
for(j=0;j<3;j++)
|
|
meshele[i].p[j]=newnum[meshele[i].p[j]];
|
|
|
|
// now, sort nodes based on newnum;
|
|
for(i=0;i<NumNodes;i++)
|
|
while(newnum[i]!=i)
|
|
{
|
|
j=newnum[i];
|
|
n=newnum[j]; newnum[j]=newnum[i]; newnum[i]=n;
|
|
swap=meshnode[j]; meshnode[j]=meshnode[i]; meshnode[i]=swap;
|
|
}
|
|
|
|
free(newnum);
|
|
|
|
SortElements();
|
|
|
|
return TRUE;
|
|
}
|