595 lines
13 KiB
C++
595 lines
13 KiB
C++
// FemmeDocCore.cpp : implementation of the CFemmeDocCore class
|
|
//
|
|
|
|
|
|
#include <stdafx.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#include "belasolv.h"
|
|
#include "belasolvDlg.h"
|
|
#include "mesh.h"
|
|
#include "spars.h"
|
|
#include "FemmeDocCore.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmeDocCore construction/destruction
|
|
|
|
CFemmeDocCore::CFemmeDocCore()
|
|
{
|
|
TheView=NULL;
|
|
Precision=NULL;
|
|
LengthUnits=NULL;
|
|
ProblemType=NULL;
|
|
Coords=NULL;
|
|
BandWidth=NULL;
|
|
NumNodes=NULL;
|
|
NumEls=NULL;
|
|
NumBlockProps=NULL;
|
|
NumPBCs=NULL;
|
|
NumLineProps=NULL;
|
|
NumPointProps=NULL;
|
|
NumCircProps=NULL;
|
|
NumBlockLabels=NULL;
|
|
|
|
meshnode=NULL;
|
|
meshele=NULL;
|
|
blockproplist=NULL;
|
|
lineproplist=NULL;
|
|
nodeproplist=NULL;
|
|
circproplist=NULL;
|
|
labellist=NULL;
|
|
pbclist=NULL;
|
|
PathName=NULL;
|
|
|
|
extRo=extRi=extZo=NULL;
|
|
}
|
|
|
|
CFemmeDocCore::~CFemmeDocCore()
|
|
{
|
|
// This space for rent.
|
|
}
|
|
|
|
void CFemmeDocCore::CleanUp()
|
|
{
|
|
if (meshnode!=NULL) free(meshnode);
|
|
if (meshele!=NULL) free(meshele);
|
|
if (blockproplist!=NULL) free(blockproplist);
|
|
if (lineproplist!=NULL) free(lineproplist);
|
|
if (nodeproplist!=NULL) free(nodeproplist);
|
|
if (circproplist!=NULL) free(circproplist);
|
|
if (labellist!=NULL) free(labellist);
|
|
if (pbclist!=NULL) free(pbclist);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmeDocCore commands
|
|
|
|
char* StripKey(char *c)
|
|
{
|
|
char *d;
|
|
int i,k;
|
|
|
|
k=(int) strlen(c);
|
|
|
|
for(i=0;i<k;i++){
|
|
if (c[i] == '='){
|
|
d=c+i+1;
|
|
return d;
|
|
}
|
|
}
|
|
|
|
return c+k;
|
|
}
|
|
|
|
BOOL CFemmeDocCore::OnOpenDocument()
|
|
{
|
|
FILE *fp;
|
|
int k;
|
|
char s[1024],q[1024];
|
|
char *v;
|
|
CPointProp PProp;
|
|
CBoundaryProp BProp;
|
|
CMaterialProp MProp;
|
|
CCircuit CProp;
|
|
CBlockLabel blk;
|
|
|
|
sprintf(s,"%s.fee",PathName);
|
|
if ((fp=fopen(s,"rt"))==NULL){
|
|
fprintf(stderr,"Couldn't read from specified .fee file\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// define some defaults
|
|
Precision=1.e-08;
|
|
Depth=-1;
|
|
ProblemType=0;
|
|
Coords=0;
|
|
NumPointProps=0;
|
|
NumLineProps=0;
|
|
NumBlockProps=0;
|
|
NumCircProps=0;
|
|
|
|
// parse the file
|
|
|
|
while (fgets(s,1024,fp)!=NULL)
|
|
{
|
|
sscanf(s,"%s",q);
|
|
|
|
// Precision
|
|
if( _strnicmp(q,"[precision]",11)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&Precision);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Units of length used by the problem
|
|
if( _strnicmp(q,"[lengthunits]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%s",q);
|
|
if( _strnicmp(q,"inches",6)==0) LengthUnits=0;
|
|
else if( _strnicmp(q,"millimeters",11)==0) LengthUnits=1;
|
|
else if( _strnicmp(q,"centimeters",1)==0) LengthUnits=2;
|
|
else if( _strnicmp(q,"mils",4)==0) LengthUnits=4;
|
|
else if( _strnicmp(q,"microns",6)==0) LengthUnits=5;
|
|
else if( _strnicmp(q,"meters",6)==0) LengthUnits=3;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Depth for 2D planar problems;
|
|
if( _strnicmp(q,"[depth]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&Depth);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Problem Type (planar or axisymmetric)
|
|
if( _strnicmp(q,"[problemtype]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%s",q);
|
|
if( _strnicmp(q,"planar",6)==0) ProblemType=0;
|
|
if( _strnicmp(q,"axisymmetric",3)==0) ProblemType=1;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Coordinates (cartesian or polar)
|
|
if( _strnicmp(q,"[coordinates]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%s",q);
|
|
if ( _strnicmp(q,"cartesian",4)==0) Coords=0;
|
|
if ( _strnicmp(q,"polar",5)==0) Coords=1;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// properties for axisymmetric external region
|
|
if( _strnicmp(q,"[extzo]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&extZo);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"[extro]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&extRo);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"[extri]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&extRi);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Point Properties
|
|
if( _strnicmp(q,"[pointprops]",12)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
if (k>0) nodeproplist=(CPointProp *)calloc(k,sizeof(CPointProp));
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<beginpoint>",11)==0){
|
|
PProp.V=0;
|
|
PProp.qp=0;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<vp>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.V);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<qp>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.qp);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endpoint>",9)==0){
|
|
nodeproplist[NumPointProps]=PProp;
|
|
NumPointProps++;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Boundary Properties;
|
|
if( _strnicmp(q,"[bdryprops]",11)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
if (k>0) lineproplist=(CBoundaryProp *)calloc(k,sizeof(CBoundaryProp));
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<beginbdry>",11)==0){
|
|
BProp.BdryFormat=0;
|
|
BProp.V=0;
|
|
BProp.qs=0;
|
|
BProp.c0=0;
|
|
BProp.c1=0;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<bdrytype>",10)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&BProp.BdryFormat);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<vs>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.V);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<qs>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.qs);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c0>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c0);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c1>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c1);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endbdry>",9)==0){
|
|
lineproplist[NumLineProps]=BProp;
|
|
NumLineProps++;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Block Properties;
|
|
if( _strnicmp(q,"[blockprops]",12)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
if (k>0) blockproplist=(CMaterialProp *)calloc(k,sizeof(CMaterialProp));
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<beginblock>",12)==0){
|
|
MProp.ex=1;
|
|
MProp.ey=1; // permittivity, relative
|
|
MProp.qv=1; // charge density, C/m^3
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<ex>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.ex);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<ey>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.ey);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<qv>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.qv);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endblock>",9)==0){
|
|
blockproplist[NumBlockProps]=MProp;
|
|
NumBlockProps++;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Conductor Properties
|
|
if( _strnicmp(q,"[conductorprops]",16)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
if(k>0) circproplist=(CCircuit *)calloc(k,sizeof(CCircuit));
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<beginconductor>",16)==0){
|
|
CProp.V=0;
|
|
CProp.q=0;
|
|
CProp.CircType=0;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<vc>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&CProp.V);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<qc>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&CProp.q);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<conductortype>",15)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&CProp.CircType);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endconductor>",14)==0){
|
|
circproplist[NumCircProps]=CProp;
|
|
NumCircProps++;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// read in regional attributes
|
|
if(_strnicmp(q,"[numblocklabels]",13)==0){
|
|
int i;
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
if (k>0) labellist=(CBlockLabel *)calloc(k, sizeof(CBlockLabel));
|
|
NumBlockLabels=k;
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%lf %lf %i %lf %i %i",&blk.x,&blk.y,&blk.BlockType,
|
|
&blk.MaxArea,&blk.InGroup,&blk.IsExternal);
|
|
blk.IsDefault = blk.IsExternal & 2;
|
|
blk.IsExternal = blk.IsExternal & 1;
|
|
blk.BlockType--;
|
|
labellist[i]=blk;
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CFemmeDocCore::LoadMesh()
|
|
{
|
|
int i,j,k,q,n0,n1,n;
|
|
char infile[256];
|
|
FILE *fp;
|
|
char s[1024];
|
|
double c[]={25.4,1.,10.,1000.,0.0254,0.001};
|
|
|
|
|
|
//read meshnodes;
|
|
sprintf(infile,"%s.node",PathName);
|
|
if((fp=fopen(infile,"rt"))==NULL){
|
|
return FALSE;
|
|
}
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i",&k); NumNodes=k;
|
|
|
|
meshnode=(CNode *)calloc(k,sizeof(CNode));
|
|
CNode node;
|
|
for(i=0;i<k;i++){
|
|
fscanf(fp,"%i",&j);
|
|
fscanf(fp,"%lf",&node.x);
|
|
fscanf(fp,"%lf",&node.y);
|
|
fscanf(fp,"%i",&n);
|
|
|
|
if(n>1){
|
|
// strip off point BC number;
|
|
j=n & 0xffff;
|
|
j=j-2;
|
|
if (j<0) j=-1;
|
|
|
|
// strip off Conductor number
|
|
n= (n - (n & 0xffff))/0x10000 - 1;
|
|
}
|
|
else{
|
|
j=-1;
|
|
n=-1;
|
|
}
|
|
node.bc=j;
|
|
node.InConductor=n;
|
|
|
|
// convert all lengths to internal working units of mm
|
|
node.x*=c[LengthUnits];
|
|
node.y*=c[LengthUnits];
|
|
|
|
meshnode[i]=node;
|
|
}
|
|
fclose(fp);
|
|
|
|
//read in periodic boundary conditions;
|
|
sprintf(infile,"%s.pbc",PathName);
|
|
if((fp=fopen(infile,"rt"))==NULL){
|
|
return FALSE;
|
|
}
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i",&k); NumPBCs=k;
|
|
|
|
if (k!=0) pbclist=(CCommonPoint *)calloc(k,sizeof(CCommonPoint));
|
|
CCommonPoint pbc;
|
|
for(i=0;i<k;i++){
|
|
fscanf(fp,"%i",&j);
|
|
fscanf(fp,"%i",&pbc.x);
|
|
fscanf(fp,"%i",&pbc.y);
|
|
fscanf(fp,"%i",&pbc.t);
|
|
pbclist[i]=pbc;
|
|
}
|
|
fclose(fp);
|
|
|
|
// read in elements;
|
|
sprintf(infile,"%s.ele",PathName);
|
|
if((fp=fopen(infile,"rt"))==NULL){
|
|
return FALSE;
|
|
}
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i",&k); NumEls=k;
|
|
|
|
meshele=(CElement *)calloc(k,sizeof(CElement));
|
|
CElement elm;
|
|
|
|
int defaultLabel;
|
|
for(i=0,defaultLabel=-1;i<NumBlockLabels;i++)
|
|
if (labellist[i].IsDefault) defaultLabel=i;
|
|
|
|
for(i=0;i<k;i++){
|
|
fscanf(fp,"%i",&j);
|
|
fscanf(fp,"%i",&elm.p[0]);
|
|
fscanf(fp,"%i",&elm.p[1]);
|
|
fscanf(fp,"%i",&elm.p[2]);
|
|
fscanf(fp,"%i",&elm.lbl);
|
|
elm.lbl--;
|
|
if(elm.lbl<0) elm.lbl=defaultLabel;
|
|
if(elm.lbl<0){
|
|
CString msg;
|
|
msg ="Material properties have not been defined for\n";
|
|
msg+="all regions. Press the \"Run Mesh Generator\"\n";
|
|
msg+="button to highlight the problem regions.";
|
|
MsgBox(msg);
|
|
fclose(fp);
|
|
sprintf(infile,"%s.ele",PathName); DeleteFile(infile);
|
|
sprintf(infile,"%s.node",PathName); DeleteFile(infile);
|
|
sprintf(infile,"%s.pbc",PathName); DeleteFile(infile);
|
|
sprintf(infile,"%s.poly",PathName); DeleteFile(infile);
|
|
sprintf(infile,"%s.edge",PathName); DeleteFile(infile);
|
|
exit(1);
|
|
}
|
|
// look up block type out of the list of block labels
|
|
elm.blk=labellist[elm.lbl].BlockType;
|
|
|
|
meshele[i]=elm;
|
|
}
|
|
fclose(fp);
|
|
|
|
// initialize edge bc's and element permeabilities;
|
|
for(i=0;i<NumEls;i++)
|
|
for(j=0;j<3;j++)
|
|
meshele[i].e[j] = -1;
|
|
|
|
// read in edges to which boundary conditions are applied;
|
|
|
|
// first, do a little bookkeeping so that element
|
|
// associated with a give edge can be identified fast
|
|
int *nmbr;
|
|
int **mbr;
|
|
|
|
nmbr=(int *)calloc(NumNodes,sizeof(int));
|
|
|
|
// Make a list of how many elements that tells how
|
|
// many elements to which each node belongs.
|
|
for(i=0;i<NumEls;i++)
|
|
for(j=0;j<3;j++)
|
|
nmbr[meshele[i].p[j]]++;
|
|
|
|
// mete out some memory to build a list of the
|
|
// connectivity...
|
|
mbr=(int **)calloc(NumNodes,sizeof(int *));
|
|
for(i=0;i<NumNodes;i++){
|
|
mbr[i]=(int *)calloc(nmbr[i],sizeof(int));
|
|
nmbr[i]=0;
|
|
}
|
|
|
|
// fill up the connectivity information;
|
|
for(i=0;i<NumEls;i++)
|
|
for(j=0;j<3;j++)
|
|
{
|
|
k=meshele[i].p[j];
|
|
mbr[k][nmbr[k]]=i;
|
|
nmbr[k]++;
|
|
}
|
|
|
|
sprintf(infile,"%s.edge",PathName);
|
|
if((fp=fopen(infile,"rt"))==NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
fscanf(fp,"%i",&k); // read in number of lines
|
|
|
|
fscanf(fp,"%i",&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",&n);
|
|
|
|
// BC number;
|
|
if (n<0)
|
|
{
|
|
n=(-n);
|
|
j = (n & 0xffff) - 2;
|
|
if (j<0) j = -1;
|
|
|
|
// Conductor number;
|
|
n= (n - (n & 0xffff))/0x10000 - 1;
|
|
if (n>=0)
|
|
{
|
|
meshnode[n0].InConductor=n;
|
|
meshnode[n1].InConductor=n;
|
|
}
|
|
}
|
|
else j=-1;
|
|
|
|
if (j>=0)
|
|
{
|
|
// search through elements to find one containing the line;
|
|
// set corresponding edge equal to the bc number
|
|
for(q=0,n=FALSE;q<nmbr[n0];q++)
|
|
{
|
|
elm=meshele[mbr[n0][q]];
|
|
|
|
if ((elm.p[0] == n0) && (elm.p[1] == n1)) {elm.e[0]=j; n=TRUE;}
|
|
if ((elm.p[0] == n1) && (elm.p[1] == n0)) {elm.e[0]=j; n=TRUE;}
|
|
|
|
if ((elm.p[1] == n0) && (elm.p[2] == n1)) {elm.e[1]=j; n=TRUE;}
|
|
if ((elm.p[1] == n1) && (elm.p[2] == n0)) {elm.e[1]=j; n=TRUE;}
|
|
|
|
if ((elm.p[2] == n0) && (elm.p[0] == n1)) {elm.e[2]=j; n=TRUE;}
|
|
if ((elm.p[2] == n1) && (elm.p[0] == n0)) {elm.e[2]=j; n=TRUE;}
|
|
|
|
meshele[mbr[n0][q]]=elm;
|
|
|
|
//this is a little hack: line charge distributions should be applied
|
|
//to at most one element;
|
|
if((lineproplist[j].BdryFormat==2) && (n)) q=nmbr[n0];
|
|
}
|
|
}
|
|
|
|
}
|
|
fclose(fp);
|
|
|
|
// free up the connectivity information
|
|
free(nmbr);
|
|
for(i=0;i<NumNodes;i++) free(mbr[i]);
|
|
free(mbr);
|
|
|
|
// clear out temporary files
|
|
sprintf(infile,"%s.ele",PathName); DeleteFile(infile);
|
|
sprintf(infile,"%s.node",PathName); DeleteFile(infile);
|
|
sprintf(infile,"%s.pbc",PathName); DeleteFile(infile);
|
|
sprintf(infile,"%s.poly",PathName); DeleteFile(infile);
|
|
|
|
return TRUE;
|
|
}
|