Path: blob/devel/ElmerGUI/Application/plugins/egmesh.cpp
3203 views
/*1ElmerGrid - A simple mesh generation and manipulation utility2Copyright (C) 1995- , CSC - IT Center for Science Ltd.34Author: Peter Raback5Email: [email protected]6Address: CSC - IT Center for Science Ltd.7Keilaranta 14802101 Espoo, Finland910This program is free software; you can redistribute it and/or11modify it under the terms of the GNU General Public License12as published by the Free Software Foundation; either version 213of the License, or (at your option) any later version.1415This program is distributed in the hope that it will be useful,16but WITHOUT ANY WARRANTY; without even the implied warranty of17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the18GNU General Public License for more details.1920You should have received a copy of the GNU General Public License21along with this program; if not, write to the Free Software22Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.23*/2425/* --------------------------: egmesh.c :----------------------------2627This module includes subroutines that formulate the mesh into structures28more useful for the user. These are the functions that should be used for29assembling. The routines usually operate on structures FemType and30BoundaryType.31*/3233#include <stdio.h>34#include <string.h>35#include <stdlib.h>36#include <math.h>37#include <limits.h>3839#include "egutils.h"40#include "egdef.h"41#include "egtypes.h"42#include "egnative.h"43#include "egmesh.h"4445#define DEBUG 0464748void GetElementInfo(int element,struct FemType *data,49Real *globalcoord,int *ind,int *material)50/* For a given element gives the coordinates and index for the knot.51This subroutine uses the standard formulation which uses up more52memory, but is easier to understand. It requires that the knots53must first be stored in struct FemType.54*/55{56int i,indi,nodesd2;57nodesd2 = data->elementtypes[element]%100;5859for(i=0;i<nodesd2;i++) {60indi = ind[i] = data->topology[element][i];61globalcoord[i] = data->x[indi];62globalcoord[i+nodesd2] = data->y[indi];63}64(*material) = data->material[element];65}6667int GetElementDimension(int elementtype)68{69int elemdim;7071elemdim = 0;7273switch (elementtype / 100) {74case 1:75elemdim = 0;76break;77case 2:78elemdim = 1;79break;80case 3:81case 4:82elemdim = 2;83break;84case 5:85case 6:86case 7:87case 8:88elemdim = 3;89break;90default:91printf("GetElementDimension: unknown elementtype %d\n",elementtype);9293}94return(elemdim);95}969798int GetMaxElementType(struct FemType *data)99{100int i,maxelementtype;101102maxelementtype = data->elementtypes[1];103for(i=1;i<=data->noelements;i++)104if(data->elementtypes[i] > maxelementtype)105maxelementtype = data->elementtypes[i];106107return(maxelementtype);108}109110111int GetMinElementType(struct FemType *data)112{113int i,minelementtype;114115minelementtype = data->elementtypes[1];116for(i=1;i<=data->noelements;i++)117if(data->elementtypes[i] < minelementtype)118minelementtype = data->elementtypes[i];119120return(minelementtype);121}122123124int GetMaxElementDimension(struct FemType *data)125{126int maxelementtype,elemdim;127128maxelementtype = GetMaxElementType(data);129elemdim = GetElementDimension(maxelementtype);130return(elemdim);131}132133134int GetMaxBodyIndex(struct FemType *data) {135int i,maxind;136137maxind = 0;138for(i=1; i <= data->noelements; i++)139maxind = MAX(maxind, data->material[i]);140return(maxind);141}142143int GetMaxBCIndex(struct BoundaryType *bound) {144int i,j,maxind;145146maxind = 0;147for(j=0;j < MAXBOUNDARIES;j++) {148if(bound[j].created == FALSE) continue;149if(bound[j].nosides == 0) continue;150151for(i=1; i <= bound[j].nosides; i++)152maxind = MAX(maxind, bound[j].types[i]);153}154return(maxind);155}156157158159160int GetCoordinateDimension(struct FemType *data,int info)161{162int i,j,noknots,coorddim;163int coordis;164Real *coord;165Real epsilon = 1.0e-20;166167noknots = data->noknots;168coorddim = 0;169170for(j=3;j>=1;j--) {171coordis = FALSE;172if( j==1 )173coord = data->x;174else if( j==2 )175coord = data->y;176else177coord = data->z;178179for(i=1;i<=noknots;i++)180if( fabs( coord[i] ) > epsilon ) {181coordis = TRUE;182break;183}184if( coordis ) coorddim = MAX( coorddim, j );185}186if(info) printf("Coordinates defined in %d dimensions\n",coorddim);187188return(coorddim);189}190191192void GetElementSide(int element,int side,int normal,193struct FemType *data,int *ind,int *sideelemtype)194/* Give the indices of a given side of a given element.195The subroutine is valid for 4, 5, 8, 9, 12 and 16196node rectangular elements, and 3 and 6 node triangular197elements.198*/199{200int i,j,elemtype,*elemind=NULL,sides,ind2[MAXNODESD2];201202/* if(element < 1 || element > data->noelements ) {203printf("Invalid index for element: %d\n",element);204bigerror("Cannot continue");205} */206207elemtype = data->elementtypes[element];208elemind = data->topology[element];209sides = elemtype/100;210*sideelemtype = 0;211212if(side < 0 && sides > 4)213side = -(side+1);214215switch (elemtype) {216case 202:217case 203:218case 204:219*sideelemtype = 101;220ind[0] = elemind[side];221break;222223case 303: /* Linear triangle */224if(side < 3) {225*sideelemtype = 202;226ind[0] = elemind[side];227ind[1] = elemind[(side+1)%3];228}229else if( side < 6 ) {230*sideelemtype = 101;231ind[0] = elemind[side-3];232}233break;234235case 306: /* 2nd order triangle */236if(side < 3) {237*sideelemtype = 203;238ind[0] = elemind[side];239ind[1] = elemind[(side+1)%3];240ind[2] = elemind[side+3];241}242else if( side < 9 ) {243*sideelemtype = 101;244ind[0] = elemind[side-3];245}246break;247248case 310: /* 3rd order triangle */249if(side < 3) {250*sideelemtype = 204;251ind[0] = elemind[side];252ind[1] = elemind[(side+1)%3];253ind[2] = elemind[2*side+3];254ind[3] = elemind[2*side+4];255}256else if( side < 13) {257*sideelemtype = 101;258ind[0] = elemind[side-3];259}260break;261262case 404: /* Linear quadrilateral */263if(side < 4) {264*sideelemtype = 202;265ind[0] = elemind[side];266ind[1] = elemind[(side+1)%4];267}268else if(side < 8) {269*sideelemtype = 101;270ind[0] = elemind[side-4];271}272break;273274case 405:275if(side < 4) {276*sideelemtype = 202;277ind[0] = elemind[side];278ind[1] = elemind[(side+1)%4];279}280else if(side < 9) {281*sideelemtype = 101;282ind[0] = elemind[side-4];283}284break;285286287case 408: /* 2nd order quadrilateral */288if(side < 4) {289*sideelemtype = 203;290ind[0] = elemind[side];291ind[1] = elemind[(side+1)%4];292ind[2] = elemind[side+4];293}294else if(side < 12) {295*sideelemtype = 101;296ind[0] = elemind[side-4];297}298break;299300case 409:301if(side < 4) {302*sideelemtype = 203;303ind[0] = elemind[side];304ind[1] = elemind[(side+1)%4];305ind[2] = elemind[side+4];306}307else if(side < 13) {308*sideelemtype = 101;309ind[0] = elemind[side-4];310}311break;312313case 412: /* 3rd order quadrilateral */314if(side < 4) {315*sideelemtype = 204;316ind[0] = elemind[side];317ind[1] = elemind[(side+1)%4];318ind[2] = elemind[2*side+4];319ind[3] = elemind[2*side+5];320}321else if(side < 16) {322*sideelemtype = 101;323ind[0] = elemind[side-4];324}325break;326327case 416:328if(side < 4) {329*sideelemtype = 204;330ind[0] = elemind[side];331ind[1] = elemind[(side+1)%4];332ind[2] = elemind[2*side+4];333ind[3] = elemind[2*side+5];334}335else if(side < 20) {336*sideelemtype = 101;337ind[0] = elemind[side-4];338}339break;340341case 504: /* Linear tetrahedron */342if(side < 4) {343*sideelemtype = 303;344if(side < 3) {345ind[0] = elemind[side];346ind[1] = elemind[(side+1)%3];347ind[2] = elemind[3];348}349if(side == 3) {350ind[0] = elemind[0];351ind[1] = elemind[2];352ind[2] = elemind[1];353}354}355else if(side < 10) {356*sideelemtype = 202;357if(side < 7) {358ind[0] = elemind[side-4];359ind[1] = elemind[3];360}361else {362ind[0] = elemind[side-7];363ind[1] = elemind[(side-6)%3];364}365}366else if(side < 14) {367*sideelemtype = 101;368ind[0] = elemind[side-10];369}370break;371372case 510: /* 2nd order tetrahedron */373374if(side < 4) {375*sideelemtype = 306;376if(side < 3) {377ind[0] = elemind[side];378ind[1] = elemind[(side+1)%3];379ind[2] = elemind[3];380ind[3] = elemind[4+side];381ind[4] = elemind[7+(side+1)%3];382ind[5] = elemind[7+side];383}384else if(side == 3) {385ind[0] = elemind[0];386ind[1] = elemind[1];387ind[2] = elemind[2];388ind[3] = elemind[4];389ind[4] = elemind[5];390ind[5] = elemind[6];391}392}393else if(side < 10) {394*sideelemtype = 203;395if(side < 7) {396ind[0] = elemind[side-4];397ind[1] = elemind[3];398ind[2] = elemind[side+3];399}400else {401ind[0] = elemind[side-7];402ind[1] = elemind[(side-6)%3];403ind[2] = elemind[side-3];404}405}406else if(side < 20) {407*sideelemtype = 101;408ind[0] = elemind[side-10];409}410411break;412413case 706: /* Linear wedge element */414if(side < 3) {415*sideelemtype = 404;416ind[0] = elemind[side];417ind[1] = elemind[(side+1)%3];418ind[2] = elemind[(side+1)%3+3];419ind[3] = elemind[side+3];420}421else if (side < 5) {422*sideelemtype = 303;423for(i=0;i<3;i++)424ind[i] = elemind[3*(side-3)+i];425}426else if(side < 14) {427*sideelemtype = 202;428if(side < 8) {429ind[0] = elemind[side-5];430ind[1] = elemind[(side-4)%3];431}432if(side < 11) {433ind[0] = elemind[3+side-8];434ind[1] = elemind[3+(side-7)%3];435}436else {437ind[0] = elemind[side-11];438ind[1] = elemind[3+side-11];439}440}441else if (side < 20) {442*sideelemtype = 101;443ind[0] = elemind[side-14];444}445break;446447case 715: /* Quadratic wedge element */448if(side < 3) {449*sideelemtype = 408;450ind[0] = elemind[side];451ind[1] = elemind[(side+1)%3];452ind[2] = elemind[(side+1)%3+3];453ind[3] = elemind[side+3];454ind[4] = elemind[6+side];455ind[5] = elemind[9+(side+1)%3];456ind[6] = elemind[12+side];457ind[7] = elemind[9+side];458}459else if (side < 5) {460*sideelemtype = 306;461for(i=0;i<3;i++) {462ind[i] = elemind[3*(side-3)+i];463ind[i+3] = elemind[3*(side-3)+6+i];464}465}466else if(side < 14) {467*sideelemtype = 202;468if(side < 8) {469ind[0] = elemind[side-5];470ind[1] = elemind[(side-4)%3];471}472if(side < 11) {473ind[0] = elemind[3+side-8];474ind[1] = elemind[3+(side-7)%3];475}476else {477ind[0] = elemind[side-11];478ind[1] = elemind[3+side-11];479}480}481else if (side < 20) {482*sideelemtype = 101;483ind[0] = elemind[side-14];484}485break;486487case 605: /* Linear pyramid */488if(side < 4) {489*sideelemtype = 303;490ind[0] = elemind[side];491ind[1] = elemind[4];492ind[2] = elemind[(side+1)%4];493}494else if (side < 5) {495*sideelemtype = 404;496for(i=0;i<4;i++)497ind[i] = elemind[i];498}499else if(side < 13) {500*sideelemtype = 202;501if(side < 9) {502ind[0] = elemind[side-5];503ind[1] = elemind[(side-4)%4];504}505else {506ind[0] = elemind[side-9];507ind[1] = elemind[4];508}509}510else if(side < 18) {511*sideelemtype = 101;512ind[0] = elemind[side-13];513}514break;515516case 613: /* 2nd order pyramid */517if(side < 4) {518*sideelemtype = 306;519ind[0] = elemind[side];520ind[1] = elemind[(side+1)%4];521ind[2] = elemind[4];522523ind[3] = elemind[side+5];524ind[4] = elemind[(side+1)%4+9];525ind[5] = elemind[side%4+9];526}527else if (side == 4) {528*sideelemtype = 408;529for(i=0;i<4;i++)530ind[i] = elemind[i];531for(i=0;i<4;i++)532ind[i+4] = elemind[i+5];533}534else if(side < 13) {535*sideelemtype = 203;536if(side < 9) {537ind[0] = elemind[(side-5)];538ind[1] = elemind[(side-4)%4];539ind[2] = elemind[side];540}541else {542ind[0] = elemind[side-9];543ind[1] = elemind[4];544ind[2] = elemind[side];545}546}547else if(side < 26) {548*sideelemtype = 101;549ind[0] = elemind[side-13];550}551break;552553case 808: /* Linear brick */554if(side < 6) {555*sideelemtype = 404;556if(side < 4) {557ind[0] = elemind[side];558ind[1] = elemind[(side+1)%4];559ind[2] = elemind[(side+1)%4+4];560ind[3] = elemind[side+4];561}562else if(side < 6) {563for(i=0;i<4;i++)564ind[i] = elemind[4*(side-4)+i];565}566}567else if(side < 18) {568*sideelemtype = 202;569if(side < 10) {570ind[0] = elemind[side-6];571ind[1] = elemind[(side-5)%4];572}573else if(side < 14) {574ind[0] = elemind[side-6];575ind[1] = elemind[(side-9)%4+4];576}577else {578ind[0] = elemind[side-14];579ind[1] = elemind[side-14+4];580}581}582else if(side < 26) {583*sideelemtype = 101;584ind[0] = elemind[side-18];585}586break;587588case 820: /* 2nd order brick */589if(side < 4) {590*sideelemtype = 408;591ind[0] = elemind[side];592ind[1] = elemind[(side+1)%4];593ind[2] = elemind[(side+1)%4+4];594ind[3] = elemind[side+4];595ind[4] = elemind[8+side];596ind[5] = elemind[12+(side+1)%4];597ind[6] = elemind[16+side];598ind[7] = elemind[12+side];599}600else if(side < 6) {601*sideelemtype = 408;602for(i=0;i<4;i++)603ind[i] = elemind[4*(side-4)+i];604for(i=0;i<4;i++)605ind[i+4] = elemind[8*(side-4)+8+i];606}607break;608609case 827:610if(side < 4) {611*sideelemtype = 409;612ind[0] = elemind[side];613ind[1] = elemind[(side+1)%4];614ind[2] = elemind[(side+1)%4+4];615ind[3] = elemind[side+4];616ind[4] = elemind[8+side];617ind[5] = elemind[12+(side+1)%4];618ind[6] = elemind[16+side];619ind[7] = elemind[12+side];620ind[8] = elemind[20+side];621}622else {623*sideelemtype = 409;624for(i=0;i<4;i++)625ind[i] = elemind[4*(side-4)+i];626for(i=0;i<4;i++)627ind[i+4] = elemind[8*(side-4)+8+i];628ind[8] = elemind[20+side];629}630break;631632default:633printf("GetElementSide: unknown elementtype %d (elem=%d,side=%d)\n",elemtype,element,side);634bigerror("Cannot continue");635}636637if(normal == -1) {638if(*sideelemtype == 202 || *sideelemtype == 203 || *sideelemtype == 303 || *sideelemtype == 404) {639j = *sideelemtype/100-1;640for(i=0;i<=j;i++)641ind2[i] = ind[i];642for(i=0;i<=j;i++)643ind[i] = ind2[j-i];644}645}646}647648649650void GetBoundaryElement(int sideind,struct BoundaryType *bound,struct FemType *data,int *ind,int *sideelemtype)651{652int element,side,normal,i,n;653654if( sideind > bound->nosides ) {655*sideelemtype = 0;656printf("Side element index %d exceeds size of boundary (%d)\n",sideind,bound->nosides);657return;658}659660element = bound->parent[sideind];661662663/*GetElementSide(elemind2,side,1,data,&sideind2[0],&sideelemtype2); */664665if(element) {666side = bound->side[sideind];667normal = bound->normal[sideind];668GetElementSide(element,side,normal,data,ind,sideelemtype);669}670else {671*sideelemtype = bound->elementtypes[sideind];672673n = *sideelemtype % 100;674675for(i=0;i<n;i++)676ind[i] = bound->topology[sideind][i];677678if(0) {679printf("sidelemtype = %d\n",*sideelemtype);680printf("ind = ");681for(i=0;i<n;i++) printf("%d ",ind[i]);682printf("\n");683}684}685}686687688689int GetElementFaces(int elemtype)690{691int basetype=0,elemfaces=0;692693basetype = elemtype / 100;694695switch (basetype) {696case 1:697elemfaces = 0;698break;699case 2:700elemfaces = 2;701break;702case 3:703elemfaces = 3;704break;705case 4:706elemfaces = 4;707break;708case 5:709elemfaces = 4;710break;711case 6:712elemfaces = 5;713break;714case 7:715elemfaces = 5;716break;717case 8:718elemfaces = 6;719break;720721default:722printf("GetElementFaces: Unknown elementtype %d\n",elemfaces);723}724725return(elemfaces);726}727728729730731732733int GetElementGraph(int element,int edge,struct FemType *data,int *ind)734{735int elemtype,basetype,elemnodes;736int hit,evenodd,quadratic,side;737int *elemind=NULL;738739elemtype = data->elementtypes[element];740basetype = elemtype / 100;741elemnodes = elemtype % 100;742quadratic = (elemnodes > basetype);743elemind = data->topology[element];744745ind[0] = ind[1] = 0;746747if(quadratic)748side = edge / 2;749else750side = edge;751752753switch (basetype) {754case 2:755if(side == 0) {756ind[0] = elemind[0];757ind[1] = elemind[1];758}759break;760case 3:761if(side < 3) {762ind[0] = elemind[side];763ind[1] = elemind[(side+1)%3];764}765break;766case 4:767if(side < 4) {768ind[0] = elemind[side];769ind[1] = elemind[(side+1)%4];770}771break;772case 5:773if(side < 3) {774ind[0] = elemind[side];775ind[1] = elemind[(side+1)%3];776}777else if(side < 6) {778ind[0] = elemind[side-3];779ind[1] = elemind[3];780}781break;782case 6:783if(side < 4) {784ind[0] = elemind[side];785ind[1] = elemind[(side+1)%4];786}787else if(side < 8) {788ind[0] = elemind[side-4];789ind[1] = elemind[4];790}791break;792case 7:793switch(side) {794case 0: ind[0]=elemind[0]; ind[1]=elemind[1]; break;795case 1: ind[0]=elemind[1]; ind[1]=elemind[2]; break;796case 2: ind[0]=elemind[2]; ind[1]=elemind[0]; break;797case 3: ind[0]=elemind[3]; ind[1]=elemind[4]; break;798case 4: ind[0]=elemind[4]; ind[1]=elemind[5]; break;799case 5: ind[0]=elemind[5]; ind[1]=elemind[3]; break;800case 6: ind[0]=elemind[0]; ind[1]=elemind[3]; break;801case 7: ind[0]=elemind[1]; ind[1]=elemind[4]; break;802case 8: ind[0]=elemind[2]; ind[1]=elemind[5]; break;803}804break;805806case 8:807if(side < 4) {808ind[0] = elemind[side];809ind[1] = elemind[(side+1)%4];810}811else if(side < 8) {812ind[0] = elemind[side-4];813ind[1] = elemind[side];814}815else if(side < 12) {816ind[0] = elemind[side-4];817ind[1] = elemind[4+(side+1)%4];818}819break;820}821822hit = (ind[0] || ind[1]);823824825if(hit && quadratic) {826evenodd = edge - 2*side;827828switch (basetype) {829case 2:830ind[evenodd] = elemind[2];831break;832833case 3:834ind[evenodd] = elemind[side+3];835break;836837case 4:838ind[evenodd] = elemind[side+4];839break;840841case 5:842ind[evenodd] = elemind[side+4];843break;844845case 6:846ind[evenodd] = elemind[side+5];847break;848849case 7:850ind[evenodd] = elemind[side+6];851break;852853case 8:854ind[evenodd] = elemind[side+8];855break;856857}858}859860return(hit);861}862863864865866int CalculateIndexwidth(struct FemType *data,int indxis,int *indx)867{868int i,ind,nonodes,indexwidth;869int imax,imin,element;870871/* Calculate the maximum bandwidth */872873indexwidth = 0;874875for(element=1; element <= data->noelements; element++) {876imin = data->noknots;877imax = 0;878nonodes = data->elementtypes[element]%100;879for(i=0;i<nonodes;i++) {880ind = data->topology[element][i];881if(indxis) ind = indx[ind];882if(ind == 0) continue;883if(ind > imax) imax = ind;884if(ind < imin) imin = ind;885}886if(imax-imin > indexwidth)887indexwidth = imax-imin;888}889890if(!indxis) data->indexwidth = indexwidth;891return(indexwidth);892}893894895void InitializeKnots(struct FemType *data)896{897int i;898899data->timesteps = 0;900data->noknots = 0;901data->noelements = 0;902data->coordsystem = COORD_CART2;903data->numbering = NUMBER_XY;904data->created = FALSE;905data->variables = 0;906data->maxnodes = 0;907data->indexwidth = 0;908data->noboundaries = 0;909data->mapgeo = 1;910data->nocorners = 0;911912data->boundarynamesexist = FALSE;913data->bodynamesexist = FALSE;914915data->nodepermexist = FALSE;916917data->nopartitions = 1;918data->partitionexist = FALSE;919data->periodicexist = FALSE;920data->nodeconnectexist = FALSE;921data->elemconnectexist = FALSE;922923data->nodalexists = FALSE;924/* data->invtopoexists = FALSE; */925data->partitiontableexists = FALSE;926data->maxpartitiontable = 0;927928data->invtopo.created = FALSE;929data->nodalgraph2.created = FALSE;930data->dualgraph.created = FALSE;931932933for(i=0;i<MAXDOFS;i++) {934data->edofs[i] = 0;935data->bandwidth[i] = 0;936strcpy(data->dofname[i],"");937}938939for(i=0;i<MAXBODIES;i++) {940data->bodyname[i] = NULL;941}942for(i=0;i<MAXBCS;i++) {943data->boundaryname[i] = NULL;944}945}946947948void AllocateKnots(struct FemType *data)949{950int i;951952data->topology = Imatrix(1,data->noelements,0,data->maxnodes-1);953data->material = Ivector(1,data->noelements);954data->elementtypes = Ivector(1,data->noelements);955956for(i=1;i<=data->noelements;i++)957data->material[i] = 0;958959for(i=1;i<=data->noelements;i++)960data->elementtypes[i] = 0;961962data->x = Rvector(1,data->noknots);963data->y = Rvector(1,data->noknots);964data->z = Rvector(1,data->noknots);965for(i=1;i<=data->noknots;i++)966data->x[i] = data->y[i] = data->z[i] = 0.0;967968data->created = TRUE;969970#if DEBUG971printf("Allocated for %d %d-node elements resulting to %d nodes\n",972data->noelements,data->maxnodes,data->noknots);973#endif974}975976977static void MovePointCircle(Real *lim,int points,Real *coords,978Real x,Real y,Real *dx,Real *dy)979{980int i;981Real x0,y0,r,r1,r2,p;982983r2 = fabs(lim[1]-lim[0]);984if(r2 > fabs(lim[2]-lim[1]))985r2 = fabs(lim[2]-lim[1]);986987for(i=0;i<points/2;i++) {988x0 = x-coords[2*i];989r1 = fabs(coords[2*i+1]);990991if(fabs(x0) >= r2) continue;992y0 = y-(lim[1]+coords[2*i+1]);993if(y0 < 0 && lim[0] > lim[1]) continue;994if(y0 > 0 && lim[2] < lim[1]) continue;995if(fabs(y0) >= r2) continue;996r = sqrt(x0*x0+y0*y0);997if(r < 1.0e-50) continue;998999if(fabs(x0) > fabs(y0)) {1000p = fabs(x0)/r - 1.0;1001if(fabs(x0) <= r1) {1002*dx += p*x0;1003*dy += p*y0;1004}1005else if(fabs(x0) <= r2) {1006*dx += p*x0*(r2-fabs(x0))/(r2-r1);1007*dy += p*y0*(r2-fabs(x0))/(r2-r1);1008}1009}1010else {1011p = fabs(y0)/r - 1.0;1012if(fabs(y0) <= r1) {1013*dx += p*x0;1014*dy += p*y0;1015}1016else if(fabs(y0) <= r2) {1017*dx += p*x0*(r2-fabs(y0))/(r2-r1);1018*dy += p*y0*(r2-fabs(y0))/(r2-r1);1019}1020}1021}1022}1023102410251026static void MovePointLinear(Real *lim,int points,Real *coords,1027Real x,Real y,Real *dx,Real *dy)1028{1029static int i=0;1030Real c,d;10311032if(y > lim[0] && y < lim[2]) {103310341035if(x <= coords[0]) {1036d = coords[1];1037}1038else if(x >= coords[points-2]) {1039d = coords[points-1];1040}1041else {1042i = 1;1043while(x > coords[2*i] && i < points/2-1) i++;1044c = (coords[2*i+1]-coords[2*i-1])/(coords[2*i]-coords[2*i-2]);1045d = coords[2*i-1] + c*(x-coords[2*i-2]);1046}10471048if(y < lim[1])1049*dy += d*(y-lim[0])/(lim[1]-lim[0]);1050else1051*dy += d*(lim[2]-y)/(lim[2]-lim[1]);1052}1053}105410551056static void MovePointAngle(Real *lim,int points,Real *coords,1057Real x,Real y,Real *dx,Real *dz)1058{1059static int i=0;1060Real x1,z1,degs;10611062degs = FM_PI/180.0;1063x1 = z1 = 0.0;10641065if(y > lim[0] && y < lim[2]) {1066if(x <= coords[0]) {1067x1 = x;1068}1069else {1070i = 1;1071while(x > coords[2*i] && i <= points/2-1) {1072x1 = x1 + cos(degs*coords[2*i-1])*(coords[2*i]-coords[2*i-2]);1073z1 = z1 + sin(degs*coords[2*i-1])*(coords[2*i]-coords[2*i-2]);1074i++;1075}1076x1 = x1 + cos(degs*coords[2*i-1])*(x-coords[2*i-2]);1077z1 = z1 + sin(degs*coords[2*i-1])*(x-coords[2*i-2]);1078}10791080if(y < lim[1]) {1081*dx += (x1-x)*(y-lim[0])/(lim[1]-lim[0]);1082*dz += z1*(y-lim[0])/(lim[1]-lim[0]);1083}1084else {1085*dx += (x1-x)*(lim[2]-y)/(lim[2]-lim[1]);1086*dz += z1*(lim[2]-y)/(lim[2]-lim[1]);1087}1088}1089}109010911092static void MovePointSinus(Real *lim,int points,Real *coords,1093Real x,Real y,Real *dx,Real *dy)1094{1095Real c,d;10961097if(y > lim[0] && y < lim[2]) {10981099if(x <= coords[0]) {1100d = 0.0;1101}1102else if(x >= coords[1]) {1103d = coords[3]*sin(coords[2]*2.*FM_PI);1104}1105else {1106c = coords[2]*2.*FM_PI/(coords[1]-coords[0]);1107d = coords[3]*sin(c*(x-coords[0]));1108}11091110if(y < lim[1])1111*dy += d*(y-lim[0])/(lim[1]-lim[0]);1112else1113*dy += d*(lim[2]-y)/(lim[2]-lim[1]);1114}1115}1116111711181119static void MovePointPowerSeries(Real *lim,int points,Real *coords,1120Real x,Real y,Real *dx,Real *dy)1121{1122int i,n;1123Real d,t,u;11241125if(y > lim[0] && y < lim[2]) {1126t = x;1127if(coords[1] > coords[0]) {1128if(t<coords[0]) t = coords[0];1129if(t>coords[1]) t = coords[1];1130}1131else {1132if(t>coords[0]) t = coords[0];1133if(t<coords[1]) t = coords[1];1134}11351136n = points-2;1137u = (t - coords[0])/(coords[1]-coords[0]);11381139d = 0.0;1140for(i=0;i<n;i++) {1141d += coords[i+2] * pow(u,i);1142}11431144if(y < lim[1]) {1145*dy += d*(y-lim[0])/(lim[1]-lim[0]);1146}1147else {1148*dy += d*(lim[2]-y)/(lim[2]-lim[1]);1149}1150}1151}115211531154static void MovePointPowerSeries2(Real *lim,int points,Real *coords,1155Real x,Real y,Real *dx,Real *dy)1156{1157int i,j,n;1158Real d,e,t,u,h;11591160if(y > lim[0] && y < lim[2]) {1161t = x;1162if(coords[1] > coords[0]) {1163if(t<coords[0]) t = coords[0];1164if(t>coords[1]) t = coords[1];1165}1166else {1167if(t>coords[0]) t = coords[0];1168if(t<coords[1]) t = coords[1];1169}11701171n = points-2;1172u = (t - coords[0])/(coords[1]-coords[0]);11731174d = 0.0;11751176d = coords[2];1177if(n>=1) d += u * coords[3];11781179for(i=2;i<n;i++) {1180h = 1.0/(i-1);1181e = 1.0;1182for(j=0;j<i;j++)1183e *= (u-j*h);1184d += coords[i+2] * e;1185}11861187if(y < lim[1]) {1188*dy += d*(y-lim[0])/(lim[1]-lim[0]);1189}1190else {1191*dy += d*(lim[2]-y)/(lim[2]-lim[1]);1192}1193}1194}1195119611971198static void MovePointPower(Real *lim,int points,Real *coords,1199Real x,Real y,Real *dx,Real *dy)1200{1201static int i=0;1202Real c,d;12031204if(y > lim[0] && y < lim[2]) {1205if(x <= coords[0]) {1206d = coords[1];1207}1208else if(x >= coords[points-2]) {1209d = coords[points-1];1210}1211else {1212i = 1;1213while(x > coords[3*i] && i < points/3-1) i++;1214c = (coords[3*i+1]-coords[3*i-2])/pow((coords[3*i]-coords[3*i-3]),coords[3*i-1]);1215d = coords[3*i-2] + c*pow((x-coords[3*i-3]),coords[3*i-1]);1216}12171218if(y < lim[1])1219*dy += d*(y-lim[0])/(lim[1]-lim[0]);1220else1221*dy += d*(lim[2]-y)/(lim[2]-lim[1]);1222}1223}12241225/* Creates airfoil shapes */1226static void MovePointNACAairfoil(Real *lim,int points,Real *coords,1227Real x,Real y,Real *dx,Real *dy)1228{1229Real p,d,t,u;12301231if(y < lim[0] || y > lim[2]) return;1232if(x < coords[0] || x > coords[1]) return;12331234if(0) {1235printf("x=%.3e y=%.3e lim0=%.3e lim2=%.3e\n",x,y,lim[0],lim[2]);1236printf("naca: %.3e %.3e %.3e\n",coords[0],coords[1],coords[2]);1237}12381239t = x;1240if(coords[1] > coords[0]) {1241if(t<coords[0]) t = coords[0];1242if(t>coords[1]) t = coords[1];1243}1244else {1245if(t>coords[0]) t = coords[0];1246if(t<coords[1]) t = coords[1];1247}12481249u = (t - coords[0])/(coords[1]-coords[0]);1250p = 0.2969*sqrt(u) - 0.1260*u - 0.3537*u*u + 0.2843*u*u*u - 0.1015*u*u*u*u;12511252d = coords[2] * (coords[1]-coords[0]) * p / 0.2;12531254if(y < lim[1]) {1255*dy += d*(y-lim[0])/(lim[1]-lim[0]);1256}1257else {1258*dy += d*(lim[2]-y)/(lim[2]-lim[1]);1259}126012611262if(0) printf("d=%.3e p=%.3e u=%.3e dy=%.3e\n",d,p,u,*dy);1263}1264126512661267static void MovePointArc(Real *lim,int points,Real *coords,1268Real x,Real y,Real *dx,Real *dy)1269{1270static int i=0;1271Real sx,sy,ss,r,rat,d,x0,y0;12721273if(y > lim[0] && y < lim[2]) {1274if(x <= coords[0]) {1275d = coords[1];1276}1277else if(x >= coords[points-2]) {1278d = coords[points-1];1279}1280else {1281i = 1;1282while(x > coords[3*i] && i < points/3-1) i++;1283sx = 0.5*(coords[3*i]-coords[3*i-3]);1284sy = 0.5*(coords[3*i+1]-coords[3*i-2]);1285r = coords[3*i-1];1286ss = sx*sx+sy*sy;1287rat = sqrt(1.0/ss-1.0/(r*r))*r;1288x0 = coords[3*i-3] + sx - sy * rat;1289y0 = coords[3*i-2] + sy + sx * rat;1290d = y0-sqrt(r*r-(x-x0)*(x-x0))*r/fabs(r);1291}12921293if(y < lim[1])1294*dy += d*(y-lim[0])/(lim[1]-lim[0]);1295else1296*dy += d*(lim[2]-y)/(lim[2]-lim[1]);1297}1298}1299130013011302void CreateKnots(struct GridType *grid,struct CellType *cell,1303struct FemType *data,int noknots,int info)1304/* Saves information concerning the knots to a special structure to avoid1305repetitious calculations. This should be used unless there is a severe1306lack of memory. GridType includes only rectangular 2D elements.1307*/1308{1309Real globalcoord[DIM*MAXNODESD2];1310Real maplim[3*MAXMAPPINGS];1311int material,nonodes,elemind,elemtype;1312int mode,level,maplevel,dim;1313int celli,cellj,i,j,k,l,ind[MAXNODESD2];1314Real x,y,dx,dy,dz,size,minsize,maxsize;13151316InitializeKnots(data);13171318dim = data->dim = grid->dimension;1319nonodes = grid->nonodes;1320data->maxnodes = grid->nonodes;1321data->nocells = grid->nocells;1322data->noelements = grid->noelements;1323data->coordsystem = grid->coordsystem;1324data->numbering = grid->numbering;1325data->indexwidth = grid->maxwidth;1326data->noknots = MAX(noknots,grid->noknots);1327data->noboundaries = grid->noboundaries;13281329AllocateKnots(data);1330minsize = 1.0e20;13311332if(dim == 1)1333elemtype = grid->nonodes + 200;1334else1335elemtype = grid->nonodes + 400;13361337for(i=1;i<=data->noelements;i++)1338data->elementtypes[i] = elemtype;13391340/* This numbers the elements the same way the knots are numbered. */1341for(cellj=1;cellj<= grid->ycells ;cellj++) { /* cells direction up */1342for(j=1; j<=grid->yelems[cellj]; j++) /* lines inside cells */1343for(celli=1;celli<= grid->xcells; celli++) /* cells direction right */1344if((k=grid->numbered[cellj][celli])) {1345material = cell[k].material;1346for(i=1; i<=grid->xelems[celli]; i++) {13471348elemind = GetElementCoordinates(&(cell)[k],i,j,globalcoord,ind);13491350if(data->noknots == grid->noknots) {1351for(l=0;l<nonodes;l++) {1352data->topology[elemind][l] = ind[l];1353data->x[ind[l]] = globalcoord[l];1354data->y[ind[l]] = globalcoord[l+nonodes];1355}1356data->material[elemind] = material;13571358}1359}1360}1361}13621363/* Map the knots as defined in structures grid */1364for(k=0;k<grid->mappings;k++) {1365j = grid->mappingline[k];1366if(grid->mappingtype[k] > 0)1367maplim[3*k+1] = grid->y[j];1368else if(grid->mappingtype[k] < 0)1369maplim[3*k+1] = grid->x[j];1370else1371continue;1372maplim[3*k] = maplim[3*k+1] - grid->mappinglimits[2*k];1373maplim[3*k+2] = maplim[3*k+1] + grid->mappinglimits[2*k+1];1374}13751376mode = 0;1377if(grid->mappings)13781379for(level=0;level<10;level++) {1380maplevel = FALSE;1381for(k=0;k<grid->mappings;k++)1382if(abs(grid->mappingtype[k]/10) == level)1383maplevel = TRUE;1384if(maplevel == FALSE) continue;13851386if(level >= 5) data->dim = 3;13871388for(i=1;i<=data->noknots;i++) {1389x = data->x[i];1390y = data->y[i];1391dx = 0.0;1392dy = 0.0;1393dz = 0.0;13941395for(k=0;k<grid->mappings;k++) {1396mode = grid->mappingtype[k]%10;1397switch (mode) {1398case 1:1399MovePointLinear(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1400x,y,&dx,&dy);1401break;1402case 2:1403MovePointPower(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1404x,y,&dx,&dy);1405break;1406case 3:1407MovePointArc(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1408x,y,&dx,&dy);1409break;1410case 4:1411MovePointCircle(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1412x,y,&dx,&dy);1413break;1414case 5:1415MovePointSinus(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1416x,y,&dx,&dy);1417break;1418case 6:1419MovePointPowerSeries(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1420x,y,&dx,&dy);1421break;1422case 7:1423MovePointPowerSeries2(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1424x,y,&dx,&dy);1425break;1426case 8:1427MovePointAngle(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1428x,y,&dx,&dz);1429break;1430case 9:1431MovePointNACAairfoil(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1432x,y,&dx,&dy);1433break;143414351436case -1:1437MovePointLinear(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1438y,x,&dy,&dx);1439break;1440case -2:1441MovePointPower(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1442y,x,&dy,&dx);1443break;1444case -3:1445MovePointArc(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1446y,x,&dy,&dx);1447break;1448case -4:1449MovePointCircle(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1450y,x,&dy,&dx);1451break;1452case -5:1453MovePointSinus(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1454y,x,&dy,&dx);1455break;1456case -6:1457MovePointPowerSeries(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1458y,x,&dy,&dx);1459break;1460case -7:1461MovePointPowerSeries2(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1462y,x,&dy,&dx);1463break;1464case -8:1465MovePointAngle(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1466y,x,&dy,&dz);1467break;1468case -9:1469MovePointNACAairfoil(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],1470y,x,&dy,&dx);1471break;147214731474}1475}14761477if(mode == 8 || mode == -8) {1478data->x[i] += dx;1479data->y[i] += dy;1480data->z[i] += dz;1481}1482else if(level >= 5) {1483data->z[i] += dx + dy;1484}1485else {1486data->x[i] += dx;1487data->y[i] += dy;1488}1489}1490}14911492minsize = 1.0e20;1493maxsize = 0.0;14941495for(i=1;i<=data->noelements;i++) {1496GetElementInfo(i,data,globalcoord,ind,&material);14971498dx = globalcoord[0]-globalcoord[1];1499dy = globalcoord[nonodes]-globalcoord[nonodes+1];1500size = dx*dx+dy*dy;1501if(size < minsize) minsize = size;1502if(size > maxsize) maxsize = size;1503dx = globalcoord[0]-globalcoord[nonodes-1];1504dy = globalcoord[nonodes]-globalcoord[2*nonodes-1];1505size = dx*dx+dy*dy;1506if(size < minsize) minsize = size;1507if(size > maxsize) maxsize = size;1508}15091510data->maxsize = sqrt(maxsize);1511data->minsize = sqrt(minsize);15121513if(info) printf("Maximum elementsize is %.3e and minimum %.3e.\n",1514data->maxsize,data->minsize);1515}15161517151815191520int CreateVariable(struct FemType *data,int variable,int unknowns,1521Real value,const char *dofname,int eorder)1522/* Create variables for the given data structure */1523{1524int i,info=FALSE;1525int timesteps;15261527if(variable == 0) return(0);15281529if(data->created == FALSE) {1530if(info) printf("CreateVariable: Knots must first be created!\n");1531return(1);1532}1533timesteps = data->timesteps;1534if(timesteps < 1) timesteps = 1;15351536if(data->edofs[variable] == 0) {15371538data->variables += 1;1539data->edofs[variable] = unknowns;1540data->alldofs[variable] = unknowns * data->noknots;1541data->bandwidth[variable] = unknowns * data->indexwidth;1542data->dofs[variable] = Rvector(1,timesteps * data->alldofs[variable]);1543if(info) printf("Created variable %s with %d dofs.\n",1544dofname,data->alldofs[variable]);1545for(i=1;i<=data->alldofs[variable]*timesteps;i++)1546data->dofs[variable][i] = value;1547}1548else if (data->edofs[variable] == unknowns) {1549if(info) printf("CreateVariable: Variable %d exists with correct number of dofs!\n",1550variable);1551}1552else {1553if(info) printf("CreateVariable: Variable %d exists with wrong number of dofs!\n",1554variable);1555return(2);1556}15571558strcpy(data->dofname[variable],dofname);15591560return(0);1561}1562156315641565void DestroyKnots(struct FemType *data)1566{1567int i;15681569if(!data->created) return;1570data->created = FALSE;15711572for(i=0;i<MAXDOFS;i++)1573if(data->edofs[i] != 0) {1574if(data->edofs[i] > 0)1575free_Rvector(data->dofs[i],1,data->alldofs[i]);1576data->edofs[i] = 0;1577}15781579free_Imatrix(data->topology,1,data->noelements,0,data->maxnodes-1);1580free_Ivector(data->material,1,data->noelements);1581free_Ivector(data->elementtypes,1,data->noelements);15821583free_Rvector(data->x,1,data->noknots);1584free_Rvector(data->y,1,data->noknots);1585free_Rvector(data->z,1,data->noknots);15861587data->noknots = 0;1588data->noelements = 0;1589data->maxnodes = 0;15901591if(data->nocorners > 0)1592free_Ivector(data->corners,1,2*data->nocorners);1593}1594159515961597int CreateBoundary(struct CellType *cell,struct FemType *data,1598struct BoundaryType *bound,int material1,int material2,1599int solidmat,int boundarytype,int info)1600/* This subroutine makes a boundary which includes all sides that separate1601two materials that fulfill the conditions in the function call. If both1602materials are positive only the sides for which both of the materials1603coincide are accepted. In other cases the negative argument tells which1604conditions the positive argument should fulfill. Note that on a boundary1605where knots are created only for the other material, this material1606should be the latter one in the function call (material). The physical1607properties (emissivity) of the materials are taken from the one given1608by the flag 'solidmat'.1609*/1610{1611int i,side,more,elem,elemind[2],nosides,no,times;1612int sidemat,thismat,size,setpoint,dimsides,cellside;16131614if(data->dim == 1)1615dimsides = 2;1616else1617dimsides = 4;16181619if(bound->created == TRUE) {1620if(info) printf("CreateBoundary: You tried to recreate the boundary!\n");1621return(1);1622}1623if(!data->created) {1624if(info) printf("CreateBoundary: You tried to create a boundary before the knots were made.");1625return(2);1626}1627if(material1 < 0 && material2 < 0) {1628if(info) printf("CreateBoundary: the material arguments are both negative");1629return(3);1630}16311632times = 0;16331634bound->created = FALSE;1635bound->nosides = 0;1636if(solidmat >= 2) solidmat -= 2;16371638startpoint:16391640/* Go through all elements which have a boundary with the given material, but1641are not themselves of that material. First only calculate their amount, then1642allocate space and tabulate them. */1643nosides = 0;164416451646for(no=1; no <= data->nocells; no++)1647for(side=0; side < dimsides; side++) {16481649if(data->dim == 1)1650cellside = 3-2*side;1651else1652cellside = side;16531654setpoint = FALSE;1655sidemat = cell[no].boundary[cellside];1656thismat = cell[no].material;16571658/* The free boundary conditions are not allowed if the negative1659keywords are used. */16601661/* Either material must be the one defined. */1662if( material1 >= 0 && material1 != sidemat) continue;1663if( material2 >= 0 && material2 != thismat) continue;1664#if 01665printf("mat=[%d %d] sidemat=%d thismat=%d side=%d\n",1666material1,material2,sidemat,thismat,side);1667#endif16681669if( material2 == -((side+2)%4+1) && sidemat == material1 &&1670sidemat != thismat) setpoint = TRUE;1671if( material1 == -(side+1) && thismat == material2 &&1672sidemat != thismat) setpoint = TRUE;16731674if( material1 == MAT_BIGGER && sidemat > material2 ) setpoint = TRUE;1675if( material1 == MAT_SMALLER && sidemat < material2 ) setpoint = TRUE;1676if( material1 == MAT_ANYTHING && sidemat != material2 ) setpoint = TRUE;1677if( material2 == MAT_BIGGER && thismat > material1 ) setpoint = TRUE;1678if( material2 == MAT_SMALLER && thismat < material1 ) setpoint = TRUE;1679if( material2 == MAT_ANYTHING && thismat != material1 ) setpoint = TRUE;1680if( sidemat == material1 && thismat == material2 ) setpoint = TRUE;16811682if(setpoint == TRUE) {1683#if 01684printf("going through boundary %d vs. %d in cell %d\n",material1,material2,no);1685#endif1686elem = 0;1687do {1688elem++;1689nosides++;1690more = GetSideInfo(cell,no,side,elem,elemind);16911692#if 01693printf("elem=%d nosides=%d no=%d side=%d elemind=%d %d\n",1694elem,nosides, no, side, elemind[0], elemind[1]);1695#endif16961697/* In the second round the values are tabulated. */1698if(times) {1699/* It is assumed that the material pointed by solidmat1700determines the surface properties. */17011702bound->parent[nosides] = elemind[0];1703bound->parent2[nosides] = elemind[1];17041705bound->side[nosides] = side;1706bound->side2[nosides] = (side+dimsides/2)%dimsides;17071708bound->types[nosides] = boundarytype;17091710/* The direction of the surface normal must be included */1711if(solidmat==FIRST) {1712bound->material[nosides] = sidemat;1713bound->normal[nosides] = 1;1714}1715if(solidmat==SECOND){1716bound->material[nosides] = thismat;1717bound->normal[nosides] = -1;1718}1719}172017211722} while(more);1723}1724}17251726if(nosides == 0) {1727if(info) printf("No boundary between materials %d and %d exists.\n",1728material1,material2);1729return(0);1730}17311732if(times == 0) {1733times++;17341735/* Allocate space. This has sometimes led to strange errors.1736The allocation takes place only in the first loop. */17371738bound->created = TRUE;1739bound->nosides = size = nosides;1740bound->coordsystem = data->coordsystem;1741bound->types = Ivector(1,nosides);1742bound->side = Ivector(1,nosides);1743bound->side2 = Ivector(1,nosides);1744bound->material = Ivector(1,nosides);1745bound->parent = Ivector(1,nosides);1746bound->parent2 = Ivector(1,nosides);1747bound->normal = Ivector(1,nosides);17481749bound->echain = FALSE;1750bound->ediscont = FALSE;17511752goto startpoint;1753}17541755if(info) printf("%d element sides between materials %d and %d were located to type %d.\n",1756nosides,material1,material2,boundarytype);17571758return(0);1759}176017611762int AllocateBoundary(struct BoundaryType *bound,int size)1763{1764int i;17651766if(bound->created == TRUE) {1767printf("AllocateBoundary: You tried to recreate the boundary!\n");1768return(1);1769}17701771bound->created = TRUE;1772bound->nosides = size;1773bound->echain = FALSE;1774bound->ediscont = FALSE;17751776bound->material = Ivector(1,size);1777bound->side = Ivector(1,size);1778bound->side2 = Ivector(1,size);1779bound->parent = Ivector(1,size);1780bound->parent2 = Ivector(1,size);1781bound->types = Ivector(1,size);1782bound->normal = Ivector(1,size);17831784for(i=1;i<=size;i++) {1785bound->material[i] = 0;1786bound->side[i] = 0;1787bound->side2[i] = 0;1788bound->parent[i] = 0;1789bound->parent2[i] = 0;1790bound->types[i] = 0;1791bound->normal[i] = 1;1792}17931794return(0);1795}1796179717981799int DestroyBoundary(struct BoundaryType *bound)1800/* Destroys boundaries of various types. */1801{1802int i,nosides;18031804if(!bound->created) {1805return(1);1806}1807nosides = bound->nosides;1808if(!nosides) {1809bound->created = FALSE;1810return(2);1811}18121813free_Ivector(bound->material,1,nosides);1814free_Ivector(bound->side,1,nosides);1815free_Ivector(bound->side2,1,nosides);1816free_Ivector(bound->parent,1,nosides);1817free_Ivector(bound->parent2,1,nosides);1818free_Ivector(bound->types,1,nosides);1819free_Ivector(bound->normal,1,nosides);18201821bound->nosides = 0;1822bound->created = FALSE;18231824#if DEBUG1825printf("%d element sides were destroyed.\n",nosides);1826#endif1827return(0);1828}1829183018311832int CreatePoints(struct CellType *cell,struct FemType *data,1833struct BoundaryType *bound,1834int param1,int param2,int pointmode,int pointtype,int info)1835{1836int size,i,no,corner,times,elem,node;18371838bound->created = FALSE;1839bound->nosides = 0;1840times = 0;18411842omstart:1843i = 0;18441845/* Create nodes that are divided by the two materials specified */1846if(pointmode == 4) {1847for(no=1; no <= data->nocells; no++)1848if(cell[no].material == param2) {18491850for(corner=0; corner < 4; corner++)1851if(cell[no].boundary[4+corner] == param1) {18521853i++;18541855if(times) {1856bound->material[i] = param2;1857bound->types[i] = pointtype;1858bound->side[i] = 4 + corner;18591860if(corner == BOTLEFT)1861elem = GetElementIndex(&cell[no],1,1);1862else if(corner == BOTRIGHT)1863elem = GetElementIndex(&cell[no],cell[no].xelem,1);1864else if(corner == TOPRIGHT)1865elem = GetElementIndex(&cell[no],cell[no].xelem,cell[no].yelem);1866else if(corner == TOPLEFT)1867elem = GetElementIndex(&cell[no],1,cell[no].yelem);18681869bound->parent[i] = elem;1870}1871}1872}1873}18741875if(pointmode == 5) {1876corner = -1;1877for(no=1; no <= data->nocells && corner <0; no++) {1878if(cell[no].xind-1 == param1 && cell[no].yind-1 == param2)1879corner = BOTLEFT;1880else if(cell[no].xind == param1 && cell[no].yind-1 == param2)1881corner = BOTRIGHT;1882else if(cell[no].xind == param1 && cell[no].yind == param2)1883corner = TOPRIGHT;1884else if(cell[no].xind-1 == param1 && cell[no].yind == param2)1885corner = TOPLEFT;1886}1887if(corner >= 0) {1888i++;1889no--;1890}18911892if(times) {1893bound->types[i] = pointtype;1894bound->side[i] = 4 + corner;18951896if(corner == BOTLEFT)1897elem = GetElementIndex(&cell[no],1,1);1898else if(corner == BOTRIGHT)1899elem = GetElementIndex(&cell[no],cell[no].xelem,1);1900else if(corner == TOPRIGHT)1901elem = GetElementIndex(&cell[no],cell[no].xelem,cell[no].yelem);1902else if(corner == TOPLEFT)1903elem = GetElementIndex(&cell[no],1,cell[no].yelem);19041905bound->parent[i] = elem;1906node = data->topology[elem][corner];1907if(info) printf("Found node %d at (%.3lg, %.3lg)\n",node,data->x[node],data->y[node]);1908}1909}19101911size = i;1912if(times == 0 && size > 0) {1913AllocateBoundary(bound,size);1914times = 1;1915goto omstart;1916}19171918if(info) printf("Created %d new points of type %d in the corner of materials %d and %d.\n",1919size,pointtype,param1,param2);19201921return(FALSE);1922}1923192419251926int CreateNewNodes(struct FemType *data,int *order,int material,int newknots)1927{1928int i,j,k,l,lmax,ind;1929int newsize,noknots,nonodes;1930int *neworder;1931Real *newx=NULL,*newy=NULL,*newz=NULL;1932Real *newdofs[MAXDOFS];19331934noknots = data->noknots;19351936printf("Creating %d new nodes for discontinuous boundary.\n",newknots);19371938/* Allocate for the new nodes */1939newsize = noknots+newknots;1940newx = Rvector(1,newsize);1941newy = Rvector(1,newsize);1942newz = Rvector(1,newsize);19431944neworder = Ivector(1,newsize);19451946for(j=1;j<MAXDOFS;j++)1947if(data->edofs[j])1948newdofs[j] = Rvector(1,data->edofs[j]*newsize);19491950/* Set the new coordinates and dofs */1951j = 0;1952for(i=1;i<=noknots;i++) {1953j++;1954neworder[j] = i;1955newx[j] = data->x[i];1956newy[j] = data->y[i];1957newz[j] = data->z[i];19581959for(k=1;k<MAXDOFS;k++) {1960if((lmax = data->edofs[k]))1961for(l=1;l<=lmax;l++)1962newdofs[k][lmax*(j-1)+l] = data->dofs[k][lmax*(i-1)+l];1963}19641965if(order[i] < 0) {1966j++;1967neworder[j] = -i;1968newx[j] = data->x[i];1969newy[j] = data->y[i];1970newz[j] = data->z[i];19711972for(k=1;k<MAXDOFS;k++) {1973if((lmax = data->edofs[k]))1974for(l=1;l<=lmax;l++)1975newdofs[k][lmax*(j-1)+l] = data->dofs[k][lmax*(i-1)+l];1976}1977}1978}19791980/* Find the old index corresponding to the new one. */1981for(i=1;i<=newsize;i++)1982if(neworder[i] > 0) {1983if(order[neworder[i]] < 0)1984order[neworder[i]] = -i;1985else1986order[neworder[i]] = i;1987}19881989/* Set the new element topology */1990for(i=1;i<=data->noelements;i++) {1991nonodes = data->elementtypes[i]%100;1992for(j=0;j<nonodes;j++) {1993ind = data->topology[i][j];1994if(data->material[i] == material && order[ind] < 0)1995data->topology[i][j] = abs(order[ind])+1;1996else1997data->topology[i][j] = abs(order[ind]);1998}1999}20002001/* Destroy old vectors and set the pointers to the new vectors. */2002free_Rvector(data->x,1,noknots);2003free_Rvector(data->y,1,noknots);2004free_Rvector(data->z,1,noknots);20052006for(k=1;k<MAXDOFS;k++)2007if(data->edofs[k]) free_Rvector(data->dofs[k],1,noknots);20082009data->noknots = newsize;2010data->x = newx;2011data->y = newy;2012data->z = newz;20132014for(k=1;k<MAXDOFS;k++) {2015if(data->edofs[k]) {2016data->dofs[k] = newdofs[k];2017data->alldofs[k] = data->edofs[k] * data->noknots;2018}2019}20202021return(0);2022}202320242025int SetDiscontinuousBoundary(struct FemType *data,struct BoundaryType *bound,2026int boundtype,int endnodes,int info)2027/* Create secondary points for a given boundary.2028This feature is handy when one wants to solve problems with discontinuous2029field variables.2030*/2031{2032int i,j,bc,ind,sideind[MAXNODESD1];2033int side,parent,newnodes,doublesides,maxtype,newbc;2034int newsuccess,noelements,nonodes,sideelemtype,sidenodes,disconttype;2035int *order=NULL;2036int mat1,mat2,par1,par2,mat1old,mat2old,material;2037static int hitsexist=FALSE,hitslength,*hits=NULL;203820392040if(boundtype < 0) {2041newbc = TRUE;2042boundtype = -boundtype;2043}2044else {2045newbc = FALSE;2046}20472048mat1old = mat2old = 0;2049doublesides = 0;20502051/* Compute the number of duplicate boundary elements */2052for(bc=0;bc<MAXBOUNDARIES;bc++) {20532054if(bound[bc].created == FALSE) continue;2055if(!bound->nosides) continue;20562057for(i=1;i<=bound[bc].nosides;i++) {2058if(bound[bc].types[i] == boundtype) {2059par1 = bound[bc].parent[i];2060par2 = bound[bc].parent2[i];2061if(par1 && par2) {2062doublesides++;2063mat1 = data->material[par1];2064mat2 = data->material[par2];2065if(!mat1old) mat1old = mat1;2066else if(mat1old != mat1) mat1old = -mat1;2067if(!mat2old) mat2old = mat2;2068else if(mat2old != mat2) mat2old = -mat2;2069}2070}2071}2072}20732074if(!doublesides) return(1);20752076if( mat1old > 0 && mat2old > 0 )2077material = MIN( mat1old, mat2old );2078else if(mat1old > 0)2079material = mat1old;2080else if(mat2old > 0)2081material = mat2old;2082else {2083printf("SetDiscontinuousBoundary: impossible to make the boundary of several materials\n");2084return(2);2085}20862087if(info) {2088printf("Creating discontinuous boundary between materials %d and %d\n",mat1old,mat2old);2089printf("New set of nodes will be created for material %d\n",material);2090}209120922093noelements = data->noelements;2094order = Ivector(1,data->noknots);2095for(i=1;i<=data->noknots;i++)2096order[i] = i;20972098/* Compute the endnodes by the fact that they have different number of2099hits */2100if(endnodes == 1) {2101if(!hitsexist) {2102hitslength = 1.1*data->noknots;2103hits = Ivector(1,hitslength);2104hitsexist = TRUE;2105}2106else if(hitslength <= data->noknots) {2107free_Ivector(hits,1,hitslength);2108hitslength = 1.1*data->noknots;2109hits = Ivector(1,hitslength);2110}21112112for(i=1;i<=data->noknots;i++)2113hits[i] = 0;21142115for(j=1;j<=noelements;j++) {2116nonodes = data->elementtypes[j]%100;2117for(i=0;i<nonodes;i++)2118hits[data->topology[j][i]] += 1;2119}2120}21212122/* If requested create a secondary boundary at the other side */2123if(newbc) {2124maxtype = 0;2125for(bc=0;bc<MAXBOUNDARIES;bc++) {2126for(i=1;i<=bound[bc].nosides;i++) {2127maxtype = MAX(maxtype, bound[bc].types[i]);2128if(bound[bc].ediscont) maxtype = MAX(maxtype, bound[bc].discont[i]);2129}2130}2131disconttype = maxtype + 1;2132if(info) printf("Type of the other side of discontinuous boundary set to %d.\n",disconttype);2133}2134else {2135disconttype = boundtype;2136}2137213821392140/* Find the number of new nodes */2141newnodes = 0;21422143for(bc=0;bc<MAXBOUNDARIES;bc++) {21442145for(i=1;i<=bound[bc].nosides;i++) {21462147if(bound[bc].types[i] != boundtype) continue;21482149if(!bound[bc].ediscont) {2150bound[bc].discont = Ivector(1,bound[bc].nosides);2151for(j=1;j<=bound[bc].nosides;j++)2152bound[bc].discont[j] = 0;2153bound[bc].ediscont = TRUE;2154}21552156parent = bound[bc].parent2[i];2157if(parent == 0) continue;2158side = bound[bc].side2[i];2159GetElementSide(parent,side,1,data,sideind,&sideelemtype);2160sidenodes = sideelemtype%100;21612162bound[bc].discont[i] = disconttype;21632164for(j=0;j<sidenodes;j++) {2165ind = abs(sideind[j]);21662167if(endnodes == 2) {2168if(order[ind] > 0) {2169newnodes++;2170order[ind] = -newnodes;2171}2172}2173else if(endnodes == 0) {2174if(order[ind] > 0)2175order[ind] = 0;2176else if(order[ind] == 0) {2177newnodes++;2178order[ind] = -newnodes;2179}2180}2181else if(endnodes == 1) {2182if(order[ind] > 0) {2183if(hits[ind] < 4) {2184newnodes++;2185order[ind] = -newnodes;2186}2187else2188order[ind] = 0;2189}2190else if(order[ind] == 0) {2191newnodes++;2192order[ind] = -newnodes;2193}2194}21952196}2197}21982199if(endnodes == 0 || endnodes == 1) {2200for(i=1;i<=data->noknots;i++)2201if(order[i] == 0)2202order[i] = i;2203}2204}22052206if(newnodes == 0) return(3);22072208newsuccess = CreateNewNodes(data,order,material,newnodes);2209return(newsuccess);2210}2211221222132214int FindPeriodicBoundary(struct FemType *data,struct BoundaryType *bound,2215int boundary1,int boundary2,int info)2216/* Create periodic boundary conditions for a given boundary pair2217boundary1, boundary2.2218*/2219{2220int i,j,k,l;2221int parent,elemtype;2222int minp[2],maxp[2],bounds[2],dp[2],sumsides[2];22232224if(bound->created == FALSE) {2225printf("SetDiscontinuousBoundary: The boundary does not exist!\n");2226return(1);2227}2228if(!bound->nosides) return(0);222922302231bounds[0] = boundary1;2232bounds[1] = boundary2;2233minp[0] = minp[1] = data->noknots+1;2234maxp[0] = maxp[1] = 0;22352236sumsides[0] = sumsides[1] = 0;2237for(j=0;j < MAXBOUNDARIES;j++) {2238if(bound->created == FALSE) continue;22392240for(i=1; i <= bound[j].nosides; i++) {22412242for(k=0;k<=1;k++) {2243if(bound[j].types[i] == bounds[k]) {22442245sumsides[k] += 1;2246if(bound[j].parent[i] > maxp[k]) maxp[k] = bound[j].parent[i];2247if(bound[j].parent[i] < minp[k]) minp[k] = bound[j].parent[i];2248}2249}2250}2251}22522253for (k=0;k<=1;k++) {2254dp[k] = maxp[k] - minp[k];2255if(info) printf("Parents of boundary %d are on the interval [%d, %d]\n",2256bounds[k],minp[k],maxp[k]);2257}22582259if(dp[0] != dp[1] || sumsides[0] != sumsides[1]) {2260printf("FindPeriodicBoundary: The simple scheme cannot handle these boundaries!\n");2261printf("dp=[%d %d] sumsides=[%d %d]\n",dp[0],dp[1],sumsides[0],sumsides[1]);2262return(1);2263}22642265for(j=0;j < MAXBOUNDARIES;j++) {2266if(bound->created == FALSE) continue;22672268for(i=1; i <= bound[j].nosides; i++) {22692270for(k=0;k<=1;k++) {2271if(bound[j].types[i] == bounds[k]) {2272parent = bound[j].parent[i];2273bound[j].parent2[i] = bound[j].parent[i] - minp[k] + minp[(k+1)%2];22742275if(!bound[j].ediscont) {2276bound[j].discont = Ivector(1,bound[j].nosides);2277for(l=1; l <= bound[j].nosides; l++)2278bound[j].discont[l] = 0;2279bound[j].ediscont = TRUE;2280}22812282bound[j].discont[i] = 2+k;2283elemtype = data->elementtypes[parent];2284if(elemtype%100 == 4) {2285bound[j].side2[i] = (bound[j].side[i] + 2) % 4;2286}2287else if(elemtype%100 == 8) {2288if(bound[j].side[i] < 4) bound[j].side2[i] = (bound[j].side[i] + 2) % 4;2289if(bound[j].side[i] >= 4) bound[j].side2[i] = 4 + (5 - bound[j].side[i]);2290}2291}2292}2293}2294}22952296if(info) printf("Periodic boundaries were set with a simple scheme\n");22972298return(2);2299}2300230123022303int SetConnectedNodes(struct FemType *data,struct BoundaryType *bound,2304int bctype,int connecttype,int info)2305/* Mark node that are related to a boundary condition of a given bctype.2306This may be used to create strong connections in the partitioning process. */2307{2308int i,j,k,bc,sideelemtype,sidenodes,nodesset;2309int sideind[MAXNODESD1],conflicts;23102311conflicts = 0;2312nodesset = 0;23132314for(bc=0;bc<MAXBOUNDARIES;bc++) {2315if(bound[bc].created == FALSE) continue;2316if(bound[bc].nosides == 0) continue;23172318for(i=1;i<=bound[bc].nosides;i++) {2319if( bctype > 0 ) {2320if(bound[bc].types[i] != bctype) continue;2321}2322else if( bctype == -1 ) {2323if( !bound[bc].parent[i] ) continue;2324}2325else if( bctype == -2 ) {2326if( !bound[bc].parent[i] ) continue;2327if( !bound[bc].parent2[i] ) continue;2328}2329else if( bctype == -3 ) {2330if( !bound[bc].parent[i] ) continue;2331if( bound[bc].parent2[i] ) continue;2332}23332334/* If the table pointing the connected nodes does not exist, create it */2335if(!data->nodeconnectexist) {2336data->nodeconnect = Ivector(1,data->noknots);2337for(k=1;k<=data->noknots;k++)2338data->nodeconnect[k] = 0;2339data->nodeconnectexist = TRUE;2340}23412342GetElementSide(bound[bc].parent[i],bound[bc].side[i],bound[bc].normal[i],2343data,sideind,&sideelemtype);2344sidenodes = sideelemtype%100;23452346for(j=0;j<sidenodes;j++) {2347k = sideind[j];2348if( data->nodeconnect[k] != connecttype ) {2349if( data->nodeconnect[k] ) conflicts += 1;2350data->nodeconnect[k] = connecttype;2351nodesset += 1;2352}2353}2354}2355}2356if(info) printf("Setting connectivity group %d for %d nodes on boundary %d\n",2357connecttype,nodesset,bctype);23582359if(conflicts) printf("The were %d conflicts in the connectivity set %d\n",2360conflicts,connecttype);23612362return(0);2363}236423652366int SetConnectedElements(struct FemType *data,int info)2367/* Create connected boundary conditions for a given bctype */2368{2369int i,j,k,nonodes,hit,nohits,con;2370int *nodeconnect;23712372if(!data->nodeconnectexist) {2373printf("Cannot create connected elements without connected nodes!\n");2374return(1);2375}2376nodeconnect = data->nodeconnect;23772378/* Allocated space for the connected elements */2379if(!data->elemconnectexist) {2380printf("Created table for connected elements\n");2381data->elemconnect = Ivector(1,data->noelements);2382for(k=1;k<=data->noelements;k++)2383data->elemconnect[k] = 0;2384data->elemconnectexist = TRUE;23852386/* Go through all the elements and check which of the elements have2387nodes that are related to a connected node */2388nohits = 0;2389for(i=1;i<=data->noelements;i++) {2390nonodes = data->elementtypes[i] % 100;2391hit = FALSE;2392for(j=0;j<nonodes;j++) {2393k = data->topology[i][j];2394con = nodeconnect[k];2395if( con ) {2396data->elemconnect[i] = MAX( con, data->elemconnect[i] );2397hit = TRUE;2398}2399}2400if(hit) nohits++;2401}24022403if(info) printf("Number of connected elements is %d (out of %d)\n",nohits,data->noelements);2404data->elemconnectexist = nohits;2405}24062407/* This is a little bit dirty. We set the connections to negative and use the unconnected2408as a permutation. */2409if( data->elemconnectexist ) {2410if(info) printf("Use connected table as a permutation for creating dual graph!\n");2411j = 0;2412for(i=1;i<=data->noelements;i++) {2413if( data->elemconnect[i] ) {2414data->elemconnect[i] = -abs(data->elemconnect[i]);2415}2416else {2417j++;2418data->elemconnect[i] = j;2419}2420}2421}24222423return(0);2424}2425242624272428int FindCorners(struct GridType *grid,struct CellType *cell,2429struct FemType *data,int info)2430/* Find the nodes in the mesh that are at material corners.2431These nodes are often of special interest.2432*/2433{2434int i,j,k,ind,cellno,elem;2435int allocated,nocorners;24362437nocorners = 0;2438allocated = FALSE;24392440omstart:24412442if(nocorners > 0) {2443data->corners = Ivector(1,2*nocorners);2444data->nocorners = nocorners;2445allocated = TRUE;2446}24472448k = 0;24492450for(i=1;i<=grid->xcells+1;i++)2451for(j=1;j<=grid->ycells+1;j++) {2452if(grid->structure[j][i] == grid->structure[j][i-1] &&2453grid->structure[j-1][i] == grid->structure[j-1][i-1])2454continue;2455if(grid->structure[j][i] == grid->structure[j-1][i] &&2456grid->structure[j][i-1] == grid->structure[j-1][i-1])2457continue;24582459/* point (i,j) must now be a corner */2460if((cellno = grid->numbered[j][i])) {2461elem = GetElementIndex(&(cell)[cellno],1,1);2462ind = BOTLEFT;2463}2464else if((cellno = grid->numbered[j][i-1])) {2465elem = GetElementIndex(&(cell)[cellno],cell[cellno].xelem,1);2466ind = BOTRIGHT;2467}2468else if((cellno = grid->numbered[j-1][i])) {2469elem = GetElementIndex(&(cell)[cellno],1,cell[cellno].yelem);2470ind = TOPLEFT;2471}2472else if((cellno = grid->numbered[j-1][i-1])) {2473elem = GetElementIndex(&(cell)[cellno],cell[cellno].xelem,cell[cellno].yelem);2474ind = TOPRIGHT;2475}2476else continue;24772478/* ind is now the index of the corner knot */2479k++;24802481if(allocated == FALSE) continue;2482data->corners[2*k-1] = elem;2483data->corners[2*k] = ind;24842485}24862487nocorners = k;24882489if(nocorners == 0) return(0);2490if(allocated == FALSE) goto omstart;24912492if(info) printf("Found %d material corners.\n",nocorners);2493return(0);2494}2495249624972498int ElementsToTriangles(struct FemType *data,struct BoundaryType *bound,2499Real critangle,int info)2500/* Make triangles out of rectangular elements */2501{2502int i,j,k,l,side,elem,i1,isum,sideelemtype;2503int noelements,elementtype,triangles,noknots,nonodes,newelements,newtype,newmaxnodes;2504int **newtopo=NULL,*newmaterial=NULL,*newelementtypes=NULL;2505int newnodes,*needed=NULL,*divisions=NULL,*division1=NULL;2506int sideind[MAXNODESD1], sideind2[MAXNODESD1];2507int allocated,maxanglej,evenodd,newelem;2508Real dx1,dx2,dy1,dy2,ds1,ds2;2509Real angles[4],maxangle;2510struct FemType data2;25112512noelements = data->noelements;2513noknots = data->noknots;2514allocated = FALSE;25152516needed = Ivector(1,noknots);2517for(i=1;i<=noknots;i++)2518needed[i] = 0;2519for(i=1;i<=noelements;i++) {2520nonodes = data->elementtypes[i] / 100;2521for(j=0;j<nonodes;j++)2522needed[data->topology[i][j]] += 1;2523}25242525divisions = Ivector(1,noelements);2526division1 = Ivector(1,noelements);2527for(i=1;i<=noelements;i++)2528divisions[i] = division1[i] = 0;25292530/* First divide the elements along the shorter diameter */25312532newelements = 0;2533newmaxnodes = 0;25342535omstart:25362537for(i=1;i<=noelements;i++) {25382539elementtype = data->elementtypes[i];25402541/* compute the four angles and divide the rectangle so that the largest angle is split */2542maxangle = 0.0;2543maxanglej = 0;2544for(j=0;j<4;j++) {2545dx1 = data->x[data->topology[i][(j+3)%4]] - data->x[data->topology[i][j]];2546dy1 = data->y[data->topology[i][(j+3)%4]] - data->y[data->topology[i][j]];2547dx2 = data->x[data->topology[i][(j+1)%4]] - data->x[data->topology[i][j]];2548dy2 = data->y[data->topology[i][(j+1)%4]] - data->y[data->topology[i][j]];2549ds1 = sqrt(dx1*dx1+dy1*dy1);2550ds2 = sqrt(dx2*dx2+dy2*dy2);2551angles[j] = (180.0/FM_PI) * acos((dx1*dx2+dy1*dy2)/(ds1*ds2));25522553/* Slightly favor divisions where corner is split */2554if(needed[data->topology[i][j]] == 1) angles[j] *= 1.001;25552556if( abs(angles[j] > maxangle)) {2557maxangle = abs(angles[j]);2558maxanglej = j;2559}2560}2561evenodd = maxanglej % 2;256225632564/* No triangularization is performed unless the critical angle is exceeded. */2565if( maxangle < critangle ) {2566triangles = 1;2567newtype = elementtype;2568newnodes = elementtype % 100;2569}2570else {2571switch(elementtype) {2572case 404:2573newtype = 303;2574newnodes = 3;2575triangles = 2;2576break;2577case 405:2578newtype = 303;2579newnodes = 3;2580triangles = 4;2581break;2582case 409:2583newtype = 306;2584newnodes = 6;2585triangles = 2;2586break;2587case 416:2588newtype = 310;2589newnodes = 10;2590triangles = 2;2591break;2592default:2593printf("ElementsToTriangles: not implemented for elementtype %d\n",elementtype);2594return(1);2595}2596}25972598newmaxnodes = MAX( newnodes, newmaxnodes );259926002601if(!allocated) {2602divisions[i] = triangles;2603division1[i] = newelements;2604newelements += triangles;2605continue;2606}26072608for(j=division1[i]+1;j<=division1[i]+divisions[i];j++) {2609newelementtypes[j] = newtype;2610newmaterial[j] = data->material[i];2611}26122613newelem = division1[i]+1;2614if(triangles == 1) {2615for(j=0;j<newnodes;j++)2616newtopo[newelem][j] = data->topology[i][j];2617}2618else {2619if(elementtype == 404 || elementtype == 409 || elementtype == 416) {2620if(evenodd) {2621newtopo[newelem][0] = data->topology[i][0];2622newtopo[newelem][1] = data->topology[i][1];2623newtopo[newelem][2] = data->topology[i][3];2624newtopo[newelem+1][0] = data->topology[i][2];2625newtopo[newelem+1][1] = data->topology[i][3];2626newtopo[newelem+1][2] = data->topology[i][1];2627}2628else {2629newtopo[newelem][0] = data->topology[i][1];2630newtopo[newelem][1] = data->topology[i][2];2631newtopo[newelem][2] = data->topology[i][0];2632newtopo[newelem+1][0] = data->topology[i][3];2633newtopo[newelem+1][1] = data->topology[i][0];2634newtopo[newelem+1][2] = data->topology[i][2];2635}2636}2637if(elementtype == 409) {2638if(evenodd) {2639newtopo[newelem][3] = data->topology[i][4];2640newtopo[newelem][4] = data->topology[i][8];2641newtopo[newelem][5] = data->topology[i][7];2642newtopo[newelem+1][3] = data->topology[i][6];2643newtopo[newelem+1][4] = data->topology[i][8];2644newtopo[newelem+1][5] = data->topology[i][5];2645}2646else {2647newtopo[newelem][3] = data->topology[i][5];2648newtopo[newelem][4] = data->topology[i][8];2649newtopo[newelem][5] = data->topology[i][4];2650newtopo[newelem+1][3] = data->topology[i][7];2651newtopo[newelem+1][4] = data->topology[i][8];2652newtopo[newelem+1][5] = data->topology[i][6];2653}2654}2655if(elementtype == 416) {2656if(evenodd) {2657newtopo[newelem][3] = data->topology[i][4];2658newtopo[newelem][4] = data->topology[i][5];2659newtopo[newelem][5] = data->topology[i][13];2660newtopo[newelem][6] = data->topology[i][15];2661newtopo[newelem][7] = data->topology[i][10];2662newtopo[newelem][8] = data->topology[i][11];2663newtopo[newelem][9] = data->topology[i][12];26642665newtopo[newelem+1][3] = data->topology[i][8];2666newtopo[newelem+1][4] = data->topology[i][9];2667newtopo[newelem+1][5] = data->topology[i][15];2668newtopo[newelem+1][6] = data->topology[i][13];2669newtopo[newelem+1][7] = data->topology[i][6];2670newtopo[newelem+1][8] = data->topology[i][7];2671newtopo[newelem+1][9] = data->topology[i][14];2672}2673else {2674newtopo[newelem][3] = data->topology[i][6];2675newtopo[newelem][4] = data->topology[i][7];2676newtopo[newelem][5] = data->topology[i][14];2677newtopo[newelem][6] = data->topology[i][12];2678newtopo[newelem][7] = data->topology[i][4];2679newtopo[newelem][8] = data->topology[i][5];2680newtopo[newelem][9] = data->topology[i][13];26812682newtopo[newelem+1][3] = data->topology[i][10];2683newtopo[newelem+1][4] = data->topology[i][11];2684newtopo[newelem+1][5] = data->topology[i][12];2685newtopo[newelem+1][6] = data->topology[i][14];2686newtopo[newelem+1][7] = data->topology[i][8];2687newtopo[newelem+1][8] = data->topology[i][9];2688newtopo[newelem+1][9] = data->topology[i][15];2689}2690}2691else if(elementtype == 405) {2692newtopo[newelem][0] = data->topology[i][0];2693newtopo[newelem][1] = data->topology[i][1];2694newtopo[newelem][2] = data->topology[i][4];2695newtopo[newelem+1][0] = data->topology[i][1];2696newtopo[newelem+1][1] = data->topology[i][2];2697newtopo[newelem+1][2] = data->topology[i][4];2698newtopo[newelem+2][0] = data->topology[i][2];2699newtopo[newelem+2][1] = data->topology[i][3];2700newtopo[newelem+2][2] = data->topology[i][4];2701newtopo[newelem+3][0] = data->topology[i][3];2702newtopo[newelem+3][1] = data->topology[i][0];2703newtopo[newelem+3][2] = data->topology[i][4];2704}2705}2706}270727082709if(!allocated) {27102711newtopo = Imatrix(1,newelements,0,newmaxnodes-1);2712newmaterial = Ivector(1,newelements);2713newelementtypes = Ivector(1,newelements);2714allocated = TRUE;27152716data2 = *data;2717data2.topology = newtopo;2718data2.material = newmaterial;2719data2.elementtypes = newelementtypes;27202721goto omstart;2722}272327242725/* Then make the corresponding mapping for the BCs.2726This is done in a brute-force way where all the2727possible new elements are checked. */27282729for(j=0;j < MAXBOUNDARIES;j++) {2730if(!bound[j].created) continue;27312732for(i=1; i <= bound[j].nosides; i++) {27332734for(l=1;l<=2;l++) {27352736if(l==1)2737k = bound[j].parent[i];2738else2739k = bound[j].parent2[i];2740if(k == 0) continue;274127422743if(l == 1)2744GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],2745data,sideind,&sideelemtype);2746else2747GetElementSide(bound[j].parent2[i],bound[j].side2[i],bound[j].normal[i],2748data,sideind,&sideelemtype);27492750if(sideelemtype/100 != 2) {2751printf("ElementsToTriangles: implemented only for BCs 202 and 203\n");2752continue;2753}27542755isum = 0;2756side = 0;2757if(divisions[k] == 1) {2758elem = division1[k]+1;2759side = bound[j].side[i];2760isum = 2;2761goto nextparent;2762}27632764/* Test for all possible elements that could be parents */2765for(elem=division1[k]+1;elem<=division1[k]+divisions[k];elem++) {2766isum = 0;2767for(i1=0;i1<3;i1++) {2768if(newtopo[elem][i1] == sideind[0]) isum++;2769if(newtopo[elem][i1] == sideind[1]) isum++;2770}27712772if(isum != 2) continue;27732774for(side=0;side<3;side++) {2775GetElementSide(elem,side,bound[j].normal[i],2776&data2,sideind2,&sideelemtype);2777isum = 0;2778for(i1=0;i1<2;i1++) {2779if(sideind2[i1] == sideind[0]) isum++;2780if(sideind2[i1] == sideind[1]) isum++;2781}27822783if(isum == 2) goto nextparent;2784}2785}27862787nextparent:2788if(isum == 2) {2789if(l == 1) {2790bound[j].parent[i] = elem;2791bound[j].side[i] = side;2792}2793if(l == 2) {2794bound[j].parent2[i] = elem;2795bound[j].side2[i] = side;2796}2797}2798else {2799printf("Failed to find parent for side %d of %d (parent %d)\n",i,j,k);2800}2801}2802}2803}280428052806free_Imatrix(data->topology,1,noelements,0,data->maxnodes-1);2807free_Ivector(data->material,1,noelements);2808free_Ivector(data->elementtypes,1,noelements);2809free_Ivector(needed,1,noknots);2810free_Ivector(divisions,1,noelements);2811free_Ivector(division1,1,noelements);28122813data->topology = newtopo;2814data->elementtypes = newelementtypes;2815data->material = newmaterial;2816data->noelements = newelements;2817data->maxnodes = newmaxnodes;28182819if(info) printf("There are %d elements after triangularization (was %d)\n",2820newelements,noelements);28212822return(0);2823}282428252826int PolarCoordinates(struct FemType *data,Real rad,int info)2827{2828int i;2829Real fii,zet,dr;28302831for(i=1;i<=data->noknots;i++) {2832zet = data->x[i];2833fii = FM_PI/180.0 * data->y[i];2834dr = data->z[i];28352836data->z[i] = zet;2837data->x[i] = (rad+dr) * cos(fii);2838data->y[i] = (rad+dr) * sin(fii);2839}28402841if(info) printf("Making coordinate transformation from polar to cartesian\n");28422843return(0);2844}284528462847int CylinderCoordinates(struct FemType *data,int info)2848{2849int i;2850Real x,y,z,rad,fii;28512852if( data->dim == 3 ) {2853for(i=1;i<=data->noknots;i++) {2854x = data->x[i];2855y = data->y[i];2856fii = FM_PI/180.0 * data->z[i];2857rad = data->x[i];28582859data->x[i] = rad * cos(fii);2860data->y[i] = rad * sin(fii);2861data->z[i] = y;2862}2863}2864else {2865for(i=1;i<=data->noknots;i++) {2866rad = data->x[i];2867fii = FM_PI/180.0 * data->y[i];28682869data->x[i] = rad * cos(fii);2870data->y[i] = rad * sin(fii);2871}2872}28732874if(info) printf("Making coordinate transformation from cylindrical to cartesian\n");28752876return(0);2877}287828792880int UniteMeshes(struct FemType *data1,struct FemType *data2,2881struct BoundaryType *bound1,struct BoundaryType *bound2,2882int nooverlap, int info)2883/* Unites two meshes for one larger mesh */2884{2885int i,j,k;2886int noelements,noknots,nonodes,maxnodes;2887int **newtopo=NULL,*newmaterial=NULL,*newelementtypes=NULL;2888Real *newx=NULL,*newy=NULL,*newz=NULL;2889int mat,usenames,*bodynameis,*boundarynameis,*bodyused,*boundaryused;2890int bcmax1,bcmin2,bcoffset;2891int bodymax1,bodymin2,bodyoffset;28922893noknots = data1->noknots + data2->noknots;2894noelements = data1->noelements + data2->noelements;2895maxnodes = MAX(data1->maxnodes,data2->maxnodes);28962897if(data2->dim > data1->dim) data1->dim = data2->dim;28982899if(0) printf("Uniting two meshes to %d nodes and %d elements.\n",noknots,noelements);29002901usenames = data1->bodynamesexist || data1->boundarynamesexist;2902bcoffset = 0; bodyoffset = 0;29032904if( usenames ) {2905bodynameis = Ivector(1,MAXBODIES);2906boundarynameis = Ivector(1,MAXBCS);2907bodyused = Ivector(1,MAXBODIES);2908boundaryused = Ivector(1,MAXBCS);29092910for(i=1;i<=MAXBODIES;i++)2911bodynameis[i] = bodyused[i] = FALSE;2912for(i=1;i<=MAXBCS;i++)2913boundarynameis[i] = boundaryused[i] = FALSE;29142915/* First mark the original bodies and boundaries that maintain their index */2916for(i=1;i<=data1->noelements;i++) {2917mat = data1->material[i];2918if( mat < MAXBODIES ) {2919if(!bodynameis[mat]) {2920bodynameis[mat] = -1;2921bodyused[mat] = TRUE;2922}2923}2924}29252926for(j=0;j < MAXBOUNDARIES;j++) {2927if(!bound1[j].created) continue;2928for(i=1; i <= bound1[k].nosides; i++) {2929mat = bound1[j].types[i];2930if( mat < MAXBCS ) {2931if(!boundarynameis[mat]) {2932boundarynameis[mat] = -1;2933boundaryused[mat] = TRUE;2934}2935}2936}2937}29382939/* Then mark the joined bodies and boundaries that are not conflicting */2940for(i=1;i<=data2->noelements;i++) {2941mat = data2->material[i];2942if( mat < MAXBODIES ) {2943if( !bodynameis[mat] ) {2944bodynameis[mat] = mat;2945bodyused[mat] = TRUE;2946if(!data1->bodyname[mat]) data1->bodyname[mat] = Cvector(0,MAXNAMESIZE);2947strcpy(data1->bodyname[mat],data2->bodyname[mat]);2948}2949}2950}29512952for(j=0;j < MAXBOUNDARIES;j++) {2953if(!bound2[j].created) continue;29542955for(i=1; i <= bound2[j].nosides; i++) {2956mat = bound2[j].types[i];2957if( mat < MAXBCS ) {2958if( !boundarynameis[mat] ) {2959boundarynameis[mat] = mat;2960boundaryused[mat] = TRUE;2961if(!data1->boundaryname[mat]) data1->boundaryname[mat] = Cvector(0,MAXNAMESIZE);2962strcpy(data1->boundaryname[mat],data2->boundaryname[mat]);2963}2964}2965}2966}296729682969/* And finally number the conflicting joined bodies and BCs */2970for(i=1;i<=data2->noelements;i++) {2971mat = data2->material[i];2972if( mat < MAXBODIES ) {2973if( bodynameis[mat] == -1) {2974for(k=1;k<MAXBODIES;k++)2975if(!bodyused[k]) break;2976if(info) printf("Renumbering body %d to %d\n",mat,k);2977bodynameis[mat] = k;2978bodyused[k] = TRUE;2979if(!data1->bodyname[k]) data1->bodyname[k] = Cvector(0,MAXNAMESIZE);2980strcpy(data1->bodyname[k],data2->bodyname[mat]);2981}2982}2983}29842985for(j=0;j < MAXBOUNDARIES;j++) {2986if(!bound2[j].created) continue;2987for(i=1; i <= bound2[j].nosides; i++) {2988mat = bound2[j].types[i];29892990if( mat < MAXBCS ) {2991if( boundarynameis[mat] == -1) {2992for(k=1;k<MAXBCS;k++)2993if(!boundaryused[k]) break;2994if(info) printf("Renumbering boundary %d to %d\n",mat,k);2995boundarynameis[mat] = k;2996boundaryused[k] = TRUE;2997if(!data1->boundaryname[k]) data1->boundaryname[k] = Cvector(0,MAXNAMESIZE);2998strcpy(data1->boundaryname[k],data2->boundaryname[mat]);2999}3000}3001}3002}30033004}3005else if (nooverlap ) {3006bcmax1 = 0;3007for(j=0;j < MAXBOUNDARIES;j++) {3008if(!bound1[j].created) continue;3009for(i=1; i <= bound1[k].nosides; i++) {3010mat = bound1[j].types[i];3011bcmax1 = MAX( bcmax1, mat );3012}3013}30143015bcmin2 = 1000;3016for(j=0;j < MAXBOUNDARIES;j++) {3017if(!bound2[j].created) continue;30183019for(i=1; i <= bound2[j].nosides; i++) {3020mat = bound2[j].types[i];3021bcmin2 = MIN( bcmin2, mat );3022}3023}3024bcoffset = MAX(0, bcmax1 - bcmin2 + 1);3025if( info ) {3026printf("Max(bc1) is %d and Min(bc2) is %d, using BC offset %d for mesh 2!\n",bcmax1,bcmin2,bcoffset);3027}30283029bodymax1 = 0;3030for(i=1;i<=data1->noelements;i++) {3031mat = data1->material[i];3032bodymax1 = MAX( bodymax1, mat );3033}30343035bodymin2 = 1000;3036for(i=1;i<=data2->noelements;i++) {3037mat = data2->material[i];3038bodymin2 = MIN( bodymin2, mat );3039}3040bodyoffset = MAX(0, bodymax1 - bodymin2 + 1);3041if( info ) {3042printf("Max(body1) is %d and Min(body2) is %d, using body offset %d for mesh 2!\n",bodymax1,bodymin2,bodyoffset);3043}3044}3045304630473048for(j=0;j < MAXBOUNDARIES;j++) {3049if(!bound2[j].created) continue;30503051for(k=j;k < MAXBOUNDARIES;k++)3052if(!bound1[k].created) break;30533054bound1[k].created = bound2[j].created;3055bound1[k].nosides = bound2[j].nosides;3056bound1[k].coordsystem = bound2[j].coordsystem;3057bound1[k].side = bound2[j].side;3058bound1[k].side2 = bound2[j].side2;3059bound1[k].parent = bound2[j].parent;3060bound1[k].parent2 = bound2[j].parent2;3061bound1[k].material = bound2[j].material;3062bound1[k].echain = bound2[j].echain;3063bound1[k].types = bound2[j].types;3064bound1[k].normal = bound2[j].normal;30653066for(i=1; i <= bound1[k].nosides; i++) {3067bound1[k].parent[i] += data1->noelements;3068if(bound1[k].parent2[i])3069bound1[k].parent2[i] += data1->noelements;30703071mat = bound2[j].types[i];3072if( usenames ) {3073if( mat < MAXBCS ) {3074bound1[k].types[i] = boundarynameis[mat];3075}3076} else {3077bound1[k].types[i] = bcoffset + mat;3078}3079}3080}30813082data1->maxnodes = maxnodes;3083newtopo = Imatrix(1,noelements,0,maxnodes-1);3084newmaterial = Ivector(1,noelements);3085newelementtypes = Ivector(1,noelements);3086newx = Rvector(1,noknots);3087newy = Rvector(1,noknots);3088newz = Rvector(1,noknots);30893090for(i=1;i<=data1->noknots;i++) {3091newx[i] = data1->x[i];3092newy[i] = data1->y[i];3093newz[i] = data1->z[i];3094}3095for(i=1;i<=data2->noknots;i++) {3096newx[i+data1->noknots] = data2->x[i];3097newy[i+data1->noknots] = data2->y[i];3098newz[i+data1->noknots] = data2->z[i];3099}31003101for(i=1;i<=data1->noelements;i++) {3102mat = data1->material[i];3103newmaterial[i] = mat;3104newelementtypes[i] = data1->elementtypes[i];3105nonodes = newelementtypes[i]%100;3106for(j=0;j<nonodes;j++)3107newtopo[i][j] = data1->topology[i][j];3108}3109for(i=1;i<=data2->noelements;i++) {3110mat = data2->material[i];3111newelementtypes[i+data1->noelements] = data2->elementtypes[i];3112nonodes = newelementtypes[i+data1->noelements]%100;3113for(j=0;j<nonodes;j++)3114newtopo[i+data1->noelements][j] = data2->topology[i][j] + data1->noknots;31153116if( usenames ) {3117if( mat < MAXBODIES ) {3118newmaterial[i+data1->noelements] = bodynameis[mat];3119}3120}3121else {3122newmaterial[i+data1->noelements] = bodyoffset + mat;3123}3124}31253126free_Imatrix(data1->topology,1,data1->noelements,0,data1->maxnodes-1);3127free_Ivector(data1->material,1,data1->noelements);3128free_Rvector(data1->x,1,data1->noknots);3129free_Rvector(data1->y,1,data1->noknots);3130free_Rvector(data1->z,1,data1->noknots);31313132free_Imatrix(data2->topology,1,data2->noelements,0,data2->maxnodes-1);3133free_Ivector(data2->material,1,data2->noelements);3134free_Rvector(data2->x,1,data2->noknots);3135free_Rvector(data2->y,1,data2->noknots);3136free_Rvector(data2->z,1,data2->noknots);31373138data1->noelements = noelements;3139data1->noknots = noknots;3140data1->topology = newtopo;3141data1->material = newmaterial;3142data1->elementtypes = newelementtypes;3143data1->x = newx;3144data1->y = newy;3145data1->z = newz;31463147if(info) printf("Two meshes were united to one with %d nodes and %d elements.\n",3148noknots,noelements);31493150return(0);3151}315231533154int CloneMeshes(struct FemType *data,struct BoundaryType *bound,3155int *ncopies,Real *meshsize,int diffmats,int info)3156/* Unites two meshes for one larger mesh */3157{3158int i,j,k,l,m;3159int noelements,noknots,nonodes,totcopies,ind,origdim;3160int **newtopo=NULL,*newmaterial=NULL,*newelementtypes=NULL,maxnodes;3161int maxmaterial,maxtype,ncopy,bndr,nosides;3162Real *newx=NULL,*newy=NULL,*newz=NULL;3163Real maxcoord[3],mincoord[3];31643165int *vparent=NULL,*vparent2=NULL,*vside=NULL,*vside2=NULL;3166int *vtypes=NULL,*vmaterial=NULL,*vnormal=NULL,*vdiscont=NULL;31673168if(info) printf("CloneMeshes: copying the mesh to a matrix\n");3169if(diffmats) {3170if(info) printf("CloneMeshes: giving each new entity new material and bc indexes\n");3171}31723173origdim = data->dim;3174totcopies = 1;3175if( ncopies[2] > 1 ) {3176data->dim = 3;3177}3178else {3179ncopies[2] = 1;3180}31813182for(i=0;i<data->dim;i++) {3183if(ncopies[i] > 1) totcopies *= ncopies[i];3184}31853186maxcoord[0] = mincoord[0] = data->x[1];3187maxcoord[1] = mincoord[1] = data->y[1];3188maxcoord[2] = mincoord[2] = data->z[1];31893190for(i=1;i<=data->noknots;i++) {3191if(data->x[i] > maxcoord[0]) maxcoord[0] = data->x[i];3192if(data->x[i] < mincoord[0]) mincoord[0] = data->x[i];3193if(data->y[i] > maxcoord[1]) maxcoord[1] = data->y[i];3194if(data->y[i] < mincoord[1]) mincoord[1] = data->y[i];3195if(data->z[i] > maxcoord[2]) maxcoord[2] = data->z[i];3196if(data->z[i] < mincoord[2]) mincoord[2] = data->z[i];3197}31983199for(i=0;i<origdim;i++) {3200if(maxcoord[i]-mincoord[i] > meshsize[i]) meshsize[i] = maxcoord[i]-mincoord[i];3201}3202if(info) printf("Meshsize to be copied: %lg %lg %lg\n",meshsize[0],meshsize[1],meshsize[2]);32033204noknots = totcopies * data->noknots;3205noelements = totcopies * data->noelements;3206maxnodes = data->maxnodes;32073208if(info) printf("Copying the mesh to %d identical domains in %d-dim.\n",totcopies,data->dim);32093210data->maxnodes = maxnodes;3211newtopo = Imatrix(1,noelements,0,maxnodes-1);3212newmaterial = Ivector(1,noelements);3213newelementtypes = Ivector(1,noelements);3214newx = Rvector(1,noknots);3215newy = Rvector(1,noknots);3216newz = Rvector(1,noknots);32173218for(l=0;l<ncopies[2];l++) {3219for(k=0;k<ncopies[1];k++) {3220for(j=0;j<ncopies[0];j++) {3221for(i=1;i<=data->noknots;i++) {3222ncopy = j+k*ncopies[0]+l*ncopies[0]*ncopies[1];3223ind = i + ncopy*data->noknots;32243225newx[ind] = data->x[i] + j*meshsize[0];3226newy[ind] = data->y[i] + k*meshsize[1];3227newz[ind] = data->z[i] + l*meshsize[2];3228}3229}3230}3231}32323233maxmaterial = 0;3234if( diffmats ) {3235for(i=1;i<=data->noelements;i++)3236if(data->material[i] > maxmaterial) maxmaterial = data->material[i];3237if(info ) printf("Material offset for cloning set to: %d\n",maxmaterial);3238}32393240for(l=0;l<ncopies[2];l++) {3241for(k=0;k<ncopies[1];k++) {3242for(j=0;j<ncopies[0];j++) {3243for(i=1;i<=data->noelements;i++) {3244ncopy = j+k*ncopies[0]+l*ncopies[1]*ncopies[0];3245ind = i + ncopy*data->noelements;32463247newmaterial[ind] = data->material[i] + diffmats*maxmaterial*ncopy;3248newelementtypes[ind] = data->elementtypes[i];3249nonodes = newelementtypes[i]%100;3250for(m=0;m<nonodes;m++)3251newtopo[ind][m] = data->topology[i][m] + ncopy*data->noknots;3252}3253}3254}3255}32563257maxtype = 0;3258if( diffmats ) {3259for(j=0;j < MAXBOUNDARIES;j++) {3260if(!bound[j].created) continue;3261for(i=1; i <= bound[j].nosides; i++)3262if(maxtype < bound[j].types[i]) maxtype = bound[j].types[i];3263}3264if(info ) printf("Boundary offset for cloning set to: %d\n",maxtype);3265}32663267for(bndr=0;bndr < MAXBOUNDARIES;bndr++) {32683269if(!bound[bndr].created) continue;32703271nosides = totcopies * bound[bndr].nosides;32723273vparent = Ivector(1, nosides);3274vparent2 = Ivector(1, nosides);3275vside = Ivector(1, nosides);3276vside2 = Ivector(1, nosides);3277vmaterial = Ivector(1, nosides);3278vtypes = Ivector(1, nosides);3279vnormal = Ivector(1, nosides);32803281if(bound[bndr].ediscont) {3282vdiscont = Ivector(1, nosides);3283for(i=1; i <= nosides; i++)3284vdiscont[i] = 0;3285}32863287for(l=0;l<ncopies[2];l++) {3288for(k=0;k<ncopies[1];k++) {3289for(j=0;j<ncopies[0];j++) {3290for(i=1; i <= bound[bndr].nosides; i++) {32913292ncopy = j+k*ncopies[0]+l*ncopies[1]*ncopies[0];3293ind = i + ncopy * bound[bndr].nosides;32943295vparent[ind] = bound[bndr].parent[i] + ncopy * data->noelements;3296vside[ind] = bound[bndr].side[i];32973298if(bound[bndr].parent2[i]) {3299vparent2[ind] = bound[bndr].parent2[i] + ncopy * data->noelements;3300vside2[ind] = bound[bndr].side2[i];3301}3302else {3303vparent2[ind] = 0.0;3304vside2[ind] = 0.0;3305}33063307vnormal[ind] = bound[bndr].normal[i];33083309if(bound[bndr].ediscont)3310vdiscont[ind] = bound[bndr].discont[i];33113312vtypes[ind] = bound[bndr].types[i] + diffmats * ncopy * maxtype;33133314vmaterial[ind] = bound[bndr].material[i] + ncopy * maxmaterial;3315}3316}3317}3318}33193320bound[bndr].nosides = nosides;3321bound[bndr].side = vside;33223323bound[bndr].side2 = vside2;3324bound[bndr].parent = vparent;3325bound[bndr].parent2 = vparent2;3326bound[bndr].types = vtypes;3327bound[bndr].material = vmaterial;3328bound[bndr].normal = vnormal;3329if(bound[bndr].ediscont)3330bound[bndr].discont = vdiscont;3331}33323333free_Imatrix(data->topology,1,data->noelements,0,data->maxnodes-1);3334free_Ivector(data->material,1,data->noelements);3335free_Rvector(data->x,1,data->noknots);3336free_Rvector(data->y,1,data->noknots);3337free_Rvector(data->z,1,data->noknots);33383339data->noelements = noelements;3340data->noknots = noknots;3341data->topology = newtopo;3342data->material = newmaterial;33433344data->elementtypes = newelementtypes;3345data->x = newx;3346data->y = newy;3347data->z = newz;33483349if( data->bodynamesexist || data->boundarynamesexist ) {3350printf("Cloning cannot treat names yet, omitting treatment of names for now!\n");3351data->bodynamesexist = FALSE;3352data->boundarynamesexist = FALSE;3353}33543355if(info) printf("The mesh was copied to several identical meshes\n");33563357return(0);3358}335933603361int MirrorMeshes(struct FemType *data,struct BoundaryType *bound,3362int *symmaxis,int diffmats,Real *meshsize,int symmbound,int info)3363/* Makes a mirror image of a mesh and unites it with the original mesh */3364{3365int i,j,m;3366int noelements,noknots,nonodes,totcopies,ind,maxnodes;3367int **newtopo=NULL,*newmaterial=NULL,*newelementtypes=NULL;3368int maxtype,bndr,nosides;3369Real *newx=NULL,*newy=NULL,*newz=NULL;3370Real maxcoord[3],mincoord[3];3371int ind0,elem0,axis1,axis2,axis3,symmcount;33723373int *vparent=NULL,*vparent2=NULL,*vside=NULL,*vside2=NULL;3374int *vtypes=NULL,*vmaterial=NULL,*vnormal=NULL,*vdiscont=NULL;33753376printf("MirrorMeshes: making a symmetric mapping of the mesh\n");33773378if(symmaxis[0]) symmaxis[0] = 1;3379if(symmaxis[1]) symmaxis[1] = 1;3380if(symmaxis[2]) symmaxis[2] = 1;3381if(data->dim < 3) symmaxis[2] = 0;33823383maxcoord[0] = mincoord[0] = data->x[1];3384maxcoord[1] = mincoord[1] = data->y[1];3385maxcoord[2] = mincoord[2] = data->z[1];33863387for(i=1;i<=data->noknots;i++) {3388if(data->x[i] > maxcoord[0]) maxcoord[0] = data->x[i];3389if(data->x[i] < mincoord[0]) mincoord[0] = data->x[i];3390if(data->y[i] > maxcoord[1]) maxcoord[1] = data->y[i];3391if(data->y[i] < mincoord[1]) mincoord[1] = data->y[i];3392if(data->z[i] > maxcoord[2]) maxcoord[2] = data->z[i];3393if(data->z[i] < mincoord[2]) mincoord[2] = data->z[i];3394}33953396for(i=0;i<3;i++) {3397if(maxcoord[i]-mincoord[i] > meshsize[i]) meshsize[i] = maxcoord[i]-mincoord[i];3398}33993400if(diffmats) diffmats = 1;34013402totcopies = 1;3403for(i=0;i<3;i++)3404if(symmaxis[i]) totcopies *= 2;34053406noknots = totcopies * data->noknots;3407noelements = totcopies * data->noelements;3408maxnodes = data->maxnodes;34093410printf("Mirroring the mesh to %d symmetrical domains.\n",totcopies);34113412data->maxnodes = maxnodes;3413newtopo = Imatrix(1,noelements,0,maxnodes-1);3414newmaterial = Ivector(1,noelements);3415newelementtypes = Ivector(1,noelements);3416newx = Rvector(1,noknots);3417newy = Rvector(1,noknots);3418newz = Rvector(1,noknots);34193420ind0 = 0;342134223423for(axis1=0;axis1 <= symmaxis[0];axis1++) {3424for(axis2=0;axis2 <= symmaxis[1];axis2++) {3425for(axis3=0;axis3 <= symmaxis[2];axis3++) {34263427for(i=1;i<=data->noknots;i++) {3428ind = i + ind0;34293430newx[ind] = (1-2*axis1) * data->x[i];3431newy[ind] = (1-2*axis2) * data->y[i];3432newz[ind] = (1-2*axis3) * data->z[i];34333434newmaterial[ind] = data->material[i];3435newelementtypes[ind] = data->elementtypes[i];3436}3437ind0 += data->noknots;3438}3439}3440}34413442elem0 = 0;3443ind0 = 0;34443445for(axis1=0;axis1 <= symmaxis[0];axis1++) {3446for(axis2=0;axis2 <= symmaxis[1];axis2++) {3447for(axis3=0;axis3 <= symmaxis[2];axis3++) {34483449for(i=1;i<=data->noelements;i++) {3450ind = i + elem0;3451newmaterial[ind] = data->material[i];3452newelementtypes[ind] = data->elementtypes[i];3453nonodes = newelementtypes[i]%100;3454for(m=0;m<nonodes;m++)3455newtopo[ind][m] = data->topology[i][m] + ind0;3456}34573458elem0 += data->noelements;3459ind0 += data->noknots;3460printf("elem0=%d ind0=%d\n",elem0,ind0);3461}3462}3463}34643465maxtype = 0;3466for(j=0;j < MAXBOUNDARIES;j++) {3467if(!bound[j].created) continue;3468for(i=1; i <= bound[j].nosides; i++)3469if(maxtype < bound[j].types[i]) maxtype = bound[j].types[i];3470}34713472for(bndr=0;bndr < MAXBOUNDARIES;bndr++) {34733474if(!bound[bndr].created) continue;3475nosides = totcopies * bound[bndr].nosides;3476ind = 0;34773478vparent = Ivector(1, nosides);3479vparent2 = Ivector(1, nosides);3480vside = Ivector(1, nosides);3481vside2 = Ivector(1, nosides);3482vmaterial = Ivector(1, nosides);3483vtypes = Ivector(1, nosides);3484vnormal = Ivector(1, nosides);34853486if(bound[bndr].ediscont) {3487vdiscont = Ivector(1, nosides);3488for(i=1;i<=nosides;i++)3489vdiscont[i] = 0;3490}34913492symmcount = 0;3493elem0 = 0;3494ind0 = 0;34953496for(axis1=0;axis1 <= symmaxis[0];axis1++) {3497for(axis2=0;axis2 <= symmaxis[1];axis2++) {3498for(axis3=0;axis3 <= symmaxis[2];axis3++) {34993500for(i=1; i <= bound[bndr].nosides; i++) {35013502if(bound[bndr].types[i] == symmbound) continue;3503ind++;35043505vparent[ind] = bound[bndr].parent[i] + elem0;3506vparent2[ind] = bound[bndr].parent2[i] + elem0;3507vside[ind] = bound[bndr].side[i];3508vside2[ind] = bound[bndr].side2[i];35093510vnormal[ind] = bound[bndr].normal[i];35113512if(bound[bndr].ediscont)3513vdiscont[ind] = bound[bndr].discont[i];35143515vtypes[ind] = bound[bndr].types[i] + diffmats * symmcount * maxtype;35163517vmaterial[ind] = bound[bndr].material[i];3518}35193520symmcount++;3521elem0 += data->noelements;3522}3523}3524}35253526nosides = ind;3527bound[bndr].nosides = nosides;3528bound[bndr].side = vside;3529bound[bndr].side2 = vside2;3530bound[bndr].parent = vparent;3531bound[bndr].parent2 = vparent2;3532bound[bndr].types = vtypes;3533bound[bndr].material = vmaterial;3534bound[bndr].normal = vnormal;3535if(bound[bndr].ediscont)3536bound[bndr].discont = vdiscont;3537}35383539free_Imatrix(data->topology,1,data->noelements,0,data->maxnodes-1);3540free_Ivector(data->material,1,data->noelements);3541free_Rvector(data->x,1,data->noknots);3542free_Rvector(data->y,1,data->noknots);3543free_Rvector(data->z,1,data->noknots);35443545data->noelements = noelements;3546data->noknots = noknots;3547data->topology = newtopo;3548data->material = newmaterial;3549data->elementtypes = newelementtypes;3550data->x = newx;3551data->y = newy;3552data->z = newz;35533554if( data->bodynamesexist || data->boundarynamesexist ) {3555printf("Mirroring cannot treat names yet, omitting treatment of names for now!\n");3556data->bodynamesexist = FALSE;3557data->boundarynamesexist = FALSE;3558}35593560if(info) printf("The mesh was copied to several identical meshes\n");35613562return(0);3563}3564356535663567static void ReorderAutomatic(struct FemType *data,int iterations,3568int *origindx,Real corder[],int info)3569{3570int i,j,k,l,nonodes,maxnodes,noelements,noknots,minwidth,indexwidth;3571int **neighbours=NULL,*newrank=NULL,*newindx=NULL,*oldrank=NULL,*oldindx=NULL;3572int nocands,*cands=NULL,ind,ind2,cantdo;3573int elemtype,indready,iter,*localorder=NULL,*localtmp=NULL,nolocal;3574Real *localdist=NULL,dx,dy,dz;35753576iterations = 3;3577iter = 0;3578maxnodes = 8;35793580noelements = data->noelements;3581noknots = data->noknots;35823583cantdo = FALSE;3584for(j=1;j<=noelements;j++) {3585elemtype = data->elementtypes[j];3586if(elemtype != 404 && elemtype != 303 && elemtype != 808) cantdo = elemtype;3587}3588if(cantdo) {3589printf("Automatic reordering not specified for elementtype %d\n",cantdo);3590return;3591}35923593printf("Allocating...\n");35943595cands = Ivector(1,maxnodes);3596localorder = Ivector(1,maxnodes);3597localtmp = Ivector(1,maxnodes);3598localdist = Rvector(1,maxnodes);35993600neighbours = Imatrix(1,noknots,1,maxnodes);3601newrank = Ivector(1,noknots);3602oldrank = Ivector(1,noknots);3603newindx = Ivector(1,noknots);3604oldindx = Ivector(1,noknots);36053606for(i=1;i<=noknots;i++)3607oldindx[i] = origindx[i];36083609for(i=1;i<=noknots;i++)3610oldrank[origindx[i]] = i;36113612minwidth = CalculateIndexwidth(data,TRUE,oldrank);3613if(info) printf("Indexwidth of the initial node order is %d.\n",minwidth);36143615for(j=1;j<=noknots;j++)3616for(i=1;i<=maxnodes;i++)3617neighbours[j][i] = 0;361836193620if(info) printf("Initializing neighbours\n");36213622for(j=1;j<=noelements;j++) {3623elemtype = data->elementtypes[j];3624nonodes = elemtype%100;3625nocands = 0;36263627for(i=0;i<nonodes;i++) {3628ind = data->topology[j][i];36293630if(elemtype == 404 || elemtype == 303) {3631nocands = 2;3632cands[1] = (i+1)%nonodes;3633cands[2] = (i+nonodes-1)%nonodes;3634}3635else if(elemtype == 808) {3636nocands = 3;3637if(i<4) {3638cands[1] = (i+1)%4;3639cands[2] = (i+3)%4;3640cands[3] = i+4;3641}3642else {3643cands[1] = (i-4+1)%4+4;3644cands[2] = (i-4+3)%4+4;3645cands[3] = i-4;3646}3647}36483649for(k=1;k<=nocands;k++) {3650ind2 = data->topology[j][cands[k]];3651for(l=1;l<=maxnodes;l++) {3652if(neighbours[ind][l] == 0) break;3653if(neighbours[ind][l] == ind2) ind2 = 0;3654}3655if(ind2) neighbours[ind][l] = ind2;3656}3657}3658}36593660#if 03661for(j=1;j<=noknots;j++) {3662printf("neighbours[%d]= ",j);3663for(l=1;l<=maxnodes;l++)3664printf("%d ",neighbours[j][l]);3665printf("\n");3666}3667#endif36683669if(info) printf("Reordering neighbours table\n");36703671for(j=1;j<=noknots;j++) {36723673nolocal = 0;3674dz = 0.0;36753676for(l=1;l<=maxnodes;l++){3677if((ind = neighbours[j][l])) {3678nolocal++;3679localtmp[l] = ind;3680dx = data->x[l] - data->x[ind];3681dy = data->y[l] - data->y[ind];3682dz = data->z[l] - data->z[ind];3683localdist[l] = corder[0]*fabs(dx) + corder[1]*fabs(dy) + corder[2]*fabs(dz);3684}3685}36863687SortIndex(nolocal,localdist,localorder);36883689for(l=1;l<=nolocal;l++)3690neighbours[j][l] = localtmp[localorder[l]];36913692#if 03693for(l=1;l<=nolocal;l++)3694printf("j=%d l=%d dist=%.3le order=%d %d\n",3695j,l,localdist[l],localorder[l],neighbours[j][l]);3696#endif3697}3698369937003701for(iter=1;iter<=iterations;iter++) {37023703if(info) printf("Optimal topology testing %d\n",iter);37043705for(i=1;i<=noknots;i++)3706newrank[i] = 0;37073708ind = 0;3709indready = 1;37103711do {3712if(indready > ind) {3713for(l=noknots;l>=1;l--)3714if(j = oldindx[l]) break;3715if(info) printf("Starting over from node %d when ind=%d indready=%d\n",j,ind,indready);3716}3717else {3718j = newindx[indready] ;3719}37203721for(l=1;ind2 = neighbours[j][l];l++) {3722if(ind2) {3723if(!newrank[ind2]) {3724ind++;3725newrank[ind2] = ind;3726newindx[ind] = ind2;3727oldindx[oldrank[ind2]] = 0;3728oldrank[ind2] = 0;3729}3730}3731}3732indready++;37333734} while(ind < noknots);37353736indexwidth = CalculateIndexwidth(data,TRUE,newrank);3737if(info) printf("Indexwidth of the suggested node order is %d.\n",indexwidth);37383739for(i=1;i<=noknots;i++)3740oldrank[i] = newrank[i];37413742for(i=1;i<=noknots;i++)3743oldindx[i] = newindx[i];37443745if(indexwidth < minwidth) {3746for(i=1;i<=noknots;i++)3747origindx[i] = newindx[i];3748minwidth = indexwidth;3749}3750}37513752free_Ivector(cands,1,maxnodes);3753free_Ivector(localorder,1,maxnodes);3754free_Ivector(localtmp,1,maxnodes);3755free_Rvector(localdist,1,maxnodes);37563757free_Imatrix(neighbours,1,noknots,1,maxnodes);3758free_Ivector(newrank,1,noknots);3759free_Ivector(oldrank,1,noknots);3760free_Ivector(newindx,1,noknots);3761free_Ivector(oldindx,1,noknots);3762}37633764376537663767void ReorderElements(struct FemType *data,struct BoundaryType *bound,3768int manual,Real corder[],int info)3769{3770int i,j,k;3771int noelements,noknots,nonodes,length;3772int **newtopology=NULL,*newmaterial=NULL,*newelementtypes=NULL;3773int *indx=NULL,*revindx=NULL,*elemindx=NULL,*revelemindx=NULL;3774int oldnoknots, oldnoelements;3775Real *newx=NULL,*newy=NULL,*newz=NULL,*arrange=NULL;3776Real dx,dy,dz,cx,cy,cz,cbase;37773778noelements = oldnoelements = data->noelements;3779noknots = oldnoknots = data->noknots;37803781if(info) printf("Reordering %d knots and %d elements in %d-dimensions.\n",3782noknots,noelements,data->dim);37833784if(noelements > noknots)3785length = noelements;3786else3787length = noknots;37883789arrange = Rvector(1,length);3790indx = Ivector(1,noknots);3791revindx = Ivector(1,noknots);3792elemindx = Ivector(1,noelements);3793revelemindx = Ivector(1,noelements);37943795if(manual == 1) {3796cx = corder[0];3797cy = corder[1];3798cz = corder[2];3799}3800else {3801Real xmin,xmax,ymin,ymax,zmin,zmax;3802xmin = xmax = data->x[1];3803ymin = ymax = data->y[1];3804zmin = zmax = data->z[1];38053806for(i=1;i<=data->noknots;i++) {3807if(xmin > data->x[i]) xmin = data->x[i];3808if(xmax < data->x[i]) xmax = data->x[i];3809if(ymin > data->y[i]) ymin = data->y[i];3810if(ymax < data->y[i]) ymax = data->y[i];3811if(zmin > data->z[i]) zmin = data->z[i];3812if(zmax < data->z[i]) zmax = data->z[i];3813}3814dx = xmax-xmin;3815dy = ymax-ymin;3816dz = zmax-zmin;38173818/* The second strategy seems to be better in many cases */3819cbase = 100.0;3820cx = pow(cbase,1.0*(dx>dy)+1.0*(dx>dz));3821cy = pow(cbase,1.0*(dy>dx)+1.0*(dy>dz));3822cz = pow(cbase,1.0*(dz>dx)+1.0*(dz>dx));38233824corder[0] = cx;3825corder[1] = cy;3826corder[2] = cz;3827}38283829if(info) printf("Ordering with (%.3lg*x + %.3lg*y + %.3lg*z)\n",cx,cy,cz);3830for(i=1;i<=noknots;i++) {3831arrange[i] = cx*data->x[i] + cy*data->y[i] + cz*data->z[i];3832}3833SortIndex(noknots,arrange,indx);38343835if(manual == 2) ReorderAutomatic(data,0,indx,corder,TRUE);38363837for(i=1;i<=noknots;i++)3838revindx[indx[i]] = i;383938403841for(j=1;j<=noelements;j++) {3842nonodes = data->elementtypes[j]%100;3843arrange[j] = 0.0;3844for(i=0;i<nonodes;i++) {3845k = data->topology[j][i];3846arrange[j] += cx*data->x[k] + cy*data->y[k] + cz*data->z[k];3847}3848}38493850SortIndex(noelements,arrange,elemindx);3851for(i=1;i<=noelements;i++)3852revelemindx[elemindx[i]] = i;385338543855#if 03856for(i=1;i<=noknots;i++)3857printf("i=%d indx=%d revi=%d f=%.2lg\n",3858i,indx[i],revindx[i],arrange[indx[i]]);3859#endif38603861if(info) printf("Moving knots to new positions\n");3862newx = Rvector(1,data->noknots);3863newy = Rvector(1,data->noknots);3864newz = Rvector(1,data->noknots);38653866for(i=1;i<=data->noknots;i++) {3867newx[i] = data->x[indx[i]];3868newy[i] = data->y[indx[i]];3869newz[i] = data->z[indx[i]];3870}38713872free_Rvector(data->x,1,data->noknots);3873free_Rvector(data->y,1,data->noknots);3874free_Rvector(data->z,1,data->noknots);38753876data->x = newx;3877data->y = newy;3878data->z = newz;38793880if(info) printf("Moving the elements to new positions\n");38813882newtopology = Imatrix(1,noelements,0,data->maxnodes-1);3883newmaterial = Ivector(1,noelements);3884newelementtypes = Ivector(1,noelements);38853886for(j=1;j<=noelements;j++) {3887newmaterial[j] = data->material[elemindx[j]];3888newelementtypes[j] = data->elementtypes[elemindx[j]];3889nonodes = newelementtypes[j]%100;3890for(i=0;i<nonodes;i++) {3891k = data->topology[elemindx[j]][i];3892newtopology[j][i] = revindx[k];3893}3894}38953896data->material = newmaterial;3897data->elementtypes = newelementtypes;3898data->topology = newtopology;389939003901printf("Moving the parents of the boundary nodes.\n");3902for(j=0;j < MAXBOUNDARIES;j++) {39033904if(!bound[j].created) continue;39053906for(i=1; i <= bound[j].nosides; i++) {39073908bound[j].parent[i] = revelemindx[bound[j].parent[i]];39093910if(bound[j].parent2[i])3911bound[j].parent2[i] = revelemindx[bound[j].parent2[i]];3912}3913}39143915i = CalculateIndexwidth(data,FALSE,indx);3916printf("Indexwidth of the new node order is %d.\n",i);39173918free_Rvector(arrange,1,length);3919free_Ivector(indx,1,oldnoknots);3920free_Ivector(revindx,1,oldnoknots);3921free_Ivector(elemindx,1,oldnoelements);3922free_Ivector(revelemindx,1,oldnoelements);3923}3924392539263927int RemoveUnusedNodes(struct FemType *data,int info)3928{3929int i,j;3930int noelements,noknots,nonodes,activeknots;3931int *indx;39323933noelements = data->noelements;3934noknots = data->noknots;39353936indx = Ivector(1,noknots);3937for(i=1;i<=noknots;i++) indx[i] = 0;39383939for(j=1;j<=noelements;j++) {3940nonodes = data->elementtypes[j] % 100;3941for(i=0;i<nonodes;i++)3942indx[ data->topology[j][i] ] = 1;3943}39443945activeknots = 0;3946j = 0;3947for(i=1;i<=noknots;i++) {3948if(indx[i]) {3949activeknots += 1;3950indx[i] = activeknots;3951}3952else {3953j++;3954if(j<=5) printf("Unused node index in mesh: %d\n",i);3955}3956}39573958if( noknots == activeknots) {3959if(info) printf("All %d nodes were used by the mesh elements\n",noknots);3960return(1);3961}39623963if(info) printf("Removing %d unused nodes (out of %d) from the mesh\n",noknots-activeknots,noknots);39643965for(j=1;j<=noelements;j++) {3966nonodes = data->elementtypes[j] % 100;3967for(i=0;i<nonodes;i++)3968data->topology[j][i] = indx[ data->topology[j][i] ];3969}39703971for(i=1;i<=noknots;i++) {3972j = indx[i];3973if(!j) continue;3974data->x[j] = data->x[i];3975data->y[j] = data->y[i];3976data->z[j] = data->z[i];3977}3978data->noknots = activeknots;39793980free_Ivector(indx,1,noknots);39813982return(0);3983}39843985398639873988void RenumberBoundaryTypes(struct FemType *data,struct BoundaryType *bound,3989int renumber, int bcoffset, int info)3990{3991int i,j,k,doinit,isordered;3992int minbc=0,maxbc=0,**mapbc;3993int elemdim=0,elemtype=0,sideind[MAXNODESD1];3994int bctype,havename,isname;39953996if(renumber) {3997if(0) printf("Renumbering boundary types\n");39983999doinit = TRUE;4000for(j=0;j < MAXBOUNDARIES;j++) {4001if(!bound[j].created) continue;40024003for(i=1;i<=bound[j].nosides;i++) {4004if(doinit) {4005maxbc = minbc = bound[j].types[i];4006doinit = FALSE;4007}4008maxbc = MAX(maxbc,bound[j].types[i]);4009minbc = MIN(minbc,bound[j].types[i]);4010}4011}4012if(doinit) return;40134014if(info) printf("Initial boundary interval [%d,%d]\n",minbc,maxbc);40154016mapbc = Imatrix(minbc,maxbc,0,2);4017for(i=minbc;i<=maxbc;i++)4018for(j=0;j<=2;j++)4019mapbc[i][j] = 0;40204021for(j=0;j < MAXBOUNDARIES;j++) {4022if(!bound[j].created) continue;4023for(i=1;i<=bound[j].nosides;i++) {4024GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],data,sideind,&elemtype);4025if(!elemtype) printf("could not find boundary element: %d %d %d\n",i,j,bound[j].parent[i]);4026elemdim = GetElementDimension(elemtype);4027bctype = bound[j].types[i];40284029if(0) printf("type and dim: %d %d %d\n",elemtype,elemdim,bctype);40304031mapbc[bctype][elemdim] += 1;4032}4033}40344035if(0) {4036for(i=minbc;i<=maxbc;i++)4037for(j=0;j<=2;j++)4038if(mapbc[i][j]) printf("bc map1: %d %d\n",i,mapbc[i][j]);4039}40404041j = 0;4042/* Give the larger dimension always a smaller BC type */4043isordered = TRUE;4044for(isname=1;isname>=0;isname--) {4045for(elemdim=2;elemdim>=0;elemdim--) {4046for(i=minbc;i<=maxbc;i++) {4047if(!mapbc[i][elemdim]) continue;40484049/* Give index 1st to the named entities, then to unnamed. */4050havename = FALSE;4051if(data->boundarynamesexist) {4052if(i<MAXBCS) {4053if(data->boundaryname[i]) havename = TRUE;4054}4055}4056if(havename != isname) break;40574058j++;4059if(i == j) {4060if( isname ) {4061printf("BC index unaltered %d in %d %dD elements of %s\n",i,mapbc[i][elemdim],elemdim,data->boundaryname[i]);4062}4063else {4064printf("BC index unaltered %d in %d %dD elements\n",i,mapbc[i][elemdim],elemdim);4065}4066}4067else {4068isordered = FALSE;4069if( isname ) {4070printf("BC index changed %d -> %d in %d %dD elements of %s\n",i,j,mapbc[i][elemdim],elemdim,data->boundaryname[i]);4071}4072else {4073printf("BC index changed %d -> %d in %d %dD elements\n",i,j,mapbc[i][elemdim],elemdim);4074}4075}4076mapbc[i][elemdim] = j;4077}4078}4079}40804081if(0) {4082for(i=minbc;i<=maxbc;i++)4083for(j=0;j<=2;j++)4084if(mapbc[i][j]) printf("bc map2: %d %d\n",i,mapbc[i][j]);4085}40864087if(isordered) {4088if(info) printf("Numbering of boundary types is already ok\n");4089}4090else {4091if(info) printf("Mapping boundary types from [%d %d] to [%d %d]\n",minbc,maxbc,1,j);40924093for(j=0;j < MAXBOUNDARIES;j++) {4094if(!bound[j].created) continue;4095for(i=1;i<=bound[j].nosides;i++) {4096GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],data,sideind,&elemtype);4097elemdim = GetElementDimension(elemtype);4098bound[j].types[i] = mapbc[bound[j].types[i]][elemdim];4099}4100}41014102if(data->boundarynamesexist) {4103char *boundaryname0[MAXBCS];41044105for(j=0;j<MAXBODIES;j++)4106boundaryname0[j] = NULL;41074108/* We need some temporal place is name mapping might not be unique */4109for(j=minbc;j<=MIN(maxbc,MAXBCS-1);j++) {4110k = 0;4111for(elemdim=2;elemdim>=0;elemdim--) {4112k = mapbc[j][elemdim];4113if(k) break;4114}4115if(k) {4116if(data->boundaryname[j]) {4117boundaryname0[j] = Cvector(0,MAXNAMESIZE);4118strcpy(boundaryname0[j],data->boundaryname[j]);4119free_Cvector(data->boundaryname[j],0,MAXNAMESIZE);4120data->boundaryname[j] = NULL;4121}4122}4123}41244125for(j=minbc;j<=MIN(maxbc,MAXBCS-1);j++) {4126k = 0;4127for(elemdim=2;elemdim>=0;elemdim--) {4128k = mapbc[j][elemdim];4129if(k) break;4130}4131if(k) {4132if(boundaryname0[j]) {4133if(!data->boundaryname[k])4134data->boundaryname[k] = Cvector(0,MAXNAMESIZE);4135strcpy(data->boundaryname[k],boundaryname0[j]);4136}4137}4138}4139}4140}4141free_Imatrix(mapbc,minbc,maxbc,0,2);4142}41434144if(bcoffset) {4145if(info) printf("Adding offset of %d to the BCs\n",bcoffset);4146for(j=0;j < MAXBOUNDARIES;j++) {4147if(!bound[j].created) continue;4148for(i=1;i<=bound[j].nosides;i++)4149bound[j].types[i] += bcoffset;4150}4151if(data->boundarynamesexist) {4152for(j=MAXBCS-bcoffset-1;j>=0;j--) {4153k = j+bcoffset;4154if(!data->boundaryname[k]) data->boundaryname[k] = Cvector(0,MAXNAMESIZE);4155strcpy(data->boundaryname[k],data->boundaryname[j]);4156}4157}4158}4159}4160416141624163void RenumberMaterialTypes(struct FemType *data,struct BoundaryType *bound,int info)4164{4165int i,j,k,noelements,doinit;4166int minmat=0,maxmat=0,*mapmat;41674168if(0) printf("Setting new material types\n");41694170noelements = data->noelements;4171if(noelements < 1) {4172printf("There are no elements to set!\n");4173return;4174}41754176doinit = TRUE;4177for(j=1;j<=noelements;j++) {4178if(doinit) {4179maxmat = minmat = data->material[j];4180doinit = FALSE;4181}4182maxmat = MAX(maxmat,data->material[j]);4183minmat = MIN(minmat,data->material[j]);4184}41854186if(info) printf("Initial body interval [%d,%d]\n",minmat,maxmat);41874188mapmat = Ivector(minmat,maxmat);4189for(i=minmat;i<=maxmat;i++) mapmat[i] = 0;41904191for(j=1;j<=noelements;j++)4192mapmat[data->material[j]] += 1;41934194j = 0;4195for(i=minmat;i<=maxmat;i++) {4196if(mapmat[i]) {4197j++;4198if(i != j) printf("body index changed %d -> %d in %d elements\n",i,j,mapmat[i]);4199mapmat[i] = j;4200}4201}42024203if(maxmat - minmat >= j || minmat != 1) {4204if(info) printf("Mapping material types from [%d %d] to [%d %d]\n",4205minmat,maxmat,1,j);4206for(j=1;j<=noelements;j++)4207data->material[j] = mapmat[data->material[j]];42084209if(data->bodynamesexist) {4210if(info) printf("Mapping entity names to follow material indexes\n");4211for(j=minmat;j<=MIN(maxmat,MAXBODIES-1);j++) {4212k = mapmat[j];4213if(k) {4214if(data->bodyname[j]) {4215if(!data->bodyname[k]) data->bodyname[k] = Cvector(0,MAXNAMESIZE);4216strcpy(data->bodyname[k],data->bodyname[j]);4217}4218}4219}4220}4221}4222else {4223if(info) printf("Numbering of bodies is already ok\n");4224}42254226free_Ivector(mapmat,minmat,maxmat);42274228if(info) printf("Renumbering of material types completed!\n");4229}4230423142324233int RemoveLowerDimensionalBoundaries(struct FemType *data,struct BoundaryType *bound,int info)4234{4235int i,j,noelements;4236int elemtype,maxelemdim,minelemdim,elemdim;4237int parent, side, sideind[MAXNODESD1],sideelemtype;4238int nosides, oldnosides,newnosides;42394240if(info) printf("Removing lower dimensional boundaries\n");42414242noelements = data->noelements;4243if(noelements < 1) return(1);42444245elemtype = GetMaxElementType(data);42464247maxelemdim = GetElementDimension(elemtype);42484249if(info) printf("Maximum elementtype is %d and dimension %d\n",elemtype,maxelemdim);42504251elemtype = GetMinElementType(data);4252minelemdim = GetElementDimension(elemtype);4253if(info) printf("Minimum elementtype is %d and dimension %d\n",elemtype,minelemdim);42544255/* Nothing to remove if the bulk mesh has 1D elements */4256if(minelemdim < 2) return(2);42574258oldnosides = 0;4259newnosides = 0;4260for(j=0;j < MAXBOUNDARIES;j++) {4261nosides = 0;4262if(!bound[j].created) continue;4263for(i=1;i<=bound[j].nosides;i++) {42644265oldnosides++;4266parent = bound[j].parent[i];42674268side = bound[j].side[i];42694270GetBoundaryElement(i,&bound[j],data,sideind,&sideelemtype);4271/* Old: GetElementSide(parent,side,1,data,sideind,&sideelemtype); */42724273elemdim = GetElementDimension(sideelemtype);42744275/* if(maxelemdim - elemdim > 1) continue; */4276/* This was changed as we want to maintain 1D BCs of a hybrid 2D/3D mesh. */4277if(minelemdim - elemdim > 1) continue;42784279nosides++;4280if(nosides == i) continue;42814282bound[j].parent[nosides] = bound[j].parent[i];4283bound[j].parent2[nosides] = bound[j].parent2[i];4284bound[j].side[nosides] = bound[j].side[i];4285bound[j].side2[nosides] = bound[j].side2[i];4286bound[j].types[nosides] = bound[j].types[i];4287}4288bound[j].nosides = nosides;4289newnosides += nosides;4290}42914292if(info) printf("Removed %d (out of %d) less than %dD boundary elements\n",4293oldnosides-newnosides,oldnosides,minelemdim-1);4294return(0);4295}42964297int RemoveInternalBoundaries(struct FemType *data,struct BoundaryType *bound,int info)4298{4299int i,j;4300int parent,parent2;4301int nosides,oldnosides,newnosides;43024303if(info) printf("Removing internal boundaries\n");43044305if( data->noelements < 1 ) return(1);43064307oldnosides = 0;4308newnosides = 0;4309for(j=0;j < MAXBOUNDARIES;j++) {4310nosides = 0;4311if(!bound[j].created) continue;4312for(i=1;i<=bound[j].nosides;i++) {43134314oldnosides++;4315parent = bound[j].parent[i];4316parent2 = bound[j].parent2[i];43174318if( parent > 0 && parent2 > 0 ) continue;43194320nosides++;4321if(nosides == i) continue;43224323bound[j].parent[nosides] = bound[j].parent[i];4324bound[j].parent2[nosides] = bound[j].parent2[i];4325bound[j].side[nosides] = bound[j].side[i];4326bound[j].side2[nosides] = bound[j].side2[i];4327bound[j].types[nosides] = bound[j].types[i];4328}4329bound[j].nosides = nosides;4330newnosides += nosides;4331}43324333if(info) printf("Removed %d (out of %d) internal boundary elements\n",4334oldnosides-newnosides,oldnosides);4335return(0);4336}433743384339#if 04340static void FindEdges(struct FemType *data,struct BoundaryType *bound,4341int material,int sidetype,int info)4342{4343int i,j,side,identical,noelements,element;4344int noknots,nomaterials,nosides,newbound;4345int maxelementtype,maxedgenodes,elemedges,maxelemedges,edge,dosides;4346int **edgetable,sideind[MAXNODESD1],sideelemtype,allocated;4347int *indx;4348Real *arrange;434943504351newbound = 0;4352nomaterials = 0;4353maxelementtype = 0;4354noelements = data->noelements;43554356printf("FindEdges: Finding edges of bulk elements of type %d\n",material);4357maxelementtype = GetMaxElementType(data);43584359if(maxelementtype/100 > 4) {4360printf("FindEdges: Implemented only for 2D elements!\n");4361dosides = 0;4362return;4363}43644365if(maxelementtype/100 <= 2) maxedgenodes = 1;4366else if(maxelementtype/100 <= 4) maxedgenodes = 2;4367maxelemedges = maxelementtype/100;43684369edgetable = Imatrix(1,maxelemedges*nomaterials,0,maxedgenodes+1);4370for(i=1;i<=maxelemedges*nomaterials;i++)4371for(j=0;j<=maxedgenodes+1;j++)4372edgetable[i][j] = 0;43734374edge = 0;4375for(element=1;element<=noelements;element++) {4376if(data->material[element] != material) continue;43774378elemedges = data->elementtypes[element]/100;43794380for(side=0;side<elemedges;side++) {4381edge++;43824383GetElementSide(element,side,1,data,sideind,&sideelemtype);4384edgetable[edge][maxedgenodes] = element;4385edgetable[edge][maxedgenodes+1] = side;43864387if(maxedgenodes == 1)4388edgetable[edge][0] = sideind[0];4389else if(maxedgenodes == 2) {4390if(sideind[0] > sideind[1]) {4391edgetable[edge][0] = sideind[0];4392edgetable[edge][1] = sideind[1];4393}4394else {4395edgetable[edge][1] = sideind[0];4396edgetable[edge][0] = sideind[1];4397}4398}4399}4400}44014402noknots = edge;4403arrange = Rvector(1,noknots);4404for(i=1;i<=noknots;i++)4405arrange[i] = 0.0;4406for(i=1;i<=noknots;i++)4407arrange[i] = edgetable[i][0];4408indx = Ivector(1,noknots);44094410SortIndex(noknots,arrange,indx);44114412allocated = FALSE;44134414omstart:4415nosides = 0;44164417for(i=1;i<=noknots;i++) {4418identical = FALSE;4419if(maxedgenodes == 1) {4420for(j=i+1;j<=noknots && edgetable[indx[i]][0] == edgetable[indx[j]][0];j++)4421identical = TRUE;4422for(j=i-1;j>=1 && edgetable[indx[i]][0] == edgetable[indx[j]][0];j--)4423identical = TRUE;4424}4425else if(maxedgenodes == 2) {4426for(j=i+1;j<=noknots && edgetable[indx[i]][0] == edgetable[indx[j]][0];j++)4427if(edgetable[indx[i]][1] == edgetable[indx[j]][1])4428identical = TRUE;4429for(j=i-1;j>=1 && edgetable[indx[i]][0] == edgetable[indx[j]][0];j--)4430if(edgetable[indx[i]][1] == edgetable[indx[j]][1])4431identical = TRUE;4432}44334434if(identical) continue;4435nosides++;4436if(allocated) {4437bound[newbound].parent[nosides] = edgetable[indx[i]][maxedgenodes];4438bound[newbound].parent2[nosides] = 0;4439bound[newbound].side[nosides] = edgetable[indx[i]][maxedgenodes+1];4440bound[newbound].side2[nosides] = 0;4441bound[newbound].types[nosides] = sidetype;4442}4443}44444445if(!allocated) {4446for(j=0;j < MAXBOUNDARIES && bound[j].created;j++);4447newbound = j;4448AllocateBoundary(&bound[newbound],nosides);4449allocated = TRUE;4450if(info) printf("Created boundary %d of type %d and size %d for material %d\n",4451newbound,sidetype,nosides,material);4452goto omstart;4453}44544455free_Ivector(indx,1,noknots);4456free_Imatrix(edgetable,1,maxelemedges*nomaterials,0,maxedgenodes+1);4457}4458#endif44594460static int CompareIndexes(int elemtype,int *ind1,int *ind2)4461{4462int i,j,same,nosides,hits;44634464hits = 0;4465nosides = elemtype / 100;4466for(i=0;i<nosides;i++)4467for(j=0;j<nosides;j++)4468if(ind1[i] == ind2[j]) hits++;44694470same = (hits == nosides);4471return(same);4472}4473447444754476int FindNewBoundaries(struct FemType *data,struct BoundaryType *bound,4477int *boundnodes,int suggesttype,int dimred,int info)4478{4479int i,j,side,identical,element,lowerdim,dim,minedge,maxedge;4480int noelements,noknots,nonodes,nosides,newbound;4481int sideind[MAXNODESD1],sideind0[MAXNODESD1],sideelemtype,sideelemtype0,allocated;4482int noboundnodes,sameside,newtype,elemtype;44834484newtype = 0;4485allocated = FALSE;4486dim = data->dim;4487if(dimred)4488lowerdim = dim - dimred;4489else4490lowerdim = dim-1;44914492noknots = data->noknots;4493noelements = data->noelements;4494noboundnodes = 0;4495newbound = 0;4496maxedge = 0;4497minedge = 0;44984499for(i=1;i<=noknots;i++)4500if(boundnodes[i]) noboundnodes++;4501if(!noboundnodes) {4502printf("FindNewBoundaries: no nonzero entries in boundnodes vector!\n");4503return(1);4504}4505else {4506if(info) printf("There are %d nonzero entries in boundnodes vector!\n",noboundnodes);4507}45084509omstart:45104511nosides = 0;4512for(element=1;element<=noelements;element++) {45134514elemtype = data->elementtypes[element];4515if(dim == 1) {4516minedge = 0;4517maxedge = elemtype/100 -1;4518}4519else if(dim == 2) {4520if(lowerdim == 1) {4521minedge = 0;4522maxedge = elemtype/100 -1;4523}4524else if(lowerdim == 0) {4525minedge = elemtype/100;4526maxedge = minedge + 1;4527}4528}4529else if(dim == 3) {4530if(lowerdim == 2) {4531minedge = 0;4532if(elemtype/100 == 5) maxedge = 3;4533else if(elemtype/100 == 6 || elemtype/100 == 7) maxedge = 4;4534else if(elemtype/100 == 8) maxedge = 5;4535}4536else if(lowerdim == 1) {4537if(elemtype/100 == 8) {4538minedge = 6;4539maxedge = 17;4540}4541else if(elemtype/100 == 5) {4542minedge = 4;4543maxedge = 9;4544}4545else4546printf("FindNewBoundaries: not implemented for all 3d boundaries\n");4547}4548else if(lowerdim == 0) {4549if(elemtype/100 == 8) {4550minedge = 18;4551maxedge = 25;4552}4553}4554}45554556for(side=minedge;side<=maxedge;side++) {45574558GetElementSide(element,side,1,data,sideind,&sideelemtype);45594560nonodes = sideelemtype % 100;4561identical = TRUE;4562for(i=0;i<nonodes;i++)4563if(!boundnodes[sideind[i]]) identical = FALSE;45644565if(!identical) continue;4566nosides++;45674568if(allocated) {4569for(i=1;i<nosides;i++) {4570if(bound[newbound].parent2[i]) continue;45714572GetElementSide(bound[newbound].parent[i],bound[newbound].side[i],45731,data,sideind0,&sideelemtype0);4574if(sideelemtype0 != sideelemtype) continue;4575sameside = CompareIndexes(sideelemtype,sideind0,sideind);4576if(sameside) {4577bound[newbound].parent2[i] = element;4578bound[newbound].side2[i] = side;4579nosides--;4580goto foundsameside;4581}4582}45834584bound[newbound].types[nosides] = newtype;4585bound[newbound].parent[nosides] = element;4586bound[newbound].side[nosides] = side;4587bound[newbound].types[nosides] = newtype;45884589foundsameside:4590continue;4591}4592}4593}45944595if(nosides) {4596if(!allocated) {4597newtype = suggesttype;4598for(j=0;j < MAXBOUNDARIES && bound[j].created;j++) {4599newbound = j;4600if(suggesttype) continue;4601for(i=1;i<=bound[j].nosides;i++)4602if(bound[j].types[i] > newtype) newtype = bound[j].types[i];4603}4604newbound++;4605if(!suggesttype) newtype++;46064607AllocateBoundary(&bound[newbound],nosides);4608allocated = TRUE;4609if(info) printf("Allocating for %d sides of boundary %d\n",nosides,newtype);4610goto omstart;4611}46124613bound[newbound].nosides = nosides;4614if(info) printf("Found %d sides of dim %d to define boundary %d\n",nosides,lowerdim,newtype);46154616for(i=1;i<=nosides;i++) {4617if(j = bound[newbound].parent2[i]) {4618if(bound[newbound].parent[i] > bound[newbound].parent2[i]) {4619bound[newbound].parent2[i] = bound[newbound].parent[i];4620bound[newbound].parent[i] = j;4621j = bound[newbound].side2[i];4622bound[newbound].side2[i] = bound[newbound].side[i];4623bound[newbound].side[i] = j;4624}4625}4626}4627}4628else {4629if(lowerdim == 0) {4630printf("The nodes do not form a boundary!\n");4631return(2);4632}4633else {4634lowerdim--;4635printf("The nodes do not form a boundary, trying with %d-dimensional elements.\n",lowerdim);4636goto omstart;4637}4638}46394640return(0);4641}4642464346444645int FindBulkBoundary(struct FemType *data,int mat1,int mat2,4646int *boundnodes,int *noboundnodes,int info)4647{4648int i,j,k;4649int nonodes,maxnodes,minnodes,material;4650Real ds,xmin=0.0,xmax=0.0,ymin=0.0,ymax=0.0,zmin=0.0,zmax=0.0,eps;4651int *visited,elemdim,*ind;4652Real *anglesum,dx1,dx2,dy1,dy2,dz1,dz2,ds1,ds2,dotprod;46534654eps = 1.0e-4;4655*noboundnodes = 0;46564657if(mat1 < 1 && mat2 < 1) {4658printf("FindBulkBoundary: Either of the materials must be positive\n");4659return(1);4660}4661else if(mat1 < 1) {4662i = mat1;4663mat1 = mat2;4664mat2 = i;4665}4666if(info) printf("Finding nodes between bulk elements of material %d and %d\n",mat1,mat2);46674668visited = Ivector(1,data->noknots);4669for(i=1;i<=data->noknots;i++)4670visited[i] = 0;46714672for(i=1;i<=data->noknots;i++)4673boundnodes[i] = 0;46744675elemdim = 0;4676for(i=1;i<=data->noelements;i++) {4677material = data->material[i];4678if(material == mat1) {4679nonodes = data->elementtypes[i] % 100;4680k = data->elementtypes[i]/100;4681if(k > elemdim) elemdim = k;46824683for(j=0;j<nonodes;j++) {4684k = data->topology[i][j];4685visited[k] += 1;4686}4687}4688}4689maxnodes = minnodes = visited[1];4690for(i=1;i<=data->noknots;i++) {4691if(visited[i] > maxnodes) maxnodes = visited[i];4692if(visited[i] < minnodes) minnodes = visited[i];4693}46944695if(elemdim == 3 || elemdim == 4) {4696anglesum = Rvector(1, data->noknots);4697for(i=1;i<=data->noknots;i++)4698anglesum[i] = 0.0;46994700for(i=1;i<=data->noelements;i++) {4701material = data->material[i];4702if(material == mat1) {4703nonodes = data->elementtypes[i]/100;4704ind = data->topology[i];47054706if(nonodes == 3 || nonodes == 4) {4707for(k=0;k<nonodes;k++) {4708dx1 = data->x[ind[(k+1)%nonodes]] - data->x[ind[k]];4709dy1 = data->y[ind[(k+1)%nonodes]] - data->y[ind[k]];4710dz1 = data->z[ind[(k+1)%nonodes]] - data->z[ind[k]];4711dx2 = data->x[ind[(k+nonodes-1)%nonodes]] - data->x[ind[k]];4712dy2 = data->y[ind[(k+nonodes-1)%nonodes]] - data->y[ind[k]];4713dz2 = data->z[ind[(k+nonodes-1)%nonodes]] - data->z[ind[k]];4714ds1 = sqrt(dx1*dx1+dy1*dy1+dz1*dz1);4715ds2 = sqrt(dx2*dx2+dy2*dy2+dz2*dz2);4716dotprod = dx1*dx2 + dy1*dy2 + dz1*dz2;47174718anglesum[ind[k]] += acos(dotprod / (ds1*ds2));4719}4720}47214722}4723}4724j = 0;4725for(i=1;i<=data->noknots;i++) {4726anglesum[i] /= 2.0 * FM_PI;4727if(anglesum[i] > 0.99) visited[i] = 0;4728if(anglesum[i] > 1.01) printf("FindBulkBoundary: surprisingly large angle %.3e in node %d\n",anglesum[i],i);4729if(visited[i]) j++;4730}4731if(0) printf("There are %d boundary node candidates\n",j);4732free_Rvector(anglesum,1,data->noknots);4733}47344735else {4736for(i=1;i<=data->noknots;i++)4737if(visited[i] == maxnodes) visited[i] = 0;47384739if(maxnodes < 2) {4740printf("FindBulkBoundary: Nodes must belong to more than %d elements.\n",maxnodes);4741return(2);4742}4743}47444745if(mat2 == 0) {4746for(i=1;i<=data->noelements;i++) {4747material = data->material[i];4748if(material == mat1) continue;47494750nonodes = data->elementtypes[i] % 100;4751for(j=0;j<nonodes;j++) {4752k = data->topology[i][j];4753boundnodes[k] += 1;4754}4755}4756for(k=1;k<=data->noknots;k++) {4757if(!visited[k])4758boundnodes[k] = 0;4759else if(visited[k] < boundnodes[k])4760boundnodes[k] = 0;4761else if(visited[k] + boundnodes[k] < maxnodes)4762boundnodes[k] = 1;4763else4764boundnodes[k] = 0;4765}4766}4767else if(mat2 == -10) {4768for(i=1;i<=data->noknots;i++)4769if(visited[i]) boundnodes[i] = 1;4770}4771else if(mat2 == -11 || mat2 == -12 || mat2 > 0) {4772for(i=1;i<=data->noelements;i++) {4773material = data->material[i];47744775if(material == mat1) continue;4776if(mat2 > 0 && material != mat2) continue;4777if(mat2 == -11 && material < mat1) continue;4778if(mat2 == -12 && material > mat1) continue;47794780nonodes = data->elementtypes[i]%100;4781for(j=0;j<nonodes;j++) {4782k = data->topology[i][j];4783if(visited[k]) boundnodes[k] = 1;4784}4785}4786}4787else if(mat2 >= -2*data->dim && mat2 <= -1) {47884789j = TRUE;4790for(i=1;i<=data->noknots;i++)4791if(visited[i]) {4792if(j) {4793xmax = xmin = data->x[i];4794ymax = ymin = data->y[i];4795zmax = zmin = data->z[i];4796j = FALSE;4797}4798else {4799if(data->x[i] > xmax) xmax = data->x[i];4800if(data->x[i] < xmin) xmin = data->x[i];4801if(data->y[i] > ymax) ymax = data->y[i];4802if(data->y[i] < ymin) ymin = data->y[i];4803if(data->z[i] > zmax) zmax = data->z[i];4804if(data->z[i] < zmin) zmin = data->z[i];4805}4806}48074808ds = (xmax-xmin)*(xmax-xmin) +4809(ymax-ymin)*(ymax-ymin) + (zmax-zmin)*(zmax-zmin);48104811ds = sqrt(ds);4812eps = 1.0e-5 * ds;481348144815for(i=1;i<=data->noknots;i++)4816if(visited[i] < maxnodes && visited[i]) {48174818if(data->dim == 1) {4819if(mat2 == -1 && fabs(data->x[i]-xmin) < eps) boundnodes[i] = 1;4820else if(mat2 == -2 && fabs(data->x[i]-xmax) < eps) boundnodes[i] = 1;4821}4822if(data->dim >= 2) {4823if(mat2 == -1 && (fabs(data->y[i]-ymin) < eps)) boundnodes[i] = 1;4824else if(mat2 == -3 && (fabs(data->y[i]-ymax) < eps)) boundnodes[i] = 1;4825else if(mat2 == -4 && (fabs(data->x[i]-xmin) < eps)) boundnodes[i] = 1;4826else if(mat2 == -2 && (fabs(data->x[i]-xmax) < eps)) boundnodes[i] = 1;4827}4828if(data->dim >= 3) {4829if(mat2 == -5 && fabs(data->z[i]-zmin) < eps) boundnodes[i] = 1;4830else if(mat2 == -6 && fabs(data->z[i]-zmax) < eps) boundnodes[i] = 1;4831}4832}48334834}4835else {4836printf("FindBulkBoundary: unknown option %d for finding a side\n",mat2);4837return(2);4838}483948404841*noboundnodes = 0;4842for(i=1;i<=data->noknots;i++)4843if(boundnodes[i]) *noboundnodes += 1;48444845if(info) printf("Located %d nodes at the interval between materials %d and %d\n",4846*noboundnodes,mat1,mat2);48474848free_Ivector(visited,1,data->noknots);4849return(0);4850}4851485248534854int FindBoundaryBoundary(struct FemType *data,struct BoundaryType *bound,int mat1,int mat2,4855int *boundnodes,int *noboundnodes,int info)4856{4857int i,j,k,l;4858int hits,nonodes,nocorners,maxnodes,minnodes,elemtype,material,bounddim;4859Real ds,xmin=0.0,xmax=0.0,ymin=0.0,ymax=0.0,zmin=0.0,zmax=0.0;4860Real eps,dx1,dx2,dy1,dy2,dz1,dz2,ds1,ds2,dotprod;4861Real *anglesum=NULL;4862int *visited,sideind[MAXNODESD2],elemind[MAXNODESD2];48634864eps = 1.0e-4;4865*noboundnodes = 0;48664867if(mat1 < 1 && mat2 < 1) {4868printf("FindBoundaryBoundary: Either of the boundaries must be positive\n");4869return(1);4870}4871else if(mat1 < 1) {4872i = mat1;4873mat1 = mat2;4874mat2 = i;4875}4876if(info) printf("Finding nodes between boundary elements of type %d and %d\n",mat1,mat2);48774878visited = Ivector(1,data->noknots);4879for(i=1;i<=data->noknots;i++)4880visited[i] = 0;48814882for(i=1;i<=data->noknots;i++)4883boundnodes[i] = 0;48844885bounddim = 0;4886/* Set a tag to all nodes that are part of the other boundary */4887for(j=0;j < MAXBOUNDARIES;j++) {4888if(!bound[j].created) continue;4889for(i=1; i <= bound[j].nosides; i++) {48904891if(bound[j].types[i] == mat1) {4892GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],4893data,sideind,&elemtype);48944895nonodes = elemtype % 100;4896nocorners = elemtype / 100;48974898for(k=0;k<nocorners;k++)4899visited[sideind[k]] += 1;4900for(k=nocorners;k<nonodes;k++)4901visited[sideind[k]] -= 1;49024903if(nocorners == 3 || nocorners == 4) {4904if(bounddim < 2) {4905anglesum = Rvector(1, data->noknots);4906for(k=1;k<=data->noknots;k++)4907anglesum[k] = 0.0;4908bounddim = 2;4909}4910nonodes = nocorners;4911for(k=0;k<nonodes;k++) {4912dx1 = data->x[sideind[(k+1)%nonodes]] - data->x[sideind[k]];4913dy1 = data->y[sideind[(k+1)%nonodes]] - data->y[sideind[k]];4914dz1 = data->z[sideind[(k+1)%nonodes]] - data->z[sideind[k]];4915dx2 = data->x[sideind[(k+nonodes-1)%nonodes]] - data->x[sideind[k]];4916dy2 = data->y[sideind[(k+nonodes-1)%nonodes]] - data->y[sideind[k]];4917dz2 = data->z[sideind[(k+nonodes-1)%nonodes]] - data->z[sideind[k]];4918ds1 = sqrt(dx1*dx1+dy1*dy1+dz1*dz1);4919ds2 = sqrt(dx2*dx2+dy2*dy2+dz2*dz2);4920dotprod = dx1*dx2 + dy1*dy2 + dz1*dz2;49214922anglesum[sideind[k]] += acos(dotprod / (ds1*ds2));4923}4924}49254926}4927}4928}49294930maxnodes = minnodes = abs(visited[1]);4931for(i=1;i<=data->noknots;i++) {4932j = abs( visited[i] );4933maxnodes = MAX( j, maxnodes );4934minnodes = MIN( j, minnodes );4935}4936if(info) printf("There are from %d to %d hits per node\n",minnodes,maxnodes);4937if(maxnodes < 2) {4938printf("FindBulkBoundary: Nodes must belong to more than %d elements.\n",maxnodes);4939return(2);4940}49414942if(bounddim == 2) {4943/* For corner nodes eliminate the ones with full angle */4944for(i=1;i<=data->noknots;i++) {4945anglesum[i] /= 2.0 * FM_PI;4946if(anglesum[i] > 0.99) visited[i] = 0;4947if(anglesum[i] > 1.01) printf("FindBulkBoundary: surprisingly large angle %.3e in node %d\n",anglesum[i],i);4948}4949free_Rvector(anglesum,1,data->noknots);49504951/* For higher order nodes eliminate the ones with more than one hits */4952k = 0;4953for(i=1;i<=data->noknots;i++) {4954if(visited[i] == -1)4955visited[i] = 1;4956else if(visited[i] < -1) {4957k++;4958visited[i] = 0;4959}4960}4961if(k && info) printf("Removed %d potential higher order side nodes from the list.\n",k);4962}49634964if(bounddim == 1) {4965if(visited[i] == maxnodes || visited[i] < 0) visited[i] = 0;4966}49674968/* Neighbour to anything */4969if(mat2 == 0) {4970for(k=1;k<=data->noknots;k++)4971if(visited[k])4972boundnodes[k] = 1;4973}4974/* Neighbour to other BCs */4975else if(mat2 == -11 || mat2 == -12 || mat2 == -10 || mat2 > 0) {4976for(j=0;j < MAXBOUNDARIES;j++) {4977if(!bound[j].created) continue;4978for(i=1; i <= bound[j].nosides; i++) {49794980material = bound[j].types[i];49814982if(material == mat1) continue;4983if(mat2 > 0 && material != mat2) continue;4984if(mat2 == -11 && material < mat1) continue;4985if(mat2 == -12 && material > mat1) continue;49864987GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],4988data,sideind,&elemtype);4989nonodes = elemtype%100;4990for(k=0;k<nonodes;k++) {4991l = sideind[k];4992if(visited[l]) boundnodes[l] = 1;4993}4994}4995}4996}49974998/* Neighbour to major coordinate directions */4999else if(mat2 >= -2*data->dim && mat2 <= -1) {50005001for(j=0;j < MAXBOUNDARIES;j++) {5002if(!bound[j].created) continue;5003for(i=1; i <= bound[j].nosides; i++) {50045005material = bound[j].types[i];5006if(material != mat1) continue;50075008GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],5009data,sideind,&elemtype);5010nonodes = elemtype%100;50115012hits = 0;5013for(k=0;k<nonodes;k++) {5014l = sideind[k];5015if(visited[l] < maxnodes) hits++;5016}5017if(!hits) continue;50185019l = sideind[0];5020xmax = xmin = data->x[l];5021ymax = ymin = data->y[l];5022zmax = zmin = data->z[l];50235024for(k=1;k<nonodes;k++) {5025l = sideind[k];5026if(data->x[l] > xmax) xmax = data->x[l];5027if(data->x[l] < xmin) xmin = data->x[l];5028if(data->y[l] > ymax) ymax = data->y[l];5029if(data->y[l] < ymin) ymin = data->y[l];5030if(data->z[l] > zmax) zmax = data->z[l];5031if(data->z[l] < zmin) zmin = data->z[l];5032}50335034ds = (xmax-xmin)*(xmax-xmin) +5035(ymax-ymin)*(ymax-ymin) + (zmax-zmin)*(zmax-zmin);5036ds = sqrt(ds);5037eps = 1.0e-3 * ds;50385039for(k=0;k<nonodes;k++) {5040elemind[k] = 0;5041l = sideind[k];5042if(!visited[l]) continue;50435044if(data->dim == 1) {5045if(mat2 == -1 && fabs(data->x[l]-xmin) < eps) boundnodes[l] = 1;5046else if(mat2 == -2 && fabs(data->x[l]-xmax) < eps) boundnodes[l] = 1;5047}5048if(data->dim >= 2) {5049if(mat2 == -1 && (fabs(data->y[l]-ymin) < eps)) elemind[l] = 1;5050else if(mat2 == -3 && (fabs(data->y[l]-ymax) < eps)) elemind[l] = 1;5051else if(mat2 == -4 && (fabs(data->x[l]-xmin) < eps)) elemind[l] = 1;5052else if(mat2 == -2 && (fabs(data->x[l]-xmax) < eps)) elemind[l] = 1;5053}5054if(data->dim >= 3) {5055if(mat2 == -5 && fabs(data->z[l]-zmin) < eps) elemind[l] = 1;5056else if(mat2 == -6 && fabs(data->z[l]-zmax) < eps) elemind[l] = 1;5057}5058}50595060if(data->dim > 1) {5061hits = 0;5062for(k=0;k<nonodes;k++)5063hits += elemind[k];50645065if(hits > 1) for(k=0;k<nonodes;k++)5066if(elemind[k]) boundnodes[sideind[k]] = 1;5067}5068}5069}5070}5071else {5072printf("FindBoundaryBoundary: unknown option %d for finding a side\n",mat2);5073return(2);5074}50755076*noboundnodes = 0;5077for(i=1;i<=data->noknots;i++)5078if(boundnodes[i]) *noboundnodes += 1;50795080if(info) printf("Located %d nodes at the interval between boundaries %d and %d\n",5081*noboundnodes,mat1,mat2);50825083free_Ivector(visited,1,data->noknots);5084return(0);5085}5086508750885089int IncreaseElementOrder(struct FemType *data,int info)5090{5091int i,j,side,element,maxcon,con,newknots,ind,ind2;5092int noelements,noknots,nonodes,maxnodes,maxelemtype,hit,node;5093int elemtype,stat;5094int **newnodetable=NULL,inds[2],**newtopo=NULL;5095Real *newx=NULL,*newy=NULL,*newz=NULL;50965097if(info) printf("Trying to increase the element order of current elements\n");50985099CreateNodalGraph(data,FALSE,info);51005101noknots = data->noknots;5102noelements = data->noelements;5103maxcon = data->nodalmaxconnections;5104maxnodes = 0;51055106newnodetable = Imatrix(0,maxcon-1,1,noknots);5107for(i=1;i<=noknots;i++)5108for(j=0;j<maxcon;j++)5109newnodetable[j][i] = 0;51105111newknots = 0;5112for(i=1;i<=noknots;i++) {5113for(j=0;j<maxcon;j++) {5114con = data->nodalgraph[j][i];5115if(con > i) {5116newknots++;5117newnodetable[j][i] = noknots + newknots;5118}5119}5120}51215122if(info) printf("There will be %d new nodes in the elements\n",newknots);51235124newx = Rvector(1,noknots+newknots);5125newy = Rvector(1,noknots+newknots);5126newz = Rvector(1,noknots+newknots);512751285129for(i=1;i<=noknots;i++) {5130newx[i] = data->x[i];5131newy[i] = data->y[i];5132newz[i] = data->z[i];5133}5134for(i=1;i<=noknots;i++) {5135for(j=0;j<maxcon;j++) {5136con = data->nodalgraph[j][i];5137ind = newnodetable[j][i];5138if(con && ind) {5139newx[ind] = 0.5*(data->x[i] + data->x[con]);5140newy[ind] = 0.5*(data->y[i] + data->y[con]);5141newz[ind] = 0.5*(data->z[i] + data->z[con]);5142}5143}5144}514551465147maxelemtype = GetMaxElementType(data);51485149if(maxelemtype <= 303)5150maxnodes = 6;5151else if(maxelemtype == 404)5152maxnodes = 8;5153else if(maxelemtype == 504)5154maxnodes = 10;5155else if(maxelemtype == 605)5156maxnodes = 13;5157else if(maxelemtype == 706)5158maxnodes = 15;5159else if(maxelemtype == 808)5160maxnodes = 20;5161else {5162printf("Not implemented for elementtype %d\n",maxelemtype);5163bigerror("IncreaseElementOrder: Cannot continue the subroutine");5164}51655166if(info) printf("New leading elementtype is %d\n",100*(maxelemtype/100)+maxnodes);51675168newtopo = Imatrix(1,noelements,0,maxnodes-1);51695170for(element=1;element<=noelements;element++) {5171elemtype = data->elementtypes[element];5172for(i=0;i<elemtype%100;i++)5173newtopo[element][i] = data->topology[element][i];5174}517551765177for(element=1;element<=data->noelements;element++) {5178elemtype = data->elementtypes[element];51795180nonodes = data->elementtypes[element] % 100;5181for(side=0;;side++) {5182hit = GetElementGraph(element,side,data,inds);51835184if(!hit) break;5185if(inds[0] > inds[1]) {5186ind = inds[1];5187ind2 = inds[0];5188}5189else {5190ind = inds[0];5191ind2 = inds[1];5192}5193for(j=0;j<maxcon;j++) {5194con = data->nodalgraph[j][ind];51955196if(con == ind2) {5197node = newnodetable[j][ind];5198newtopo[element][nonodes+side] = node;5199}5200}5201}52025203elemtype = 100*(elemtype/100)+nonodes+side;5204data->elementtypes[element] = elemtype;5205}52065207stat = DestroyNodalGraph(data,info);52085209free_Rvector(data->x,1,data->noknots);5210free_Rvector(data->y,1,data->noknots);5211free_Rvector(data->z,1,data->noknots);5212free_Imatrix(data->topology,1,data->noelements,0,data->maxnodes);5213free_Imatrix(newnodetable,0,maxcon-1,1,noknots);52145215data->x = newx;5216data->y = newy;5217data->z = newz;5218data->topology = newtopo;52195220data->noknots += newknots;5221data->maxnodes = maxnodes;52225223if(info) printf("Increased the element order from 1 to 2\n");52245225return(0);5226}5227522852295230static void CylindricalCoordinateTransformation(struct FemType *data,Real r1,Real r2,5231int rectangle)5232{5233int i,j,j2,ind1,ind2,nonodes1;5234Real x,y,r,f,z,q,x2,y2,z2,dx,dy,dz,eps,mult;5235int hits,trials,tests;5236int candidates,*candidatelist=NULL,*indx=NULL;52375238if(rectangle) {5239printf("Rectangular geometry with r1=%.4lg for %d nodes.\n",5240r1,data->noknots);5241}5242else {5243printf("Cylindrical geometry with r1=%.4lg r2=%.4lg for %d nodes.\n",5244r1,r2,data->noknots);5245}524652475248for(i=1;i<=data->noknots;i++) {5249r = data->x[i];5250z = data->y[i];5251f = data->z[i];52525253data->z[i] = z;52545255if(r >= r2) {5256data->x[i] = cos(f)*r;5257data->y[i] = sin(f)*r;5258}5259else if(r <= r2) {52605261mult = r/r1;52625263if(r > r1) {5264q = (r-r1)/(r2-r1);5265r = r1;5266}5267else {5268q = -1.0;5269}52705271if(f <= 0.25*FM_PI) {5272data->x[i] = r;5273data->y[i] = r1*4*(f-0.00*FM_PI)/FM_PI;5274}5275else if(f <= 0.75*FM_PI) {5276data->y[i] = r;5277data->x[i] = -r1*4*(f-0.5*FM_PI)/FM_PI;5278}5279else if(f <= 1.25*FM_PI) {5280data->x[i] = -r;5281data->y[i] = -r1*4*(f-1.0*FM_PI)/FM_PI;5282}5283else if(f <= 1.75*FM_PI){5284data->y[i] = -r;5285data->x[i] = r1*4*(f-1.5*FM_PI)/FM_PI;5286}5287else {5288data->x[i] = r;5289data->y[i] = r1*4*(f-2.0*FM_PI)/FM_PI;5290}52915292if(!rectangle && q > 0.0) {5293data->x[i] = (1-q)*data->x[i] + q*cos(f)*r2;5294data->y[i] = (1-q)*data->y[i] + q*sin(f)*r2;5295}5296else if(rectangle && mult > 1.0) {5297data->y[i] *= mult;5298data->x[i] *= mult;5299}5300} /* r <= r2 */5301}53025303eps = 1.0e-3 * data->minsize;53045305candidates = 0;5306candidatelist = Ivector(1,data->noknots);5307indx = Ivector(1,data->noknots);53085309for(i=1;i<=data->noknots;i++)5310indx[i] = 0;53115312for(j=1;j<=data->noelements;j++) {5313nonodes1 = data->elementtypes[j]%100;5314for(i=0;i<nonodes1;i++) {5315ind2 = data->topology[j][i];5316indx[ind2] = ind2;5317}5318}531953205321for(i=1;i<=data->noknots;i++) {5322if(!indx[i]) continue;53235324x = data->x[i];5325y = data->y[i];5326if(fabs(y) > r1+eps) continue;5327if((fabs(x) > r1+eps) && (fabs(y) > eps) ) continue;5328if((fabs(x) > eps) && (fabs(y) > eps) &&5329(fabs(fabs(x)-r1) > eps) && (fabs(fabs(y)-r1) > eps)) continue;53305331candidates++;5332candidatelist[candidates] = i;5333}5334printf("%d/%d candidates for duplicate nodes.\n",candidates,data->noknots);53355336hits = tests = trials = 0;5337for(j=1;j<=candidates;j++) {5338ind1 = indx[candidatelist[j]];5339x = data->x[ind1];5340y = data->y[ind1];5341z = data->z[ind1];53425343for(j2=j+1;j2<=candidates;j2++) {5344ind2 = indx[candidatelist[j2]];53455346x2 = data->x[ind2];5347y2 = data->y[ind2];5348z2 = data->z[ind2];53495350dx = x-x2;5351dy = y-y2;5352dz = z-z2;53535354tests++;5355if(dx*dx + dy*dy + dz*dz < eps*eps) {5356if(ind2 != ind1) {5357indx[candidatelist[j2]] = ind1;5358hits++;5359}5360}5361}5362}5363printf("Found %d double nodes in %d tests.\n",hits,tests);53645365for(j=1;j<=data->noelements;j++) {5366nonodes1 = data->elementtypes[j]%100;5367for(i=0;i<nonodes1;i++) {5368ind2 = data->topology[j][i];5369if(ind2 != indx[ind2]) {5370trials++;5371data->topology[j][i] = indx[ind2];5372}5373}5374}5375free_Ivector(indx,1,data->noknots);5376free_Ivector(candidatelist,1,data->noknots);53775378printf("Eliminated %d nodes from topology.\n",trials);5379}538053815382static void CylindricalCoordinateImprove(struct FemType *data,Real factor,5383Real r1,Real r2)5384{5385int i;5386Real x,y,r,q,q2,c,cmin,cmax,eps;53875388printf("Cylindrical coordinate for r1=%.4lg and r2=%.4lg.\n",r1,r2);53895390eps = 1.0e-10;53915392cmin = 1.0/(3.0-sqrt(3.));5393cmax = 1.0;53945395if(factor > 1.0) factor=1.0;5396else if(factor < 0.0) factor=0.0;53975398c = cmin+(cmax-cmin)*factor;53995400if(fabs(c-1.0) < eps) return;54015402printf("Improving cylindrical mesh quality r1=%.4lg, r2=%.4lg and c=%.4lg\n",r1,r2,c);54035404for(i=1;i<=data->noknots;i++) {5405x = data->x[i];5406y = data->y[i];54075408r = sqrt(x*x+y*y);5409if(r >= r2) continue;5410if(r < eps) continue;54115412if(fabs(x) <= r1+eps && fabs(y) <= r1+eps) {5413if(fabs(x) < fabs(y)) {5414q = fabs(x/y);5415data->x[i] = (c*q+(1.-q))*x;5416data->y[i] = (c*q+(1.-q))*y;5417}5418else {5419q = fabs(y/x);5420data->x[i] = (c*q+(1.-q))*x;5421data->y[i] = (c*q+(1.-q))*y;5422}5423}5424else {5425if(fabs(x) < fabs(y)) {5426q = fabs(x/y);5427q2 = (fabs(y)-r1)/(r2*fabs(y/r)-r1);5428data->x[i] = (c*q+(1.-q)) *x*(1-q2) + q2*x;5429data->y[i] = (c*q+(1.-q)) *(1-q2)*y + q2*y;5430}5431else {5432q = fabs(y/x);5433q2 = (fabs(x)-r1)/(r2*fabs(x/r)-r1);5434data->x[i] = (c*q+(1.-q))*(1-q2)*x + q2*x;5435data->y[i] = (c*q+(1.-q))*y*(1-q2) + q2*y;5436}5437}5438}5439}544054415442void CylindricalCoordinateCurve(struct FemType *data,5443Real zet,Real rad,Real angle)5444{5445int i;5446Real x,y,z;5447Real z0,z1,f,f0,z2,x2,r0;54485449printf("Cylindrical coordinate curve, zet=%.3lg rad=%.3lg angle=%.3lg\n",5450zet,rad,angle);54515452r0 = rad;5453f0 = FM_PI*(angle/180.);5454z0 = zet;5455z1 = z0+r0*f0;54565457for(i=1;i<=data->noknots;i++) {54585459if(data->dim == 2) {5460z = data->x[i];5461x = data->y[i];5462}5463else {5464x = data->x[i];5465y = data->y[i];5466z = data->z[i];5467}54685469if(z <= z0) continue;54705471if(z >= z1) {5472z2 = z0 + sin(f0)*(r0+x) + cos(f0)*(z-z1);5473x2 = (cos(f0)-1.0)*r0 + cos(f0)*x - sin(f0)*(z-z1);5474}5475else {5476f = (z-z0)/r0;5477z2 = z0 + sin(f)*(r0+x);5478x2 = (cos(f)-1.0)*r0 + cos(f)*x;5479}54805481if( data->dim == 2) {5482data->x[i] = z2;5483data->y[i] = x2;5484}5485else {5486data->z[i] = z2;5487data->x[i] = x2;5488}54895490}5491}549254935494void SeparateCartesianBoundaries(struct FemType *data,struct BoundaryType *bound,int info)5495{5496int i,j,k,l,type,maxtype,addtype,elemsides,totsides,used,hit;5497int sideelemtype,sideind[MAXBOUNDARIES];5498Real x,y,z,sx,sy,sz,sxx,syy,szz,dx,dy,dz;5499Real bclim[MAXBOUNDARIES];5500int bc[MAXBOUNDARIES],bcdim[MAXBOUNDARIES];5501Real eps=1.0e-4;55025503maxtype = 0;5504totsides = 0;5505for(j=0;j<MAXBOUNDARIES;j++) {5506if(!bound[j].created) continue;5507if(!bound[j].nosides) continue;55085509for(i=1;i<=bound[j].nosides;i++) {5510totsides++;5511for(k=1;k<=bound[j].nosides;k++)5512if(maxtype < bound[j].types[k]) maxtype = bound[j].types[k];5513}5514}55155516if(info) {5517printf("Maximum boundary type is %d\n",maxtype);5518printf("Number of boundaries is %d\n",totsides);5519}5520addtype = maxtype;55215522for(type=1;type<=maxtype;type++) {55235524for(i=0;i<MAXBOUNDARIES;i++)5525bclim[i] = 0.0;5526for(i=0;i<MAXBOUNDARIES;i++)5527bc[i] = bcdim[i] = 0;5528used = FALSE;55295530for(j=0;j<MAXBOUNDARIES;j++) {55315532if(!bound[j].created) continue;5533if(!bound[j].nosides) continue;55345535for(k=1;k<=bound[j].nosides;k++) {55365537if(bound[j].types[k] != type) continue;5538GetElementSide(bound[j].parent[k],bound[j].side[k],bound[j].normal[k],5539data,sideind,&sideelemtype);55405541sx = sy = sz = 0.0;5542sxx = syy = szz = 0.0;5543elemsides = sideelemtype%100;55445545/* Compute the variance within each axis */5546for(l=0;l<elemsides;l++) {5547x = data->x[sideind[l]];5548y = data->y[sideind[l]];5549z = data->z[sideind[l]];5550sx += x;5551sy += y;5552sz += z;5553sxx += x*x;5554syy += y*y;5555szz += z*z;5556}5557sx /= elemsides;5558sy /= elemsides;5559sz /= elemsides;5560sxx /= elemsides;5561syy /= elemsides;5562szz /= elemsides;5563dx = sqrt(sxx-sx*sx);5564dy = sqrt(syy-sy*sy);5565dz = sqrt(szz-sz*sz);55665567if(sideelemtype < 300 && dz < eps) {55685569if(dx < eps * dy) {5570hit = FALSE;5571for(i=0;i<MAXBOUNDARIES && bcdim[i];i++) {5572if(bcdim[i] == 1 && fabs(bclim[i]-sx) < eps*fabs(dy)) {5573bound[j].types[k] = bc[i];5574hit = TRUE;5575break;5576}5577}55785579if(!hit) {5580if(used) {5581addtype++;5582printf("Adding new BC %d in Y-direction\n",addtype);5583bc[i] = addtype;5584bound[j].types[k] = bc[i];5585}5586else {5587bc[i] = bound[j].types[k];5588}5589bcdim[i] = 1;5590bclim[i] = sx;5591used = TRUE;5592}5593}55945595if(dy < eps * dx) {5596hit = FALSE;5597for(i=0;i<MAXBOUNDARIES && bcdim[i];i++) {5598if(bcdim[i] == 2 && fabs(bclim[i]-sy) < eps*fabs(dx)) {5599bound[j].types[k] = bc[i];5600hit = TRUE;5601break;5602}5603}5604if(!hit) {5605if(used) {5606addtype++;5607printf("Adding new BC %d in X-direction\n",addtype);5608bc[i] = addtype;5609bound[j].types[k] = bc[i];5610}5611else {5612bc[i] = bound[j].types[k];5613}5614bcdim[i] = 2;5615bclim[i] = sy;5616used = TRUE;5617}5618}5619}5620else {5621if(dx < eps*dy && dx < eps*dz) {5622}5623else if(dy < eps*dx && dy < eps*dz) {5624}5625}5626}5627}5628}5629}56305631563256335634void SeparateMainaxisBoundaries(struct FemType *data,struct BoundaryType *bound)5635{5636int i,j,k,l,maxtype,addtype,elemsides;5637int sideelemtype,sideind[MAXNODESD1];5638int axistype[4],axishit[4],axissum,axismax,done;5639Real x,y,z,sx,sy,sz,sxx,syy,szz,dx,dy,dz;5640Real eps=1.0e-6;56415642maxtype = 0;5643addtype = 0;56445645for(j=0;j<data->noboundaries;j++) {56465647if(!bound[j].created) continue;5648if(!bound[j].nosides) continue;56495650for(i=1;i<=bound[j].nosides;i++) {5651for(k=1;k<=bound[j].nosides;k++)5652if(maxtype < bound[j].types[k]) maxtype = bound[j].types[k];5653}5654}5655printf("Maximum boundary type is %d\n",maxtype);56565657#if 05658for(j=0;j<data->noboundaries;j++) {5659if(!bound[j].created) continue;5660if(!bound[j].nosides) continue;5661if(bound[j].type) {5662bound[j].types = Ivector(1,bound[j].nosides);5663for(k=1;k<=bound[j].nosides;k++)5664bound[j].types[k] = bound[j].type;5665bound[j].type = 0;5666}5667}5668#endif56695670for(j=0;j<data->noboundaries;j++) {5671if(!bound[j].created) continue;5672if(!bound[j].nosides) continue;56735674for(k=0;k<4;k++) axishit[k] = 0;56755676done = 0;56775678omstart:56795680for(k=1;k<=bound[j].nosides;k++) {56815682GetElementSide(bound[j].parent[k],bound[j].side[k],bound[j].normal[k],5683data,sideind,&sideelemtype);56845685sx = sy = sz = 0.0;5686sxx = syy = szz = 0.0;5687elemsides = sideelemtype%100;56885689/* Compute the variance within each axis */5690for(l=0;l<elemsides;l++) {5691x = data->x[sideind[l]];5692y = data->y[sideind[l]];5693z = data->z[sideind[l]];5694sx += x;5695sy += y;5696sz += z;5697sxx += x*x;5698syy += y*y;5699szz += z*z;5700}5701sx /= elemsides;5702sy /= elemsides;5703sz /= elemsides;5704sxx /= elemsides;5705syy /= elemsides;5706szz /= elemsides;5707dx = sqrt(sxx-sx*sx);5708dy = sqrt(syy-sy*sy);5709dz = sqrt(szz-sz*sz);57105711if(dx < eps*dy && dx < eps*dz) {5712if(sx > 0.0) {5713if(done) {5714if(axistype[0]) bound[j].types[k] = maxtype + axistype[0];5715}5716else5717axishit[0] += 1;5718}5719if(sx < 0.0) {5720if(done) {5721if(axistype[1]) bound[j].types[k] = maxtype + axistype[1];5722}5723else5724axishit[1] += 1;5725}5726}5727else if(dy < eps*dx && dy < eps*dz) {5728if(sy > 0.0) {5729if(done) {5730if(axistype[2]) bound[j].types[k] = maxtype + axistype[2];5731}5732else5733axishit[2] += 1;5734}5735if(sy < 0.0) {5736if(done) {5737if(axistype[3]) bound[j].types[k] = maxtype + axistype[3];5738}5739else5740axishit[3] += 1;5741}5742}5743}57445745/* All this is done to select the sidetype appropriately */5746if(!done) {5747axissum = 0;5748axismax = 0;57495750for(k=0;k<4;k++) {5751axissum += axishit[k];5752if(axishit[k]) addtype++;5753}57545755if(axissum) {5756for(k=0;k<4;k++) {5757axismax = 0;5758for(l=0;l<4;l++) {5759if(axishit[l] > axishit[axismax])5760axismax = l;5761}5762axistype[axismax] = k+1;5763axishit[axismax] = -(k+1);5764}57655766if(axissum == bound[j].nosides) {5767for(k=0;k<4;k++)5768axistype[k] -= 1;5769addtype--;5770}57715772if(addtype) {5773printf("Separating %d rectangular boundaries from boundary %d.\n",addtype,j);5774done = 1;5775goto omstart;5776}5777else done = 0;5778}5779}5780maxtype += addtype;5781}5782}578357845785void CreateKnotsExtruded(struct FemType *dataxy,struct BoundaryType *boundxy,5786struct GridType *grid,5787struct FemType *data,struct BoundaryType *bound,5788int info)5789/* Create mesh from 2D mesh either by extrusion or by rotation.5790Also create the additional boundaries using automated numbering. */5791{5792#define MAXNEWBC 2005793int i,j,k,l,m,n,knot0,knot1,knot2,elem0,size,kmax,noknots,origtype;5794int nonodes3d,nonodes2d,bclevel,bcset;5795int cellk,element,level,side,parent,parent2,layers,elemtype,material_too_large;5796int material,material2,ind1,ind2;5797int *indx=NULL,*topo=NULL;5798int sideelemtype,sideind[MAXNODESD1],sidetype,minsidetype,maxsidetype,cummaxsidetype,newbounds;5799int refmaterial1[MAXNEWBC],refmaterial2[MAXNEWBC],refsidetype[MAXNEWBC],indxlength;5800Real z,*newx=NULL,*newy=NULL,*newz=NULL,corder[3];5801Real meanx,meany;5802int layerbcoffset;5803int usenames;58045805if(grid->rotate)5806SetElementDivisionCylinder(grid,info);5807else if(grid->dimension == 3)5808SetElementDivisionExtruded(grid,info);5809else {5810printf("CreateKnotsExtruded: unknown option!\n");5811return;5812}58135814InitializeKnots(data);58155816data->dim = 3;58175818origtype = 0;5819for(i=1;i<=dataxy->noelements;i++)5820origtype = MAX( origtype, dataxy->elementtypes[i]);58215822if(origtype == 202)5823elemtype = 404;5824else if(origtype == 303)5825elemtype = 706;5826else if(origtype == 404)5827elemtype = 808;5828else if(origtype == 408)5829elemtype = 820;5830else if(origtype == 409)5831elemtype = 827;5832else {5833printf("CreateKnotsExtruded: not implemented for elementtypes %d!\n",origtype);5834return;5835}5836printf("Maximum elementtype %d extruded to type %d.\n",origtype,elemtype);58375838nonodes2d = origtype%100;5839data->maxnodes = nonodes3d = elemtype%100;5840if(nonodes3d <= 8)5841layers = 1;5842else5843layers = 2;58445845/* Initialize the 3D mesh structure */5846data->noknots = noknots = dataxy->noknots*(layers*grid->totzelems+1);5847data->noelements = dataxy->noelements * grid->totzelems;5848data->coordsystem = dataxy->coordsystem;5849data->numbering = dataxy->numbering;5850data->noboundaries = dataxy->noboundaries;5851data->maxsize = dataxy->maxsize;5852data->minsize = dataxy->minsize;5853data->partitionexist = FALSE;5854data->periodicexist = FALSE;5855data->nodeconnectexist = FALSE;5856data->elemconnectexist = FALSE;58575858usenames = dataxy->bodynamesexist || dataxy->boundarynamesexist;5859if( usenames ) {5860if( grid->zmaterialmapexists ) {5861printf("Cannot extrude names when there is a given material mapping!\n");5862usenames = FALSE;5863}5864else {5865if(info) printf("Trying to maintain entity names in extrusion\n");5866}5867}5868586958705871maxsidetype = 0;58725873AllocateKnots(data);5874indxlength = MAX(data->noknots,data->noelements);5875indx = Ivector(0,indxlength);5876for(i=0;i<=indxlength;i++)5877indx[i] = 0;58785879newbounds = 0;5880if(grid->dimension == 3)5881newbounds = grid->zcells+1;5882else if(grid->rotate) {5883if(grid->rotateblocks < 4)5884newbounds = 4;5885if(grid->rotatecartesian)5886newbounds += grid->rotateblocks;5887}58885889/* Initialize the boundaries of the 3D mesh */5890for(j=0;j<data->noboundaries+newbounds;j++) {5891if(boundxy[j].created || j>=data->noboundaries) {5892bound[j] = boundxy[j];5893bound[j].created = TRUE;58945895size = bound[j].nosides = boundxy[j].nosides * grid->totzelems;5896if(j >= data->noboundaries) size = dataxy->noelements;58975898bound[j].coordsystem = COORD_CART3;5899bound[j].side = Ivector(1,size);5900bound[j].side2 = Ivector(1,size);5901bound[j].material = Ivector(1,size);5902bound[j].parent = Ivector(1,size);5903bound[j].parent2 = Ivector(1,size);5904bound[j].types = Ivector(1,size);5905bound[j].normal = Ivector(1,size);59065907for(i=1;i<=size;i++) {5908bound[j].types[i] = 0;5909bound[j].side[i] = 0;5910bound[j].side2[i] = 0;5911bound[j].parent[i] = 0;5912bound[j].parent2[i] = 0;5913bound[j].material[i] = 0;5914bound[j].normal[i] = 1;5915}5916bound[j].echain = FALSE;5917bound[j].ediscont = FALSE;5918}5919}5920if(info) printf("Allocated for %d new BC lists\n",j);59215922knot0 = 0;5923knot1 = layers*dataxy->noknots;5924if(layers == 2)5925knot2 = dataxy->noknots;5926else5927knot2 = 0;5928elem0 = 0;5929level = 0;5930material_too_large = 0;59315932/* Set the element topology of the extruded mesh */5933for(cellk=1;cellk <= grid->zcells ;cellk++) {59345935kmax = grid->zelems[cellk];59365937for(k=1;k<=kmax; k++) {59385939level++;59405941for(element=1;element <= dataxy->noelements;element++) {59425943origtype = dataxy->elementtypes[element];5944nonodes2d = origtype % 100;59455946if(origtype == 202)5947elemtype = 404;5948else if(origtype == 303)5949elemtype = 706;5950else if(origtype == 404)5951elemtype = 808;5952else if(origtype == 408)5953elemtype = 820;5954else if(origtype == 409)5955elemtype = 827;59565957if( grid->zmaterialmapexists ) {5958material = dataxy->material[element];5959if(material > grid->maxmaterial ) {5960material_too_large += 1;5961continue;5962}5963material = grid->zmaterialmap[cellk][material];5964if(material <= 0 ) continue;5965}5966else {5967if(dataxy->material[element] < grid->zfirstmaterial[cellk]) continue;5968if(dataxy->material[element] > grid->zlastmaterial[cellk]) continue;59695970if(grid->zmaterial[cellk])5971material = grid->zmaterial[cellk];5972else5973material = dataxy->material[element];5974}59755976if(grid->rotate) {5977meanx = 0.0;5978for(i=0;i<nonodes2d;i++)5979meanx += dataxy->x[dataxy->topology[element][i]];5980meanx = fabs(meanx/nonodes2d);5981}5982if(grid->rotate && meanx < 0.0) continue;5983if(grid->rotate && cellk%2==0 && meanx < grid->rotateradius1) continue;59845985elem0++;5986/* Vector telling the new element order. */5987indx[(level-1)*dataxy->noelements+element] = elem0;5988data->elementtypes[elem0] = elemtype;5989data->material[elem0] = material;59905991if(elemtype == 706) {5992for(i=0;i<3;i++) {5993data->topology[elem0][i] = dataxy->topology[element][i]+knot0;5994data->topology[elem0][i+3] = dataxy->topology[element][i]+knot1;5995}5996}5997else if(elemtype == 808) {5998for(i=0;i<4;i++) {5999data->topology[elem0][i] = dataxy->topology[element][i]+knot0;6000data->topology[elem0][i+4] = dataxy->topology[element][i]+knot1;6001}6002}6003if(elemtype == 820 || elemtype == 827) {6004for(i=0;i<4;i++) {6005data->topology[elem0][i] = dataxy->topology[element][i]+knot0;6006data->topology[elem0][i+4] = dataxy->topology[element][i]+knot1;6007data->topology[elem0][i+8] = dataxy->topology[element][i+4]+knot0;6008data->topology[elem0][i+12] = dataxy->topology[element][i]+knot2;6009data->topology[elem0][i+16] = dataxy->topology[element][i+4]+knot1;6010}6011}6012if(elemtype == 827) {6013for(i=0;i<4;i++)6014data->topology[elem0][20+i] = dataxy->topology[element][4+i]+knot2;6015data->topology[elem0][24] = dataxy->topology[element][8]+knot0;6016data->topology[elem0][25] = dataxy->topology[element][8]+knot1;6017data->topology[elem0][26] = dataxy->topology[element][8]+knot2;6018}6019else if(elemtype == 404) {6020data->topology[elem0][0] = dataxy->topology[element][0]+knot0;6021data->topology[elem0][1] = dataxy->topology[element][1]+knot0;6022data->topology[elem0][2] = dataxy->topology[element][1]+knot1;6023data->topology[elem0][3] = dataxy->topology[element][0]+knot1;6024}6025}6026knot0 += layers*dataxy->noknots;6027knot1 += layers*dataxy->noknots;6028knot2 += layers*dataxy->noknots;6029}6030}6031data->noelements = elem0;6032printf("Extruded mesh has %d elements in %d levels.\n",elem0,level);6033printf("Simple extrusion would have %d elements\n",level*dataxy->noelements);60346035if( material_too_large > 0 ) {6036printf("Material index exceeded %d the size of material permutation table (%d)!\n",6037material_too_large,grid->maxmaterial);6038printf("Give the max material with > Extruded Max Material < , if needed\n");6039}604060416042if(elem0 == 0) bigerror("No use to continue with zero elements!");60436044/* Set the nodal coordinates of the extruded mesh. */6045knot0 = 0;6046for(cellk=1;cellk <= grid->zcells ;cellk++) {60476048if(cellk == 1) k=0;6049else k=1;6050for(;k<=grid->zelems[cellk]; k++) {60516052if(grid->zlinear[cellk]) {6053z = grid->z[cellk-1] + k*grid->dz[cellk];6054}6055else if(grid->zexpand[cellk] > 0.0) {6056z = grid->z[cellk-1] + grid->dz[cellk] *6057(1.- pow(grid->zratios[cellk],(Real)(k))) / (1.-grid->zratios[cellk]);6058}6059else if(grid->zelems[cellk] <= 2) {6060z = grid->z[cellk-1] + k*grid->dz[cellk];6061}6062else {6063if((k<=grid->zelems[cellk]/2)) {6064z = grid->z[cellk-1] + grid->dz[cellk] *6065(1.- pow(grid->zratios[cellk],(Real)(k))) / (1.-grid->zratios[cellk]);6066}6067else {6068z = grid->z[cellk] - grid->dz[cellk] *6069(1.- pow(grid->zratios[cellk],(Real)(grid->zelems[cellk]-k))) / (1.-grid->zratios[cellk]);6070}6071}60726073for(i=1;i <= dataxy->noknots;i++) {6074data->x[i+knot0] = dataxy->x[i];6075data->y[i+knot0] = dataxy->y[i];6076data->z[i+knot0] = z;6077}6078knot0 += layers * dataxy->noknots;6079}6080}608160826083/* Set the coordinates for the middle nodes in case6084of quadratic elements. */6085if(elemtype == 820 || elemtype == 827) {6086for(element=1;element <= data->noelements;element++) {6087topo = data->topology[element];6088for(i=0;i<4;i++) {6089data->x[topo[i+12]] = 0.5*(data->x[topo[i]]+data->x[topo[i+4]]);6090data->y[topo[i+12]] = 0.5*(data->y[topo[i]]+data->y[topo[i+4]]);6091data->z[topo[i+12]] = 0.5*(data->z[topo[i]]+data->z[topo[i+4]]);6092}6093if(elemtype == 827) {6094for(i=0;i<4;i++) {6095data->x[topo[i+20]] = 0.5*(data->x[topo[12+i]]+data->x[topo[12+(i+1)%4]]);6096data->y[topo[i+20]] = 0.5*(data->y[topo[12+i]]+data->y[topo[12+(i+1)%4]]);6097data->z[topo[i+20]] = 0.5*(data->z[topo[12+i]]+data->z[topo[12+(i+1)%4]]);6098}6099data->x[topo[26]] = 0.5*(data->x[topo[0]]+data->x[topo[6]]);6100data->y[topo[26]] = 0.5*(data->y[topo[0]]+data->y[topo[6]]);6101data->z[topo[26]] = 0.5*(data->z[topo[0]]+data->z[topo[6]]);6102}6103}6104}61056106/* Perform cylindrical coordinate transformation */6107if(grid->rotate)6108CylindricalCoordinateTransformation(data,grid->rotateradius1,6109grid->rotateradius2,grid->rotatecartesian);61106111cummaxsidetype = 0;6112sidetype = 0;61136114/* Extrude the 2D boundary conditions. Initially BCs typically have parents with6115different material. If due to selective extrusion they become the same then6116the extruded BC does not have that component. */6117for(j=0;j<data->noboundaries;j++) {6118if(!bound[j].created) continue;61196120maxsidetype = 0;6121minsidetype = INT_MAX;6122side = 0;6123level = 0;61246125for(cellk=1;cellk <= grid->zcells ;cellk++) {6126for(k=1;k<=grid->zelems[cellk]; k++) {6127level++;61286129for(i=1;i<=boundxy[j].nosides;i++){61306131/* Find the parent element indexes and the corresponding material indexes */6132ind1 = (level-1)*dataxy->noelements + boundxy[j].parent[i];6133parent = indx[ind1];61346135if(parent) material = data->material[parent];6136else material = 0;61376138if(boundxy[j].parent2[i]) {6139ind2 = (level-1)*dataxy->noelements + boundxy[j].parent2[i];6140parent2 = indx[ind2];6141}6142else6143parent2 = 0;61446145if(parent2) material2 = data->material[parent2];6146else material2 = 0;61476148if((parent || parent2) && (material != material2)) {6149side++;61506151if(!parent & !parent2) printf("no parent = %d %d %d %d %d\n",parent,parent2,ind1,ind2,level);61526153sidetype = boundxy[j].types[i];6154bound[j].types[side] = sidetype;61556156maxsidetype = MAX( maxsidetype, sidetype );6157minsidetype = MIN( minsidetype, sidetype );61586159if(parent) {6160bound[j].parent[side] = parent;6161bound[j].parent2[side] = parent2;6162bound[j].side[side] = boundxy[j].side[i];6163bound[j].side2[side] = boundxy[j].side2[i];6164bound[j].material[side] = material;6165}6166else {6167bound[j].parent[side] = parent2;6168bound[j].parent2[side] = parent;6169bound[j].side[side] = boundxy[j].side2[i];6170bound[j].side2[side] = boundxy[j].side[i];6171bound[j].material[side] = material2;6172}61736174/* The sides have different convention for 1D initial elements */6175if(elemtype == 404) {6176if(bound[j].side[side] == 0) bound[j].side[side] = 3;6177if(bound[j].side2[side] == 0) bound[j].side2[side] = 3;6178}6179}6180}6181}6182}6183bound[j].nosides = side;6184cummaxsidetype = MAX( maxsidetype, cummaxsidetype );61856186if(info) {6187if(side)6188printf("Extruded BCs list %d of types [%d,%d] has %d elements.\n",6189j,minsidetype,maxsidetype,side);6190else6191printf("Extruded BCs list %d has no elements!\n",j);6192}61936194}61956196bcset = dataxy->noboundaries-1;619761986199if( usenames ) {6200for(i=1;i< MAXBODIES;i++) {6201if(dataxy->bodyname[i]) {6202if(!data->bodyname[i]) data->bodyname[i] = Cvector(0,MAXNAMESIZE);6203strcpy(data->bodyname[i],dataxy->bodyname[i]);6204}6205}6206for(i=1;i< MAXBCS;i++) {6207if(dataxy->boundaryname[i]) {6208if(!data->boundaryname[i]) data->boundaryname[i] = Cvector(0,MAXNAMESIZE);6209strcpy(data->boundaryname[i],dataxy->boundaryname[i]);6210}6211}6212data->bodynamesexist = TRUE;6213data->boundarynamesexist = TRUE;6214}621562166217/* Find the BCs that are created for constant z-levels.6218Here number all parent combinations so that each pair gets6219a new BC index. They are numbered by their order of appearance. */6220layerbcoffset = grid->layerbcoffset;62216222if(grid->layeredbc) {62236224if( !layerbcoffset ) sidetype = maxsidetype;62256226/* Find the BCs between layers. */6227if(grid->dimension == 3 || grid->rotatecartesian) {6228side = 0;6229level = 0;6230bclevel = 0;623162326233/* Go through extruded cells */6234for(cellk=1;cellk <= grid->zcells ;cellk++) {6235int swap,redo;6236redo = FALSE;62376238redolayer:6239maxsidetype = 0;6240minsidetype = INT_MAX;62416242/* Go through element layers within cells */6243for(k=1;k<=grid->zelems[cellk]; k++) {6244level++;6245if(!(k == 1) && !(cellk == grid->zcells && k==grid->zelems[cellk])) continue;62466247/* Last cell in case of last just one element layer gives rise to two BCs */6248if(cellk == grid->zcells && k == grid->zelems[cellk]) {6249if(grid->zelems[cellk] == 1)6250redo = TRUE;6251else {6252level++;6253}6254}62556256if(grid->rotatecartesian && cellk % 2 == 1) continue;6257if(grid->rotatecartesian && k != 1) continue;62586259/* If layred bc offset is defined then the BCs are numbered deterministically6260otherwise there is a complicated method of defining the BC index so that6261indexes would be used in order. */6262if(!layerbcoffset) {6263for(i=0;i<MAXNEWBC;i++) {6264refmaterial1[i] = 0;6265refmaterial2[i] = 0;6266refsidetype[i] = 0;6267}6268}6269side = 0;6270bcset++;6271bclevel++;6272maxsidetype = 0;6273minsidetype = INT_MAX;62746275for(i=1;i<=dataxy->noelements;i++){6276origtype = dataxy->elementtypes[i];6277nonodes2d = origtype % 100;62786279if(origtype == 202)6280elemtype = 404;6281else if(origtype == 303)6282elemtype = 706;6283else if(origtype == 404)6284elemtype = 808;6285else if(origtype == 408)6286elemtype = 820;6287else if(origtype == 409)6288elemtype = 827;62896290/* Check the parent elements of the layers. Only create a BC if the parents are6291different. */6292ind1 = (level-2)*dataxy->noelements + i;6293if(ind1 < 1)6294parent = 0;6295else6296parent = indx[ind1];62976298ind2 = (level-1)*dataxy->noelements + i;6299if(ind2 > indxlength)6300parent2 = 0;6301else6302parent2 = indx[ind2];63036304/* If only 2nd parent is given swap the order */6305if(parent == 0 && parent2 != 0) {6306parent = parent2;6307parent2 = 0;6308swap = 1;6309}6310else {6311swap = 0;6312}63136314if(!parent) continue;63156316/* Get the materials related to the parents */6317material = data->material[parent];6318if(parent2)6319material2 = data->material[parent2];6320else6321material2 = 0;63226323if(grid->rotatecartesian && !material2) {6324if(origtype == 303) GetElementSide(parent,4-swap,1,data,sideind,&sideelemtype);6325else GetElementSide(parent,5-swap,1,data,sideind,&sideelemtype);6326meanx = meany = 0.0;6327if(cellk%4 == 2) {6328for(l=0;l<sideelemtype%100;l++) {6329meanx += data->y[sideind[l]];6330meany += data->z[sideind[l]];6331}6332}6333else {6334for(l=0;l<sideelemtype%100;l++) {6335meanx += data->x[sideind[l]];6336meany += data->z[sideind[l]];6337}6338}6339meanx = fabs(meanx)/(sideelemtype%100);6340meany = fabs(meany)/(sideelemtype%100);63416342if(fabs(meanx - grid->rotateradius1) > 1.0e-12) {6343material2 = material;6344}6345else {6346for(m=0;m<grid->xcells && grid->x[m]+1.0e-12 < meanx;m++);6347for(n=0;n<grid->ycells && grid->y[n]+1.0e-12 < meany;n++);6348material2 = grid->structure[n][m+1];6349}6350}63516352/* Create bc index only if the materials are different */6353if(material != material2) {6354side++;63556356bound[bcset].nosides = side;6357bound[bcset].parent[side] = parent;6358bound[bcset].parent2[side] = parent2;6359bound[bcset].material[side] = material;63606361if(origtype == 303) {6362bound[bcset].side[side] = 4-swap;6363bound[bcset].side2[side] = 3+swap;6364}6365else {6366bound[bcset].side[side] = 5-swap;6367bound[bcset].side2[side] = 4+swap;6368}63696370/* Simple and deterministic, and complex and continuous numbering */6371if(layerbcoffset) {6372sidetype = bclevel * layerbcoffset + dataxy->material[i];6373bound[bcset].types[side] = sidetype;6374maxsidetype = MAX( sidetype, maxsidetype );6375minsidetype = MIN( sidetype, minsidetype );6376}6377else {6378for(m=0;m<MAXNEWBC;m++) {6379if(refmaterial1[m] == material && refmaterial2[m] == material2) {6380break;6381}6382else if(refmaterial1[m] == 0 && refmaterial2[m] == 0) {6383refmaterial1[m] = material;6384refmaterial2[m] = material2;6385sidetype++;6386maxsidetype = MAX( sidetype, maxsidetype );6387minsidetype = MIN( sidetype, minsidetype );6388refsidetype[m] = sidetype;6389break;6390}6391else if(m == MAXNEWBC-1) {6392printf("Layer includes more than %d new BCs!\n",MAXNEWBC);6393}6394}6395l = refsidetype[m];6396bound[bcset].types[side] = l;639763986399if( usenames ) {6400if(!data->boundaryname[l]) data->boundaryname[l] = Cvector(0,MAXNAMESIZE);6401if( bclevel == 1 )6402sprintf(data->boundaryname[l],"%s%s",6403dataxy->bodyname[dataxy->material[i]],"_Start");6404else if( cellk == grid->zcells )6405sprintf(data->boundaryname[l],"%s%s",6406dataxy->bodyname[dataxy->material[i]],"_End");6407else6408sprintf(data->boundaryname[l],"%s%s%d",6409dataxy->bodyname[dataxy->material[i]],"_Level",bclevel);6410}641164126413}64146415}6416}64176418if(info) {6419if(side)6420printf("Layer BCs list %d of types [%d,%d] has %d elements.\n",6421bcset,minsidetype,maxsidetype,side);6422else6423printf("Layer BCs list %d has no elements!\n",bcset);6424}64256426if(redo == TRUE) {6427goto redolayer;6428}6429}6430}6431}6432}643364346435/* Create four additional boundaries that may be used to force6436symmetry constraints. These are only created if the object6437is only partially rotated. */64386439bcset++;6440if(grid->rotate && grid->rotateblocks < 4) {6441int o,p;6442int blocks, maxradi,addtype;6443Real eps,fii,rad,meanrad,maxrad,xc,yc,dfii,fii0,rads[4],fiis[4];64446445o = p = 0;6446eps = 1.0e-3;6447blocks = grid->rotateblocks;64486449for(element=1;element<=data->noelements;element++) {64506451for(side=0;side<6;side++) {6452GetElementSide(element,side,1,data,&sideind[0],&sideelemtype);64536454meanrad = 0.0;6455maxrad = 0.0;6456maxradi = 0;64576458j = sideelemtype/100;6459if(j==1) break;64606461for(i=0;i<j;i++) {6462xc = data->x[sideind[i]];6463yc = data->y[sideind[i]];64646465rad = sqrt(yc*yc+xc*xc);6466fii = 2*atan2(yc,xc)/FM_PI; /* Map fii to [0 4] */64676468rads[i] = rad;6469fiis[i] = fii;64706471if(rad > maxrad) {6472maxrad = rad;6473maxradi = i;6474}6475meanrad += rad / j;6476}64776478fii0 = fiis[maxradi];6479dfii = 0.0;6480for(i=0;i<4;i++) {6481if(rads[i] > eps * maxrad) {6482if( fabs(fiis[i]-fii0) > dfii) dfii = fabs(fiis[i]-fii0);6483}6484}64856486if(dfii > eps) continue;64876488addtype = -1;64896490/* BCs for zero angle */6491if(fabs(fii0) < eps) {6492o++;6493if(meanrad < grid->rotateradius2)6494addtype = 0;6495else6496addtype = 2;6497}6498/* BCs for angles 90, 180 or 270. */6499else if(fabs(fii0-blocks) < eps) {6500p++;6501if(meanrad < grid->rotateradius2)6502addtype = 1;6503else6504addtype = 3;6505}65066507if( addtype >= 0) {6508bound[bcset+addtype].nosides++;6509k = bound[bcset+addtype].nosides;6510bound[bcset+addtype].side[k] = side;6511bound[bcset+addtype].parent[k] = element;6512bound[bcset+addtype].types[k] = sidetype+addtype+1;6513}6514}6515}65166517for(addtype=0;addtype<4;addtype++) {6518l = bcset+addtype;6519if(bound[l].nosides == 0) {6520bound[l].created = FALSE;6521}6522else {6523bound[l].created = TRUE;6524if(info) {6525if(bound[l].nosides)6526printf("Symmetry BCs list %d of type %d has %d elements.\n",6527l,sidetype+addtype+1,bound[l].nosides);6528else6529printf("Symmetry BCs list %d has no elements!\n",l);6530}6531}6532}6533bcset += 4;6534}6535data->noboundaries = bcset+1;653665376538/* Renumber the element nodes so that all integers are used.6539Allocate new space for the new nodes and their coordinates. */65406541for(i=1;i<=data->noknots;i++)6542indx[i] = 0;65436544for(element=1;element<=data->noelements;element++) {6545nonodes3d = data->elementtypes[element] % 100;6546for(i=0;i<nonodes3d;i++)6547indx[data->topology[element][i]] = 1;6548}65496550j = 0;6551for(i=1;i<=data->noknots;i++)6552if(indx[i])6553indx[i] = ++j;65546555if(j < data->noknots) {6556printf("%d original nodes moved to %d new ones.\n",data->noknots,j);6557newx = Rvector(1,j);6558for(i=1;i<=data->noknots;i++)6559newx[indx[i]] = data->x[i];65606561newy = data->x;6562data->x = newx;6563for(i=1;i<=data->noknots;i++)6564newy[indx[i]] = data->y[i];65656566newz = data->y;6567data->y = newy;6568for(i=1;i<=data->noknots;i++)6569newz[indx[i]] = data->z[i];65706571free_Rvector(data->z,1,data->noknots);6572data->z = newz;6573data->noknots = j;65746575for(element=1;element<=data->noelements;element++) {6576nonodes3d = data->elementtypes[element] % 100;6577for(i=0;i<nonodes3d;i++)6578data->topology[element][i] = indx[data->topology[element][i]];6579}6580}65816582if(grid->rotate) {6583ReorderElements(data,bound,FALSE,corder,info);65846585CylindricalCoordinateImprove(data,grid->rotateimprove,6586grid->rotateradius1,grid->rotateradius2);65876588if(0 && grid->rotatecurve)6589CylindricalCoordinateCurve(data,grid->curvezet,6590grid->curverad,grid->curveangle);65916592if(grid->rotatecartesian)6593SeparateMainaxisBoundaries(data,bound);65946595printf("Created %d elements and %d nodes by rotation of %d degrees.\n",6596data->noelements,data->noknots,90*grid->rotateblocks);6597}6598else if(grid->dimension == 3)6599if(info) printf("Created %d elements and %d nodes by extruding the 2D geometry\n",6600data->noelements,data->noknots);66016602free_Ivector(indx,0,indxlength);660366046605/* Enforce constant helicity for the mesh if requested */6606if( grid->zhelicityexists ) {6607Real helicity,fii,x,y,z,minz,maxz;66086609helicity = (FM_PI/180.0)*grid->zhelicity;66106611minz = maxz = data->z[1];6612for(i=1;i<=data->noknots;i++) {6613minz = MIN(minz,data->z[i]);6614maxz = MAX(maxz,data->z[i]);6615}6616for(i=1;i<=data->noknots;i++) {6617x = data->x[i];6618y = data->y[i];6619z = data->z[i];6620fii = helicity*(z-minz)/(maxz-minz);66216622data->x[i] = cos(fii)*x - sin(fii)*y;6623data->y[i] = sin(fii)*x + cos(fii)*y;6624}6625if(info) printf("Applied helicity of %12.5le degrees\n",grid->zhelicity);6626}66276628}6629663066316632void ReduceElementOrder(struct FemType *data,int matmin,int matmax)6633/* Reduces the element order at material interval [matmin,matmax] */6634{6635int i,j,element,material,elemcode1,elemcode2,maxnode,reduced;6636int *indx=NULL;6637Real *newx=NULL,*newy=NULL,*newz=NULL;66386639indx = Ivector(0,data->noknots);6640for(i=0;i<=data->noknots;i++)6641indx[i] = 0;6642reduced = 0;66436644for(element=1;element<=data->noelements;element++) {6645elemcode1 = data->elementtypes[element];6646material = data->material[element];6647elemcode2 = elemcode1;6648if(material >= matmin && material <= matmax)6649elemcode2 = 101*(elemcode1/100);6650if(elemcode2 == 505) elemcode2 = 504; /* tetrahedron */6651else if(elemcode2 == 606) elemcode2 = 605; /* pyramid */6652else if(elemcode2 == 707) elemcode2 = 706; /* prism */6653#if 06654printf("element=%d codes=[%d,%d]\n",element,elemcode1,elemcode2);6655printf("mat=%d interval=[%d,%d]\n",material,matmin,matmax);6656#endif6657if(elemcode2 < elemcode1)6658reduced++;6659maxnode = elemcode2%100;6660for(i=0;i<maxnode;i++)6661indx[data->topology[element][i]] = 1;6662data->elementtypes[element] = elemcode2;6663}66646665printf("The element order is reduced in %d elements at interval [%d,%d]\n",6666reduced,matmin,matmax);66676668j = 0;6669for(i=1;i<=data->noknots;i++)6670if(indx[i])6671indx[i] = ++j;66726673printf("%d original nodes moved to %d new ones.\n",data->noknots,j);66746675newx = Rvector(1,j);6676newy = Rvector(1,j);6677newz = Rvector(1,j);66786679for(i=1;i<=data->noknots;i++) {6680newx[indx[i]] = data->x[i];6681newy[indx[i]] = data->y[i];6682newz[indx[i]] = data->z[i];6683}66846685free_Rvector(data->x,1,data->noknots);6686free_Rvector(data->y,1,data->noknots);6687free_Rvector(data->z,1,data->noknots);66886689data->x = newx;6690data->y = newy;6691data->z = newz;6692data->noknots = j;66936694for(element=1;element<=data->noelements;element++) {6695maxnode = data->elementtypes[element]%100;6696for(i=0;i<maxnode;i++)6697data->topology[element][i] = indx[data->topology[element][i]];6698}6699}67006701670267036704void MergeElements(struct FemType *data,struct BoundaryType *bound,6705int manual,Real corder[],Real eps,int mergebounds,int info)6706{6707int i,j,k,l;6708int noelements,noknots,newnoknots,nonodes;6709int *mergeindx=NULL,*doubles=NULL;6710Real *newx=NULL,*newy=NULL,*newz=NULL;6711Real cx,cy,cz,dx,dy,dz,cdist,dist;67126713ReorderElements(data,bound,manual,corder,TRUE);67146715/* The known ordering by vector corder[] is used to6716reduce the cost of finding the merged nodes. */67176718cx = corder[0];6719cy = corder[1];6720cz = corder[2];67216722/* Normalizing for future use */6723cdist = sqrt(cx*cx+cy*cy+cz*cz);6724cx /= cdist;6725cy /= cdist;6726cz /= cdist;67276728noelements = data->noelements;6729noknots = data->noknots;6730newnoknots = noknots;67316732mergeindx = Ivector(1,noknots);6733for(i=1;i<=noknots;i++)6734mergeindx[i] = 0;67356736doubles = Ivector(1,noknots);6737for(i=1;i<=noknots;i++)6738doubles[i] = 0;67396740if(info) printf("Merging nodes close (%.3lg) to one another.\n",eps);67416742dz = 0.0;6743for(i=1;i<noknots;i++) {6744if(mergeindx[i]) continue;67456746for(j=i+1; j<=noknots;j++) {6747if(mergeindx[j]) continue;67486749dx = data->x[i] - data->x[j];6750dy = data->y[i] - data->y[j];6751dz = data->z[i] - data->z[j];67526753if(fabs(cx*dx+cy*dy+cz*dz) > eps) break;67546755dist = dx*dx + dy*dy + dz*dz;67566757if(dist < eps*eps) {6758doubles[i] = doubles[j] = TRUE;6759mergeindx[j] = -i;6760newnoknots--;6761}6762}6763}67646765if(mergebounds) MergeBoundaries(data,bound,doubles,info);676667676768j = 0;6769for(i=1;i<=noknots;i++)6770if(mergeindx[i] == 0)6771mergeindx[i] = ++j;67726773for(i=1;i<=noknots;i++) {6774if(mergeindx[i] < 0)6775mergeindx[i] = mergeindx[-mergeindx[i]];6776}67776778printf("%d original nodes merged to %d new nodes.\n",6779noknots,newnoknots);67806781newx = Rvector(1,newnoknots);6782newy = Rvector(1,newnoknots);6783newz = Rvector(1,newnoknots);67846785for(i=1;i<=noknots;i++) {6786newx[mergeindx[i]] = data->x[i];6787newy[mergeindx[i]] = data->y[i];6788newz[mergeindx[i]] = data->z[i];6789}67906791free_Rvector(data->x,1,data->noknots);6792free_Rvector(data->y,1,data->noknots);6793free_Rvector(data->z,1,data->noknots);67946795data->x = newx;6796data->y = newy;6797data->z = newz;67986799#if 06800if(info) printf("Merging the topologies.\n");6801#endif68026803l = 0;6804for(j=1;j<=noelements;j++) {6805nonodes = data->elementtypes[j] % 100;6806for(i=0;i<nonodes;i++) {6807k = data->topology[j][i];6808data->topology[j][i] = mergeindx[k];6809}6810}68116812data->noknots = newnoknots;6813free_Ivector(mergeindx,1,noknots);68146815if(info) printf("Merging of nodes is complete.\n");6816}6817681868196820void MergeBoundaries(struct FemType *data,struct BoundaryType *bound,int *doubles,int info)6821{6822int i,i2,j,k,l,totsides,newsides,sidenodes,sideelemtype,side;6823int parent,sideind[MAXNODESD1];68246825totsides = 0;6826newsides = 0;68276828if(info) printf("Eliminating boundaries at joined nodes\n");68296830for(j=0;j<MAXBOUNDARIES;j++) {6831if(!bound[j].created) continue;6832if(!bound[j].nosides) continue;68336834i2 = 0;6835for(i=1;i<=bound[j].nosides;i++) {68366837parent = bound[j].parent[i];6838side = bound[j].side[i];68396840GetElementSide(parent,side,1,data,sideind,&sideelemtype);6841sidenodes = sideelemtype % 100;68426843l = 0;6844for(k=0;k<sidenodes;k++)6845if(doubles[sideind[k]]) l++;68466847if(l < sidenodes) {6848i2++;68496850if(i != i2) {6851bound[j].parent[i2] = bound[j].parent[i];6852bound[j].parent2[i2] = bound[j].parent2[i];6853bound[j].side[i2] = bound[j].side[i];6854bound[j].side2[i2] = bound[j].side2[i];6855bound[j].types[i2] = bound[j].types[i];6856bound[j].normal[i2] = bound[j].normal[i];6857}6858}68596860}6861totsides += bound[j].nosides;6862newsides += i2;6863bound[j].nosides = i2;6864if(!i2) bound[j].created = FALSE;6865}68666867if(info) printf("Eliminated %d boundaries from original set of %d.\n",totsides-newsides,totsides);68686869}6870687168726873void IsoparametricElements(struct FemType *data,struct BoundaryType *bound,6874int bcstoo,int info)6875{6876int i,j,k;6877int noelements,noknots;6878int element,side,sideelemtype,sidenodes,elemtype;6879int *bcindx=NULL,*topo=NULL,sideind[MAXNODESD1];6880Real *x=NULL,*y=NULL,*z=NULL;68816882noelements = data->noelements;6883noknots = data->noknots;6884x = data->x;6885y = data->y;6886z = data->z;68876888bcindx = Ivector(1,noknots);6889for(i=1;i<=noknots;i++)6890bcindx[i] = FALSE;68916892for(j=0;j < MAXBOUNDARIES;j++) {6893if(!bound[j].created) continue;68946895for(i=1; i <= bound[j].nosides; i++) {6896element = bound[j].parent[i];6897side = bound[j].side[i];68986899GetElementSide(element,side,1,data,sideind,&sideelemtype);69006901sidenodes = sideelemtype%100;69026903for(k=0;k<sidenodes;k++)6904bcindx[sideind[k]] = TRUE;6905}6906}69076908for(j=1;j<=noelements;j++) {6909elemtype = data->elementtypes[j];6910topo = data->topology[j];69116912if(elemtype == 306) {6913for(i=0;i<3;i++) {6914if(!bcindx[topo[i+3]]) {6915x[topo[i+3]] = 0.5*(x[topo[i]]+x[topo[(i+1)%3]]);6916y[topo[i+3]] = 0.5*(y[topo[i]]+y[topo[(i+1)%3]]);6917}6918}69196920}6921else if(elemtype == 310) {6922for(i=0;i<3;i++) {6923if(!bcindx[topo[2*i+3]]) {6924x[topo[2*i+3]] = (2.0*x[topo[i]]+1.0*x[topo[(i+1)%3]])/3.0;6925x[topo[2*i+4]] = (1.0*x[topo[i]]+2.0*x[topo[(i+1)%3]])/3.0;6926y[topo[2*i+3]] = (2.0*y[topo[i]]+1.0*y[topo[(i+1)%3]])/3.0;6927y[topo[2*i+4]] = (1.0*y[topo[i]]+2.0*y[topo[(i+1)%3]])/3.0;6928}6929}6930x[topo[9]] = (x[topo[0]]+x[topo[1]]+x[topo[2]])/3.0;6931y[topo[9]] = (y[topo[0]]+y[topo[1]]+y[topo[2]])/3.0;6932}6933else if(elemtype == 408 || elemtype == 409) {6934for(i=0;i<4;i++) {6935if(!bcindx[topo[i+4]]) {6936x[topo[i+4]] = 0.5*(x[topo[i]]+x[topo[(i+1)%4]]);6937y[topo[i+4]] = 0.5*(y[topo[i]]+y[topo[(i+1)%4]]);6938}6939}6940if(elemtype == 409) {6941x[topo[8]] = 0.25*(x[topo[0]]+x[topo[1]]+x[topo[2]]+x[topo[3]]);6942y[topo[8]] = 0.25*(y[topo[0]]+y[topo[1]]+y[topo[2]]+y[topo[3]]);6943}6944}6945else if(elemtype == 412 || elemtype == 416) {6946for(i=0;i<4;i++) {6947if(!bcindx[topo[2*i+4]]) {6948x[topo[2*i+4]] = (2.0*x[topo[i]]+1.0*x[topo[(i+1)%4]])/3.0;6949x[topo[2*i+5]] = (1.0*x[topo[i]]+2.0*x[topo[(i+1)%4]])/3.0;6950y[topo[2*i+4]] = (2.0*y[topo[i]]+1.0*y[topo[(i+1)%4]])/3.0;6951y[topo[2*i+5]] = (1.0*y[topo[i]]+2.0*y[topo[(i+1)%4]])/3.0;6952}6953}6954if(elemtype == 416) {6955Real xmean,ymean;6956xmean = (x[topo[0]]+x[topo[1]]+x[topo[2]]+x[topo[3]])/4.0;6957ymean = (y[topo[0]]+y[topo[1]]+y[topo[2]]+y[topo[3]])/4.0;6958for(i=0;i<4;i++) {6959x[topo[11+i]] = (2.*xmean + 1.0*x[i]) / 3.0;6960y[topo[11+i]] = (2.*ymean + 1.0*y[i]) / 3.0;6961}6962}6963}6964else {6965printf("IsoparametricElements: Not implemented for elementtype %d\n",elemtype);6966}6967}69686969if(info) printf("The elements were forced to be isoparametric\n");6970}6971697269736974void ElementsToBoundaryConditions(struct FemType *data,6975struct BoundaryType *bound,int retainorphans,int info)6976{6977int i,j,k,l,sideelemtype,sideelemtype2,elemind,elemind2,sideelem,sameelem;6978int sideind[MAXNODESD1],sideind2[MAXNODESD1],elemsides,side,hit,same,minelemtype;6979int sidenodes,sidenodes2,maxelemtype,elemtype,elemdim,sideelements,material;6980int *moveelement=NULL,*parentorder=NULL,*possible=NULL,**invtopo=NULL;6981int noelements,maxpossible,noknots,maxelemsides,twiceelem,sideelemdim,minelemdim,maxelemdim;6982int debug,unmoved,removed,elemhits,loopdim,lowdimbulk;6983int notfound,*notfounds=NULL,movenames;698469856986if(info) {6987printf("Moving bulk elements to boundary elements\n");6988if(0) printf("Trying to retain orphans: %d\n",retainorphans);6989}69906991for(j=0;j < MAXBOUNDARIES;j++)6992bound[j].created = FALSE;6993for(j=0;j < MAXBOUNDARIES;j++)6994bound[j].nosides = 0;69956996noelements = data->noelements;6997noknots = data->noknots;69986999movenames = (data->bodynamesexist && !data->boundarynamesexist);7000if(data->bodynamesexist && info) {7001if(movenames)7002printf("Moving boundarynames together with elements\n");7003else7004printf("Assuming that boundaries names are already Ok!\n");7005}70067007maxelemtype = GetMaxElementType(data);7008if(info) printf("Leading bulk elementtype is %d\n",maxelemtype);70097010minelemtype = GetMinElementType(data);7011if(info) printf("Trailing bulk elementtype is %d\n",minelemtype);70127013maxelemdim = GetElementDimension(maxelemtype);7014minelemdim = GetElementDimension(minelemtype);7015if( maxelemdim - minelemdim == 0) {7016if(info) printf("No lower dimensional elements present!\n");7017return;7018}70197020if(maxelemdim-minelemdim > 1 ) {7021int **tagcount;7022int mintag,maxtag,tag,overlap;70237024mintag=maxtag=tag=overlap=-1;70257026if(info) printf("Checking that different dimensions have unique boundary tags!\n");70277028for(k=0;k<=2;k++) {7029for(i=1;i<=noelements;i++) {7030elemdim = GetElementDimension(data->elementtypes[i]);7031tag = data->material[i];70327033/* Get the tag interval for all elements */7034if(k==0) {7035if(maxtag==-1) {7036mintag = maxtag = tag;7037}7038else {7039mintag = MIN(mintag,tag);7040maxtag = MAX(maxtag,tag);7041}7042}70437044/* Count the number of tags for each dimensional */7045else if(k==1) {7046tagcount[elemdim][tag] += 1;7047}70487049/* Set the new tags for lower dimensions */7050else if(k==2) {7051if(elemdim < maxelemdim ) {7052data->material[i] = tagcount[elemdim][tag];7053}7054}7055}70567057if(k==0) {7058if(info) printf("Tag interval for boundaries: [%d %d]\n",mintag,maxtag);7059tagcount = Imatrix(0,maxelemdim,mintag,maxtag);7060for(i=0;i<=maxelemdim;i++)7061for(j=mintag;j<=maxtag;j++)7062tagcount[i][j] = 0;7063}7064else if(k==1) {7065for(j=mintag;j<=maxtag;j++) {7066overlap = 0;7067for(i=0;i<maxelemdim;i++)7068if(tagcount[i][j]) overlap++;7069if(overlap>1) break;7070}7071if(overlap>1) {7072if(info) printf("We have an overlap, applying offsets!\n");7073tag = 0;7074for(i=maxelemdim-1;i>=0;i--)7075for(j=mintag;j<=maxtag;j++) {7076if(tagcount[i][j]) {7077if(tag+1 <= j) {7078tag = j;7079}7080else {7081tag++;7082if(info) printf("Replacing tag in %d-dim %d -> %d\n",i,j,tag);7083}7084tagcount[i][j] = tag;7085}7086}7087}7088else {7089if(info) printf("No overlap, no offsets needed!\n");7090break;7091}7092}7093else if(k==2) {7094if(info) printf("Renumbered tags for boundary elements!\n");7095}7096}7097free_Imatrix(tagcount,0,maxelemdim,mintag,maxtag);7098}70997100moveelement = Ivector(1,noelements);71017102sideelements = 0;7103maxelemtype = 0;7104maxelemsides = 0;7105unmoved = 0;7106removed = 0;7107notfound = 0;7108lowdimbulk = 0;71097110for(i=1;i<=noelements;i++) {7111moveelement[i] = FALSE;7112sideelemdim = GetElementDimension(data->elementtypes[i]);71137114/* Lower dimensional elements are candidates to become BC elements */7115moveelement[i] = maxelemdim - sideelemdim;7116if(moveelement[i]) sideelements++;7117}7118if(info) printf("There are %d (out of %d) lower dimensional elements.\n",7119sideelements,noelements);7120if(sideelements == 0) return;71217122AllocateBoundary(bound,sideelements);71237124/* Compute maximum number of hits for inverse topology */7125possible = Ivector(1,noknots);7126for(i=1;i<=noknots;i++) possible[i] = 0;7127for(elemind=1;elemind <= data->noelements;elemind++) {7128/* if(moveelement[elemind]) continue; */7129elemtype = data->elementtypes[elemind];7130if(elemtype < 200 ) continue;7131for(i=0;i<data->elementtypes[elemind]%100;i++) {7132j = data->topology[elemind][i];7133possible[j] += 1;7134}7135}71367137j = 1;7138maxpossible = possible[1];7139for(i=1;i<=noknots;i++) {7140if(maxpossible < possible[i]) {7141maxpossible = possible[i];7142j = i;7143}7144}7145if(info) printf("Node %d belongs to maximum of %d elements\n",j,maxpossible);71467147/* Make a table showing to which elements a node belongs to7148Include only the potential parents which are not to be moved to BCs. */7149invtopo = Imatrix(1,noknots,1,maxpossible);7150for(i=1;i<=noknots;i++)7151for(j=1;j<=maxpossible;j++)7152invtopo[i][j] = 0;71537154for(elemind=1;elemind <= data->noelements;elemind++) {7155/* if(moveelement[elemind]) continue; */7156elemtype = data->elementtypes[elemind];7157if(elemtype < 200 ) continue;7158for(i=0;i<elemtype%100;i++) {7159k = data->topology[elemind][i];7160for(l=1;invtopo[k][l];l++);7161invtopo[k][l] = elemind;7162}7163}71647165sideelem = 0;7166sameelem = 0;7167twiceelem = 0;71687169debug = FALSE;71707171/* Go through boundary element candidates starting from higher dimension */7172for(loopdim=maxelemdim-1;loopdim>=0;loopdim--) {71737174if(debug) printf("loopdim = %d\n",loopdim);71757176for(elemind=1;elemind <= data->noelements;elemind++) {71777178if(!moveelement[elemind]) continue;71797180same = FALSE;7181sideelemtype = data->elementtypes[elemind];71827183/* Only check the elements that have right dimension */7184sideelemdim = GetElementDimension(sideelemtype);7185if(sideelemdim != loopdim ) continue;71867187sidenodes = sideelemtype % 100;7188for(i=0;i<sidenodes;i++)7189sideind[i] = data->topology[elemind][i];7190elemhits = 0;71917192if(debug) printf("Finding elem: %d %d %d\n",elemind,sideelemtype,sideelemdim);719371947195for(l=1;l<=maxpossible;l++) {7196elemind2 = invtopo[sideind[0]][l];71977198if(!elemind2) continue;71997200/* The parent should be an element that will not become BC element */7201if(moveelement[elemind2]) continue;72027203elemtype = data->elementtypes[elemind2];7204elemdim = GetElementDimension(elemtype);72057206/* Owner element should have higher dimension */7207if(elemdim <= sideelemdim ) continue;72087209hit = 0;7210for(i=0;i<sidenodes;i++)7211for(j=0;j<elemtype%100;j++)7212if(sideind[i] == data->topology[elemind2][j]) hit++;72137214if(hit < sidenodes) continue;72157216if(hit > sidenodes) printf("Strange: elemhits %d vs. elemnodes %d\n",hit,sidenodes);7217if(hit >= sidenodes) elemhits++;72187219for(side=0;side<=100;side++) {7220GetElementSide(elemind2,side,1,data,&sideind2[0],&sideelemtype2);72217222if(sideelemtype2 == 0 ) break;72237224if(sideelemtype2 < 300 && sideelemtype > 300) break;7225if(sideelemtype2 < 200 && sideelemtype > 200) break;7226if(sideelemtype2 != sideelemtype ) continue;72277228sidenodes2 = sideelemtype2 % 100;7229if(sidenodes != sidenodes2) continue;7230if(sidenodes2 == 1 && sidenodes > 1) break;72317232hit = 0;7233for(i=0;i<sidenodes;i++)7234for(j=0;j<sidenodes2;j++)7235if(sideind[i] == sideind2[j]) hit++;72367237if(0) printf("%d hits in element %d\n",hit,sideelemtype2);7238if(hit == sidenodes) break;72397240if(sideelemtype != sideelemtype2) {7241printf("Hits in element after mismatch: %d vs. %d\n",sideelemtype,sideelemtype2);7242continue;7243}7244}7245if( sidenodes == 1 && !hit) {7246printf("elemind = %d sideind %d vs. ",elemind,sideind[0]);7247for(j=0;j<sidenodes2;j++)7248printf("%d ",sideind2[j]);7249printf("\n");7250}72517252if(hit < sidenodes || !sideelemtype2) {7253if(0) printf("Preliminary hit but not really: %d %d\n",hit,sidenodes);7254continue;7255}72567257if(same) {7258sameelem += 1;7259bound->parent2[sideelem] = elemind2;7260bound->side2[sideelem] = side;72617262if(debug) printf(" Found 2nd: %d %d %d\n",elemind,elemind2,side);7263goto foundtwo;7264}7265else {7266sideelem += 1;7267same = TRUE;7268if(debug) printf(" Found 1st: %d %d %d %d %d\n",elemind,elemind2,side,sideelemtype,sideelemtype2);72697270bound->parent[sideelem] = elemind2;7271bound->side[sideelem] = side;7272bound->parent2[sideelem] = 0;7273bound->side2[sideelem] = 0;7274material = data->material[elemind];7275bound->types[sideelem] = material;72767277if(sidenodes == 2) {7278if((sideind[0]-sideind[1])*(sideind2[0]-sideind2[1])<0)7279bound->normal[sideelem] = -1;7280}7281if(movenames) {7282data->boundarynamesexist = TRUE;7283if(material < MAXBODIES && material < MAXBCS) {7284if(!data->boundaryname[material]) {7285data->boundaryname[material] = Cvector(0,MAXNAMESIZE);7286if(data->bodyname[material]) {7287strcpy(data->boundaryname[material],data->bodyname[material]);7288free_Cvector(data->bodyname[material],0,MAXNAMESIZE);7289data->bodyname[material] = NULL;7290}7291else7292sprintf(data->boundaryname[material],"body%d",material);7293}7294}7295if(!strncmp(data->boundaryname[material],"body",4)) {7296strncpy(data->boundaryname[material],"bnry",4);7297}7298}72997300/* Only try to find two parents if the boundary element is one degree smaller than maximum dimension */7301if(moveelement[elemind] > 1) goto foundtwo;7302}7303}73047305if(!same) {7306/* If the element is of dimension DIM-1 then create a table showing where they are */7307if(retainorphans ) {7308/* If we have only one degree smaller unfound element then keep them as bulk elements. */7309if( moveelement[elemind] == 1) {7310moveelement[elemind] = 0;7311lowdimbulk++;7312if(debug) printf(" Bulk: %d\n",elemind);7313}7314else {7315if(!notfound) {7316notfounds = Ivector(1,noelements);7317for(i=1;i<=noelements;i++)7318notfounds[i] = FALSE;7319}7320notfound++;7321notfounds[elemind] = TRUE;73227323if(0) {7324printf("element: elemind = %d type = %d nodes = %d elemhits = %d\n",7325elemind,sideelemtype,sidenodes,elemhits);7326printf(" inds =");7327for(i=0;i<sidenodes;i++)7328printf(" %d ",sideind[i]);7329printf("\n");7330}73317332if(debug) printf(" Unfound: %d\n",elemind);7333}7334}7335else {7336if(debug) printf(" Removed: %d\n",elemind);73377338moveelement[elemind] = -1;7339removed += 1;7340}7341}73427343foundtwo:7344continue;73457346}73477348if(0) printf("Intermediate results: %d %d %d %d\n",twiceelem,sameelem,sideelem,removed);7349}73507351if(twiceelem) printf("Found %d sides that were multiply given\n",twiceelem);7352if(sameelem) printf("Found %d side elements that have two parents.\n",sameelem);735373547355if(sideelem == sideelements) {7356printf("Found correctly %d side elements.\n",sideelem);7357}7358else {7359printf("Studied %d lower dimensional elements\n",sideelements);7360printf("Defined %d side elements\n",sideelem);7361printf("Defined %d lower dimensional bulk elements\n",lowdimbulk);73627363bound->nosides = sideelem;73647365printf("Removing %d lower dimensional elements from the element list\n",removed);7366if(notfound) {7367if(0) printf("************************** WARNING **********************\n");7368if(retainorphans) {7369printf("Adding %d elements to boundary without parent information\n",notfound);73707371bound->elementtypes = Ivector(sideelem+1,sideelements);7372for(i=sideelem+1;i<=sideelements;i++) bound->elementtypes[i] = 0;73737374bound->topology = Imatrix(sideelem+1,sideelements,0,MAXNODESD2-1);73757376for(elemind=1;elemind <= data->noelements;elemind++) {7377if(!notfounds[elemind]) continue;7378sideelem++;73797380j = data->elementtypes[elemind];7381bound->elementtypes[sideelem] = j;73827383for(i=0;i<j%100;i++)7384bound->topology[sideelem][i] = data->topology[elemind][i];73857386/* Adding some constant here could be used for debugging */7387bound->types[sideelem] = data->material[elemind] + 1*10;7388bound->parent[sideelem] = 0;7389}7390bound->nosides = sideelem;7391}7392else {7393printf("Removing %d lower dimensional elements without parent information\n",notfound);7394}7395}7396}73977398/* Reorder remaining bulk elements */7399parentorder = Ivector(1,noelements);7400for(i=1;i<=noelements;i++)7401parentorder[i] = 0;74027403j = 0;7404for(i=1;i<=noelements;i++) {7405if(moveelement[i] == 0) {7406k = data->elementtypes[i];74077408j++;7409parentorder[i] = j;74107411if(debug) printf("Bulk is: %d %d\n",i,j);74127413if( i != j ) {7414data->material[j] = data->material[i];7415data->elementtypes[j] = data->elementtypes[i];7416for(l=0;l<k%100;l++)7417data->topology[j][l] = data->topology[i][l];7418}7419}7420}7421data->noelements = j;7422if(info) printf("Parent elements were reordered up to index %d.\n",j);742374247425/* Reorder boundary to point at the new arrangement of master elements */7426for(i=1;i<=bound->nosides;i++) {7427if(!bound->parent[i]) continue;74287429if( !parentorder[bound->parent[i]] ) {7430printf("Zero reorder: %d %d %d\n",i,bound->parent[i],bound->side[i]);7431bigerror("Sorry folks!");7432}74337434if(bound->parent[i]) bound->parent[i] = parentorder[bound->parent[i]];7435if(bound->parent2[i]) bound->parent2[i] = parentorder[bound->parent2[i]];74367437GetElementSide(bound->parent[i],bound->side[i],1,data,&sideind2[0],&sideelemtype2);74387439if(0) GetBoundaryElement(i,&bound[j],data,&sideind2[0],&sideelemtype2);7440}74417442if(info) printf("Moved %d elements (out of %d) to new positions\n",j,noelements);74437444free_Ivector(parentorder,1,noelements);74457446free_Ivector(moveelement,1,noelements);7447free_Ivector(possible,1,noknots);7448free_Imatrix(invtopo,1,noknots,1,maxpossible);7449if(notfound) free_Ivector(notfounds,1,noelements);74507451if(debug) printf("All done\n");74527453return;7454}745574567457int SideAndBulkMappings(struct FemType *data,struct BoundaryType *bound,struct ElmergridType *eg,int info)7458{7459int i,j,l,currenttype;746074617462if(eg->sidemappings) {7463if(info) printf("Renumbering boundary types with %d mappings\n",eg->sidemappings);74647465for(l=0;l<eg->sidemappings;l++)7466if(info) printf("Setting boundary types between %d and %d to %d\n",7467eg->sidemap[3*l],eg->sidemap[3*l+1],eg->sidemap[3*l+2]);74687469for(j=0;j < MAXBOUNDARIES;j++) {7470if(!bound[j].created) continue;74717472for(i=1; i <= bound[j].nosides; i++) {7473if((currenttype = bound[j].types[i])) {7474for(l=0;l<eg->sidemappings;l++) {7475if(currenttype >= eg->sidemap[3*l] && currenttype <= eg->sidemap[3*l+1]) {7476bound[j].types[i] = eg->sidemap[3*l+2];7477currenttype = -1;7478}7479}7480}7481}7482}7483if(info) printf("Renumbering boundary types finished\n");7484}74857486if(eg->bulkmappings) {7487if(info) printf("Renumbering bulk types with %d mappings\n",eg->bulkmappings);74887489for(l=0;l<eg->bulkmappings;l++)7490if(info) printf("Setting material types between %d and %d to %d\n",7491eg->bulkmap[3*l],eg->bulkmap[3*l+1],eg->bulkmap[3*l+2]);7492for(j=1;j<=data->noelements;j++) {7493currenttype = data->material[j];7494for(l=0;l<eg->bulkmappings;l++) {7495if(currenttype >= eg->bulkmap[3*l] && currenttype <= eg->bulkmap[3*l+1]) {7496data->material[j] = eg->bulkmap[3*l+2];7497currenttype = -1;7498}7499}7500}7501if(info) printf("Renumbering material indexes finished\n");7502}7503return(0);7504}7505750675077508int SideAndBulkBoundaries(struct FemType *data,struct BoundaryType *bound,struct ElmergridType *eg,int info)7509{7510int l;7511int *boundnodes,noboundnodes;7512boundnodes = Ivector(1,data->noknots);75137514if(eg->bulkbounds) {7515for(l=0;l<eg->bulkbounds;l++) {7516FindBulkBoundary(data,eg->bulkbound[3*l],eg->bulkbound[3*l+1],7517boundnodes,&noboundnodes,info);7518FindNewBoundaries(data,bound,boundnodes,eg->bulkbound[3*l+2],1,info);7519}7520}7521if(eg->boundbounds) {7522for(l=0;l<eg->boundbounds;l++) {7523FindBoundaryBoundary(data,bound,eg->boundbound[3*l],eg->boundbound[3*l+1],7524boundnodes,&noboundnodes,info);7525FindNewBoundaries(data,bound,boundnodes,eg->boundbound[3*l+2],2,info);7526}7527}7528free_Ivector(boundnodes,1,data->noknots);75297530return(0);7531}753275337534void NodesToBoundaryChain(struct FemType *data,struct BoundaryType *bound,7535int *bcinds,int *bctags,int nbc,int bccount,7536int info)7537{7538int i,j,k,l,sideelemtype,sideelemtype2,elemind,elemind2,sideelem,sameelem;7539int sideind[MAXNODESD1],sideind2[MAXNODESD1],elemsides,side,hit,same,minelemtype;7540int sidenodes,sidenodes2,elemtype,elemdim,sideelements,material;7541int *possible=NULL,**invtopo=NULL;7542int noelements,maxpossible,noknots,twiceelem,sideelemdim;7543int elemhits,bci;754475457546if(info) printf("Creating boundary elements from boundary nodes\n");75477548for(j=0;j < MAXBOUNDARIES;j++)7549bound[j].created = FALSE;7550for(j=0;j < MAXBOUNDARIES;j++)7551bound[j].nosides = 0;75527553noelements = data->noelements;7554noknots = data->noknots;75557556sideelements = nbc - bccount;7557printf("Expected number of BC elements: %d\n",sideelements);75587559AllocateBoundary(bound,sideelements);75607561/* Calculate how may times a node appears */7562possible = Ivector(1,noknots);7563for(i=1;i<=noknots;i++) possible[i] = 0;7564for(elemind=1;elemind <= data->noelements;elemind++) {7565for(i=0;i<data->elementtypes[elemind]%100;i++) {7566j = data->topology[elemind][i];7567possible[j] += 1;7568}7569}75707571j = 1;7572maxpossible = possible[1];7573for(i=1;i<=noknots;i++) {7574if(maxpossible < possible[i]) {7575maxpossible = possible[i];7576j = i;7577}7578}7579if(info) printf("Node %d belongs to maximum of %d elements\n",j,maxpossible);75807581/* Make a table showing to which elements a node belongs to7582Include only the potential parents which are not to be moved to BCs. */7583invtopo = Imatrix(1,noknots,1,maxpossible);75847585for(i=1;i<=noknots;i++)7586for(j=1;j<=maxpossible;j++)7587invtopo[i][j] = 0;75887589for(elemind=1;elemind <= data->noelements;elemind++) {7590elemtype = data->elementtypes[elemind];7591for(i=0;i<elemtype%100;i++) {7592k = data->topology[elemind][i];7593for(l=1;invtopo[k][l];l++); /* Yes, this is really ok. We look for unset entry. */7594invtopo[k][l] = elemind;7595}7596}75977598sideelem = 0;7599sameelem = 0;7600twiceelem = 0;76017602/* These are here by construction because we are looking for a chain of nodes7603and trying to create 202 elements of them! */7604sidenodes = 2;7605sideelemtype = 202;76067607for(bci=1;bci<nbc;bci++) {76087609same = FALSE;76107611if( bctags[bci] != bctags[bci+1] ) continue;76127613sideind[0] = bcinds[bci];7614sideind[1] = bcinds[bci+1];7615material = bctags[bci];76167617elemhits = 0;76187619/* Go through potential parents elements using the inverse topology */7620for(l=1;l<=maxpossible;l++) {7621elemind2 = invtopo[sideind[0]][l];76227623if(!elemind2) continue;76247625elemtype = data->elementtypes[elemind2];7626hit = 0;7627for(i=0;i<sidenodes;i++)7628for(j=0;j<elemtype%100;j++)7629if(sideind[i] == data->topology[elemind2][j]) hit++;76307631/* We must have all hits to have a chance of finding bc */7632if(hit < sidenodes) continue;76337634elemhits++;76357636/* Now find on which side the bc is */7637for(side=0;side<3;side++) {7638GetElementSide(elemind2,side,1,data,&sideind2[0],&sideelemtype2);7639if( sideelemtype2 != sideelemtype ) printf("This should not happen!\n");76407641hit = 0;7642for(i=0;i<sidenodes;i++)7643for(j=0;j<sidenodes;j++)7644if(sideind[i] == sideind2[j]) hit++;76457646if(hit < sidenodes) continue;76477648if(same) {7649/* Ok, we found the other parent for this already */7650sameelem += 1;7651bound->parent2[sideelem] = elemind2;7652bound->side2[sideelem] = side;7653goto foundtwo;7654}7655else {7656/* We haven't found parents for this bc elements yet */7657sideelem += 1;7658same = TRUE;7659bound->parent[sideelem] = elemind2;7660bound->side[sideelem] = side;7661bound->parent2[sideelem] = 0;7662bound->side2[sideelem] = 0;7663bound->types[sideelem] = material;7664if(sidenodes == 2) {7665if((sideind[0]-sideind[1])*(sideind2[0]-sideind2[1])<0)7666bound->normal[sideelem] = -1;7667}7668}7669}7670}7671foundtwo:7672continue;7673}76747675if(twiceelem) printf("Found %d sides that were multiply given\n",twiceelem);7676if(sameelem) printf("Found %d side elements that have two parents.\n",sameelem);767776787679if(sideelem == sideelements) {7680printf("Found correctly %d side elements.\n",sideelem);7681}7682else {7683printf("Found %d side elements, could have found %d\n",sideelem,sideelements);7684}76857686bound->nosides = sideelem;76877688free_Ivector(possible,1,noknots);7689free_Imatrix(invtopo,1,noknots,1,maxpossible);76907691return;7692}76937694769576967697int FindPeriodicNodes(struct FemType *data,int periodicdim[],int info)7698{7699int i,j,i2,j2,dim;7700int noknots,hit,tothits;7701int *topbot=NULL,*indxper=NULL;7702int botn,topn,*revindtop=NULL,*revindbot=NULL;7703Real eps,dist,dx,dy,dz,coordmax,coordmin;7704Real *coord=NULL,*toparr=NULL,*botarr=NULL,epsmin;770577067707if(data->dim < 3) periodicdim[2] = 0;7708if(!periodicdim[0] && !periodicdim[1] && !periodicdim[2]) return(1);77097710if(data->periodicexist) {7711printf("FindPeriodicNodes: Subroutine is called for second time?\n");7712return(2);7713}77147715noknots = data->noknots;7716tothits = 0;77177718data->periodicexist = TRUE;7719indxper = Ivector(1,noknots);7720data->periodic = indxper;7721topbot = Ivector(1,noknots);772277237724for(i=1;i<=noknots;i++)7725indxper[i] = i;77267727for(dim=1;dim<=3;dim++) {7728if(!periodicdim[dim-1]) continue;77297730if(info) printf("Finding periodic nodes in direction %d\n",dim);77317732if(dim==1) coord = data->x;7733else if(dim==2) coord = data->y;7734else coord = data->z;77357736coordmax = coordmin = coord[1];77377738for(i=1;i<=data->noknots;i++) {7739if(coordmax < coord[i]) coordmax = coord[i];7740if(coordmin > coord[i]) coordmin = coord[i];7741}77427743if(info) printf("Coordinate in dimension %d is at the interval [%.3lg, %.3lg]\n",7744dim,coordmin,coordmax);77457746if(coordmax-coordmin < 1.0e-10) continue;7747eps = 1.0e-5 * (coordmax-coordmin);77487749topn = botn = 0;7750for(i=1;i<=data->noknots;i++) {7751if(fabs(coord[i]-coordmax) < eps) {7752topn++;7753topbot[i] = topn;7754}7755else if(fabs(coord[i] - coordmin) < eps) {7756botn++;7757topbot[i] = -botn;7758}7759else {7760topbot[i] = 0;7761}7762}77637764if(topn != botn) {7765printf("There should be equal number of top and bottom nodes (%d vs. %d)!\n",topn,botn);7766return(3);7767}7768else {7769if(info) printf("Looking for %d periodic nodes\n",topn);7770}77717772toparr = Rvector(1,topn);7773botarr = Rvector(1,botn);7774revindtop = Ivector(1,topn);7775revindbot = Ivector(1,botn);77767777topn = botn = 0;7778for(i=1;i<=noknots;i++) {7779j = topbot[i];7780if(j > 0) {7781topn++;7782revindtop[topn] = i;7783}7784else if(j < 0) {7785j = abs(j);7786botn++;7787revindbot[botn] = i;7788}7789}77907791if(data->dim == 2) {7792for(i=1;i<=botn;i++) {7793j = revindbot[i];7794hit = FALSE;7795for(i2=1;i2<=topn;i2++) {7796j2 = revindtop[i2];7797if(dim == 1)7798dist = fabs(data->y[j] - data->y[j2]);7799else7800dist = fabs(data->x[j] - data->x[j2]);7801if(dist < eps) {7802hit = TRUE;7803goto hit2d;7804}7805}78067807hit2d:7808if(hit) {7809tothits++;7810if(indxper[j] == j) indxper[j2] = j;7811else if(indxper[indxper[j]]==indxper[j]) {7812indxper[j2] = indxper[j];7813}7814else {7815printf("unknown 2d case!\n");7816}7817}7818else {7819printf("Couldn't find a periodic counterpart for node %d at [%.3lg %.3lg]]\n",7820j,data->x[j],data->y[j]);7821}7822}7823}7824else if(data->dim == 3) {7825dx = dy = dz = 0.0;7826for(i=1;i<=botn;i++) {7827j = revindbot[i];7828hit = FALSE;7829epsmin = coordmax - coordmin;78307831for(i2=1;i2<=topn;i2++) {7832j2 = revindtop[i2];7833if(dim == 1) {7834dy = data->y[j] - data->y[j2];7835dz = data->z[j] - data->z[j2];7836}7837else if(dim == 2) {7838dx = data->x[j] - data->x[j2];7839dz = data->z[j] - data->z[j2];7840}7841else {7842dx = data->x[j] - data->x[j2];7843dy = data->y[j] - data->y[j2];7844}7845if(dx*dx+dy*dy+dz*dz < eps*eps) {7846hit = TRUE;7847goto hit3d;7848}7849}78507851hit3d:7852if(hit) {7853tothits++;7854indxper[j2] = indxper[j];7855}7856else {7857printf("The periodic counterpart for node %d was not found!\n",j);7858}7859}7860}78617862free_Rvector(toparr,1,topn);7863free_Rvector(botarr,1,botn);7864free_Ivector(revindtop,1,topn);7865free_Ivector(revindbot,1,botn);7866}78677868if(info) printf("Found all in all %d periodic nodes.\n",tothits);78697870free_Ivector(topbot,1,noknots);78717872return(0);7873}78747875787678777878int FindPeriodicParents(struct FemType *data,struct BoundaryType *bound,int info)7879{7880int i,j,k,k2,l,l2,totsides,newsides,sidenodes,sideelemtype,side;7881int noknots,maxhits,nodes,hits,hits2,targets,mappings,targetnode;7882int parent,parent2,sideind[MAXNODESD1],sideind2[MAXNODESD1];7883int **periodicparents=NULL, *periodichits=NULL,*periodictarget=NULL,*indexper=NULL;78847885totsides = 0;7886newsides = 0;7887targets = 0;7888parent2 = 0;78897890if(info) printf("Finding secondary periodic parents for boundary elements\n");78917892if(!data->periodicexist) {7893printf("FindPeriodicParents: Periodic nodes are not defined\n");7894return(2);7895}78967897indexper = data->periodic;78987899/* Set pointers that point to the periodic nodes */7900noknots = data->noknots;7901periodictarget = Ivector(1,noknots);7902for(i=1;i<=noknots;i++)7903periodictarget[i] = 0;79047905mappings = 0;7906for(i=1;i<=noknots;i++) {7907j = indexper[i];7908if( j != i) {7909mappings++;7910periodictarget[j] = i;7911}7912}79137914if(0) for(i=1;i<=noknots;i++)7915printf("indexes(%d) : %d %d\n",i,indexper[i],periodictarget[i]);791679177918if(info) printf("Number of potential periodic mappings is %d\n",mappings);7919for(i=1;i<=noknots;i++)7920if(periodictarget[i]) targets++;7921if(info) printf("Number of potential periodic targets is %d\n",targets);792279237924/* Vector telling how many elements are associated with the periodic nodes */7925maxhits = 0;7926periodichits = Ivector(1,noknots);7927for(i=1;i<=noknots;i++)7928periodichits[i] = 0;79297930/* Create the matrix telling which elements are associated with the periodic nodes */7931setparents:7932for(j=1;j <= data->noelements;j++) {7933nodes = data->elementtypes[j] % 100;7934for(i=0;i<nodes;i++) {7935k = data->topology[j][i];7936if( k != indexper[k] ) {7937periodichits[k] += 1;7938if( maxhits > 0 ) {7939periodicparents[k][periodichits[k]] = j;7940}7941}7942}7943}79447945if( maxhits == 0 ) {7946for(i=1;i<=noknots;i++)7947maxhits = MAX( maxhits, periodichits[i] );79487949printf("Maximum number of elements associated with periodic nodes is %d\n",maxhits);7950periodicparents = Imatrix(1,noknots,1,maxhits);7951for(i=1;i<=noknots;i++) {7952periodichits[i] = 0;7953for(j=1;j<=maxhits;j++)7954periodicparents[i][j] = 0;7955}7956goto setparents;7957}79587959for(j=0;j<MAXBOUNDARIES;j++) {7960if(!bound[j].created) continue;7961if(!bound[j].nosides) continue;79627963for(i=1;i<=bound[j].nosides;i++) {79647965/* If secondary parent already set skip */7966if(bound[j].parent2[i]) continue;79677968parent = bound[j].parent[i];7969if(0) printf("1st parent %d\n",parent);79707971side = bound[j].side[i];79727973GetElementSide(parent,side,1,data,sideind,&sideelemtype);7974sidenodes = sideelemtype % 100;79757976/* Some node must be periodic target and others either target or mapped nodes */7977hits = hits2 = 0;7978for(k=0;k<sidenodes;k++) {7979l = sideind[k];7980if( periodictarget[l] )7981hits++;7982else if(indexper[l] != l)7983hits2++;7984}7985if(!hits || hits + hits2 < sidenodes) continue;79867987if(0) printf("Trying to find other parent for boundary %d and parent %d\n",7988bound[j].types[i],parent);7989if(0) printf("hits = %d %d %d\n",hits,hits2,sidenodes);79907991totsides++;79927993/* The parent is the one element that has exactly the same set of periodic nodes */7994for(l=0;l<sidenodes;l++) {7995targetnode = periodictarget[sideind[l]];7996if(!targetnode) continue;79977998for(l2=1;l2<=periodichits[targetnode];l2++) {7999int side,elemtype,elemsides,sideelemtype2;80008001parent2 = periodicparents[targetnode][l2];8002if(parent == parent2) continue;80038004elemtype = data->elementtypes[parent2];8005elemsides = GetElementFaces(elemtype);80068007for(side=0;side<elemsides;side++) {8008GetElementSide(parent2,side,1,data,sideind2,&sideelemtype2);8009if( sideelemtype != sideelemtype2 ) continue;80108011hits = 0;8012for(k=0;k<sidenodes;k++) {8013for(k2=0;k2<sidenodes;k2++) {8014if( indexper[sideind[k]] == indexper[sideind2[k2]]) {8015hits++;8016break;8017}8018}8019}8020if(hits == sidenodes) goto found;8021}8022}8023}80248025found:8026if(hits == sidenodes) {8027newsides++;8028if(0) printf("Parents joined by boundary element: %d %d\n",parent,parent2);8029bound[j].parent2[i] = -parent2;8030}8031else {8032printf("Could not find a periodic counterpart: %d/%d/%d\n",j,i,parent);8033printf("ind = %d ",sideind[0]);8034for(k=1;k<sidenodes;k++)8035printf("%d ",sideind[k]);8036printf("\n");8037}8038}8039}80408041free_Ivector(periodictarget,1,noknots);8042free_Ivector(periodichits,1,noknots);8043free_Imatrix(periodicparents,1,noknots,1,maxhits);80448045if(info) printf("Found %d secondary parents for %d potential sides.\n",newsides,totsides);8046return(0);8047}80488049805080518052int CreateBoundaryLayer(struct FemType *data,struct BoundaryType *bound,8053int nolayers, int *layerbounds, int *layernumber,8054Real *layerratios, Real *layerthickness, int *layerparents,8055int maxfilters, Real layereps, int info)8056/* Create Boundary layers that may be used to solve accurately fluid8057flow problems and similar equations. */8058{8059int i,j,k,l,m,n,i2,i3,nonodes,maxbc,newbc;8060int noknots,noelements,elemindx,nodeindx,elemtype;8061int oldnoknots,oldnoelements,maxelemtype,oldmaxnodes;8062int nonewnodes,nonewelements,dolayer,dim,order,midpoints;8063int checkmaterials,parent,parent2,use2,second;8064Real dx,dy,ds,ratio,q,p,rectfactor;8065Real *newx=NULL,*newy=NULL,*newz=NULL,*oldx=NULL,*oldy=NULL,*elemwidth=NULL;8066Real e1x,e1y,e2x,e2y;8067int sideelemtype,ind[MAXNODESD2],sidebc[MAXNODESD1];8068int *layernode=NULL,*newelementtypes=NULL,**newtopo=NULL,**oldtopo=NULL;8069int *topomap=NULL,*newmaterial=NULL,*herit=NULL,*inside=NULL,*nonlin=NULL;8070int endbcs, *endparents=NULL, *endtypes=NULL, *endnodes=NULL, *endnodes2=NULL, *endneighbours=NULL;80718072if(0) printf("maxfilters=%d layereps=%.3e\n",maxfilters,layereps);80738074if(!maxfilters) maxfilters = 1000;8075if(layereps < 1.0e-20) layereps = 1.0e-3;8076rectfactor = 1.0e2;8077midpoints = FALSE;8078order = 1;8079dim = data->dim;80808081maxelemtype = GetMaxElementType(data);8082if(maxelemtype > 409) {8083printf("Subroutine implemented only up to 2nd degree in 2D!\n");8084bigerror("Cannot continue");8085}80868087if(info) printf("Largest elementtype is %d\n",maxelemtype);80888089second = FALSE;8090checkmaterials = FALSE;8091for(k=0;k<nolayers;k++)8092if(layerparents[k]) checkmaterials = TRUE;809380948095omstart:80968097oldnoelements = noelements = data->noelements;8098oldnoknots = noknots = data->noknots;8099oldmaxnodes = data->maxnodes;81008101layernode = Ivector(1,oldnoknots);8102for(i=1;i<=oldnoknots;i++) layernode[i] = 0;810381048105/* Go through all the boundaries with boundary layer definitions and compute8106the number of new nodes and new elements. */8107nonewnodes = 0;8108nonewelements = 0;8109maxbc = 0;81108111/* Go through the layers and check which ones are active */8112for(j=0;j<MAXBOUNDARIES;j++) {8113if(!bound[j].created) continue;81148115for(i=1;i<=bound[j].nosides;i++) {8116dolayer = FALSE;8117parent = bound[j].parent[i];8118use2 = FALSE;8119if(bound[j].types[i] > maxbc) maxbc = bound[j].types[i];81208121for(k=0;k<nolayers;k++) {81228123if(bound[j].types[i] == layerbounds[k]) {8124if(checkmaterials) {8125if(layerparents[k] < 0) continue;81268127if(data->material[parent] == layerparents[k])8128dolayer = k + 1;8129else if((parent = bound[j].parent2[i])) {8130if(data->material[parent] == layerparents[k]) {8131use2 = TRUE;8132dolayer = k + 1;8133}8134}8135}8136else {8137dolayer = k + 1;8138}8139}8140}81418142if(!dolayer) continue;814381448145/* We have found an boundary element to extrude */8146if(use2)8147GetElementSide(bound[j].parent2[i],bound[j].side2[i],bound[j].normal[i],8148data,ind,&sideelemtype);8149else8150GetElementSide(parent,bound[j].side[i],bound[j].normal[i],8151data,ind,&sideelemtype);81528153nonewelements += layernumber[dolayer-1];81548155midpoints = FALSE;8156if(sideelemtype == 202) {8157order = 1;8158}8159else if(sideelemtype == 203) {8160order = 2;8161if(maxelemtype > 408) midpoints = TRUE;8162}81638164for(l=0;l<sideelemtype%100;l++) {81658166/* No layer has yet been created for this node */8167if(!layernode[ind[l]]) {81688169layernode[ind[l]] = -(noknots + nonewnodes);81708171if(l < sideelemtype/100 || midpoints)8172nonewnodes += order * layernumber[dolayer-1];8173else8174nonewnodes += layernumber[dolayer-1];8175}8176else {8177layernode[ind[l]] = abs(layernode[ind[l]]);8178}8179}8180}8181}81828183if(!nonewelements) {8184if(info) printf("Found no active boundary layers!\n");8185return(0);8186}81878188/* For higher order elements remove the middlenodes from the list of cornernodes */8189if(maxelemtype%100 > 4) {8190for(j=1;j<=noelements;j++) {8191elemtype = data->elementtypes[j];8192for(i=elemtype/100;i<elemtype%100;i++) {8193k = data->topology[j][i];8194layernode[k] = abs(layernode[k]);8195}8196}8197}819881998200/* Negative indexed means that the node is an end node of the newly created boundary */8201endbcs = 0;8202for(i=1;i<=noknots;i++)8203if(layernode[i] < 0) endbcs++;82048205if(endbcs) {8206endparents = Ivector(1,endbcs);8207endtypes = Ivector(1,endbcs);8208endnodes = Ivector(1,endbcs);8209endnodes2 = Ivector(1,endbcs);82108211endneighbours = Ivector(1,2*endbcs);8212for(i=1;i<=endbcs;i++)8213endparents[i] = endtypes[i] = endnodes[i] = endnodes2[i] = 0;82148215endbcs = 0;8216for(i=1;i<=noknots;i++) {8217if(layernode[i] < 0) {8218endbcs++;8219endparents[endbcs] = i;8220}8221}8222}822382248225/* Check if the new boundary is already connected to some one,8226however it must be different from the extruded boundary */8227for(i2=1;i2<=endbcs;i2++) {8228for(j=0;j<MAXBOUNDARIES;j++) {8229if(!bound[j].created) continue;82308231for(i=1;i<=bound[j].nosides;i++) {82328233GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],8234data,ind,&sideelemtype);82358236/* Check that the node is one of the single nodes */8237dolayer = FALSE;8238for(i3=0;i3<sideelemtype%100;i3++)8239if(ind[i3] == endparents[i2]) {8240dolayer = TRUE;8241break;8242}8243if(!dolayer) continue;82448245/* First check that the found boundary has a correct parent material */8246dolayer = FALSE;8247if(checkmaterials) {8248for(k=0;k<nolayers;k++) {8249if(layerparents[k] < 0) continue;8250parent = bound[j].parent[i];8251if(data->material[parent] == layerparents[k])8252dolayer = TRUE;8253else if((parent = bound[j].parent2[i])) {8254if(data->material[parent] == layerparents[k]) {8255dolayer = TRUE;8256}8257}8258}8259}8260if(!dolayer) continue;82618262/* Finally check that this is not one of the extruded boundaries */8263dolayer = FALSE;8264for(k=0;k<nolayers;k++) {8265if(layerparents[k] < 0) continue;8266if(bound[j].types[i] == layerbounds[k]) dolayer = TRUE;8267}8268if(dolayer) {8269endneighbours[2*i2-1] = ind[1-i3];8270continue;8271}82728273endtypes[i2] = bound[j].types[i];8274dx = fabs(data->x[ind[0]] - data->x[ind[1]]);8275dy = fabs(data->y[ind[0]] - data->y[ind[1]]);82768277if(dx < rectfactor * dy && dy < rectfactor * dx) {8278endnodes[i2] = ind[i3];8279if(sideelemtype%100 > 2) endnodes2[i2] = ind[2];8280endneighbours[2*i2] = ind[1-i3];8281}82828283if(info) printf("Found an existing boundary %d for the single node %d %d\n",8284bound[j].types[i],endparents[i2],endnodes[i2]);82858286goto foundbc;8287}8288}82898290foundbc:82918292if(!endtypes[i2]) {8293maxbc++;8294endtypes[i2] = maxbc;8295}8296}829782988299/* Find the first unused bc */8300for(j=0;j<MAXBOUNDARIES;j++)8301if(!bound[j].created) {8302newbc = j;8303bound[newbc].nosides = 0;8304break;8305}83068307/* Find the maximum of layers */8308i = 0;8309for(k=0;k<nolayers;k++)8310if(layernumber[k] > i) i = layernumber[k];83118312if(endbcs) {8313if(info) {8314printf("Allocating for additional %d boundary elements into bc %d.\n",8315bound[newbc].nosides,newbc);8316}8317AllocateBoundary(&bound[newbc],i*endbcs);8318bound[newbc].created = FALSE;8319bound[newbc].nosides = 0;8320}832183228323/* The size of new mesh */8324noknots = data->noknots + nonewnodes;8325noelements = data->noelements + nonewelements;83268327oldnoelements = data->noelements;8328oldnoknots = data->noknots;83298330if(info) {8331printf("Creating additional %d elements and %d nodes.\n",nonewelements,nonewnodes);8332printf("Boundary layer mesh has %d elements and %d nodes.\n",noelements,noknots);8333}83348335/* there will be more nodes if the original mesh consists of triangles */8336if(maxelemtype <= 303)8337data->maxnodes = 4;8338else if(maxelemtype == 306)8339data->maxnodes = 8;83408341/* Allocate more space for the enlarged data set */8342newtopo = Imatrix(1,noelements,0,data->maxnodes-1);8343newmaterial = Ivector(1,noelements);8344newelementtypes = Ivector(1,noelements);8345newx = Rvector(1,noknots);8346newy = Rvector(1,noknots);8347newz = Rvector(1,noknots);8348for(i=1;i<=noknots;i++) newz[i] = 0.0;83498350elemwidth = Rvector(1,nonewelements);8351for(i=1;i<=nonewelements;i++) elemwidth[i] = 0.0;83528353herit = Ivector(1,noknots);8354for(i=1;i<=oldnoknots;i++) herit[i] = i;8355for(i=oldnoknots+1;i<=noknots;i++) herit[i] = 0;835683578358/* Set the old topology */8359for(j=1;j<=data->noelements;j++) {8360newmaterial[j] = data->material[j];8361newelementtypes[j] = data->elementtypes[j];8362for(i=0;i<data->elementtypes[j]%100;i++)8363newtopo[j][i] = data->topology[j][i];8364}83658366/* Set the old nodes */8367for(i=1;i<=data->noknots;i++) {8368newx[i] = data->x[i];8369newy[i] = data->y[i];8370}83718372topomap = Ivector(1,noknots);8373for(i=1;i<=noknots;i++) topomap[i] = i;83748375inside = Ivector(1,noelements);8376for(i=1;i<=noelements;i++) inside[i] = FALSE;83778378/* Set the new node topology and nodes */8379elemindx = data->noelements;8380for(j=0;j<MAXBOUNDARIES;j++) {8381if(!bound[j].created) continue;83828383for(i=1;i<=bound[j].nosides;i++) {83848385dolayer = FALSE;8386parent = bound[j].parent[i];8387parent2 = bound[j].parent2[i];8388use2 = FALSE;83898390for(k=0;k<nolayers;k++) {8391if(bound[j].types[i] == layerbounds[k]) {8392if(checkmaterials) {8393if(layerparents[k] < 0) continue;83948395if(data->material[parent] == layerparents[k]) {8396dolayer = k + 1;8397}8398else if(parent2) {8399l = parent;8400parent = parent2;8401parent2 = l;8402if(data->material[parent] == layerparents[k]) {8403use2 = TRUE;8404dolayer = k + 1;8405}8406}8407}8408else dolayer = k + 1;8409}8410}841184128413if(!dolayer) continue;84148415if(use2)8416GetElementSide(bound[j].parent2[i],bound[j].side2[i],bound[j].normal[i],8417data,ind,&sideelemtype);8418else8419GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],8420data,ind,&sideelemtype);84218422inside[parent] = 1;84238424if(sideelemtype == 202)8425order = 1;8426else if(sideelemtype == 203)8427order = 2;84288429/* Check if some node should result into additional BC */8430for(i2=0;i2<sideelemtype%100;i2++) {8431sidebc[i2] = FALSE;8432if(i2 < 2 && layernode[ind[i2]] < 0) {8433layernode[ind[i2]] = abs(layernode[ind[i2]]);8434sidebc[i2] = TRUE;8435}8436}84378438/* Define the normal of the surface */8439dy = -(data->x[ind[1]] - data->x[ind[0]]);8440dx = data->y[ind[1]] - data->y[ind[0]];8441ds = sqrt(dx*dx+dy*dy);8442dx /= ds;8443dy /= ds;84448445n = layernumber[dolayer-1];8446ds = -layerthickness[dolayer-1];84478448for(l=0;l < n;l++) {8449elemindx++;84508451newmaterial[elemindx] = data->material[parent];8452inside[elemindx] = 1;84538454if(n <= 1 || fabs(layerratios[dolayer-1]-1.0) < 0.001) {8455q = (1.0*(l+1))/n;8456elemwidth[elemindx-oldnoelements] = ds / n;8457}8458else {8459ratio = pow(layerratios[dolayer-1],-1./(n-1.));8460q = (1.- pow(ratio,(Real)(l+1))) / (1.-pow(ratio,(Real)(n)));8461p = (1.- pow(ratio,(Real)(l))) / (1.-pow(ratio,(Real)(n)));8462elemwidth[elemindx-oldnoelements] = (q-p) * ds;8463}846484658466for(m=0;m<sideelemtype%100;m++) {84678468/* Make the possible additional BC appearing at side of the BL */8469if(sidebc[m]) {84708471bound[newbc].nosides += 1;8472i2 = bound[newbc].nosides;8473bound[newbc].parent[i2] = elemindx;8474bound[newbc].parent2[i2] = 0;8475bound[newbc].side[i2] = 3 - 2*m;8476bound[newbc].side2[i2] = 0;84778478for(i3=1;i3<=endbcs;i3++)8479if(ind[m] == endparents[i3]) {8480bound[newbc].types[i2] = endtypes[i3];8481endneighbours[2*i3-1] = layernode[ind[m]] + 1;8482break;8483}8484}84858486/* Set the node coordinates */8487if(m < 2) {8488nodeindx = layernode[ind[m]] + order*(l+1);8489}8490else {8491nodeindx = layernode[ind[m]] + (1+midpoints)*(l+1);8492}8493e1x = dx * q * ds;8494e1y = dy * q * ds;84958496/* Compute the normal of a joined node */8497if(herit[nodeindx] != 0) {84988499e2x = newx[nodeindx] - data->x[ind[m]];8500e2y = newy[nodeindx] - data->y[ind[m]];85018502p = (e1x*e2x + e1y*e2y)/(sqrt(e1x*e1x+e1y*e1y)*sqrt(e2x*e2x+e2y*e2y));85038504newx[nodeindx] += e1x - p * e2x;8505newy[nodeindx] += e1y - p * e2y;8506}8507else {8508herit[nodeindx] = ind[m];8509newx[nodeindx] = data->x[ind[m]] + e1x;8510newy[nodeindx] = data->y[ind[m]] + e1y;8511}8512}85138514/* Create the bulk elements */8515if(l==0) {8516newtopo[elemindx][3] = ind[0];8517newtopo[elemindx][2] = ind[1];8518if(order == 2) newtopo[elemindx][6] = ind[2];8519}8520else {8521newtopo[elemindx][3] = layernode[ind[0]] + order*l;8522newtopo[elemindx][2] = layernode[ind[1]] + order*l;8523if(order == 2) newtopo[elemindx][6] = layernode[ind[2]] + (midpoints+1)*l;8524}8525newtopo[elemindx][0] = layernode[ind[0]] + order*(l+1);8526newtopo[elemindx][1] = layernode[ind[1]] + order*(l+1);85278528if(order == 2) {8529newtopo[elemindx][7] = layernode[ind[0]] + order*l+1;8530newtopo[elemindx][5] = layernode[ind[1]] + order*l+1;8531newtopo[elemindx][4] = layernode[ind[2]] + (midpoints+1)*(l+1);8532if(midpoints) newtopo[elemindx][8] = layernode[ind[2]] + 2*l+1;8533}85348535if(order == 1) {8536newelementtypes[elemindx] = 404;8537}8538else if(midpoints) {8539newelementtypes[elemindx] = 409;8540}8541else {8542newelementtypes[elemindx] = 408;8543}854485458546if(l == n-1 && parent2) {85478548elemtype = data->elementtypes[parent2];8549inside[parent2] = 2;85508551for(i2=0;i2<elemtype%100;i2++) {8552for(i3=0;i3<sideelemtype%100;i3++) {8553if(data->topology[parent2][i2] == ind[i3]) {8554if(i3 < 2) {8555topomap[ind[i3]] = layernode[ind[i3]] + order * n;8556}8557else {8558topomap[ind[i3]] = layernode[ind[i3]] + (midpoints+1) * n;8559}8560}8561}8562}8563}8564}85658566/* Finally set the BC to point to the new boundary */8567if(use2) {8568bound[j].side2[i] = 0;8569bound[j].parent2[i] = elemindx;8570}8571else {8572bound[j].side[i] = 0;8573bound[j].parent[i] = elemindx;8574}8575}8576}857785788579{8580int *inside2;8581inside2 = Ivector(1,noknots);8582for(i=1;i<=noknots;i++) inside2[i] = 0;85838584/* Put a marker to all nodes that belong to elements that are on the outside */8585for(j=1;j<=noelements;j++) {8586if(inside[j] == 2) {8587elemtype = data->elementtypes[j];8588for(i=0;i<elemtype/100;i++) {8589inside2[newtopo[j][i]] = TRUE;8590}8591}8592}85938594/* Now check other outside elements that have at least 2 nodes that are also on outside */8595for(j=1;j<=noelements;j++) {8596if(!inside[j]) {8597elemtype = data->elementtypes[j];8598k = 0;8599for(i=0;i<elemtype/100;i++)8600if(inside2[newtopo[j][i]]) k++;8601if(k > 1) inside[j] = 2;8602}8603}8604free_Ivector(inside2,1,noknots);86058606/* Still, go through all elements and if they are not on the list of8607active materials assume them outside */8608if(checkmaterials) {8609for(j=1;j<=oldnoelements;j++) {8610dolayer = FALSE;8611for(k=0;k<nolayers;k++)8612if(data->material[j] == layerparents[k]) dolayer = TRUE;86138614if(!dolayer) {8615if(inside[j] == 1) printf("Element %d of material %d should be in the inside\n",8616j,data->material[j]);8617inside[j] = 2;8618}8619}8620}86218622/* And finally remap the nodes that are on the outside */8623for(j=1;j<=noelements;j++) {8624if(inside[j] == 2) {8625elemtype = data->elementtypes[j];8626for(i=0;i<elemtype%100;i++)8627newtopo[j][i] = topomap[data->topology[j][i]];8628}8629}8630}863186328633/* Put the pointers to the enlarged data set and destroy the old data */8634oldx = data->x;8635oldy = data->y;8636oldtopo = data->topology;86378638data->noelements = noelements;8639data->noknots = noknots;8640data->x = newx;8641data->y = newy;8642data->z = newz;86438644free_Ivector(data->elementtypes,1,oldnoelements);8645data->elementtypes = newelementtypes;86468647free_Ivector(data->material,1,oldnoelements);8648data->material = newmaterial;8649data->topology = newtopo;865086518652/* In case one wants to fit the mesh inside the original mesh8653the mesh nodes may be put to new positions using an appropriate filter. */865486558656/* For higher order elements remove the middlenodes from the list of cornernodes */8657if(maxelemtype%100 > 4) {8658if(info) printf("Marking the higher order nodes\n");86598660nonlin = Ivector(1,noknots);8661for(i=1;i<=noknots;i++) nonlin[i] = FALSE;86628663for(j=1;j<=noelements;j++) {8664elemtype = data->elementtypes[j];8665for(i=elemtype/100;i<elemtype%100;i++) {8666k = data->topology[j][i];8667nonlin[k] = TRUE;8668}8669}8670}867186728673if(maxfilters) {8674int method,iter;8675int ind1,ind2,ind3,*fixedx=NULL,*fixedy=NULL;8676Real *aidx=NULL,*aidy=NULL,*weights=NULL;8677Real maxerror=0.0,minds,dx2,dy2,ds2,fii;86788679/* There are three methods how to put the weight in the filter,86801) 1/s, 2) fii/s, 3) sin(fii)/s, the second option seems to be best. */8681method = 2;86828683if(info) printf("Filtering the mesh to meet the original geometry\n");86848685fixedx = Ivector(1,noknots);8686fixedy = Ivector(1,noknots);8687weights = Rvector(1,noknots);8688aidx = Rvector(1,noknots);8689aidy = Rvector(1,noknots);86908691/* Set all the fixed boundaries */8692for(i=1;i<=noknots;i++) fixedx[i] = fixedy[i] = 0;86938694/* First, make all other materials except the ones with BL to be fixed */8695if(checkmaterials) {8696for(j=1;j<=noelements;j++) {86978698elemtype = data->elementtypes[j];8699dolayer = FALSE;8700for(k=0;k<nolayers;k++)8701if(data->material[j] == layerparents[k]) dolayer = TRUE;87028703for(i=0;i<elemtype/100;i++) {8704ind1 = data->topology[j][i];8705if(dolayer && fixedx[ind1]%2 == 0)8706fixedx[ind1] += 1;8707if(!dolayer && fixedx[ind1] < 2)8708fixedx[ind1] += 2;8709}8710}8711for(i=1;i<=noknots;i++) {8712if(fixedx[i] == 2)8713fixedy[i] = 2;8714else8715fixedx[i] = 0;8716}8717}87188719/* Then set all BC:s fixed except the tangential ones */8720for(j=0;j<MAXBOUNDARIES;j++) {8721if(!bound[j].created) continue;87228723for(i=1;i<=bound[j].nosides;i++) {87248725GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],8726data,ind,&sideelemtype);87278728dx = fabs(newx[ind[0]] - newx[ind[1]]);8729dy = fabs(newy[ind[0]] - newy[ind[1]]);8730if(dx > rectfactor * dy) {8731for(l=0;l<sideelemtype%100;l++) {8732fixedy[ind[l]] = TRUE;8733}8734}8735else if(dy > rectfactor * dx) {8736for(l=0;l<sideelemtype%100;l++) {8737fixedx[ind[l]] = TRUE;8738}8739}8740else {8741for(l=0;l<sideelemtype%100;l++) {8742fixedy[ind[l]] = TRUE;8743fixedx[ind[l]] = TRUE;8744}8745}8746}8747}874887498750/* Then set possibly all remaining active boundaries to be fixed */8751for(j=0;j<MAXBOUNDARIES;j++) {8752if(!bound[j].created) continue;87538754for(i=1;i<=bound[j].nosides;i++) {87558756dolayer = FALSE;8757parent = bound[j].parent[i];8758parent2 = bound[j].parent2[i];8759use2 = FALSE;87608761GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],8762data,ind,&sideelemtype);87638764for(k=0;k<nolayers;k++) {8765if(bound[j].types[i] == layerbounds[k]) {8766if(checkmaterials) {8767if(layerparents[k] < 0) continue;87688769if(data->material[parent] == layerparents[k]) {8770dolayer = k + 1;8771}8772else if(parent2) {8773l = parent;8774parent = parent2;8775parent2 = l;8776if(data->material[parent] == layerparents[k]) {8777use2 = TRUE;8778dolayer = k + 1;8779}8780}8781}8782else dolayer = k + 1;8783}8784}87858786if(dolayer) {8787for(l=0;l<sideelemtype%100;l++) {8788fixedy[ind[l]] = TRUE;8789fixedx[ind[l]] = TRUE;8790}8791}8792}8793}87948795/* Finally loose the problematic triple nodes */8796for(j=1;j<=endbcs;j++) {8797k = endnodes[j];8798if(k) {8799fixedx[k] = FALSE;8800fixedy[k] = FALSE;8801}88028803/* for second order elements */8804k = endnodes2[j];8805if(k) {8806fixedx[k] = FALSE;8807fixedy[k] = FALSE;8808}8809}881088118812j = 0;8813for(i=1;i<=noknots;i++) if(fixedx[i]) j += 1;8814if(info) printf("Number of fixed nodes in x-direction is %d\n",j);88158816j = 0;8817for(i=1;i<=noknots;i++) if(fixedy[i]) j += 1;8818if(info) printf("Number of fixed nodes in y-direction is %d\n",j);88198820for(j=1;j<=noknots;j++) {88218822if(fixedx[j]) {8823if(j <= oldnoknots)8824newx[j] = aidx[j] = oldx[j];8825else8826newx[j] = aidx[j] = oldx[herit[j]];8827}8828if(fixedy[j]) {8829if(j <= oldnoknots)8830newy[j] = aidy[j] = oldy[j];8831else8832newy[j] = aidy[j] = oldy[herit[j]];8833}8834}883588368837for(iter=1;iter<=maxfilters;iter++) {8838maxerror = 0.0;8839minds = 1.0e10;88408841for(j=1;j<=noknots;j++) {88428843weights[j] = 0.0;88448845if(!fixedx[j]) {8846aidx[j] = newx[j];8847newx[j] = 0.0;8848}8849if(!fixedy[j]) {8850aidy[j] = newy[j];8851newy[j] = 0.0;8852}8853}88548855for(j=1;j<=noelements;j++) {8856elemtype = data->elementtypes[j];8857nonodes = elemtype / 100;88588859for(i=0;i<nonodes;i++) {88608861i2 = (i+1)%nonodes;8862i3 = (i+2)%nonodes;88638864ind1 = data->topology[j][i];8865ind2 = data->topology[j][i2];8866ind3 = data->topology[j][i3];88678868if(j<=oldnoelements) {8869dx = oldx[oldtopo[j][i2]] - oldx[oldtopo[j][i]];8870dy = oldy[oldtopo[j][i2]] - oldy[oldtopo[j][i]];8871ds = sqrt(dx*dx+dy*dy);8872}8873else {8874ds = fabs(elemwidth[j-oldnoelements]);8875}8876if(ds < minds) minds = ds;887788788879if(j<=oldnoelements) {8880dx2 = oldx[oldtopo[j][i2]] - oldx[oldtopo[j][i3]];8881dy2 = oldy[oldtopo[j][i2]] - oldy[oldtopo[j][i3]];8882ds2 = sqrt(dx2*dx2+dy2*dy2);8883}8884else {8885ds2 = fabs(elemwidth[j-oldnoelements]);8886}88878888if(j <= oldnoelements && ds * ds2 < 1.0e-50) {8889printf("problem elem %d and nodes %d (%d %d)\n",j,i2,i,i3);8890printf("dist ds=%.3e ds2=%.3e\n",ds,ds2);8891printf("coord: %.3e %.3e\n",oldx[oldtopo[j][i2]], oldy[oldtopo[j][i2]]);8892continue;8893}88948895if(abs(method) == 2 && j<=oldnoelements) {8896fii = acos((dx*dx2+dy*dy2)/(ds*ds2)) / (FM_PI/2.0);8897}8898else if(abs(method) == 3 && j<=oldnoelements) {8899fii = acos((dx*dx2+dy*dy2)/(ds*ds2));8900fii = sin(fii);8901}8902else {8903fii = 1.0;8904}890589068907/* Eliminate the very difficult triple nodes */8908dolayer = FALSE;8909for(k=1;k<=endbcs;k++)8910if(ind2 == endnodes[k]) dolayer = k;89118912if(dolayer) {8913for(k=1;k<=2;k++) {8914if(endneighbours[2*(dolayer-1)+k] == ind1) {8915weights[ind2] += fii / ds;8916if(!fixedx[ind2]) newx[ind2] += aidx[ind1] * fii / ds;8917if(!fixedy[ind2]) newy[ind2] += aidy[ind1] * fii / ds;8918}8919}8920for(k=1;k<=2;k++) {8921if(endneighbours[2*(dolayer-1)+k] == ind3) {8922weights[ind2] += fii / ds2;8923if(!fixedx[ind2]) newx[ind2] += aidx[ind3] * fii / ds2;8924if(!fixedy[ind2]) newy[ind2] += aidy[ind3] * fii / ds2;8925}8926}8927}8928else {8929if(ind2 <= oldnoknots || herit[ind1] == herit[ind2]) {8930weights[ind2] += fii / ds;8931if(!fixedx[ind2]) newx[ind2] += aidx[ind1] * fii / ds;8932if(!fixedy[ind2]) newy[ind2] += aidy[ind1] * fii / ds;8933}89348935if(ind2 <= oldnoknots || herit[ind3] == herit[ind2]) {8936weights[ind2] += fii / ds2;8937if(!fixedx[ind2]) newx[ind2] += aidx[ind3] * fii / ds2;8938if(!fixedy[ind2]) newy[ind2] += aidy[ind3] * fii / ds2;8939}8940}8941}8942}89438944if(maxelemtype%100 > 4) {8945for(j=1;j<=noknots;j++) {8946if(nonlin[j]) continue;89478948if(weights[j] > 1.0e-50) {8949if(!fixedx[j]) newx[j] /= weights[j];8950if(!fixedy[j]) newy[j] /= weights[j];8951}8952else if(iter==1) {8953printf("no weight for index %d\n",j);8954}89558956dx = newx[j] - aidx[j];8957dy = newy[j] - aidy[j];89588959ds = dx*dx + dy*dy;8960if(ds > maxerror) maxerror = ds;8961}8962}8963else {8964for(j=1;j<=noknots;j++) {8965if(!fixedx[j]) newx[j] /= weights[j];8966if(!fixedy[j]) newy[j] /= weights[j];89678968dx = newx[j]-aidx[j];8969dy = newy[j]-aidy[j];89708971ds = dx*dx + dy*dy;8972if(ds > maxerror) maxerror = ds;8973}8974}89758976maxerror = sqrt(maxerror) / minds;8977if(maxerror < layereps) break;8978}89798980if(info) {8981printf("Filtered the new node coordinates %d times with final error %.3e.\n",8982iter-1,maxerror);8983}89848985/* In higher order elements map the middle nodes so that they lie in between8986the corner nodes */898789888989if(maxelemtype%100 > 4) {8990for(j=1;j<=noelements;j++) {8991elemtype = data->elementtypes[j];8992if(elemtype%100 <= elemtype/100) continue;89938994if(elemtype == 306) {8995for(k=0;k<3;k++) {8996if(!fixedx[newtopo[j][k+3]]) {8997newx[newtopo[j][k+3]] = 0.5 * (newx[newtopo[j][k]] + newx[newtopo[j][(k+1)%3]]);8998}8999if(!fixedy[newtopo[j][k+3]]) {9000newy[newtopo[j][k+3]] = 0.5 * (newy[newtopo[j][k]] + newy[newtopo[j][(k+1)%3]]);9001}9002}9003}90049005else if(elemtype == 408 || elemtype == 409) {90069007if(elemtype == 409) {9008newx[newtopo[j][8]] = 0.0;9009newy[newtopo[j][8]] = 0.0;9010}90119012for(k=0;k<4;k++) {9013if(!fixedx[newtopo[j][k+4]]) {9014newx[newtopo[j][k+4]] = 0.5 * (newx[newtopo[j][k]] + newx[newtopo[j][(k+1)%4]]);9015}9016if(!fixedy[newtopo[j][k+4]]) {9017newy[newtopo[j][k+4]] = 0.5 * (newy[newtopo[j][k]] + newy[newtopo[j][(k+1)%4]]);9018}9019if(elemtype == 409) {9020newx[newtopo[j][8]] += 0.25 * newx[newtopo[j][k]];9021newy[newtopo[j][8]] += 0.25 * newy[newtopo[j][k]];9022}9023}9024}9025else {9026printf("Unknown elementtype %d\n",elemtype);9027}9028}9029}90309031free_Ivector(fixedx,1,noknots);9032free_Ivector(fixedy,1,noknots);90339034free_Rvector(aidx,1,noknots);9035free_Rvector(aidy,1,noknots);9036free_Rvector(weights,1,noknots);9037}90389039if(bound[newbc].nosides > 0)9040bound[newbc].created = TRUE;904190429043/* In higher order elements map the middle nodes so that they lie in between9044the corner nodes. Elemtypes must be 408 or 409 since they are created in this9045subroutine */90469047if(!maxfilters && maxelemtype%100 > 4) {9048if(info) printf("Making the higher order nodes to lie in between\n");90499050for(j=oldnoelements+1;j<=noelements;j++) {90519052elemtype = data->elementtypes[j];9053if(elemtype%100 <= elemtype/100) continue;90549055if(elemtype == 408 || elemtype == 409) {90569057if(elemtype == 409) {9058newx[newtopo[j][8]] = 0.0;9059newy[newtopo[j][8]] = 0.0;9060}90619062for(k=0;k<4;k++) {9063newx[newtopo[j][k+4]] = 0.5 * (newx[newtopo[j][k]] + newx[newtopo[j][(k+1)%4]]);9064newy[newtopo[j][k+4]] = 0.5 * (newy[newtopo[j][k]] + newy[newtopo[j][(k+1)%4]]);90659066if(elemtype == 409) {9067newx[newtopo[j][8]] += 0.25 * newx[newtopo[j][k]];9068newy[newtopo[j][8]] += 0.25 * newy[newtopo[j][k]];9069}9070}9071}9072}9073}907490759076#if 09077ReorderElements(data,bound,FALSE,corder,info);9078#endif90799080free_Imatrix(oldtopo,1,oldnoelements,0,oldmaxnodes-1);9081free_Ivector(layernode,1,oldnoknots);9082free_Rvector(oldx,1,oldnoknots);9083free_Rvector(oldy,1,oldnoknots);90849085if(info) printf("Boundary layers created successfully.\n");90869087if(checkmaterials && !second) {9088for(k=0;k<nolayers;k++) {9089if(layerparents[k] < 0) second = TRUE;9090layerparents[k] = -layerparents[k];9091}9092if(second) {9093if(info) printf("\nPerforming boundary layer generation again for negative materials\n");9094goto omstart;9095}9096}90979098return(0);9099}910091019102910391049105int CreateBoundaryLayerDivide(struct FemType *data,struct BoundaryType *bound,9106int nolayers, int *layerbounds, int *layernumber,9107Real *layerratios, Real *layerthickness, int *layerparents,9108int info)9109/* Create Boundary layers that may be used to solve accurately fluid9110flow problems and similar equations. In this subroutine the boundary layer9111is created by dividing the elements close to boundary. */9112{9113int i,j,k,l,dim,maxbc,maxelemtype,dolayer,parent,nlayer,sideelemtype,elemind,side;9114int noelements,noknots,oldnoknots,oldnoelements,oldmaxnodes,nonewnodes,nonewelements;9115int maxcon,elemsides,elemdone,midpoints,order,bcnodes,elemhits,elemtype,goforit;9116int ind[MAXNODESD2],baseind[2],topnode[2],basenode[2];9117int *layernode=NULL,*newelementtypes=NULL,**newtopo=NULL,**oldtopo=NULL;9118int *newmaterial=NULL,**edgepairs=NULL,*sharednode=NULL;9119Real dx[2],dy[2],x0[2],y0[2];9120Real *newx=NULL,*newy=NULL,*newz=NULL,*oldx=NULL,*oldy=NULL,*oldz=NULL;9121Real slayer,qlayer,ratio,q;912291239124dim = data->dim;9125maxelemtype = GetMaxElementType(data);91269127if(maxelemtype > 409) {9128printf("Subroutine implemented only up to 2nd degree!\n");9129return(2);9130}91319132if(info) printf("Largest elementtype is %d\n",maxelemtype);913391349135oldnoelements = noelements = data->noelements;9136oldnoknots = noknots = data->noknots;9137oldmaxnodes = data->maxnodes;91389139layernode = Ivector(1,oldnoknots);9140for(i=1;i<=oldnoknots;i++)9141layernode[i] = 0;91429143sharednode = Ivector(1,oldnoknots);9144for(i=1;i<=oldnoknots;i++)9145sharednode[i] = 0;914691479148/* Go through all the boundaries with boundary layer definitions and compute9149the number of nodes at the surface. */91509151maxbc = 0;9152qlayer = 0.0;9153slayer = 0.0;9154nlayer = 0;91559156/* Go through the layers and check which ones are active */9157for(j=0;j<MAXBOUNDARIES;j++) {9158if(!bound[j].created) continue;91599160for(i=1;i<=bound[j].nosides;i++) {9161dolayer = FALSE;9162parent = bound[j].parent[i];9163if(bound[j].types[i] > maxbc) maxbc = bound[j].types[i];91649165for(k=0;k<nolayers;k++) {9166if(bound[j].types[i] == layerbounds[k]) {9167nlayer = layernumber[k];9168slayer = layerthickness[k];9169qlayer = layerratios[k];9170dolayer = TRUE;9171}9172}9173if(!dolayer) continue;91749175/* We have found an active boundary layer */9176GetElementSide(parent,bound[j].side[i],bound[j].normal[i],9177data,ind,&sideelemtype);91789179midpoints = FALSE;9180if(sideelemtype == 202) {9181order = 1;9182}9183else if(sideelemtype == 203) {9184order = 2;9185if(maxelemtype > 408) midpoints = TRUE;9186}91879188for(l=0;l<sideelemtype%100;l++)9189layernode[ind[l]] += 1;9190}9191}91929193if(slayer > 1.0 || slayer < 1.0e-20)9194slayer = 1.0;91959196bcnodes = 0;9197maxcon = 0;9198for(i=1;i<=data->noknots;i++) {9199if(layernode[i]) bcnodes++;9200maxcon = MAX(maxcon, layernode[i]);9201}92029203if(info) printf("Found %d new nodes in the boundary layers!\n",bcnodes);9204if(!bcnodes) return(0);9205if(info) printf("There are %d connections at maximum\n",maxcon);92069207/* there will be more nodes if the original mesh consists of triangles */9208if(maxelemtype <= 303)9209data->maxnodes = 4;9210else if(maxelemtype == 306)9211data->maxnodes = 8;92129213/* Compute the number of new elements */9214nonewelements = 0;9215for(j=1;j<=data->noelements;j++) {9216elemhits = 0;9217elemtype = data->elementtypes[j];9218for(i=0;i<elemtype%100;i++) {9219k = data->topology[j][i];9220if( layernode[k]) {9221sharednode[k] += 1;9222elemhits++;9223}9224}9225if(elemhits) {9226nonewelements += nlayer ;9227if(elemhits != 2) nonewelements += nlayer + 1;9228}9229}9230printf("There will %d new elements\n",nonewelements);92319232/* This is a conservative estimate */9233nonewnodes = 2*nonewelements;92349235edgepairs = Imatrix(1,nonewnodes,1,3);9236for(j=1;j<=nonewnodes;j++)9237edgepairs[j][1] = edgepairs[j][2] = edgepairs[j][3] = 0;923892399240/* The size of new mesh */9241oldnoelements = data->noelements;9242oldnoknots = data->noknots;9243oldtopo = data->topology;9244oldx = data->x;9245oldy = data->y;9246oldz = data->z;92479248noknots = oldnoknots + nonewnodes;9249noelements = oldnoelements + nonewelements;92509251if(info) {9252printf("Creating additional %d elements and %d nodes.\n",nonewelements,nonewnodes);9253printf("Boundary layer mesh has at maximum %d elements and %d nodes.\n",noelements,noknots);9254}92559256/* Allocate more space for the enlarged data set */9257newtopo = Imatrix(1,noelements,0,data->maxnodes-1);9258newmaterial = Ivector(1,noelements);9259newelementtypes = Ivector(1,noelements);9260newx = Rvector(1,noknots);9261newy = Rvector(1,noknots);9262newz = Rvector(1,noknots);92639264/* Set the old topology */9265for(j=1;j<=data->noelements;j++) {9266newmaterial[j] = data->material[j];9267newelementtypes[j] = data->elementtypes[j];9268for(i=0;i<data->elementtypes[j]%100;i++)9269newtopo[j][i] = data->topology[j][i];9270}92719272/* Set the old nodes */9273for(i=1;i<=data->noknots;i++) {9274newx[i] = data->x[i];9275newy[i] = data->y[i];9276newz[i] = data->z[i];9277}92789279noelements = data->noelements;9280elemind = noelements;9281noknots = data->noknots;92829283/* Go through elements and make the new elements and nodes */9284for(j=1;j<=data->noelements;j++) {9285elemhits = 0;9286elemtype = data->elementtypes[j];9287elemsides = elemtype % 100;9288for(i=0;i<elemsides;i++)9289if( layernode[ data->topology[j][i] ]) elemhits++;9290if(!elemhits) continue;92919292if(elemtype == 404) {9293elemdone = FALSE;92949295for(side=0;side<elemsides;side++) {92969297goforit = FALSE;9298if(elemhits == 2 || elemhits == 3)9299if(layernode[oldtopo[j][side]] && layernode[oldtopo[j][(side+1)%elemsides]]) goforit = TRUE;9300if(elemhits == 1)9301if(layernode[oldtopo[j][side]]) goforit = TRUE;9302if(!goforit) continue;93039304/* Treat the special case of three hits9305In case of corners find the single node that is not on the boundary */9306if(elemhits == 3) {9307for(k=0;k<4;k++)9308if(!layernode[oldtopo[j][k]]) break;9309if(0) printf("Special node %d in corner %d\n",oldtopo[j][k],k);93109311basenode[0] = oldtopo[j][side];9312basenode[1] = oldtopo[j][(side+1)%elemsides];9313topnode[0] = oldtopo[j][k];9314topnode[1] = oldtopo[j][k];9315}9316else if(elemhits == 2) {9317basenode[0] = oldtopo[j][side];9318basenode[1] = oldtopo[j][(side+1)%elemsides];9319topnode[0] = oldtopo[j][(side+3)%elemsides];9320topnode[1] = oldtopo[j][(side+2)%elemsides];9321}9322else if(elemhits == 1) {9323basenode[0] = oldtopo[j][side];9324basenode[1] = basenode[0];9325topnode[0] = oldtopo[j][(side+3)%elemsides];9326topnode[1] = oldtopo[j][(side+1)%elemsides];9327}93289329for(k=0;k<=1;k++) {9330for(i=1;i<=nonewnodes;i++) {9331if(!edgepairs[i][1]) break;9332if(basenode[k] == edgepairs[i][1] && topnode[k] == edgepairs[i][2]) break;9333}9334if(!edgepairs[i][1]) {9335edgepairs[i][1] = basenode[k];9336edgepairs[i][2] = topnode[k];9337baseind[k] = noknots;9338edgepairs[i][3] = baseind[k];9339noknots += nlayer;9340}9341else {9342if(0) printf("Using existing nodes\n");9343baseind[k] = edgepairs[i][3];9344}9345x0[k] = oldx[basenode[k]];9346y0[k] = oldy[basenode[k]];9347dx[k] = oldx[topnode[k]] - x0[k];9348dy[k] = oldy[topnode[k]] - y0[k];93499350for(i=1;i<=nlayer;i++) {9351if(nlayer <= 1 || fabs(qlayer-1.0) < 0.001) {9352q = (1.0*i) / (nlayer+1);9353}9354else {9355ratio = pow(qlayer,1.0/nlayer);9356q = (1.- pow(ratio,1.0*i)) / (1.- pow(ratio,1.0+nlayer));9357}9358q *= slayer;9359newx[baseind[k]+i] = x0[k] + q * dx[k];9360newy[baseind[k]+i] = y0[k] + q * dy[k];9361}9362}93639364/* 0:th element */9365if(elemhits == 1) {9366newelementtypes[j] = 303;9367newtopo[j][0] = basenode[0];9368newtopo[j][1] = baseind[1] + 1;9369newtopo[j][2] = baseind[0] + 1;9370}9371else if(elemhits == 3 && elemdone) {9372elemind++;9373newelementtypes[elemind] = 404;9374newmaterial[elemind] = newmaterial[j];9375newtopo[elemind][side] = basenode[0];9376newtopo[elemind][(side+1)%elemsides] = basenode[1];9377newtopo[elemind][(side+2)%elemsides] = baseind[1] + 1;9378newtopo[elemind][(side+3)%elemsides] = baseind[0] + 1;9379}9380else {9381newtopo[j][(side+2)%elemsides] = baseind[1] + 1;9382newtopo[j][(side+3)%elemsides] = baseind[0] + 1;9383}93849385for(i=1;i<nlayer;i++) {9386elemind++;9387newelementtypes[elemind] = 404;9388newmaterial[elemind] = newmaterial[j];9389newtopo[elemind][0] = baseind[0] + i;9390newtopo[elemind][1] = baseind[1] + i;9391newtopo[elemind][2] = baseind[1] + i+1;9392newtopo[elemind][3] = baseind[0] + i+1;9393}93949395/* n:th element */9396if(elemhits == 3) {9397elemind++;9398newelementtypes[elemind] = 303;9399newmaterial[elemind] = newmaterial[j];9400newtopo[elemind][0] = baseind[0] + nlayer;9401newtopo[elemind][1] = baseind[1] + nlayer;9402newtopo[elemind][2] = topnode[0];9403}9404else if(elemhits == 2 || elemhits == 1) {9405elemind++;9406newelementtypes[elemind] = 404;9407newmaterial[elemind] = newmaterial[j];9408newtopo[elemind][0] = baseind[0] + nlayer;9409newtopo[elemind][1] = baseind[1] + nlayer;9410newtopo[elemind][2] = topnode[1];9411newtopo[elemind][3] = topnode[0];9412}9413/* n+1:th element */9414if(elemhits == 1) {9415elemind++;9416newelementtypes[elemind] = 303;9417newmaterial[elemind] = newmaterial[j];9418newtopo[elemind][0] = topnode[1];9419newtopo[elemind][1] = oldtopo[j][(side+2)%elemsides];9420newtopo[elemind][2] = topnode[0];9421}94229423elemdone = TRUE;9424}9425if(!elemdone)9426printf("cannot handle quadrilaterals with %d hits\n",elemhits);9427}942894299430else if(elemtype == 303) {9431elemdone = FALSE;94329433for(side=0;side<elemsides;side++) {94349435goforit = FALSE;9436if(elemhits == 2) {9437if(layernode[oldtopo[j][side]] && layernode[oldtopo[j][(side+1)%elemsides]]) goforit = TRUE;9438}9439else if(elemhits == 1) {9440if(layernode[oldtopo[j][side]]) goforit = TRUE;9441}9442else if(elemhits == 3) {9443if(sharednode[oldtopo[j][side]] == 1) goforit = TRUE;94449445printf("The boundary layer creation for certain corner triangles is omitted\n");9446goforit = FALSE;9447}9448if(!goforit) continue;94499450if(elemhits == 3) {9451if(1) printf("Special node %d in corner %d\n",oldtopo[j][side],side);9452basenode[0] = oldtopo[j][side];9453basenode[1] = basenode[0];9454topnode[0] = oldtopo[j][(side+2)%elemsides];9455topnode[1] = oldtopo[j][(side+1)%elemsides];9456}9457else if(elemhits == 2) {9458basenode[0] = oldtopo[j][side];9459basenode[1] = oldtopo[j][(side+1)%elemsides];9460topnode[0] = oldtopo[j][(side+2)%elemsides];9461topnode[1] = topnode[0];9462}9463else if(elemhits == 1) {9464basenode[0] = oldtopo[j][side];9465basenode[1] = basenode[0];9466topnode[0] = oldtopo[j][(side+2)%elemsides];9467topnode[1] = oldtopo[j][(side+1)%elemsides];9468}94699470for(k=0;k<=1;k++) {9471for(i=1;i<=nonewnodes;i++) {9472if(!edgepairs[i][1]) break;9473if(basenode[k] == edgepairs[i][1] && topnode[k] == edgepairs[i][2]) break;9474}9475if(!edgepairs[i][1]) {9476edgepairs[i][1] = basenode[k];9477edgepairs[i][2] = topnode[k];9478baseind[k] = noknots;9479edgepairs[i][3] = baseind[k];9480noknots += nlayer;9481}9482else {9483if(0) printf("Using existing nodes\n");9484baseind[k] = edgepairs[i][3];9485}94869487x0[k] = oldx[basenode[k]];9488y0[k] = oldy[basenode[k]];9489dx[k] = oldx[topnode[k]] - x0[k];9490dy[k] = oldy[topnode[k]] - y0[k];94919492for(i=1;i<=nlayer;i++) {9493if(nlayer <= 1 || fabs(qlayer-1.0) < 0.001) {9494q = (1.0*i) / (nlayer+1);9495}9496else {9497ratio = pow(qlayer,1.0/nlayer);9498q = (1.- pow(ratio,1.0*i)) / (1.- pow(ratio,1.0*nlayer));9499}9500q *= slayer;9501newx[baseind[k]+i] = x0[k] + q * dx[k];9502newy[baseind[k]+i] = y0[k] + q * dy[k];9503}9504}95059506/* 0:th element */9507if(elemhits == 1 || elemhits == 3) {9508newelementtypes[j] = 303;9509newtopo[j][0] = basenode[0];9510newtopo[j][1] = baseind[1] + 1;9511newtopo[j][2] = baseind[0] + 1;9512}9513else if(elemhits == 2) {9514newelementtypes[j] = 404;9515newtopo[j][side] = basenode[0];9516newtopo[j][(side+1)%4] = basenode[1];9517newtopo[j][(side+2)%4] = baseind[1] + 1;9518newtopo[j][(side+3)%4] = baseind[0] + 1;9519}95209521for(i=1;i<nlayer;i++) {9522elemind++;9523newelementtypes[elemind] = 404;9524newmaterial[elemind] = newmaterial[j];9525newtopo[elemind][0] = baseind[0] + i;9526newtopo[elemind][1] = baseind[1] + i;9527newtopo[elemind][2] = baseind[1] + i+1;9528newtopo[elemind][3] = baseind[0] + i+1;9529}95309531/* n:th element */9532if(elemhits == 1 || elemhits == 3) {9533elemind++;9534newelementtypes[elemind] = 404;9535newmaterial[elemind] = newmaterial[j];9536newtopo[elemind][0] = baseind[0] + nlayer;9537newtopo[elemind][1] = baseind[1] + nlayer;9538newtopo[elemind][2] = topnode[1];9539newtopo[elemind][3] = topnode[0];9540}9541else if(elemhits == 2) {9542elemind++;9543newelementtypes[elemind] = 303;9544newmaterial[elemind] = newmaterial[j];9545newtopo[elemind][0] = baseind[0] + nlayer;9546newtopo[elemind][1] = baseind[1] + nlayer;9547newtopo[elemind][2] = topnode[1];9548}9549elemdone = TRUE;9550}9551if(!elemdone)9552printf("cannot handle triangles with %d hits\n",elemhits);9553}95549555else {9556printf("Not implemented for element %d\n",elemtype);9557}9558}9559noelements = elemind;95609561data->x = newx;9562data->y = newy;9563data->topology = newtopo;9564data->material = newmaterial;9565data->elementtypes = newelementtypes;9566data->noknots = noknots;9567data->noelements = elemind;95689569printf("The created boundary layer mesh has at %d elements and %d nodes.\n",noelements,noknots);95709571return(0);9572}9573957495759576int RotateTranslateScale(struct FemType *data,struct ElmergridType *eg,int info)9577{9578int i;9579Real x,y,z,xz,yz,yx,zx,zy,xy,cx,cy,cz;9580Real xmin, xmax, ymin, ymax, zmin, zmax;95819582if(eg->scale) {9583if(info) printf("Scaling mesh with vector [%.3lg %.3lg %.3lg]\n",9584eg->cscale[0],eg->cscale[1],eg->cscale[2]);9585for(i=1;i<=data->noknots;i++) {9586data->x[i] *= eg->cscale[0];9587data->y[i] *= eg->cscale[1];9588data->z[i] *= eg->cscale[2];9589}9590if(0) printf("Scaling of mesh finished.\n");9591}95929593if(eg->rotate) {9594if(info) printf("Rotating mesh with degrees [%.3lg %.3lg %.3lg]\n",9595eg->crotate[0],eg->crotate[1],eg->crotate[2]);9596cx = FM_PI * eg->crotate[0]/180.0;9597cy = FM_PI * eg->crotate[1]/180.0;9598cz = FM_PI * eg->crotate[2]/180.0;95999600for(i=1;i<=data->noknots;i++) {96019602x = data->x[i];9603y = data->y[i];9604z = data->z[i];96059606xz = x*cos(cz) + y*sin(cz);9607yz = -x*sin(cz) + y*cos(cz);96089609if( fabs(cx) > 1.0e-8 || fabs(cy) > 1.0e-8 ) {9610yx = yz*cos(cx) + z*sin(cx);9611zx = -yz*sin(cx) + z*cos(cx);96129613zy = zx*cos(cy) + xz*sin(cy);9614xy = -zx*sin(cy) + xz*cos(cy);96159616data->x[i] = xy;9617data->y[i] = yx;9618data->z[i] = zy;9619}9620else {9621data->x[i] = xz;9622data->y[i] = yz;9623}9624}9625if(0) printf("Rotation of mesh finished.\n");9626}96279628if(eg->translate) {9629if(info) printf("Translating the mesh with vector [%.3lg %.3lg %.3lg]\n",9630eg->ctranslate[0],eg->ctranslate[1],eg->ctranslate[2]);9631for(i=1;i<=data->noknots;i++) {9632data->x[i] += eg->ctranslate[0];9633data->y[i] += eg->ctranslate[1];9634data->z[i] += eg->ctranslate[2];9635}9636if(0) printf("Translation of mesh finished.\n");9637}96389639if(eg->center) {9640xmin = xmax = data->x[1];9641ymin = ymax = data->y[1];9642zmin = zmax = data->z[1];96439644for(i=1;i<=data->noknots;i++) {9645xmax = MAX( xmax, data->x[i] );9646xmin = MIN( xmin, data->x[i] );9647ymax = MAX( ymax, data->y[i] );9648ymin = MIN( ymin, data->y[i] );9649zmax = MAX( zmax, data->z[i] );9650zmin = MIN( zmin, data->z[i] );9651}9652cx = 0.5 * (xmin + xmax);9653cy = 0.5 * (ymin + ymax);9654cz = 0.5 * (zmin + zmax);96559656if(info) printf("Setting new center to %.3e %.3e %.3e\n",cx,cy,cz);96579658for(i=1;i<=data->noknots;i++) {9659data->x[i] -= cx;9660data->y[i] -= cy;9661data->z[i] -= cz;9662}9663}96649665return(0);9666}9667966896699670int CreateNodalGraph(struct FemType *data,int full,int info)9671{9672int i,j,k,l,m,totcon,noelements, noknots,elemtype,nonodes,hit,ind,ind2;9673int maxcon,percon,edge;96749675printf("Creating a nodal graph of the finite element mesh\n");96769677if(data->nodalexists) {9678printf("The nodal graph already exists!\n");9679smallerror("Nodal graph not done");9680return(1);9681}96829683maxcon = 0;9684totcon = 0;9685percon = 0;9686noelements = data->noelements;9687noknots = data->noknots;96889689for(i=1;i<=noelements;i++) {9690elemtype = data->elementtypes[i];96919692/* This sets only the connections resulting from element edges */9693if(!full) {9694int inds[2];9695for(edge=0;;edge++) {9696if( !GetElementGraph(i,edge,data,&inds[0]) ) break;96979698ind = inds[0];9699ind2 = inds[1];97009701hit = FALSE;9702for(l=0;l<maxcon;l++) {9703if(data->nodalgraph[l][ind] == ind2) hit = TRUE;9704if(data->nodalgraph[l][ind] == 0) break;9705}9706if(!hit) {9707if(l >= maxcon) {9708data->nodalgraph[maxcon] = Ivector(1,noknots);9709for(m=1;m<=noknots;m++)9710data->nodalgraph[maxcon][m] = 0;9711maxcon++;9712}9713data->nodalgraph[l][ind] = ind2;9714totcon++;9715}97169717/* Make also so symmetric connection */9718for(l=0;l<maxcon;l++) {9719if(data->nodalgraph[l][ind2] == ind) hit = TRUE;9720if(data->nodalgraph[l][ind2] == 0) break;9721}9722if(!hit) {9723if(l >= maxcon) {9724data->nodalgraph[maxcon] = Ivector(1,noknots);9725for(m=1;m<=noknots;m++)9726data->nodalgraph[maxcon][m] = 0;9727maxcon++;9728}9729data->nodalgraph[l][ind2] = ind;9730totcon++;9731}9732}9733}97349735/* This sets all elemental connections */9736else {9737nonodes = data->elementtypes[i] % 100;9738for(j=0;j<nonodes;j++) {9739ind = data->topology[i][j];9740for(k=0;k<nonodes;k++) {9741ind2 = data->topology[i][k];9742if(ind == ind2) continue;97439744hit = FALSE;9745for(l=0;l<maxcon;l++) {9746if(data->nodalgraph[l][ind] == ind2) hit = TRUE;9747if(data->nodalgraph[l][ind] == 0) break;9748}9749if(!hit) {9750if(l >= maxcon) {9751data->nodalgraph[maxcon] = Ivector(1,noknots);9752for(m=1;m<=noknots;m++)9753data->nodalgraph[maxcon][m] = 0;9754maxcon++;9755}9756data->nodalgraph[l][ind] = ind2;9757totcon++;9758}9759}9760}9761}97629763}97649765/* This adds the periodic connections */9766if( data->periodicexist ) {9767for(ind=1;ind<=noknots;ind++) {9768ind2 = data->periodic[ind];9769if(ind == ind2) continue;97709771hit = FALSE;9772for(l=0;l<maxcon;l++) {9773if(data->nodalgraph[l][ind] == ind2) hit = TRUE;9774if(data->nodalgraph[l][ind] == 0) break;9775}9776if(!hit) {9777if(l >= maxcon) {9778data->nodalgraph[maxcon] = Ivector(1,noknots);9779for(m=1;m<=noknots;m++)9780data->nodalgraph[maxcon][m] = 0;9781maxcon++;9782}9783data->nodalgraph[l][ind] = ind2;9784totcon++;9785percon++;9786}9787}9788}97899790data->nodalmaxconnections = maxcon;9791data->nodalexists = TRUE;97929793if(info) {9794printf("There are at maximum %d connections in nodal graph.\n",maxcon);9795printf("There are at all in all %d connections in nodal graph.\n",totcon);9796if(percon) printf("There are %d periodic connections in nodal graph.\n",percon);9797}97989799return(0);9800}980198029803int DestroyNodalGraph(struct FemType *data,int info)9804{9805int i,maxcon, noknots;98069807if(!data->nodalexists) {9808printf("You tried to destroy a non-existing nodal graph\n");9809return(1);9810}98119812maxcon = data->nodalmaxconnections;9813noknots = data->noknots;98149815for(i=0;i<maxcon;i++)9816free_Ivector(data->nodalgraph[i],1,noknots);98179818data->nodalmaxconnections = 0;9819data->nodalexists = FALSE;98209821if(info) printf("The nodal graph was destroyed\n");9822return(0);9823}9824982598269827int CreateInverseTopology(struct FemType *data,int info)9828{9829int i,j,k,l,m,noelements,noknots,elemtype,nonodes,ind;9830int *neededby,minneeded,maxneeded;9831int step,totcon;9832int *rows,*cols;9833struct CRSType *invtopo;98349835invtopo = &data->invtopo;9836if(invtopo->created) {9837if(0) printf("The inverse topology already exists!\n");9838return(0);9839}98409841printf("Creating an inverse topology of the finite element mesh\n");98429843noelements = data->noelements;9844noknots = data->noknots;98459846neededby = Ivector(1,noknots);9847totcon = 0;98489849for(step=1;step<=2;step++) {98509851for(i=1;i<=noknots;i++)9852neededby[i] = 0;98539854for(i=1;i<=noelements;i++) {9855elemtype = data->elementtypes[i];9856nonodes = data->elementtypes[i] % 100;98579858for(j=0;j<nonodes;j++) {9859ind = data->topology[i][j];98609861if( step == 1 ) {9862neededby[ind] += 1;9863totcon += 1;9864}9865else {9866k = rows[ind-1] + neededby[ind];9867cols[k] = i-1;9868neededby[ind] += 1;9869}9870}9871}98729873if( step == 1 ) {9874rows = Ivector( 0, noknots );9875rows[0] = 0;9876for(i=1;i<=noknots;i++)9877rows[i] = rows[i-1] + neededby[i];98789879cols = Ivector( 0, totcon-1 );9880for(i=0;i<totcon;i++)9881cols[i] = 0;98829883invtopo->cols = cols;9884invtopo->rows = rows;9885invtopo->colsize = totcon;9886invtopo->rowsize = noknots;9887invtopo->created = TRUE;9888}9889}98909891minneeded = maxneeded = neededby[1];9892for(i=1;i<=noknots;i++) {9893minneeded = MIN( minneeded, neededby[i]);9894maxneeded = MAX( maxneeded, neededby[i]);9895}98969897free_Ivector(neededby,1,noknots);98989899if(info) {9900printf("There are from %d to %d connections in the inverse topology.\n",minneeded,maxneeded);9901printf("Each node is in average in %.3f elements\n",1.0*totcon/noknots);9902}99039904return(0);9905}9906990799089909int CreateDualGraph(struct FemType *data,int unconnected,int info)9910{9911int totcon,dcon,noelements,noknots,elemtype,nonodes,i,j,k,l,i2,m,ind,hit,ci,ci2;9912int dualmaxcon,invmaxcon,showgraph,freeelements,step,orphanelements,stat;9913int *elemconnect,*neededby;9914int *dualrow,*dualcol,dualsize,dualmaxelem,allocated;9915int *invrow,*invcol;9916struct CRSType *dualgraph;99179918if(info) printf("Creating a dual graph of the finite element mesh\n");99199920dualgraph = &data->dualgraph;9921if(dualgraph->created) {9922printf("The dual graph already exists!\n");9923return(1);9924}99259926CreateInverseTopology(data,info);99279928noelements = data->noelements;9929noknots = data->noknots;9930freeelements = noelements;9931orphanelements = 0;99329933/* If a dual graph only for the unconnected nodes is requested do that.9934Basically the connected nodes are omitted in the graph. */9935if( unconnected ) {9936if(info) printf("Removing connected nodes from the dual graph\n");9937if( data->nodeconnectexist ) {9938if(info) printf("Creating connected elements list from the connected nodes\n");9939SetConnectedElements(data,info);9940}9941if( data->elemconnectexist ) {9942elemconnect = data->elemconnect;9943freeelements -= data->elemconnectexist;9944}9945else {9946unconnected = FALSE;9947}9948if(info) printf("List of unconnected elements created\n");9949}99509951showgraph = FALSE;9952if(showgraph) printf("elemental graph ij pairs\n");99539954data->dualexists = TRUE;9955dualmaxcon = 0;9956dualmaxelem = 0;99579958invrow = data->invtopo.rows;9959invcol = data->invtopo.cols;996099619962/* This marker is used to identify the connections already accounted for */9963neededby = Ivector(1,freeelements);9964for(i=1;i<=freeelements;i++)9965neededby[i] = 0;99669967allocated = FALSE;9968omstart:99699970totcon = 0;99719972for(i=1;i<=noelements;i++) {9973if(showgraph) printf("%d :: ",i);99749975dcon = 0;9976elemtype = data->elementtypes[i];9977nonodes = data->elementtypes[i] % 100;99789979if( unconnected ) {9980ci = elemconnect[i];9981if( ci < 0 ) continue;9982}9983else {9984ci = i;9985}9986if(allocated) dualrow[ci-1] = totcon;99879988if(0) printf("i=%d %d\n",i,elemtype);99899990for(step=1;step<=2;step++) {9991for(j=0;j<nonodes;j++) {9992ind = data->topology[i][j];99939994if(0) printf("ind=%d\n",ind);999599969997for(k=invrow[ind-1];k<invrow[ind];k++) {9998i2 = invcol[k]+1;999910000if( i2 == i ) continue;1000110002if( unconnected ) {10003ci2 = elemconnect[i2];10004if( ci2 < 0 ) continue;10005}10006else {10007ci2 = i2;10008}1000910010/* In the first cycle mark the needed connections,10011and in the second cycle set the marker to zero for next round. */10012if( step == 1 ) {10013if( neededby[ci2] ) continue;10014neededby[ci2] = TRUE;1001510016if(0) printf("ci ci2 = %d %d\n",ci,ci2);1001710018/* If the dual graph has been allocated populate it */10019if(allocated) {10020dualcol[totcon] = ci2-1;10021}1002210023dcon += 1;10024totcon += 1;10025if( dcon > dualmaxcon ) {10026dualmaxcon = dcon;10027dualmaxelem = i;10028}10029}10030else {10031neededby[ci2] = FALSE;10032}10033}10034}10035}10036if( dcon == 0 && allocated ) {10037orphanelements += 1;10038}10039}1004010041if(allocated) {10042dualrow[dualsize] = totcon;10043}10044else {10045dualsize = freeelements;10046if(info) printf("Allocating for the dual graph for %d with %d connections\n",dualsize,totcon);10047dualrow = Ivector(0,dualsize);10048for(i=1;i<=dualsize;i++)10049dualrow[i] = 0;1005010051dualcol = Ivector(0,totcon-1);10052for(i=0;i<totcon;i++)10053dualcol[i] = 0;1005410055dualgraph->cols = dualcol;10056dualgraph->rows = dualrow;10057dualgraph->rowsize = dualsize;10058dualgraph->colsize = totcon;10059dualgraph->created = TRUE;1006010061allocated = TRUE;1006210063goto omstart;10064}1006510066if( orphanelements && info ) {10067printf("There are %d elements in the dual mesh that are not connected!\n",orphanelements);10068if(unconnected) printf("The orphan elements are likely caused by the hybrid partitioning\n");10069}100701007110072#if 010073j = totcon; k = 0;10074for(i=1;i<=dualsize;i++){10075l = dualrow[i]-dualrow[i-1];10076if(l <= 0 ) printf("row(%d) = %d %d %d\n",i,l,dualrow[i],dualrow[i-1]);10077j = MIN(j,l);10078k = MAX(k,l);10079}10080printf("range dualrow: %d %d\n",j,k);1008110082j = totcon; k = 0;10083for(i=0;i<totcon;i++) {10084j = MIN(j,dualcol[i]);10085k = MAX(k,dualcol[i]);10086}10087printf("range dualcol: %d %d\n",j,k);10088#endif100891009010091if(info) {10092printf("There are at maximum %d connections in dual graph (in element %d).\n",dualmaxcon,dualmaxelem);10093printf("There are at all in all %d connections in dual graph.\n",totcon);10094printf("Average connection per active element in dual graph is %.3f\n",1.0*totcon/freeelements);10095}1009610097free_Ivector( neededby,1,freeelements);1009810099/* Inverse topology is created for partitioning only and then the direct10100topology is needed elsewhere as well. Do do not destroy it. */10101if(0) stat = DestroyInverseTopology(data,info);1010210103return(0);10104}101051010610107int DestroyCRSMatrix(struct CRSType *sp) {1010810109if(sp->created) {10110if(0) printf("You tried to destroy a non-existing sparse matrix\n");10111return(1);10112}1011310114free_Ivector( sp->rows, 0, sp->rowsize );10115free_Ivector( sp->cols, 0, sp->colsize-1);10116sp->rowsize = 0;10117sp->colsize = 0;10118sp->created = FALSE;1011910120return(0);10121}101221012310124int DestroyInverseTopology(struct FemType *data,int info)10125{10126int stat;10127stat = DestroyCRSMatrix( &data->invtopo );10128return(stat);10129}1013010131int DestroyDualGraph(struct FemType *data,int info)10132{10133int stat;10134stat = DestroyCRSMatrix( &data->dualgraph );10135return(stat);10136}1013710138101391014010141int MeshTypeStatistics(struct FemType *data,int info)10142{10143int i,elemtype,maxelemtype,minelemtype;10144int *elemtypes=NULL;1014510146maxelemtype = minelemtype = data->elementtypes[1];1014710148for(i=1;i<=data->noelements;i++) {10149elemtype = data->elementtypes[i];10150maxelemtype = MAX( maxelemtype, elemtype );10151minelemtype = MIN( minelemtype, elemtype );10152}1015310154elemtypes = Ivector(minelemtype,maxelemtype);10155for(i=minelemtype;i<=maxelemtype;i++)10156elemtypes[i] = 0;1015710158for(i=1;i<=data->noelements;i++) {10159elemtype = data->elementtypes[i];10160elemtypes[elemtype] += 1;10161}1016210163if(info) {10164printf("Number of different elementtypes\n");10165for(i=minelemtype;i<=maxelemtype;i++)10166if(elemtypes[i]) printf("\t%d\t%d\n",i,elemtypes[i]);10167}1016810169free_Ivector(elemtypes,minelemtype,maxelemtype);10170return(0);10171}1017210173int BoundingBox(struct FemType *data,int nomesh,int nomeshes,int info)10174{10175int i;10176Real xmin, xmax, ymin, ymax, zmin, zmax, sidemax;1017710178xmin = xmax = data->x[1];10179ymin = ymax = data->y[1];10180zmin = zmax = data->z[1];1018110182for(i=1; i<=data->noknots; i++){10183xmax = MAX( xmax, data->x[i] );10184xmin = MIN( xmin, data->x[i] );10185ymax = MAX( ymax, data->y[i] );10186ymin = MIN( ymin, data->y[i] );10187zmax = MAX( zmax, data->z[i] );10188zmin = MIN( zmin, data->z[i] );10189}10190sidemax = MAX(xmax-xmin,ymax-ymin);10191sidemax = MAX(sidemax,zmax-zmin);1019210193if(nomeshes > 1) {10194printf("Bounding box of all nodes in mesh[%d] of [%d] meshes:\n",nomesh,nomeshes);10195}10196else {10197printf("Bounding box of all nodes in mesh:\n");10198}1019910200printf("X:[%lg,%lg] ",xmin,xmax);10201printf("Y:[%lg,%lg] ",ymin,ymax);10202printf("Z:[%lg,%lg]\n",zmin,zmax);1020310204if(sidemax > 49.9) {10205printf("\nNotice: the longest bounding box side length of [%lg] is greater than 50.\n",sidemax);10206printf("ElmerGUI includes a library of material properties, defined in SI units. If using ElmerGUI, \n");10207printf("then the geometry is expected to have meters as length. Geometry that exceeds 50 meters \n");10208printf("in length or width or height may not be intended. Many Geometry generators assume \n");10209printf("millimeters as the basic unit of length. Scaling the geometry from millimeters to meters \n");10210printf("may be the desired action. For more help, search the Elmer users forum for posts \n");10211printf("about SI units, or for posts about Coordinate Scaling.\n");10212printf("Scaling can be accomplished in at least three ways, as follows:\n");10213printf(" 1. Define the original geometry in meters, not millimeters.\n");10214printf(" 2. Call ElmerGrid with -scale 0.001 0.001 0.001 as an option.\n");10215printf(" 3. Add Coordinate Scaling = 0.001 to the simulation section of the sif file.\n");10216printf("If using Elmer to analyze large geometry, such as a glacier, then ignore this notice.\n\n");10217}1021810219return(0);10220}102211022210223