00001 #ifndef __Exponent_Engine_hpp__
00002 #define __Exponent_Engine_hpp__
00003
00004 #include<stdio.h>
00005 #include<stdlib.h>
00006 #include<assert.h>
00007 #include<algorithm>
00008 #include<iostream>
00009 #include<stdexcept>
00010 #include<vector>
00011
00012
00013 #define fv_max(a,b) (a) > (b) ? (a) : (b)
00014
00015 enum eBaseType {
00016 eTensor = 0x0,
00017 eComplete = 0x1,
00018 };
00019
00020
00021 extern int shape_functions_3D(int pdeg,int base,double*,double*,double*,double*,double*);
00022 int degree_3d(int pdeg,int base_type,int direction);
00023 template<typename TExp,typename TScalar> class ExponentEngine;
00024
00025 template<typename TExp,typename TScalar>
00026 std::ostream& operator << (std::ostream& os, const ExponentEngine<TExp,TScalar>& rhs);
00027
00028 template<typename TExp,typename TScalar>
00029 class ExponentEngine
00030 {
00031 public:
00032 struct fvType2 {
00033 union {
00034 TExp u[2];
00035 struct { TExp x,y; };
00036 };
00037 };
00038 struct fvType3 {
00039 union {
00040 TExp u[3];
00041 struct { TExp x,y,z; };
00042 };
00043 bool operator==(const fvType3& rhs) {
00044 return (x == rhs.x && y == rhs.y && z == rhs.z);
00045 }
00046 };
00047
00048 typedef std::vector<fvType3> vExpm;
00049
00050 public:
00051 ExponentEngine(int pdeg = 101,int base = 0);
00052 ~ExponentEngine();
00053
00054 void Set(int pdeg,int base);
00055 const fvType3* GetExpMap() const { return _expms.data(); }
00056 int GetPdeg() const { return _pdeg; }
00057 int GetBaseType() const { return _base; }
00058 int GetNumShapeFunc() const { return _num_shap; }
00059
00060 protected:
00061 vExpm _expms;
00062 int _pdeg;
00063 eBaseType _base;
00064 int _num_shap;
00065
00066 private:
00067 void init();
00068 bool test();
00069 int convert(vExpm& expms);
00070 static int degree_3d(int pdeg,int base_type, int direction);
00071 static int num_shape_func(int pdeg,int base);
00072 static int order_3d(int pdeg,int base_type, fvType3 expm[]);
00073 static int order_2d(int pdeg,int base_type, fvType2 expm[]);
00074 static int order_1d(int pdeg,TExp expm[]);
00075 static void multiply_1d(int pdeg,TScalar pt,TScalar* outPhi,TScalar* outdPhi);
00076
00077 ExponentEngine(const ExponentEngine&);
00078 ExponentEngine& operator=(const ExponentEngine&);
00079
00080
00081 friend int shape_functions_3D(int pdeg,int base,double*,double*,double*,double*,double*);
00082 };
00083
00084 template<typename TExp,typename TScalar>
00085 ExponentEngine<TExp,TScalar>::ExponentEngine(int pdeg,int base) {
00086 Set(pdeg,base);
00087 }
00088
00089 template<typename TExp,typename TScalar>
00090 ExponentEngine<TExp,TScalar>::~ExponentEngine() {
00091 _expms.clear();
00092 }
00093
00094
00095 template<typename TExp,typename TScalar>
00096 void ExponentEngine<TExp,TScalar>::Set(int pdeg,int base) {
00097 if (pdeg > 10 && base == eComplete) {
00098 char msg[64];
00099 sprintf(msg,"Warrning: degre value %d is out of range (<10) for COMPLETE type!\n",pdeg);
00100 throw std::runtime_error(msg);
00101 }
00102 if (pdeg < 101 && base == eTensor) {
00103 char msg[64];
00104 sprintf(msg,"Warrning: degre value %d is invalid (>=101) for TENSOR type!\n",pdeg);
00105 throw std::runtime_error(msg);
00106 }
00107 if (base != eTensor && base != eComplete) {
00108 char msg[64];
00109 sprintf(msg,"Warrning: unknown base type: %d allowed %d - TENSOR and %d - COMPLETE!\n",base,eTensor,eComplete);
00110 throw std::runtime_error(msg);
00111 }
00112 _pdeg = pdeg;
00113 _base = static_cast<eBaseType>(base);
00114 init();
00115 if (!test()) throw std::runtime_error("test failed!");
00116 vExpm expms;
00117 convert(expms);
00118 expms.clear();
00119 }
00120
00121 template<typename TExp,typename TScalar>
00122 void ExponentEngine<TExp,TScalar>::init() {
00123 _num_shap = num_shape_func(_pdeg,_base);
00124 if (_num_shap) {
00125 if (!_expms.empty())_expms.clear();
00126 _expms.resize(_num_shap);
00127 int num = order_3d(_pdeg,_base,_expms.data());
00128 printf("num = %d shape = %d\n",num,_num_shap);
00129 assert(num == _num_shap);
00130 }
00131 }
00132
00133 template<typename TExp,typename TScalar>
00134 bool ExponentEngine<TExp,TScalar>::test() {
00135 if (_base == eTensor) return true;
00136 bool passed = true;
00137 for (int i=0; i < _num_shap; ++i) {
00138 const fvType3* p = &_expms[i];
00139 TExp sum = p->x + p->y + p->z;
00140 if (sum > _pdeg) {
00141 passed = false;
00142 std::cout << "Test fsild for phi[" << i << "] = { "
00143 << p->x << ", " << p->y << ", " << p->z << "}\n";
00144 }
00145 }
00146 return passed;
00147 }
00148
00149
00150 template<typename TExp,typename TScalar>
00151 int ExponentEngine<TExp,TScalar>::convert(vExpm& expms)
00152 {
00153 if (!expms.empty()) expms.clear();
00154 int pdeg0 = degree_3d(_pdeg,_base,0); pdeg0++;
00155 int pdeg1 = degree_3d(_pdeg,_base,1); pdeg1++;
00156 int pdeg2 = degree_3d(_pdeg,_base,2); pdeg2++;
00157 printf("pdeg: %d %d %d\n",pdeg0,pdeg1,pdeg2);
00158 int kk = 0;
00159 if (_base == eComplete) {
00160 for(int i = 0; i < pdeg0; ++i)
00161 {
00162 for(int j = 0; j < pdeg1-i; ++j)
00163 for(int k = 0; k < pdeg2-j-i; ++k)
00164 {
00165 fvType3 el = {k,j,i};
00166 expms.push_back(el);
00167 ++kk;
00168
00169 }
00170 }
00171 }
00172 else {
00173 for(int i = 0; i < pdeg0; ++i)
00174 {
00175 for(int j = 0; j < pdeg1; ++j)
00176 for(int k = 0; k < pdeg2-i; ++k)
00177 {
00178 fvType3 el = {i,k,j};
00179 expms.push_back(el);
00180 ++kk;
00181
00182 }
00183 }
00184 }
00185
00186 std::vector<int> pos;
00187 int i = 0;
00188
00189 for (auto el : expms) {
00190 printf("el: {%d, %d, %d}\n",el.x,el.y,el.z);
00191 auto it = std::find(_expms.begin(),_expms.end(),el);
00192 int p = std::distance(_expms.begin(),it);
00193
00194 assert(p < _num_shap);
00195 pos.push_back(p);
00196 }
00197
00198
00199
00200 printf("kk = %d %d\n",kk,pos.size());
00201 assert(pos.size() == expms.size());
00202 for (int i =0; i < _num_shap; ++i)
00203 printf("%d ref = {%d, %d %d}\t%d\tcurr = {%d, %d, %d}\n",i,expms[i].x,expms[i].y,expms[i].z,pos[i],
00204 _expms[i].x,_expms[i].y,_expms[i].z);
00205
00206 return static_cast<int>(pos.size());
00207 }
00208
00209
00210
00211
00212 template<typename TExp,typename TScalar>
00213 int ExponentEngine<TExp,TScalar>::num_shape_func(int pdeg,int base) {
00214 int num_shap = 0;
00215 printf("in num_shape_func pdeg = %d\n",pdeg);
00216 switch (base) {
00217 case eTensor: {
00218 int porderz,porder;
00219 porderz = pdeg / 100;
00220 porder = pdeg % 100;
00221 num_shap = (porderz+1)*(porder+1)*(porder+2)/2;
00222 printf("in tensor num_shape_func = %d\n",num_shap);
00223 } break;
00224 case eComplete: {
00225 int porder=pdeg;
00226 num_shap = (porder+1)*(porder+2)*(porder+3)/6;
00227 printf("in complate num_shape_func = %d\n",num_shap);
00228 } break;
00229 default:
00230 std::cerr << "Warrning: invalid base type for number of shape function evaluation: " << base << std::endl;
00231 break;
00232 }
00233 return (num_shap);
00234 }
00235
00236
00237
00238
00239 template<typename TExp,typename TScalar>
00240 int ExponentEngine<TExp,TScalar>::order_3d(int pdeg,int base_type, fvType3 expm[])
00241 {
00242 printf("in order_3d\n");
00243 if (pdeg == 0) {
00244 expm[0].x = expm[1].y = expm[2].z = 0;
00245 return 1;
00246 }
00247 else if (pdeg == 100) {
00248 expm[0].x = 0; expm[0].y = 0; expm[0].z = 0;
00249 expm[1].x = 0; expm[1].y = 0; expm[1].z = 1;
00250 return 2;
00251 }
00252 else if (pdeg == 1 && base_type == eTensor) {
00253 expm[0].x = 0; expm[0].y = 0; expm[0].z = 0;
00254 expm[1].x = 1; expm[1].y = 0; expm[1].z = 0;
00255 expm[2].x = 0; expm[2].y = 1; expm[2].z = 0;
00256 return 3;
00257 }
00258 else if (pdeg == 2 && base_type == eTensor) {
00259 expm[0].x = 0; expm[0].y = 0; expm[0].z = 0;
00260 expm[1].x = 1; expm[1].y = 0; expm[1].z = 0;
00261 expm[2].x = 0; expm[2].y = 1; expm[2].z = 0;
00262 expm[3].x = 2; expm[3].y = 0; expm[3].z = 0;
00263 expm[4].x = 1; expm[4].y = 1; expm[4].z = 0;
00264 expm[5].x = 0; expm[5].y = 2; expm[5].z = 0;
00265 return 6;
00266 }
00267 else {
00268 printf("in linear and highorder_3d\n");
00269 expm[0].x = 0; expm[0].y = 0; expm[0].z = 0;
00270 expm[1].x = 1; expm[1].y = 0; expm[1].z = 0;
00271 expm[2].x = 0; expm[2].y = 1; expm[2].z = 0;
00272 expm[3].x = 0; expm[3].y = 0; expm[3].z = 1;
00273 if (pdeg == 1) return 4;
00274
00275 expm[4].x = 1; expm[4].y = 0; expm[4].z = 1;
00276 expm[5].x = 0; expm[5].y = 1; expm[5].z = 1;
00277 if (pdeg == 101) return 6;
00278
00279 expm[6].x = 1; expm[6].y = 1; expm[6].z = 0;
00280 if (pdeg == 2 && base_type == eComplete) {
00281 expm[7].x = 2; expm[7].y = 0; expm[7].z = 0;
00282 expm[8].x = 0; expm[8].y = 2; expm[8].z = 0;
00283 expm[9].x = 0; expm[9].y = 0; expm[9].z = 2;
00284 return 10;
00285 }
00286
00287 expm[7].x = 1; expm[7].y = 1; expm[7].z = 1;
00288 int base_type_2D = eComplete;
00289 int pdegx,pdegz;
00290 if (base_type == eTensor) {
00291 pdegx = pdeg % 100;
00292 pdegz = pdeg / 100;
00293 }
00294 else if (base_type == eComplete) {
00295 if (pdeg < 100) {
00296 pdegx = pdeg;
00297 pdegz = pdeg;
00298 }
00299 else {
00300 pdegx = pdeg % 100;
00301 pdegz = pdeg / 100;
00302 std::cout << "pdegs: " << pdegx << " " << pdegz << std::endl;
00303 }
00304 }
00305 else {
00306 printf("Type of base not valid for prisms!\n");
00307 exit(-1);
00308 }
00309
00310 fvType2 ssn[60];
00311 TExp ttn[10];
00312 int num_shap_2D = order_2d(pdegx,base_type_2D,ssn);
00313 assert(num_shap_2D < 60);
00314 order_1d(pdegz,ttn);
00315
00316 int num_shap;
00317 if (base_type == eTensor) {
00318 int kk = 6;
00319 printf("in etensor\n");
00320 for(int j=0;j<2;j++) {
00321 for(int i=3;i<num_shap_2D;i++){
00322 expm[kk].x = ssn[i].x; expm[kk].y = ssn[i].y; expm[kk++].z = ttn[j];
00323 }
00324 }
00325 for(int j=2;j<pdegz+1;j++) {
00326 for(int i=0;i<num_shap_2D;i++) {
00327 expm[kk].x = ssn[i].x; expm[kk].y = ssn[i].y; expm[kk++].z = ttn[j];
00328 }
00329 }
00330 num_shap = kk;
00331 }
00332 else if (base_type == eComplete) {
00333 printf("in complate\n");
00334 int kk = 8, ii= 0;
00335 for (int j=0;j<2;j++) {
00336 for (int i=0;i<2;i++) {
00337 for (int k=2;k<=pdeg-i-j;k++){
00338 expm[kk].x = ssn[ii].x; expm[kk].y = ssn[ii].y; expm[kk++].z = ttn[k];
00339 }
00340 ii++;
00341 }
00342 }
00343 for (int j=0;j<2;j++) {
00344 for (int i=2;i<=pdeg-j;i++) {
00345 for(int k=0;k<=pdeg-i-j;k++){
00346 expm[kk].x = ssn[ii].x; expm[kk].y = ssn[ii].y; expm[kk++].z = ttn[k];
00347 }
00348 ii++;
00349 }
00350 }
00351 for (int j=2;j<=pdeg;j++) {
00352 for (int i=0;i<=pdeg-j;i++) {
00353 for(int k=0;k<=pdeg-i-j;k++){
00354 expm[kk].x = ssn[ii].x; expm[kk].y = ssn[ii].y; expm[kk++].z = ttn[k];
00355 }
00356 ii++;
00357 }
00358 }
00359 num_shap=kk;
00360 }
00361 else {
00362 printf("Unsupported base type: %d\n",base_type);
00363 }
00364 return num_shap;
00365 }
00366 printf("This is not correct\n");
00367 return(0);
00368 }
00369
00370 template<typename TExp,typename TScalar>
00371 int ExponentEngine<TExp,TScalar>::order_2d(int pdeg,int base_type,fvType2 expm[])
00372 {
00373 if (pdeg == 0) {
00374 expm[0].x = 0; expm[0].y = 0;
00375 return(1);
00376 }
00377 else if (pdeg == 10) {
00378 expm[0].x = 0; expm[0].y = 0;
00379 expm[1].x = 0; expm[1].y = 1;
00380 return 2;
00381 }
00382 else if (pdeg == 1 && base_type == eTensor) {
00383
00384 expm[0].x = 0; expm[0].y = 0;
00385 expm[1].x = 1; expm[1].y = 0;
00386 return 2;
00387 }
00388 else {
00389
00390 expm[0].x = 0; expm[0].y = 0;
00391 expm[1].x = 1; expm[1].y = 0;
00392 expm[2].x = 0; expm[2].y = 1;
00393 if (pdeg == 1){
00394
00395 return 3;
00396 }
00397 expm[3].x = 1; expm[3].y = 1;
00398 if (pdeg == 11) {
00399
00400 return 4;
00401 }
00402
00403
00404 int pdego = pdeg;
00405 int pdegx,pdegy;
00406 if (pdeg > 10){
00407 pdegx = pdeg % 10;
00408 pdegy = pdeg / 10;
00409 pdeg = fv_max(pdegx,pdegy);
00410 }
00411 else {
00412 pdegx = pdeg;
00413 pdegy = pdeg;
00414 }
00415
00416
00417 TExp ttn[10], ssn[10];
00418 order_1d(pdegx,ssn);
00419 order_1d(pdegy,ttn);
00420 int ii = 4;
00421 if (pdego < 10) {
00422 if (base_type == eComplete) {
00423 for (int j = 0; j < 2; j++) {
00424 for (int i = 2; i <= pdeg-j; i++) {
00425 expm[ii].x = ssn[i]; expm[ii++].y = ttn[j];
00426 }
00427 }
00428 for (int j=2; j<= pdeg; j++) {
00429 for (int i=0; i<=pdeg-j; i++) {
00430 expm[ii].x = ssn[i]; expm[ii++].y = ttn[j];
00431 }
00432 }
00433 }
00434 else if (base_type == eTensor) {
00435 ii=4;
00436 for (int j=0;j<2;j++) {
00437 for (int i=2;i<=pdeg;i++) {
00438 expm[ii].x = ssn[i]; expm[ii++].y = ttn[j];
00439 }
00440 }
00441 for (int j=2;j<=pdeg;j++) {
00442 for (int i=0;i<=pdeg;i++) {
00443 expm[ii].x = ssn[i]; expm[ii++].y = ttn[j];
00444 }
00445 }
00446 }
00447 } else {
00448 for (int j=0;j<2;j++) {
00449 for (int i=2;i<=pdegx;i++) {
00450 expm[ii].x = ssn[i]; expm[ii++].y = ttn[j];
00451 }
00452 }
00453 for (int j=2;j<=pdegy;j++) {
00454 for (int i=0;i<=pdegx;i++) {
00455 expm[ii].x = ssn[i]; expm[ii++].y = ttn[j];
00456 }
00457 }
00458 }
00459 return(ii);
00460 }
00461
00462 printf("Wrong parameters for order_2d!\n");
00463 return 0;
00464 }
00465
00466 template<typename TExp,typename TScalar>
00467 inline int ExponentEngine<TExp,TScalar>::order_1d(int pdeg,TExp expm[]) {
00468
00469 for (int i = 0; i <= pdeg; ++i) expm[i] = i;
00470 return(pdeg+1);
00471 }
00472
00473 template<typename TExp,typename TScalar>
00474 inline void ExponentEngine<TExp,TScalar>::multiply_1d(int pdeg,
00475 TScalar pt,TScalar* outPhi,TScalar* outdPhi)
00476 {
00477 outPhi[0] = 1.0;
00478 if (pdeg > 0) outPhi[1] = pt;
00479 for (int i=2;i<=pdeg;++i) {
00480 outPhi[i] = pt*outPhi[i-1];
00481 }
00482
00483 if (outdPhi != nullptr) {
00484 outdPhi[0] = 0.0;
00485 if (pdeg > 0) outdPhi[1] = 1.0;
00486 for (int i=2;i<=pdeg;++i) {
00487 outdPhi[i] = TScalar(i)*outPhi[i-1];
00488 }
00489
00490
00491
00492 }
00493 }
00494
00495
00496
00497 template<typename TExp,typename TScalar>
00498 std::ostream& operator<<(std::ostream& os,const ExponentEngine<TExp,TScalar>& e) {
00499 os << "Exponent map for p: " << e.GetPdeg() << " base: " << e.GetBaseType() << std::endl;
00500 for (int i=0;i<e.GetNumShapeFunc();++i) {
00501 os << "phi[" << i << "] = "
00502 << e.GetExpMap()[i].x << ", "
00503 << e.GetExpMap()[i].y << ", "
00504 << e.GetExpMap()[i].z << std::endl;
00505 }
00506 os << "Shape function number: " << e.GetNumShapeFunc() << std::endl;
00507 os << "end\n";
00508 return os;
00509 }
00510
00511
00512
00513
00514 #endif