![]() |
MechSys
1.0
Computing library for simulations in continuum and discrete mechanics
|
00001 /************************************************************************ 00002 * MechSys - Open Library for Mechanical Systems * 00003 * Copyright (C) 2005 Dorival M. Pedroso, Raul Durand * 00004 * Copyright (C) 2009 Sergio Galindo * 00005 * * 00006 * This program is free software: you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation, either version 3 of the License, or * 00009 * any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License * 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> * 00018 ************************************************************************/ 00019 00022 #ifndef MECHSYS_DOMAIN_H 00023 #define MECHSYS_DOMAIN_H 00024 00025 // Std Lib 00026 #include <iostream> 00027 #include <sstream> // for istringstream, ostringstream 00028 #include <cstdarg> // for va_list, va_start, va_end 00029 #include <map> 00030 00031 // Hdf5 00032 #ifdef USE_HDF5 00033 #include <hdf5.h> 00034 #include <hdf5_hl.h> 00035 #endif 00036 00037 // MechSys 00038 #include <mechsys/geomtype.h> 00039 #include <mechsys/util/maps.h> 00040 #include <mechsys/util/fatal.h> 00041 #include <mechsys/util/numstreams.h> 00042 #include <mechsys/util/stopwatch.h> 00043 #include <mechsys/models/model.h> 00044 #include <mechsys/fem/element.h> 00045 #include <mechsys/mesh/mesh.h> 00046 #include <mechsys/draw.h> 00047 00048 #include <mechsys/fem/beam.h> 00049 00050 namespace FEM 00051 { 00052 00053 // boundary condition function 00054 struct BCfunc { 00055 String Name; // ex: zero, load, myfunction1, etc. 00056 String Type; // ex: cte, rmp 00057 Array<String> Prms; // ex: c, m, ta, tb, tc, A, om 00058 Array<double> Vals; // ex: 1, 2, 3, 4, 5, 6, 7 00059 Array<String> Units; // ex: m kPa - s s - - 00060 }; 00061 00062 // face boundary condition 00063 struct FaceBc { 00064 int Tag; // ex: -11 00065 Array<String> Keys; // ex: qn, pw, ux, uy, uz, wwx, wwy, wwz 00066 Array<String> Funcs; // ex: zero, load, myfunction1, etc. 00067 }; 00068 00069 // node boundary condition 00070 struct NodeBc { 00071 int Tag; // ex: -100 00072 Array<String> Keys; // ex: pw, ux, uy, uz, wwx, wwy, wwz 00073 Array<String> Funcs; // ex: zero, load, myfunction1, etc. 00074 }; 00075 00076 //void AddFaceBc(Array<FaceBc> & Fbcs, int tag, 00077 00078 typedef std::map<Node*,Array<double> > Res_t; 00079 typedef std::map<int, Array<Element*> > Tag2Eles_t; 00080 00081 typedef void (*pVTUfunc) (Vec3_t const & X, double Time, SDPair & KeysVals); 00082 00083 class Domain 00084 { 00085 public: 00086 // static 00087 static bool PARA; 00088 static bool WithInfo; 00089 00090 // enum 00091 enum BryTagType_t { None_t, Element_t, Border_t, Node_t }; 00092 00093 // typedefs 00094 typedef std::map<String,BCFuncs*> MDatabase_t; 00095 typedef std::map<int,Model*> Models_t; 00096 00097 // Constructor 00098 Domain (Mesh::Generic const & Msh, 00099 Dict const & Prps, 00100 Dict const & Mdls, 00101 Dict const & Inis, 00102 char const * FNKey=NULL, 00103 Array<int> const * OutV=NULL, 00104 pVTUfunc pVTU=NULL); 00105 00106 // Destructor 00107 ~Domain (); 00108 00109 // Methods 00110 void SetBCsNew (Array<BCfunc> const & Bfuns, Array<FaceBc> const & Fbcs, Array<NodeBc> const & Nbcs); 00111 void SetBCs (Dict const & BCs); 00112 void NewNodsClearU (); 00113 void PrintResults (char const * NF="%15.6e", bool OnlySummary=false, bool WithElems=true, double Tol=1.0e-10) const; 00114 void WriteMPY (char const * FileKey, MPyPrms const & Prms) const; // TODO: WriteHDF5 file with results and then create a post-processing script (in Python?) to generate .mpy files ///< Write MeshPython file .mpy (run with: python FileKey.mpy, needs PyLab) 00115 void WriteVTU (char const * FileKey, bool DoExtrapolation=true) const; // TODO: WriteHDF5 file with results and then create a post-processing script (in Python?) to generate .vtu files ///< Write file for ParaView 00116 bool CheckErrorNods (Table const & NodSol, SDPair const & NodTol) const; 00117 bool CheckErrorEles (Table const & EleSol, SDPair const & EleTol) const; 00118 bool CheckErrorIPs (Table const & EleSol, SDPair const & EleTol) const; 00119 void PrintBCs (std::ostream & os, double tf=1.0) const; 00120 void SaveState (char const * FileKey) const; 00121 void LoadState (char const * FileKey); 00122 void SetGeostatic (SDPair const & Data); 00123 00124 // Internal methods 00125 void NodalResults (bool OnlyOutNods=false) const; 00126 void OutResults (char const * VTUFName=NULL, bool HeaderOnly=false); 00127 void CalcReactions (Table & NodesReactions, SDPair & SumReactions) const; 00128 00129 // Data 00130 double Time; 00131 size_t IdxOut; 00132 Dict const & Prps; 00133 Dict const & Inis; 00134 int NDim; 00135 Models_t Mdls; 00136 Models_t XMdls; 00137 pVTUfunc VTUfunc; 00138 std::map<int,Node*> VertID2Node; 00139 Array<Node*> Nods; 00140 Array<Element*> Eles; 00141 Array<Node*> TgdNods; 00142 Array<Element*> TgdEles; 00143 Array<Node*> OutNods; 00144 Array<Element*> OutEles; 00145 Array<std::ofstream*> FilNods; 00146 Array<Element*> Beams; 00147 MDatabase_t MFuncs; 00148 Array<Node*> InterNodes; 00149 Tag2Eles_t Tag2Eles; 00150 Array<Node*> ActNods; 00151 Array<Element*> ActEles; 00152 Array<Node*> NodsWithPF; 00153 Array<Node*> NodsWithPU; 00154 Array<Element*> ElesWithBC; 00155 Array<Node*> NodsPins; 00156 Array<Node*> NodsIncSup; 00157 Array<Node*> StgNewNods; 00158 00159 // Nodal results 00160 bool HasDisps; 00161 bool HasVeloc; 00162 bool HasWDisch; 00163 Array<String> AllUKeys; 00164 Array<String> AllFKeys; 00165 Array<String> AllUKeysBCF; 00166 Array<String> AllFKeysBCF; 00167 Array<String> AllExtraKeys; 00168 Array<String> AllExtraKeysBCF; 00169 Array<String> AllEKeys; 00170 mutable Res_t NodResults; 00171 mutable Res_t NodResCount; 00172 }; 00173 00174 bool Domain::PARA = false; 00175 bool Domain::WithInfo = true; 00176 00177 00179 00180 00181 std::ostream & operator<< (std::ostream & os, Domain const & D) 00182 { 00183 String buf; 00184 buf.Printf("\n%s--- Models -------------------------------------------------------------------%s\n",TERM_CLR3,TERM_RST); 00185 os << buf; 00186 for (Domain::Models_t::const_iterator p=D.Mdls.begin(); p!=D.Mdls.end(); ++p) 00187 os << p->first << " " << (*p->second) << std::endl; 00188 00189 buf.Printf("\n%s--- E(x)tra Models -----------------------------------------------------------%s\n",TERM_CLR3,TERM_RST); 00190 os << buf; 00191 for (Domain::Models_t::const_iterator p=D.XMdls.begin(); p!=D.XMdls.end(); ++p) 00192 os << p->first << " " << (*p->second) << std::endl; 00193 00194 buf.Printf("\n%s--- Elements properties ------------------------------------------------------%s\n",TERM_CLR3,TERM_RST); 00195 os << buf; 00196 os << D.Prps << std::endl; 00197 00198 buf.Printf("\n%s--- Initial values -----------------------------------------------------------%s\n",TERM_CLR3,TERM_RST); 00199 os << buf; 00200 os << D.Inis << std::endl; 00201 00202 buf.Printf("\n%s--- Nodes --------------------------------------------------------------------%s\n",TERM_CLR3,TERM_RST); 00203 os << buf; 00204 for (size_t i=0; i<D.Nods.Size(); ++i) os << (*D.Nods[i]) << "\n"; 00205 00206 buf.Printf("\n%s--- Elements -----------------------------------------------------------------%s\n",TERM_CLR3,TERM_RST); 00207 os << buf; 00208 for (size_t i=0; i<D.Eles.Size(); ++i) os << (*D.Eles[i]) << "\n"; 00209 00210 buf.Printf("\n%s--- Elements by tags ---------------------------------------------------------%s\n",TERM_CLR3,TERM_RST); 00211 os << buf; 00212 for (Tag2Eles_t::const_iterator it=D.Tag2Eles.begin(); it!=D.Tag2Eles.end(); ++it) 00213 { 00214 os << " Tag = " << it->first << " : Elements = "; 00215 for (size_t i=0; i<it->second.Size(); ++i) os << it->second[i]->Cell.ID << " "; 00216 os << "\n"; 00217 } 00218 return os; 00219 } 00220 00221 inline void Domain::PrintBCs (std::ostream & os, double tf) const 00222 { 00223 Array<double> T(2); 00224 T = 0.0, tf; 00225 for (size_t k=0; k<T.Size(); ++k) 00226 { 00227 String buf; 00228 os << "\n -----------------------------------------------------------------------------\n"; 00229 buf.Printf(" Boundary conditions at t = %g\n",T[k]); 00230 os << buf; 00231 for (size_t i=0; i<Nods.Size(); ++i) 00232 { 00233 Node const & nod = (*Nods[i]); 00234 if (nod.NPU()>0 || nod.NPF()>0 || nod.HasIncSup()) 00235 { 00236 os << Util::_4 << nod.Vert.ID << " "; 00237 if (nod.NPU()>0) 00238 { 00239 os << TERM_CLR4 << "PU:{" << TERM_RST; 00240 for (size_t i=0; i<nod.NPU(); ++i) 00241 { 00242 os << nod.PUKey(i) << "=" << nod.PU(i,T[k]); 00243 if (i!=nod.NPU()-1) os << " "; 00244 } 00245 os << TERM_CLR4 << "} " << TERM_RST; 00246 } 00247 if (nod.NPF()>0) 00248 { 00249 os << TERM_CLR5 << "PF:{" << TERM_RST; 00250 for (size_t i=0; i<nod.NPF(); ++i) 00251 { 00252 os << nod.PFKey(i) << "=" << nod.PF(i,T[k]); 00253 if (i!=nod.NPF()-1) os << " "; 00254 } 00255 os << TERM_CLR5 << "} " << TERM_RST; 00256 } 00257 if (nod.HasIncSup()) os << TERM_CLR1 << "INCSUP" << TERM_RST; 00258 os << std::endl; 00259 } 00260 } 00261 } 00262 } 00263 00264 // Constructor and destructor 00265 00266 inline Domain::Domain (Mesh::Generic const & Msh, Dict const & ThePrps, Dict const & TheMdls, Dict const & TheInis, char const * FNKey, Array<int> const * OutV, pVTUfunc pVTU) 00267 : Time(0.0), IdxOut(0), Prps(ThePrps), Inis(TheInis), NDim(Msh.NDim), VTUfunc(pVTU), HasDisps(false), HasVeloc(false), HasWDisch(false) 00268 { 00269 // info 00270 #ifdef HAS_MPI 00271 if (PARA && MPI::COMM_WORLD.Get_rank()!=0) WithInfo = false; 00272 #endif 00273 Util::Stopwatch stopwatch(/*activated*/WithInfo); 00274 if (WithInfo) printf("\n%s--- Domain --- allocating nodes and elements ---------------------------------------%s\n",TERM_CLR1,TERM_RST); 00275 00276 // allocate models 00277 for (size_t i=0; i<TheMdls.Keys.Size(); ++i) 00278 { 00279 int tag = TheMdls.Keys[i]; 00280 if (!Prps.HasKey(tag)) throw new Fatal("Domain::Domain: Prps and Mdls dictionaries must have the same tags"); 00281 if (TheMdls(tag).HasKey("name")) 00282 { 00283 String model_name; 00284 MODEL.Val2Key (TheMdls(tag)("name"), model_name); 00285 Mdls[tag] = AllocModel (model_name, NDim, TheMdls(tag), NULL); 00286 } 00287 else throw new Fatal("Domain::Domain: Dictionary of models must have keyword 'name' defining the name of the model"); 00288 if (TheMdls(tag).HasKey("xname")) 00289 { 00290 String model_name; 00291 MODEL.Val2Key (TheMdls(tag)("xname"), model_name); 00292 XMdls[tag] = AllocModel (model_name, NDim, TheMdls(tag), Mdls[tag]); 00293 } 00294 } 00295 00296 // set nodes from mesh 00297 for (size_t i=0; i<Msh.Verts.Size(); ++i) 00298 { 00299 #ifdef HAS_MPI 00300 if (PARA) 00301 { 00302 // skip vertices that aren't in this partition 00303 if (Msh.Verts[i]->PartIDs.Find(MPI::COMM_WORLD.Get_rank())<0) continue; 00304 } 00305 #endif 00306 // new node 00307 Nods.Push (new Node((*Msh.Verts[i]))); 00308 if (Msh.Verts[i]->Tag<0) TgdNods.Push (Nods.Last()); 00309 VertID2Node[Msh.Verts[i]->ID] = Nods.Last(); 00310 00311 // add DOFs to node and set BCs keys, BCs callbacks keys, extra keys, and extra keys callbacks' keys 00312 for (size_t k=0; k<Msh.Verts[i]->Shares.Size(); ++k) 00313 { 00314 // find variable keys 00315 int cell_tag = Msh.Verts[i]->Shares[k].C->Tag; 00316 String prob, prob_nd; 00317 PROB.Val2Key (Prps(cell_tag)("prob"), prob); 00318 prob_nd.Printf ("%s%dD", prob.CStr(), NDim); 00319 ElementVarKeys_t ::const_iterator it = ElementVarKeys .find (prob_nd); 00320 ElementExtraKeys_t::const_iterator jt = ElementExtraKeys.find (prob_nd); 00321 if (it==ElementVarKeys .end()) throw new Fatal("Domain::Domain: Could not find %s in ElementVarKeys map",prob_nd.CStr()); 00322 if (jt==ElementExtraKeys.end()) throw new Fatal("Domain::Domain: Could not find %s in ElementExtraKeys map",prob_nd.CStr()); 00323 00324 // add DOF to node 00325 Nods.Last()->AddDOF (it->second.first.CStr(), it->second.second.CStr()); 00326 00327 // collect U keys 00328 Array<String> ukeys; 00329 Util::Keys2Array (it->second.first, ukeys); 00330 for (size_t m=0; m<ukeys.Size(); ++m) 00331 { 00332 String upukey(ukeys[m]); 00333 upukey .ToUpper (); 00334 AllUKeys .XPush (ukeys[m]); 00335 AllUKeysBCF.XPush (upukey); 00336 if (ukeys[m]=="ux") HasDisps = true; 00337 } 00338 00339 // collect F keys 00340 Array<String> fkeys; 00341 Util::Keys2Array (it->second.second, fkeys); 00342 for (size_t m=0; m<fkeys.Size(); ++m) 00343 { 00344 String upfkey(fkeys[m]); 00345 upfkey .ToUpper (); 00346 AllFKeys .XPush (fkeys[m]); 00347 AllFKeysBCF.XPush (upfkey); 00348 } 00349 00350 // collect extra keys 00351 for (size_t m=0; m<jt->second.Size(); ++m) 00352 { 00353 String upextkey(jt->second[m]); 00354 upextkey .ToUpper (); 00355 AllExtraKeys .XPush (jt->second[m]); 00356 AllExtraKeysBCF.XPush (upextkey); 00357 } 00358 } 00359 00360 /* 00361 std::cout << "AllUKeys = " << AllUKeys << std::endl; 00362 std::cout << "AllFKeys = " << AllFKeys << std::endl; 00363 std::cout << "AllUKeysBCF = " << AllUKeysBCF << std::endl; 00364 std::cout << "AllFKeysBCF = " << AllFKeysBCF << std::endl; 00365 std::cout << "AllExtraKeys = " << AllExtraKeys << std::endl; 00366 std::cout << "AllExtraKeysBCF = " << AllExtraKeysBCF << std::endl; 00367 */ 00368 00369 #ifdef HAS_MPI 00370 if (PARA) 00371 { 00372 // set subset of shared nodes (between partitions) 00373 if (Msh.Verts[i]->PartIDs.Size()>1) InterNodes.Push (Nods.Last()); 00374 } 00375 #endif 00376 // set list of nodes for output 00377 if (FNKey!=NULL && OutV!=NULL) 00378 { 00379 bool has_tag = (Msh.Verts[i]->Tag<0 ? OutV->Has(Msh.Verts[i]->Tag) : false); 00380 if (OutV->Has(Msh.Verts[i]->ID) || has_tag) 00381 { 00382 String buf; buf.Printf("%s_nod_%d.res", FNKey, Msh.Verts[i]->ID); 00383 std::ofstream * of = new std::ofstream (buf.CStr(),std::ios::out); 00384 OutNods.Push (Nods.Last()); 00385 FilNods.Push (of); 00386 } 00387 } 00388 } 00389 00390 // check size of Nods 00391 if (Nods.Size()==0) throw new Fatal("FEM::Domain::Domain: There is a problem with the Msh structure (probably the domain decomposition has failed).\n The array of Nodes is empty."); 00392 00393 // set elements from mesh 00394 for (size_t i=0; i<Msh.Cells.Size(); ++i) 00395 { 00396 #ifdef HAS_MPI 00397 if (PARA) 00398 { 00399 // skip elements that aren't in this partition 00400 if (Msh.Cells[i]->PartID!=MPI::COMM_WORLD.Get_rank()) continue; 00401 } 00402 #endif 00403 int tag = Msh.Cells[i]->Tag; 00404 if (!Prps.HasKey(tag)) throw new Fatal("Domain::SetMesh: Dictionary of element properties does not have tag=%d",tag); 00405 if (Prps(tag).HasKey("prob")) 00406 { 00407 // problem name 00408 String prob_name; 00409 PROB.Val2Key (Prps(tag)("prob"), prob_name); 00410 00411 // model 00412 Model const * mdl = NULL; 00413 Models_t::const_iterator m = Mdls.find(tag); 00414 if (m!=Mdls.end()) mdl = m->second; 00415 00416 // extra model 00417 Model const * xmdl = NULL; 00418 Models_t::const_iterator xm = XMdls.find(tag); 00419 if (xm!=XMdls.end()) xmdl = xm->second; 00420 00421 // connectivity 00422 bool has_outnode = false; // does this new element have any node belonging to the output array ? 00423 Array<Node*> nodes(Msh.Cells[i]->V.Size()); 00424 for (size_t k=0; k<nodes.Size(); ++k) 00425 { 00426 std::map<int,Node*>::const_iterator it = VertID2Node.find(Msh.Cells[i]->V[k]->ID); 00427 if (it==VertID2Node.end()) throw new Fatal("FEM::Domain::Domain:: There is a problem with the Msh structure (probably the domain decomposition has failed).\n Could not find Node # %d necessary for the definition of Element # %d.",Msh.Cells[i]->V[k]->ID,Msh.Cells[i]->ID); 00428 nodes[k] = it->second; 00429 00430 // check if node of element belongs to output array 00431 if (OutNods.Size()>0) { if (OutNods.Has(nodes[k])) has_outnode = true; } 00432 } 00433 00434 // allocate element 00435 if (Inis.HasKey(tag)) Eles.Push (AllocElement(prob_name, NDim, (*Msh.Cells[i]), mdl, xmdl, Prps(tag), Inis(tag), nodes)); 00436 else Eles.Push (AllocElement(prob_name, NDim, (*Msh.Cells[i]), mdl, xmdl, Prps(tag), SDPair() , nodes)); 00437 00438 // set subset of active elements 00439 if (Eles.Last()->Active) ActEles.Push (Eles.Last()); 00440 00441 // set array of Beams 00442 if (prob_name=="Beam") Beams.Push (Eles.Last()); 00443 00444 // elements with tagged borders (edges/faces) 00445 if (Msh.Cells[i]->BryTags.size()>0 || prob_name=="Beam") TgdEles.Push (Eles.Last()); 00446 00447 // map tag to element 00448 Tag2Eles[tag].Push (Eles.Last()); 00449 00450 // element belongs to output array 00451 if (has_outnode) OutEles.Push (Eles.Last()); 00452 00453 // collect all element keys 00454 Array<String> keys; 00455 Eles.Last()->StateKeys (keys); 00456 for (size_t j=0; j<keys.Size(); ++j) 00457 { 00458 if (keys[j]=="vx") HasVeloc = true; 00459 if (keys[j]=="qwx") HasWDisch = true; 00460 AllEKeys.XPush (keys[j]); // push only if item is not in array yet 00461 } 00462 } 00463 else throw new Fatal("Domain::SetMesh: Dictionary of properties must have keyword 'prob' defining the type of element corresponding to a specific problem"); 00464 } 00465 00466 // check size of Eles 00467 if (Eles.Size()==0) throw new Fatal("FEM::Domain::Domain: There is a problem with the Msh structure (probably the domain decomposition has failed).\n The array of Elements is empty."); 00468 00469 // set pin nodes 00470 if (Msh.Pins.size()>0) 00471 { 00472 for (Mesh::Pin_t::const_iterator p=Msh.Pins.begin(); p!=Msh.Pins.end(); ++p) 00473 { 00474 std::map<int,Node*>::const_iterator it0 = VertID2Node.find (p->first->ID); 00475 if (it0==VertID2Node.end()) throw new Fatal("FEM::Domain::Domain:: There is a problem with the Msh structure (probably the domain decomposition has failed).\n Could not find Node # %d corresponding to a Pin.",p->first->ID); 00476 #ifdef HAS_MPI 00477 if (PARA) 00478 { 00479 // skip pins that aren't in this partition 00480 if (p->first->PartIDs.Find(MPI::COMM_WORLD.Get_rank())<0) continue; 00481 } 00482 #endif 00483 Array<Node*> con_nods; // connected nodes to this pin 00484 for (size_t i=0; i<p->second.Size(); ++i) 00485 { 00486 std::map<int,Node*>::const_iterator it1 = VertID2Node.find (p->second[i]->ID); 00487 if (it1==VertID2Node.end()) throw new Fatal("FEM::Domain::Domain:: There is a problem with the Msh structure (probably the domain decomposition has failed).\n Could not find Node # %d connected to Pin # %d. Both pins must be in the same partition.",p->second[i]->ID,p->first->ID); 00488 con_nods.Push (it1->second); 00489 } 00490 it0->second->SetPin (con_nods); 00491 NodsPins.Push (it0->second); 00492 } 00493 } 00494 00495 // set subset of active nodes (must be after the creation of elements) 00496 for (size_t i=0; i<Nods.Size(); ++i) 00497 { 00498 if (Nods[i]->NShares>0) ActNods.Push (Nods[i]); 00499 } 00500 00501 // print header of output files 00502 OutResults (/*vtufname*/NULL, /*headeronly*/true); 00503 00504 // write file with IDs and tags of output nodes 00505 if (FNKey!=NULL && OutV!=NULL) 00506 { 00507 String buf(FNKey); buf.append("_out_nods.res"); 00508 std::ofstream of(buf.CStr(), std::ios::out); 00509 buf.Printf("%6s %6s %16s %16s %16s\n","id","tag","x","y","z"); 00510 of << buf; 00511 for (size_t i=0; i<OutNods.Size(); ++i) 00512 { 00513 buf.Printf("%6d %6d %16.8e %16.8e %16.8e\n",OutNods[i]->Vert.ID, OutNods[i]->Vert.Tag, OutNods[i]->Vert.C(0), OutNods[i]->Vert.C(1), OutNods[i]->Vert.C(2)); 00514 of << buf; 00515 } 00516 of.close(); 00517 } 00518 } 00519 00520 inline Domain::~Domain() 00521 { 00522 for (Domain::Models_t::iterator p=Mdls.begin(); p!=Mdls.end(); ++p) delete p->second; 00523 for (Domain::Models_t::iterator p=XMdls.begin(); p!=XMdls.end(); ++p) delete p->second; 00524 for (size_t i=0; i<Nods .Size(); ++i) if (Nods [i]!=NULL) delete Nods [i]; 00525 for (size_t i=0; i<Eles .Size(); ++i) if (Eles [i]!=NULL) delete Eles [i]; 00526 for (size_t i=0; i<FilNods.Size(); ++i) if (FilNods[i]!=NULL) { FilNods[i]->close(); delete FilNods[i]; } 00527 } 00528 00529 // Methods 00530 00531 inline void Domain::SetBCsNew (Array<BCfunc> const & Bfuns, Array<FaceBc> const & Fbcs, Array<NodeBc> const & Nbcs) 00532 { 00533 } 00534 00535 inline void Domain::SetBCs (Dict const & BCs) 00536 { 00537 // info 00538 #ifdef HAS_MPI 00539 if (PARA && MPI::COMM_WORLD.Get_rank()!=0) WithInfo = false; 00540 #endif 00541 Util::Stopwatch stopwatch(/*activated*/WithInfo); 00542 if (WithInfo) printf("\n%s--- Domain --- setting BCs and activating/deactivating elements --------------------%s\n",TERM_CLR1,TERM_RST); 00543 00544 // clear previous BCs 00545 for (size_t i=0; i<NodsWithPU.Size(); ++i) NodsWithPU[i]->DelPUs (); 00546 for (size_t i=0; i<NodsWithPF.Size(); ++i) NodsWithPF[i]->DelPFs (); 00547 for (size_t i=0; i<NodsIncSup.Size(); ++i) NodsIncSup[i]->DelIncSup (); 00548 for (size_t i=0; i<ElesWithBC.Size(); ++i) ElesWithBC[i]->ClrBCs (); 00549 00550 // map used to track whether BC was already set or not 00551 std::map<int,BryTagType_t> bc_set; // maps: btag => type of BC: none, element, border, node 00552 for (Dict_t::const_iterator it=BCs.begin(); it!=BCs.end(); ++it) bc_set[it->first] = None_t; 00553 00554 // 'BCs' at the element itself (ex: 'activate', 's':source, 'qn' at beams, etc.). 00555 // This must come before the setting up of 'real' boundary conditions, since, for example, 00556 // some nodes may become activated or deactivated 00557 ElesWithBC.Resize (0); 00558 for (Dict_t::const_iterator dict_it=BCs.begin(); dict_it!=BCs.end(); ++dict_it) 00559 { 00560 // auxiliar variables 00561 int btag = dict_it->first; // the element/boundary tag 00562 SDPair const & bcs = dict_it->second; // the boundary conditions 00563 00564 // check if tag corresponds to element tag (and not boundary tag) 00565 Tag2Eles_t::const_iterator it = Tag2Eles.find(btag); 00566 if (it!=Tag2Eles.end()) // found elements with this btag 00567 { 00568 bc_set[btag] = Element_t; // flag BC set 00569 for (size_t k=0; k<bcs.Keys.Size(); ++k) 00570 { 00571 // callback function 00572 BCFuncs * bcfun = NULL; 00573 if (AllExtraKeysBCF.Has(bcs.Keys[k])) // callback specified 00574 { 00575 String mfkey; 00576 mfkey.Printf ("%d_%s", btag, bcs.Keys[k].ToLowerCpy().CStr()); 00577 MDatabase_t::const_iterator q = MFuncs.find(mfkey); 00578 if (q==MFuncs.end()) throw new Fatal("FEM::Domain::SetBCs: Multiplier function with Element Tag=%d was not found in MFuncs database ('%s' key)",btag,mfkey.CStr()); 00579 else bcfun = q->second; 00580 } 00581 00582 // check if bc key is not U or F key 00583 if (AllUKeys.Has(bcs.Keys[k])) throw new Fatal("FEM::Domain::SetBCs: Boundary condition '%s' with tag==%d cannot be applied to the Element", bcs.Keys[k].CStr(), btag); 00584 if (AllFKeys.Has(bcs.Keys[k])) throw new Fatal("FEM::Domain::SetBCs: Boundary condition '%s' with tag==%d cannot be applied to the Element", bcs.Keys[k].CStr(), btag); 00585 00586 00587 printf("\n\n"); 00588 for (size_t ib=0; ib<bcs.Keys.Size(); ++ib) 00589 { 00590 printf("[1;35m%s => %g[0m\n", bcs.Keys[ib].CStr(), bcs(bcs.Keys[ib])); 00591 } 00592 printf("\n\n"); 00593 00594 00595 00596 00597 00598 00599 00600 00601 00602 00603 00604 00605 00606 00607 00608 00609 // TODO: 'deactivate' and 'gravity' must be together 00610 // currently this code is splitting them => major rewrite needed 00611 00612 00613 00614 00615 00616 00617 00618 00619 00620 00621 00622 00623 00624 00625 00626 00627 00628 // set BCs: ex: 'activate', 's', 'qn', etc. 00629 SDPair bc; 00630 bc.Set (bcs.Keys[k].ToLowerCpy().CStr(), bcs(bcs.Keys[k])); 00631 00632 // TODO: extra arguments need to be passed onto some elements => fix this 00633 //if (bcs.HasKey("activate")) 00634 //{ 00635 //bc.Set("activate", bcs("activate")); 00636 //bc.Set("gravity", bcs("gravity")); 00637 //} 00638 //if (bcs.HasKey("deactivate")) // environment temperature 00639 //{ 00640 //bc.Set("deactivate", bcs("deactivate")); 00641 //bc.Set("gravity", bcs("gravity")); 00642 //} 00643 00644 for (size_t i=0; i<it->second.Size(); ++i) // for each element 00645 { 00646 Element * ele = it->second[i]; 00647 ele->SetBCs (/*idx_side(ignored)*/0, bc, bcfun); 00648 ElesWithBC.Push (ele); 00649 } 00650 } 00651 } 00652 } 00653 00654 // BCs at the edges/faces of elements or at nodes 00655 typedef std::pair<Element*,int> eleside_t; // (element,side) pair 00656 typedef std::pair<int,SDPair> tagbcs_t; // (tag,bcs data) pair 00657 std::map<eleside_t,tagbcs_t> eleside2tag_to_ubc; // maps: (ele,side) ==> U bry cond: (tag,Ubcs) 00658 std::map<eleside_t,tagbcs_t> eleside2tag_to_fbc; // maps: (ele,side) ==> F bry cond: (tag,Fbcs) 00659 std::map<Node*,tagbcs_t> nod2tag_to_ubc; // map: node ==> U bry cond: (tag,Ubcs) 00660 std::map<Node*,tagbcs_t> nod2tag_to_fbc; // map: node ==> F bry cond: (tag,Fbcs) 00661 for (Dict_t::const_iterator dict_it=BCs.begin(); dict_it!=BCs.end(); ++dict_it) 00662 { 00663 // auxiliar variables 00664 int btag = dict_it->first; // the element/boundary tag 00665 SDPair const & bcs = dict_it->second; // the boundary conditions 00666 00667 // find elements with edges equal to this btag 00668 for (size_t j=0; j<TgdEles.Size(); ++j) // for each element with tagged border 00669 { 00670 if (TgdEles[j]->Active) // active element 00671 { 00672 Mesh::BryTag_t const & eftags = TgdEles[j]->Cell.BryTags; 00673 for (Mesh::BryTag_t::const_iterator p=eftags.begin(); p!=eftags.end(); ++p) 00674 { 00675 int idx_side = p->first; 00676 int side_tag = p->second; 00677 if (side_tag==btag) // found 00678 { 00679 // flag BC set 00680 std::map<int,BryTagType_t>::const_iterator it = bc_set.find(btag); 00681 if (it->second==None_t) bc_set[btag] = Border_t; 00682 else if (it->second!=Border_t) throw new Fatal("FEM::Domain::SetBCs: Boundary tag==%d cannot be applied to %s and borders (edges/faces) at the same time",btag,(it->second==Element_t?"elements":"nodes")); 00683 00684 // split Ubcs from Fbcs 00685 eleside_t es(TgdEles[j],idx_side); // (edge/face,side) pair 00686 for (size_t k=0; k<bcs.Keys.Size(); ++k) 00687 { 00688 if (bcs.Keys[k]=="incsup") // is inclined support 00689 { 00690 eleside2tag_to_ubc[es].first = btag; 00691 eleside2tag_to_ubc[es].second = bcs; // has to be copied because of the extra parameters such as 'alpha' and so on 00692 break; 00693 } 00694 else 00695 { 00696 if (AllUKeys.Has(bcs.Keys[k]) || AllUKeysBCF.Has(bcs.Keys[k])) // is U key or U callback function 00697 { 00698 eleside2tag_to_ubc[es].first = btag; 00699 eleside2tag_to_ubc[es].second.Set (bcs.Keys[k].CStr(), bcs(bcs.Keys[k])); // cannot copy bcs here because we don't want F values 00700 } 00701 else // is F key or 'qn', 'qt', etc. 00702 { 00703 eleside2tag_to_fbc[es].first = btag; 00704 eleside2tag_to_fbc[es].second.Set (bcs.Keys[k].CStr(), bcs(bcs.Keys[k])); // cannot copy bcs here because we don't want U values 00705 } 00706 } 00707 } 00708 } 00709 } 00710 } 00711 } 00712 00713 // find nodes with tags equal to this btag 00714 for (size_t j=0; j<TgdNods.Size(); ++j) 00715 { 00716 if (TgdNods[j]->NShares>0) // active node 00717 { 00718 if (TgdNods[j]->Vert.Tag==btag) // found 00719 { 00720 // flag BC set 00721 std::map<int,BryTagType_t>::const_iterator it = bc_set.find(btag); 00722 if (it->second==None_t) bc_set[btag] = Node_t; 00723 else if (it->second!=Node_t) throw new Fatal("FEM::Domain::SetBCs: Boundary tag==%d cannot be applied to %s and nodes at the same time",btag,(it->second==Element_t?"elements":"borders (edges/faces)")); 00724 00725 // split U bcs from F bcs 00726 for (size_t k=0; k<bcs.Keys.Size(); ++k) 00727 { 00728 if (bcs.Keys[k]=="incsup") // inclined support 00729 { 00730 nod2tag_to_ubc[TgdNods[j]].first = btag; 00731 nod2tag_to_ubc[TgdNods[j]].second = bcs; // has to be copied because of the extra parameters such as 'alpha' and so on 00732 break; 00733 } 00734 else 00735 { 00736 if (AllUKeys.Has(bcs.Keys[k]) || AllUKeysBCF.Has(bcs.Keys[k])) // is U key or U callback function 00737 { 00738 nod2tag_to_ubc[TgdNods[j]].first = btag; 00739 nod2tag_to_ubc[TgdNods[j]].second.Set (bcs.Keys[k].CStr(), bcs(bcs.Keys[k])); // cannot copy bcs here because we don't want F values 00740 } 00741 else if (AllFKeys.Has(bcs.Keys[k]) || AllFKeysBCF.Has(bcs.Keys[k])) // is F key or F callback function 00742 { 00743 nod2tag_to_fbc[TgdNods[j]].first = btag; 00744 nod2tag_to_fbc[TgdNods[j]].second.Set (bcs.Keys[k].CStr(), bcs(bcs.Keys[k])); // cannot copy bcs here because we don't want F values 00745 } 00746 else throw new Fatal("FEM::Domain::SetBCs: Boundary condition '%s' (tag==%d) cannot be specified to Nodes (node # %d)", bcs.Keys[k].CStr(), btag, TgdNods[j]->Vert.ID); 00747 } 00748 } 00749 } 00750 } 00751 } 00752 } 00753 00754 // check if all tags were set 00755 if (!PARA) // only in serial problems, since this processor may not know the tags of other elements/nodes in other processors 00756 { 00757 for (std::map<int,BryTagType_t>::const_iterator it=bc_set.begin(); it!=bc_set.end(); ++it) 00758 { 00759 if (it->second==None_t) throw new Fatal("FEM::Domain::SetBCs: Could not find any element, edge/face, or node with boundary tag == %d",it->first); 00760 } 00761 } 00762 00763 // set F bcs at sides (edges/faces) of elements 00764 for (std::map<eleside_t,tagbcs_t>::iterator p=eleside2tag_to_fbc.begin(); p!=eleside2tag_to_fbc.end(); ++p) 00765 { 00766 Element * ele = p->first.first; 00767 int idx_side = p->first.second; 00768 int bc_tag = p->second.first; 00769 SDPair const & bcs = p->second.second; 00770 for (size_t k=0; k<bcs.Keys.Size(); ++k) 00771 { 00772 String key = bcs.Keys[k].ToLowerCpy(); 00773 SDPair bc; 00774 bc.Set (key.CStr(), bcs(bcs.Keys[k])); 00775 00776 // TODO: extra arguments need to be passed onto some elements => fix this 00777 if (bcs.HasKey("h")) // convection transmissivity coefficient 00778 { 00779 bc.Set("h", bcs("h")); 00780 } 00781 if (bcs.HasKey("Tinf")) // environment temperature 00782 { 00783 bc.Set("Tinf", bcs("Tinf")); 00784 } 00785 00786 if (AllFKeysBCF.Has(bcs.Keys[k]) || AllExtraKeysBCF.Has(bcs.Keys[k])) // callback specified 00787 { 00788 String mfkey; 00789 mfkey.Printf ("%d_%s", bc_tag, key.CStr()); 00790 MDatabase_t::const_iterator q = MFuncs.find(mfkey); 00791 if (q==MFuncs.end()) throw new Fatal("FEM::Domain::SetBCs: Multiplier function with boundary (edge/face) Tag=%d was not found in MFuncs database ('%s' key)",bc_tag,mfkey.CStr()); 00792 ele->SetBCs (idx_side, bc, q->second); 00793 } 00794 else ele->SetBCs (idx_side, bc, NULL); 00795 } 00796 } 00797 00798 // set F bcs at nodes 00799 for (std::map<Node*,tagbcs_t>::iterator p=nod2tag_to_fbc.begin(); p!=nod2tag_to_fbc.end(); ++p) 00800 { 00801 Node * nod = p->first; 00802 int bc_tag = p->second.first; 00803 SDPair const & bcs = p->second.second; 00804 for (size_t k=0; k<bcs.Keys.Size(); ++k) 00805 { 00806 if (AllFKeysBCF.Has(bcs.Keys[k])) // callback specified 00807 { 00808 String key = bcs.Keys[k].ToLowerCpy(); 00809 String mfkey; 00810 mfkey.Printf ("%d_%s", bc_tag, key.CStr()); 00811 MDatabase_t::const_iterator q = MFuncs.find(mfkey); 00812 if (q==MFuncs.end()) throw new Fatal("FEM::Domain::SetBCs: Multiplier function with boundary (nodes) Tag=%d was not found in MFuncs database ('%s' key)",bc_tag,mfkey.CStr()); 00813 nod->AddToPF (key, bcs(bcs.Keys[k]), q->second); 00814 } 00815 else nod->AddToPF (bcs.Keys[k], bcs(bcs.Keys[k]), NULL); 00816 } 00817 } 00818 00819 // set U bcs at sides (edges/faces) of elements 00820 for (std::map<eleside_t,tagbcs_t>::iterator p=eleside2tag_to_ubc.begin(); p!=eleside2tag_to_ubc.end(); ++p) 00821 { 00822 Element * ele = p->first.first; 00823 int idx_side = p->first.second; 00824 int bc_tag = p->second.first; 00825 SDPair const & bcs = p->second.second; 00826 for (size_t k=0; k<bcs.Keys.Size(); ++k) 00827 { 00828 String key = bcs.Keys[k].ToLowerCpy(); 00829 SDPair bc; 00830 bc.Set (key.CStr(), bcs(bcs.Keys[k])); 00831 if (AllUKeysBCF.Has(bcs.Keys[k])) // callback specified 00832 { 00833 String mfkey; 00834 mfkey.Printf ("%d_%s", bc_tag, key.CStr()); 00835 MDatabase_t::const_iterator q = MFuncs.find(mfkey); 00836 if (q==MFuncs.end()) throw new Fatal("FEM::Domain::SetBCs: Multiplier function with boundary (edge/face) Tag=%d was not found in MFuncs database ('%s' key)",bc_tag,mfkey.CStr()); 00837 ele->SetBCs (idx_side, bc, q->second); 00838 } 00839 else ele->SetBCs (idx_side, bc, NULL); 00840 } 00841 } 00842 00843 // set U bcs at nodes 00844 for (std::map<Node*,tagbcs_t>::iterator p=nod2tag_to_ubc.begin(); p!=nod2tag_to_ubc.end(); ++p) 00845 { 00846 Node * nod = p->first; 00847 int bc_tag = p->second.first; 00848 SDPair const & bcs = p->second.second; 00849 for (size_t k=0; k<bcs.Keys.Size(); ++k) 00850 { 00851 if (bcs.HasKey("incsup")) 00852 { 00853 if (NDim!=2) throw new Fatal("FEM::Domain::SetBCs: Inclined support is not implemented for 3D problems yet"); 00854 nod->SetIncSup (bcs("alpha")); 00855 break; 00856 } 00857 else 00858 { 00859 if (AllUKeysBCF.Has(bcs.Keys[k])) // callback specified 00860 { 00861 String key = bcs.Keys[k].ToLowerCpy(); 00862 String mfkey; 00863 mfkey.Printf ("%d_%s", bc_tag, key.CStr()); 00864 MDatabase_t::const_iterator q = MFuncs.find(mfkey); 00865 if (q==MFuncs.end()) throw new Fatal("FEM::Domain::SetBCs: Multiplier function with boundary (nodes) Tag=%d was not found in MFuncs database ('%s' key)",bc_tag,mfkey.CStr()); 00866 nod->SetPU (key, bcs(bcs.Keys[k]), q->second); 00867 } 00868 else nod->SetPU (bcs.Keys[k], bcs(bcs.Keys[k]), NULL); 00869 } 00870 } 00871 } 00872 00873 // set subsets of active nodes, nodes with prescribed U and/or F, and nodes with inclined supports 00874 Array<Node*> prev_act_nods(ActNods); // previous active nodes 00875 StgNewNods.Resize (0); // new nodes activated here 00876 ActNods .Resize (0); 00877 NodsWithPU.Resize (0); 00878 NodsWithPF.Resize (0); 00879 NodsIncSup.Resize (0); 00880 for (size_t i=0; i<Nods.Size(); ++i) 00881 { 00882 if (Nods[i]->NShares>0) 00883 { 00884 ActNods.Push (Nods[i]); 00885 if (!prev_act_nods.Has(Nods[i])) StgNewNods.Push (Nods[i]); // node was just activated 00886 } 00887 if (Nods[i]->NPU()>0) NodsWithPU.Push (Nods[i]); 00888 if (Nods[i]->HasIncSup()) NodsIncSup.Push (Nods[i]); 00889 if (Nods[i]->NPF()>0) 00890 { 00891 NodsWithPF.Push (Nods[i]); 00892 Nods[i]->AccumPF (); // accumulate PF inside Node (to calculate Reactions later) 00893 } 00894 } 00895 00896 //std::cout << "prev_act_nods = "; for (size_t i=0; i<prev_act_nods.Size(); ++i) std::cout << prev_act_nods[i]->Vert.ID << " "; std::cout << std::endl; 00897 //std::cout << "StgNewNods = "; for (size_t i=0; i<StgNewNods .Size(); ++i) std::cout << StgNewNods [i]->Vert.ID << " "; std::cout << std::endl; 00898 00899 // set subsets of active elements 00900 ActEles.Resize (0); 00901 for (size_t i=0; i<Eles.Size(); ++i) { if (Eles[i]->Active) ActEles.Push (Eles[i]); } 00902 } 00903 00904 inline void Domain::NewNodsClearU () 00905 { 00906 for (size_t i=0; i<StgNewNods.Size(); ++i) StgNewNods[i]->ClearU (); 00907 } 00908 00909 inline void Domain::PrintResults (char const * NF, bool OnlySummary, bool WithElems, double Tol) const 00910 { 00911 printf("\n%s--- Results ------------------------------------------------------------------------%s\n",TERM_CLR1,TERM_RST); 00912 00913 // number format for text 00914 String fmt; 00915 fmt.TextFmt (NF); 00916 00917 if (!OnlySummary) 00918 { 00919 // nodes: header 00920 String buf; 00921 std::cout << TERM_CLR2 << Util::_6 << "Node"; 00922 for (size_t i=0; i<AllUKeys.Size(); ++i) { buf.Printf(fmt, AllUKeys[i].CStr()); std::cout<<buf; } 00923 for (size_t i=0; i<AllFKeys.Size(); ++i) { buf.Printf(fmt, AllFKeys[i].CStr()); std::cout<<buf; } 00924 printf("%s\n",TERM_RST); 00925 00926 // nodes: data 00927 for (size_t i=0; i<ActNods.Size(); ++i) 00928 { 00929 std::cout << Util::_6 << ActNods[i]->Vert.ID; 00930 for (size_t j=0; j<AllUKeys.Size(); ++j) 00931 { 00932 buf.Printf(NF, ActNods[i]->UOrZero(AllUKeys[j])); 00933 std::cout << buf; 00934 } 00935 for (size_t j=0; j<AllFKeys.Size(); ++j) 00936 { 00937 buf.Printf(NF, ActNods[i]->FOrZero(AllFKeys[j])); 00938 std::cout << buf; 00939 } 00940 printf("\n"); 00941 } 00942 printf("\n"); 00943 } 00944 00945 // reactions 00946 String buf; 00947 Table reac; 00948 SDPair sum; 00949 CalcReactions (reac, sum); 00950 printf("\n Reactions\n%s %6s",TERM_CLR2,"Node"); 00951 for (size_t i=1; i<reac.Keys.Size(); ++i) 00952 { 00953 String tmp("R"); 00954 tmp.append (reac.Keys[i]); 00955 buf.Printf (fmt, tmp.CStr()); 00956 std::cout<<buf; 00957 } 00958 printf("%s\n",TERM_RST); 00959 for (size_t i=0; i<reac.NRows; ++i) 00960 { 00961 printf(" %6d",static_cast<int>(reac("Node",i))); 00962 for (size_t j=1; j<reac.Keys.Size(); ++j) printf(NF,reac(reac.Keys[j],i)); 00963 printf("\n"); 00964 } 00965 printf(" -------------------------------------------------------------------\n"); 00966 printf(" %6s","Sum"); 00967 for (size_t j=0; j<sum.Keys.Size(); ++j) 00968 { 00969 double val = sum(sum.Keys[j]); 00970 printf(NF,(fabs(val)>Tol?val:0.0)); 00971 } 00972 printf("\n"); 00973 } 00974 00975 inline void Domain::WriteMPY (char const * FNKey, FEM::MPyPrms const & Prms) const 00976 { 00977 // pointer to array of elements 00978 Array<Element*> const * eles = (Prms.OnlyBeams ? &Beams : &ActEles); 00979 00980 // find min and max M and N 00981 if (Prms.FindMLimits && Beams.Size()>0) 00982 { 00983 FEM::Beam const * e0 = static_cast<FEM::Beam const *>(Beams[0]); 00984 double N,V,M; 00985 e0->CalcRes (0.0, N,V,M); 00986 Prms.EleMmin = e0; 00987 Prms.EleMmax = e0; 00988 Prms.EleNmin = e0; 00989 Prms.EleNmax = e0; 00990 Prms.EleVmin = e0; 00991 Prms.EleVmax = e0; 00992 Prms.Mmin = M; 00993 Prms.Mmax = M; 00994 Prms.Nmin = N; 00995 Prms.Nmax = N; 00996 Prms.Vmin = V; 00997 Prms.Vmax = V; 00998 Prms.rMmin = 0.0; 00999 Prms.rMmax = 0.0; 01000 for (size_t i=0; i<Beams.Size(); ++i) 01001 { 01002 FEM::Beam const * e = static_cast<FEM::Beam const *>(Beams[i]); 01003 for (size_t j=0; j<=Prms.NDiv; ++j) 01004 { 01005 double r = static_cast<double>(j)/static_cast<double>(Prms.NDiv); 01006 e->CalcRes (r, N,V,M); 01007 if (M<Prms.Mmin) { Prms.Mmin=M; Prms.EleMmin=e; Prms.rMmin=r; } 01008 if (M>Prms.Mmax) { Prms.Mmax=M; Prms.EleMmax=e; Prms.rMmax=r; } 01009 if (N<Prms.Nmin) { Prms.Nmin=N; Prms.EleNmin=e; } 01010 if (N>Prms.Nmax) { Prms.Nmax=N; Prms.EleNmax=e; } 01011 if (V<Prms.Vmin) { Prms.Vmin=V; Prms.EleVmin=e; } 01012 if (V>Prms.Vmax) { Prms.Vmax=V; Prms.EleVmax=e; } 01013 } 01014 } 01015 } 01016 01017 // calculate scale factor for diagrams 01018 if (Prms.AutoLimits) 01019 { 01020 // bounding box 01021 Vec3_t min, max, del; 01022 min = (*eles)[0]->Con[0]->Vert.C(0), (*eles)[0]->Con[0]->Vert.C(1), (*eles)[0]->Con[0]->Vert.C(2); 01023 max = (*eles)[0]->Con[1]->Vert.C(0), (*eles)[0]->Con[1]->Vert.C(1), (*eles)[0]->Con[1]->Vert.C(2); 01024 for (size_t i=1; i<eles->Size(); ++i) 01025 { 01026 for (size_t j=0; j<(*eles)[i]->Con.Size(); ++j) 01027 { 01028 if ((*eles)[i]->Con[j]->Vert.C(0)<min(0)) min(0) = (*eles)[i]->Con[j]->Vert.C(0); 01029 if ((*eles)[i]->Con[j]->Vert.C(1)<min(1)) min(1) = (*eles)[i]->Con[j]->Vert.C(1); 01030 if ((*eles)[i]->Con[j]->Vert.C(2)<min(2)) min(2) = (*eles)[i]->Con[j]->Vert.C(2); 01031 if ((*eles)[i]->Con[j]->Vert.C(0)>max(0)) max(0) = (*eles)[i]->Con[j]->Vert.C(0); 01032 if ((*eles)[i]->Con[j]->Vert.C(1)>max(1)) max(1) = (*eles)[i]->Con[j]->Vert.C(1); 01033 if ((*eles)[i]->Con[j]->Vert.C(2)>max(2)) max(2) = (*eles)[i]->Con[j]->Vert.C(2); 01034 } 01035 } 01036 01037 // max distance in mesh 01038 del = max - min; 01039 Prms.MaxDist = Norm(del); 01040 01041 // scale factor 01042 double max_abs = 0; 01043 double N,V,M; 01044 if (Prms.DrawN) 01045 { 01046 if (Prms.EleNmin!=NULL) 01047 { 01048 static_cast<FEM::Beam const *>(Prms.EleNmin)->CalcRes (0.0, N,V,M); 01049 if (fabs(N)>max_abs) max_abs = fabs(N); 01050 } 01051 if (Prms.EleNmax!=NULL) 01052 { 01053 static_cast<FEM::Beam const *>(Prms.EleNmax)->CalcRes (0.0, N,V,M); 01054 if (fabs(N)>max_abs) max_abs = fabs(N); 01055 } 01056 } 01057 else if (Prms.DrawV) 01058 { 01059 if (Prms.EleVmin!=NULL) 01060 { 01061 static_cast<FEM::Beam const *>(Prms.EleVmin)->CalcRes (0.0, N,V,M); 01062 if (fabs(V)>max_abs) max_abs = fabs(V); 01063 } 01064 if (Prms.EleVmax!=NULL) 01065 { 01066 static_cast<FEM::Beam const *>(Prms.EleVmax)->CalcRes (0.0, N,V,M); 01067 if (fabs(V)>max_abs) max_abs = fabs(V); 01068 } 01069 } 01070 else 01071 { 01072 if (Prms.EleMmin!=NULL) 01073 { 01074 static_cast<FEM::Beam const *>(Prms.EleMmin)->CalcRes (Prms.rMmin, N,V,M); 01075 if (fabs(M)>max_abs) max_abs = fabs(M); 01076 } 01077 if (Prms.EleMmax!=NULL) 01078 { 01079 static_cast<FEM::Beam const *>(Prms.EleMmax)->CalcRes (Prms.rMmax, N,V,M); 01080 if (fabs(M)>max_abs) max_abs = fabs(M); 01081 } 01082 } 01083 Prms.SF = (Prms.PctMaxDist * Prms.MaxDist) / (max_abs>0.0 ? max_abs : 1.0); 01084 } 01085 01086 // elements and diagrams 01087 std::ostringstream oss; 01088 MPL::Header (oss); 01089 for (size_t i=0; i<eles->Size(); ++i) (*eles)[i]->Draw (oss, Prms); 01090 MPL::AddPatch (oss); 01091 01092 // reactions 01093 if (Prms.WithReac) 01094 { 01095 Table reac; 01096 SDPair sum; 01097 CalcReactions (reac, sum); 01098 for (size_t i=0; i<reac.NRows; ++i) 01099 { 01100 int id = static_cast<int>(reac("Node",i)); 01101 if (Prms.ReacNodes.Has(id)) 01102 { 01103 std::map<int,Node*>::const_iterator it = VertID2Node.find(id); 01104 if (it!=VertID2Node.end()) 01105 { 01106 FEM::Node const * nod = const_cast<FEM::Node const *>(it->second); 01107 String buf; 01108 buf.Printf ("text(%g,%g, 'Rx=%g, Ry=%g', fontsize=9, color='blue', ha='center', va='top', backgroundcolor='white')\n", 01109 nod->Vert.C(0), nod->Vert.C(1), (reac.Keys.Has("ux") ? reac("ux",i) : 0), 01110 (reac.Keys.Has("uy") ? reac("uy",i) : 0)); 01111 oss << buf; 01112 } 01113 } 01114 } 01115 } 01116 01117 // output string 01118 if (Prms.Extra!=NULL) oss << Prms.Extra; 01119 if (Prms.PNG) MPL::SaveFig (FNKey, oss); 01120 else MPL::Show (oss); 01121 01122 // write file 01123 String fn(FNKey); fn.append(".mpy"); 01124 std::ofstream of(fn.CStr(), std::ios::out); 01125 of << oss.str(); 01126 of.close (); 01127 } 01128 01129 inline void Domain::WriteVTU (char const * FNKey, bool DoExtrapolation) const 01130 { 01131 // extrapolate results 01132 if (DoExtrapolation) NodalResults (); 01133 01134 // data 01135 size_t nn = ActNods.Size(); // number of active nodes 01136 size_t ne = ActEles.Size(); // number of active elements 01137 01138 // header 01139 std::ostringstream oss; 01140 oss << "<?xml version=\"1.0\"?>\n"; 01141 oss << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n"; 01142 oss << " <UnstructuredGrid>\n"; 01143 oss << " <Piece NumberOfPoints=\"" << nn << "\" NumberOfCells=\"" << ne << "\">\n"; 01144 01145 // nodes: coordinates 01146 oss << " <Points>\n"; 01147 oss << " <DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"ascii\">\n"; 01148 size_t k = 0; oss << " "; 01149 std::map<int,int> VertID2LocID; 01150 for (size_t i=0; i<nn; ++i) 01151 { 01152 VertID2LocID[ActNods[i]->Vert.ID] = i; 01153 oss << " " << Util::_8s << ActNods[i]->Vert.C(0) << " "; 01154 oss << Util::_8s << ActNods[i]->Vert.C(1) << " "; 01155 oss << Util::_8s << (NDim==3?ActNods[i]->Vert.C(2):0.0); 01156 k++; 01157 VTU_NEWLINE (i,k,nn,6/3-1,oss); 01158 } 01159 oss << " </DataArray>\n"; 01160 oss << " </Points>\n"; 01161 01162 // elements: connectivity, offsets, types 01163 oss << " <Cells>\n"; 01164 oss << " <DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">\n"; 01165 k = 0; oss << " "; 01166 for (size_t i=0; i<ne; ++i) 01167 { 01168 size_t nne = (NDim==2 ? NVertsToVTKNVerts2D[ActEles[i]->Con.Size()] : NVertsToVTKNVerts3D[ActEles[i]->Con.Size()]); 01169 oss << " "; 01170 for (size_t j=0; j<nne; ++j) oss << VertID2LocID[ActEles[i]->Con[j]->Vert.ID] << " "; 01171 k++; 01172 VTU_NEWLINE (i,k,ne,40/ActEles[i]->Con.Size(),oss); 01173 } 01174 oss << " </DataArray>\n"; 01175 oss << " <DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">\n"; 01176 k = 0; oss << " "; 01177 size_t offset = 0; 01178 for (size_t i=0; i<ne; ++i) 01179 { 01180 size_t nne = (NDim==2 ? NVertsToVTKNVerts2D[ActEles[i]->Con.Size()] : NVertsToVTKNVerts3D[ActEles[i]->Con.Size()]); 01181 offset += nne; 01182 oss << (k==0?" ":" ") << offset; 01183 k++; 01184 VTU_NEWLINE (i,k,ne,40,oss); 01185 } 01186 oss << " </DataArray>\n"; 01187 oss << " <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n"; 01188 k = 0; oss << " "; 01189 for (size_t i=0; i<ne; ++i) 01190 { 01191 if (NDim==2) oss << (k==0?" ":" ") << NVertsToVTKCell2D[ActEles[i]->Con.Size()]; 01192 else oss << (k==0?" ":" ") << NVertsToVTKCell3D[ActEles[i]->Con.Size()]; 01193 k++; 01194 VTU_NEWLINE (i,k,ne,40,oss); 01195 } 01196 oss << " </DataArray>\n"; 01197 oss << " </Cells>\n"; 01198 01199 // data -- nodes 01200 oss << " <PointData Scalars=\"point_scalars\">\n"; 01201 for (size_t i=0; i<AllUKeys.Size(); ++i) 01202 { 01203 if (!(AllUKeys[i]=="ux" || AllUKeys[i]=="uy" || AllUKeys[i]=="uz")) 01204 { 01205 oss << " <DataArray type=\"Float64\" Name=\"" << AllUKeys[i] << "\" NumberOfComponents=\"1\" format=\"ascii\">\n"; 01206 k = 0; oss << " "; 01207 for (size_t j=0; j<nn; ++j) 01208 { 01209 oss << (k==0?" ":" ") << ActNods[j]->UOrZero(AllUKeys[i]); 01210 k++; 01211 VTU_NEWLINE (j,k,nn,6-1,oss); 01212 } 01213 oss << " </DataArray>\n"; 01214 } 01215 } 01216 01217 // data -- nodes -- IDs 01218 oss << " <DataArray type=\"Float64\" Name=\"" << "tag,id" << "\" NumberOfComponents=\"2\" format=\"ascii\">\n"; 01219 k = 0; oss << " "; 01220 for (size_t j=0; j<nn; ++j) 01221 { 01222 oss << " " << ActNods[j]->Vert.Tag << " " << ActNods[j]->Vert.ID << " "; 01223 k++; 01224 VTU_NEWLINE (j,k,nn,40/2-1,oss); 01225 } 01226 oss << " </DataArray>\n"; 01227 01228 // data -- nodes -- displacements 01229 if (HasDisps) 01230 { 01231 oss << " <DataArray type=\"Float64\" Name=\"" << "u" << "\" NumberOfComponents=\"3\" format=\"ascii\">\n"; 01232 k = 0; oss << " "; 01233 for (size_t i=0; i<nn; ++i) 01234 { 01235 oss << " " << Util::_8s << ActNods[i]->U("ux") << " "; 01236 oss << Util::_8s << ActNods[i]->U("uy") << " "; 01237 oss << Util::_8s << (NDim==3 ? ActNods[i]->U("uz") : 0.0); 01238 k++; 01239 VTU_NEWLINE (i,k,nn,6/3-1,oss); 01240 } 01241 oss << " </DataArray>\n"; 01242 } 01243 01244 // data -- nodes -- extrapolated values 01245 for (size_t i=0; i<AllEKeys.Size(); ++i) 01246 { 01247 if (!(AllEKeys[i]=="vx" || AllEKeys[i]=="vy" || AllEKeys[i]=="vz")) 01248 { 01249 oss << " <DataArray type=\"Float64\" Name=\"" << AllEKeys[i] << "\" NumberOfComponents=\"1\" format=\"ascii\">\n"; 01250 k = 0; oss << " "; 01251 for (size_t j=0; j<nn; ++j) 01252 { 01253 double cnt = NodResCount[ActNods[j]][i]; 01254 oss << (k==0?" ":" ") << NodResults[ActNods[j]][i] / (cnt>0.0 ? cnt : 1.0); 01255 k++; 01256 VTU_NEWLINE (j,k,nn,6-1,oss); 01257 } 01258 oss << " </DataArray>\n"; 01259 } 01260 } 01261 01262 // data -- nodes -- velocities 01263 if (HasVeloc) 01264 { 01265 size_t idx_vx=-1, idx_vy=-1, idx_vz=-1; 01266 for (size_t i=0; i<AllEKeys.Size(); ++i) 01267 { 01268 if (AllEKeys[i]=="vx") idx_vx = i; 01269 if (AllEKeys[i]=="vy") idx_vy = i; 01270 if (AllEKeys[i]=="vz") idx_vz = i; 01271 } 01272 oss << " <DataArray type=\"Float64\" Name=\"" << "v" << "\" NumberOfComponents=\"3\" format=\"ascii\">\n"; 01273 k = 0; oss << " "; 01274 for (size_t j=0; j<nn; ++j) 01275 { 01276 double cnt_x = NodResCount[ActNods[j]][idx_vx]; 01277 double cnt_y = NodResCount[ActNods[j]][idx_vy]; 01278 double cnt_z = (NDim==3 ? NodResCount[ActNods[j]][idx_vz] : 0.0); 01279 oss << " " << Util::_8s << NodResults[ActNods[j]][idx_vx] / (cnt_x>0.0 ? cnt_x : 1.0) << " "; 01280 oss << Util::_8s << NodResults[ActNods[j]][idx_vy] / (cnt_y>0.0 ? cnt_y : 1.0) << " "; 01281 oss << Util::_8s << (NDim==3 ? NodResults[ActNods[j]][idx_vz] / (cnt_z>0.0 ? cnt_z : 1.0) : 0.0); 01282 k++; 01283 VTU_NEWLINE (j,k,nn,6/3-1,oss); 01284 } 01285 oss << " </DataArray>\n"; 01286 } 01287 01288 // data -- nodes -- specific water discharge 01289 if (HasWDisch) 01290 { 01291 size_t idx_vx=-1, idx_vy=-1, idx_vz=-1; 01292 for (size_t i=0; i<AllEKeys.Size(); ++i) 01293 { 01294 if (AllEKeys[i]=="qwx") idx_vx = i; 01295 if (AllEKeys[i]=="qwy") idx_vy = i; 01296 if (AllEKeys[i]=="qwz") idx_vz = i; 01297 } 01298 oss << " <DataArray type=\"Float64\" Name=\"" << "qw" << "\" NumberOfComponents=\"3\" format=\"ascii\">\n"; 01299 k = 0; oss << " "; 01300 for (size_t j=0; j<nn; ++j) 01301 { 01302 double cnt_x = NodResCount[ActNods[j]][idx_vx]; 01303 double cnt_y = NodResCount[ActNods[j]][idx_vy]; 01304 double cnt_z = (NDim==3 ? NodResCount[ActNods[j]][idx_vz] : 0.0); 01305 oss << " " << Util::_8s << NodResults[ActNods[j]][idx_vx] / (cnt_x>0.0 ? cnt_x : 1.0) << " "; 01306 oss << Util::_8s << NodResults[ActNods[j]][idx_vy] / (cnt_y>0.0 ? cnt_y : 1.0) << " "; 01307 oss << Util::_8s << (NDim==3 ? NodResults[ActNods[j]][idx_vz] / (cnt_z>0.0 ? cnt_z : 1.0) : 0.0); 01308 k++; 01309 VTU_NEWLINE (j,k,nn,6/3-1,oss); 01310 } 01311 oss << " </DataArray>\n"; 01312 } 01313 01314 // extra values from callback (solution?) 01315 if (VTUfunc!=NULL) 01316 { 01317 SDPair pairs; 01318 (*VTUfunc) (Vec3_t(0,0,0),0, pairs); 01319 for (size_t i=0; i<pairs.Keys.Size(); ++i) 01320 { 01321 oss << " <DataArray type=\"Float64\" Name=\"" << pairs.Keys[i] << "\" NumberOfComponents=\"1\" format=\"ascii\">\n"; 01322 k = 0; oss << " "; 01323 for (size_t j=0; j<nn; ++j) 01324 { 01325 SDPair p; 01326 (*VTUfunc) (Nods[j]->Vert.C, Time, p); 01327 oss << (k==0?" ":" ") << p(pairs.Keys[i]); 01328 k++; 01329 VTU_NEWLINE (j,k,nn,6-1,oss); 01330 } 01331 oss << " </DataArray>\n"; 01332 } 01333 } 01334 01335 // data -- nodes -- end 01336 oss << " </PointData>\n"; 01337 01338 // data -- elements 01339 oss << " <CellData Scalars=\"cell_scalars\">\n"; 01340 oss << " <DataArray type=\"Float64\" Name=\"" << "Tag,ID" << "\" NumberOfComponents=\"2\" format=\"ascii\">\n"; 01341 k = 0; oss << " "; 01342 for (size_t j=0; j<ne; ++j) 01343 { 01344 oss << " " << ActEles[j]->Cell.Tag << " " << ActEles[j]->Cell.ID << " "; 01345 k++; 01346 VTU_NEWLINE (j,k,ne,40/2-1,oss); 01347 } 01348 oss << " </DataArray>\n"; 01349 oss << " </CellData>\n"; 01350 01351 // bottom 01352 oss << " </Piece>\n"; 01353 oss << " </UnstructuredGrid>\n"; 01354 oss << "</VTKFile>" << std::endl; 01355 01356 // write to file 01357 String fn(FNKey); fn.append(".vtu"); 01358 std::ofstream of(fn.CStr(), std::ios::out); 01359 of << oss.str(); 01360 of.close(); 01361 } 01362 01363 inline bool Domain::CheckErrorNods (Table const & NodSol, SDPair const & NodTol) const 01364 { 01365 // check 01366 if (NodSol.NRows!=Nods.Size()) throw new Fatal("Domain::CheckErrorNods: Number of rows (%d) in table NodSol with the nodes solution must be equal to the number of nodes (%d)",NodSol.NRows,Nods.Size()); 01367 01368 // header 01369 printf("\n%s--- Error Summary --- nodes --------------------------------------------------------%s\n",TERM_CLR1,TERM_RST); 01370 std::cout << TERM_CLR2 << Util::_4<< "Key" << Util::_8s<<"Min" << Util::_8s<<"Mean" << Util::_8s<<"Max" << Util::_8s<<"Norm"; 01371 printf("%s\n",TERM_RST); 01372 01373 // results 01374 bool error = false; 01375 01376 // nodes 01377 Table reac; // reactions 01378 SDPair sumR; // sum of reactions 01379 bool reactions_calculated = false; 01380 bool nodresults_calculated = false; 01381 for (size_t i=0; i<NodSol.Keys.Size(); ++i) 01382 { 01383 // calc error 01384 String key = NodSol.Keys[i]; 01385 Array<double> err(NodSol.NRows); 01386 if (key[0]=='R') // reaction 01387 { 01388 if (!reactions_calculated) 01389 { 01390 CalcReactions (reac, sumR); 01391 reactions_calculated = true; 01392 } 01393 String ukey; 01394 for (size_t j=1; j<key.size(); ++j) ukey.Printf("%s%c",ukey.CStr(),key[j]); 01395 for (size_t j=0; j<Nods.Size(); ++j) 01396 { 01397 long pos = reac("Node").Find (Nods[j]->Vert.ID); 01398 if (pos<0) err[j] = 0.0; 01399 else err[j] = fabs(reac(ukey,pos) - NodSol(key,j)); 01400 } 01401 } 01402 else 01403 { 01404 for (size_t j=0; j<Nods.Size(); ++j) 01405 { 01406 if (Nods[j]->NShares>0) 01407 { 01408 if (AllUKeys.Has(key)) err[j] = fabs(Nods[j]->U(key.CStr()) - NodSol(key,j)); 01409 else if (AllFKeys.Has(key)) err[j] = fabs(Nods[j]->F(key.CStr()) - NodSol(key,j)); 01410 else 01411 { 01412 if (!nodresults_calculated) 01413 { 01414 NodalResults (); 01415 nodresults_calculated = true; 01416 } 01417 long pos = AllEKeys.Find(key); 01418 if (pos<0) throw new Fatal("Domain::CheckErrorNods: Could not find key=%s in AllEKeys (extrapolated variables) array",key.CStr()); 01419 double cnt = NodResCount[Nods[j]][pos]; 01420 err[j] = fabs(NodResults[Nods[j]][pos]/(cnt>0.0?cnt:1.0) - NodSol(key,j)); 01421 } 01422 } 01423 else err[j] = 0.0; 01424 } 01425 } 01426 01427 // summary 01428 if (!NodTol.HasKey(key)) throw new Fatal("Domain::CheckErrorNods: NodTol structure with the tolerances must have key=%s",key.CStr()); 01429 double max_err = err.TheMax(); 01430 double tol = NodTol(key); 01431 std::cout << Util::_4<< key << Util::_8s<<err.TheMin() << Util::_8s<<err.Mean(); 01432 std::cout << (max_err>tol ? TERM_RED : TERM_GREEN) << Util::_8s<<max_err << TERM_RST << Util::_8s<<err.Norm() << "\n"; 01433 if (max_err>tol) error = true; 01434 } 01435 01436 return error; 01437 } 01438 01439 inline bool Domain::CheckErrorEles (Table const & EleSol, SDPair const & EleTol) const 01440 { 01441 // check 01442 if (EleSol.NRows!=Eles.Size()) throw new Fatal("Domain::CheckErrorEles: Number of rows (%d) in table EleSol with the elements solution must be equal to the number of elements (%d)",EleSol.NRows,Eles.Size()); 01443 01444 // header 01445 printf("\n%s--- Error Summary --- centre of elements -------------------------------------------%s\n",TERM_CLR1,TERM_RST); 01446 std::cout << TERM_CLR2 << Util::_4<< "Key" << Util::_8s<<"Min" << Util::_8s<<"Mean" << Util::_8s<<"Max" << Util::_8s<<"Norm"; 01447 printf("%s\n",TERM_RST); 01448 01449 // results 01450 bool error = false; 01451 01452 // elements 01453 for (size_t i=0; i<EleSol.Keys.Size(); ++i) 01454 { 01455 // calc error 01456 String key = EleSol.Keys[i]; 01457 Array<double> err(EleSol.NRows); 01458 for (size_t j=0; j<Eles.Size(); ++j) 01459 { 01460 Array<SDPair> loc_res; // local results: size==number of nodes in element 01461 ActEles[j]->StateAtNodes (loc_res); 01462 SDPair ave; // average 01463 ave = loc_res[0]; 01464 for (size_t k=1; k<loc_res.Size(); ++k) 01465 { 01466 ave.AddVal (key.CStr(), loc_res[k](key)); 01467 } 01468 err [j] = fabs(ave(key)/loc_res.Size() - EleSol(key,j)); 01469 } 01470 01471 // summary 01472 if (!EleTol.HasKey(key)) throw new Fatal("Domain::CheckErrorEles: EleTol structure with the tolerances must have key=%s",key.CStr()); 01473 double max_err = err.TheMax(); 01474 double tol = EleTol(key); 01475 std::cout << Util::_4<< key << Util::_8s<<err.TheMin() << Util::_8s<<err.Mean(); 01476 std::cout << (max_err>tol ? TERM_RED : TERM_GREEN) << Util::_8s<<max_err << TERM_RST << Util::_8s<<err.Norm() << "\n"; 01477 if (max_err>tol) error = true; 01478 } 01479 01480 return error; 01481 } 01482 01483 inline bool Domain::CheckErrorIPs (Table const & EleSol, SDPair const & EleTol) const 01484 { 01485 // header 01486 printf("\n%s--- Error Summary --- integration points -------------------------------------------%s\n",TERM_CLR1,TERM_RST); 01487 std::cout << TERM_CLR2 << Util::_4<< "Key" << Util::_8s<<"Min" << Util::_8s<<"Mean" << Util::_8s<<"Max" << Util::_8s<<"Norm"; 01488 printf("%s\n",TERM_RST); 01489 01490 // results 01491 bool error = false; 01492 01493 // elements 01494 for (size_t i=0; i<EleSol.Keys.Size(); ++i) 01495 { 01496 // calc error 01497 String key = EleSol.Keys[i]; 01498 Array<double> err(EleSol.NRows); 01499 for (size_t j=0; j<Eles.Size(); ++j) 01500 { 01501 if (Eles[j]->GE==NULL) throw new Fatal("Domain::CheckErrorIPs: This method works only when GE (geometry element) is not NULL"); 01502 Array<SDPair> res; 01503 Eles[j]->StateAtIPs (res); 01504 for (size_t k=0; k<Eles[j]->GE->NIP; ++k) 01505 { 01506 size_t row = k + j*Eles[j]->GE->NIP; 01507 err [row] = fabs(res[k](key) - EleSol(key,row)); 01508 } 01509 } 01510 01511 // summary 01512 if (!EleTol.HasKey(key)) throw new Fatal("Domain::CheckErrorIPs: EleTol structure with the tolerances must have key=%s",key.CStr()); 01513 double max_err = err.TheMax(); 01514 double tol = EleTol(key); 01515 std::cout << Util::_4<< key << Util::_8s<<err.TheMin() << Util::_8s<<err.Mean(); 01516 std::cout << (max_err>tol ? TERM_RED : TERM_GREEN) << Util::_8s<<max_err << TERM_RST << Util::_8s<<err.Norm() << "\n"; 01517 if (max_err>tol) error = true; 01518 } 01519 std::cout << "\n"; 01520 01521 return error; 01522 } 01523 01524 inline void Domain::SaveState (char const * FileKey) const 01525 { 01526 #ifdef USE_HDF5 01527 // open HDF5 file 01528 String fn(FileKey); 01529 fn.append(".hdf5"); 01530 hid_t hdf = H5Fcreate (fn.CStr(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); 01531 01532 // number of nodes and elements 01533 int nods_sz[1] = { static_cast<int>(Nods.Size()) }; 01534 int eles_sz[1] = { static_cast<int>(Eles.Size()) }; 01535 double time [1] = { Time }; 01536 hsize_t unit_sz[1] = { 1 }; 01537 H5LTmake_dataset_int (hdf, "/NNods", 1, unit_sz, nods_sz); 01538 H5LTmake_dataset_int (hdf, "/NEles", 1, unit_sz, eles_sz); 01539 H5LTmake_dataset_double (hdf, "/Time", 1, unit_sz, time); 01540 01541 // define HDF5 table with node results 01542 size_t ncols = AllUKeys.Size() + AllFKeys.Size(); 01543 size_t row_size = sizeof(double) * ncols; 01544 size_t col_offsets[ncols]; 01545 //size_t col_sizes [ncols]; 01546 hid_t col_types [ncols]; 01547 for (size_t i=0; i<ncols; ++i) 01548 { 01549 col_offsets[i] = i * sizeof(double); 01550 //col_sizes [i] = sizeof(double); 01551 col_types [i] = H5T_NATIVE_DOUBLE; 01552 } 01553 char const * col_labels[ncols]; 01554 for (size_t i=0; i<AllUKeys.Size(); ++i) col_labels[ i] = AllUKeys[i].CStr(); 01555 for (size_t i=0; i<AllFKeys.Size(); ++i) col_labels[AllUKeys.Size()+i] = AllFKeys[i].CStr(); 01556 01557 // create HDF5 table with node results 01558 H5TBmake_table ("U and F values at nodes", hdf, "/Nods", /*nfields*/ncols, /*nrecords*/Nods.Size(), row_size, col_labels, col_offsets, col_types, /*chunk_size*/10, /*fill_data*/NULL, /*compress*/false, /*data*/NULL); 01559 01560 // fill HDF5 table with node results 01561 int col_idx[1]; 01562 double dbl_dat[1]; 01563 size_t dbl_siz[1] = { sizeof(double) }; 01564 for (size_t i=0; i<Nods.Size(); ++i) 01565 { 01566 for (size_t j=0; j<AllUKeys.Size(); ++j) 01567 { 01568 col_idx[0] = j; 01569 dbl_dat[0] = Nods[i]->UOrZero(AllUKeys[j]); 01570 H5TBwrite_fields_index (hdf, "/Nods", /*nfields*/1, col_idx, /*row_idx*/i, /*nrecords*/1, sizeof(double), /*offset*/0, dbl_siz, dbl_dat); 01571 } 01572 for (size_t j=0; j<AllFKeys.Size(); ++j) 01573 { 01574 col_idx[0] = AllFKeys.Size() + j; 01575 dbl_dat[0] = Nods[i]->FOrZero(AllFKeys[j]); 01576 H5TBwrite_fields_index (hdf, "/Nods", /*nfields*/1, col_idx, /*row_idx*/i, /*nrecords*/1, sizeof(double), /*offset*/0, dbl_siz, dbl_dat); 01577 } 01578 } 01579 01580 // save elements' states 01581 String buf; 01582 hsize_t sta_size[1]; 01583 hid_t eles = H5Gcreate (hdf, "/Eles", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 01584 for (size_t i=0; i<Eles.Size(); ++i) 01585 { 01586 buf.Printf ("ele_%d",i); 01587 hid_t ele = H5Gcreate (eles, buf.CStr(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 01588 for (size_t j=0; j<Eles[i]->Sta.Size(); ++j) 01589 { 01590 buf.Printf ("sta_%d",j); 01591 Array<double> pck; 01592 Eles[i]->Sta[j]->Pack (pck); 01593 sta_size[0] = pck.Size(); 01594 H5LTmake_dataset_double (ele, buf.CStr(), /*rank*/1, sta_size, pck.GetPtr()); 01595 } 01596 } 01597 01598 // close file 01599 H5Fclose (hdf); 01600 #else 01601 throw new Fatal("Domain::SaveState: This method needs USE_HDF5 defined"); 01602 #endif 01603 } 01604 01605 inline void Domain::LoadState (char const * FileKey) 01606 { 01607 #ifdef USE_HDF5 01608 // open HDF5 file 01609 String fn(FileKey); 01610 fn.append(".hdf5"); 01611 hid_t hdf = H5Fopen (fn.CStr(), H5F_ACC_RDONLY, H5P_DEFAULT); 01612 01613 // number of nodes and elements 01614 int nods_sz[1]; 01615 int eles_sz[1]; 01616 double time [1]; 01617 H5LTread_dataset_int (hdf, "/NNods", nods_sz); 01618 H5LTread_dataset_int (hdf, "/NEles", eles_sz); 01619 H5LTread_dataset_double (hdf, "/Time", time); 01620 if (nods_sz[0]!=(int)Nods.Size()) throw new Fatal("Domain::LoadState(%s) Number of nodes in file (%d) is different from number of nodes in Domain (%zd)",FileKey,nods_sz[0],Nods.Size()); 01621 if (eles_sz[0]!=(int)Eles.Size()) throw new Fatal("Domain::LoadState(%s) Number of elemnts in file (%d) is different from number of elements in Domain (%zd)",FileKey,eles_sz[0],Eles.Size()); 01622 Time = time[0]; 01623 01624 // read table with node results 01625 int col_idx[1]; 01626 double dbl_dat[1]; 01627 size_t dbl_siz[1] = { sizeof(double) }; 01628 for (size_t i=0; i<Nods.Size(); ++i) 01629 { 01630 for (size_t j=0; j<AllUKeys.Size(); ++j) 01631 { 01632 col_idx[0] = j; 01633 H5TBread_fields_index (hdf, "/Nods", /*nfields*/1, col_idx, /*row_idx*/i, /*nrecords*/1, sizeof(double), /*offset*/0, dbl_siz, dbl_dat); 01634 Nods[i]->TrySetU (AllUKeys[j], dbl_dat[0]); 01635 } 01636 for (size_t j=0; j<AllFKeys.Size(); ++j) 01637 { 01638 col_idx[0] = AllFKeys.Size() + j; 01639 H5TBread_fields_index (hdf, "/Nods", /*nfields*/1, col_idx, /*row_idx*/i, /*nrecords*/1, sizeof(double), /*offset*/0, dbl_siz, dbl_dat); 01640 Nods[i]->TrySetF (AllFKeys[j], dbl_dat[0]); 01641 } 01642 } 01643 01644 // read elements' states 01645 String buf; 01646 //hsize_t sta_size[1]; 01647 hid_t eles = H5Gopen (hdf, "/Eles", H5P_DEFAULT); 01648 for (size_t i=0; i<Eles.Size(); ++i) 01649 { 01650 buf.Printf ("ele_%d",i); 01651 hid_t ele = H5Gopen (eles, buf.CStr(), H5P_DEFAULT); 01652 for (size_t j=0; j<Eles[i]->Sta.Size(); ++j) 01653 { 01654 buf.Printf ("sta_%d",j); 01655 Array<double> pck(Eles[i]->Sta[j]->PckSize()); 01656 //sta_size[0] = pck.Size(); 01657 H5LTread_dataset_double (ele, buf.CStr(), pck.GetPtr()); 01658 Eles[i]->Sta[j]->Unpack (pck); 01659 } 01660 } 01661 01662 // close file 01663 H5Fclose (hdf); 01664 01665 #else 01666 throw new Fatal("Domain::LoadState: This method needs USE_HDF5 defined"); 01667 #endif 01668 } 01669 01670 inline void Domain::SetGeostatic (SDPair const & Data) 01671 { 01672 // Prp must have: geosta, surf, K0, gamNat, gamSat 01673 // Prp may have: wtable, gamW, pospw (to force only positive values of pw) 01674 01675 /* 01676 double z_surf = Prp("surf"); 01677 double K0 = Prp("K0"); 01678 bool pos_pw = (Prp.HasKey("pospw") ? Prp("pospw")>0 : false); 01679 bool has_water = Prp.HasKey("water"); 01680 double z_water = 0; 01681 if (GTy==pse_t) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, geometry cannot be of 'plane-stress' (pse) type"); 01682 if (!Prp.HasKey("K0")) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'K0' must be provided in 'Prp' dictionary"); 01683 if (!Prp.HasKey("surf")) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'surf' must be provided in 'Prp' dictionary"); 01684 if (has_water) 01685 { 01686 z_water = Prp("water"); 01687 if (z_water>z_surf) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'water' must be smaller than or equal to 'surf'"); 01688 // TODO: this last condition can be removed, but sv calculation in the next lines must be corrected 01689 } 01690 if (Mdl->GamW <0.0) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'gamW' must be positive"); 01691 if (Mdl->GamNat<0.0) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'gamNat' must be positive"); 01692 if (Mdl->GamSat<0.0) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'gamSat' must be positive"); 01693 for (size_t i=0; i<GE->NIP; ++i) 01694 { 01695 // elevation of point 01696 Vec_t X; 01697 CoordsOfIP (i, X); 01698 double z = (NDim==2 ? X(1) : X(2)); 01699 if (z>z_surf) throw new Fatal("EquilibElem::EquilibElem: 'surf' must be greater than any point in the domain.\n\tThere is a point [%g,%g,%g] above surf=%g.",X(0),X(1),(NDim==3?X(2):0.0),z_surf); 01700 01701 // pore-water pressure and total vertical stress 01702 double pw = 0.0; 01703 double sv; 01704 if (has_water) 01705 { 01706 double hw = z_water-z; // column of water 01707 pw = (hw>0.0 ? Mdl->GamW*hw : (pos_pw ? 0.0 : Mdl->GamW*hw)); 01708 if (z>z_water) sv = (z_surf-z)*Mdl->GamNat; 01709 else sv = (z_surf-z_water)*Mdl->GamNat + (z_water-z)*Mdl->GamSat; 01710 } 01711 else sv = (z_surf-z)*Mdl->GamNat; 01712 sv *= (-1.0); // convert soil-mech. convention to classical mech. convention 01713 01714 // vertical and horizontal effective stresses 01715 double sv_ = sv + pw; // effective vertical stresss 01716 double sh_ = K0*sv_; // effective horizontal stress 01717 double sh = sh_ - pw; // total horizontal stress 01718 01719 // set stress tensor with __total__ stresses 01720 Vec_t & sig = static_cast<EquilibState *>(Sta[i])->Sig; 01721 if (NDim==2) sig = sh, sv, sh, 0.0; 01722 else sig = sh, sh, sv, 0.0,0.0,0.0; 01723 } 01724 01725 01726 // pw at IP 01727 if (geosta) 01728 { 01729 // elevation of point 01730 Vec_t X; 01731 CoordsOfIP (i, X); 01732 double z = (NDim==2 ? X(1) : X(2)); 01733 01734 // pore-water pressure 01735 double hw = Prp("water")-z; // column of water 01736 double pw = (hw>0.0 ? gamW*hw : (pos_pw ? 0.0 : gamW*hw)); 01737 ini.Set ("pw", pw); 01738 } 01739 */ 01740 } 01741 01742 // Internal methods 01743 01744 inline void Domain::NodalResults (bool OnlyOutNods) const 01745 { 01746 // extrapolate from elements' IPs to nodes 01747 Array<Node*> const * nods; 01748 Array<Element*> const * eles; 01749 if (OnlyOutNods) 01750 { 01751 nods = &OutNods; 01752 eles = &OutEles; 01753 } 01754 else 01755 { 01756 nods = &ActNods; 01757 eles = &ActEles; 01758 } 01759 for (size_t i=0; i<nods->Size(); ++i) 01760 { 01761 NodResults [(*nods)[i]].Resize (AllEKeys.Size()); // results at nodes 01762 NodResCount[(*nods)[i]].Resize (AllEKeys.Size()); // count how many times a varable was added to a node 01763 NodResults [(*nods)[i]].SetValues (0.0); 01764 NodResCount[(*nods)[i]].SetValues (0.0); 01765 } 01766 for (size_t i=0; i<eles->Size(); ++i) 01767 { 01768 Array<SDPair> loc_res; // local results: size==number of nodes in element 01769 (*eles)[i]->StateAtNodes (loc_res); 01770 for (size_t j=0; j<AllEKeys.Size(); ++j) 01771 { 01772 if (loc_res[0].HasKey(AllEKeys[j])) 01773 { 01774 for (size_t k=0; k<(*eles)[i]->Con.Size(); ++k) 01775 { 01776 if (OnlyOutNods) 01777 { 01778 // skip nodes that are not in array OutNods 01779 if (!nods->Has((*eles)[i]->Con[k])) continue; 01780 } 01781 NodResults [(*eles)[i]->Con[k]][j] += loc_res[k](AllEKeys[j]); 01782 NodResCount[(*eles)[i]->Con[k]][j] += 1.0; 01783 } 01784 } 01785 } 01786 } 01787 } 01788 01789 inline void Domain::OutResults (char const * VTUFName, bool HeaderOnly) 01790 { 01791 // VTU 01792 if (VTUFName!=NULL) 01793 { 01794 // extrapolate values to (all) nodes 01795 NodalResults (); 01796 01797 // write file 01798 String fkey; 01799 fkey.Printf ("%s_%08d", VTUFName, IdxOut); 01800 WriteVTU (fkey.CStr(), /*do_extrapolation*/false); 01801 01802 // next index of files 01803 IdxOut++; 01804 } 01805 else if (OutNods.Size()>0) 01806 { 01807 // extrapolate values to (some) nodes 01808 if (!HeaderOnly) NodalResults (/*only_outnods*/true); 01809 } 01810 01811 // nodes 01812 for (size_t i=0; i<OutNods.Size(); ++i) 01813 { 01814 if (HeaderOnly) 01815 { 01816 (*FilNods[i]) << Util::_8s << "Time"; 01817 for (size_t j=0; j<AllUKeys.Size(); ++j) (*FilNods[i]) << Util::_8s << AllUKeys[j]; 01818 for (size_t j=0; j<AllUKeys.Size(); ++j) (*FilNods[i]) << Util::_8s << ("v"+AllUKeys[j].substr(1,AllUKeys[j].size())); 01819 for (size_t j=0; j<AllFKeys.Size(); ++j) (*FilNods[i]) << Util::_8s << AllFKeys[j]; 01820 for (size_t j=0; j<AllEKeys.Size(); ++j) (*FilNods[i]) << Util::_8s << AllEKeys[j]; 01821 (*FilNods[i]) << "\n"; 01822 } 01823 else 01824 { 01825 (*FilNods[i]) << Util::_8s << Time; 01826 for (size_t j=0; j<AllUKeys.Size(); ++j) (*FilNods[i]) << Util::_8s << OutNods[i]->UOrZero(AllUKeys[j]); 01827 for (size_t j=0; j<AllUKeys.Size(); ++j) (*FilNods[i]) << Util::_8s << OutNods[i]->VOrZero(AllUKeys[j]); 01828 for (size_t j=0; j<AllFKeys.Size(); ++j) (*FilNods[i]) << Util::_8s << OutNods[i]->FOrZero(AllFKeys[j]); 01829 for (size_t j=0; j<AllEKeys.Size(); ++j) 01830 { 01831 double cnt = NodResCount[OutNods[i]][j]; 01832 (*FilNods[i]) << Util::_8s << NodResults[OutNods[i]][j] / (cnt>0.0 ? cnt : 1.0); 01833 } 01834 (*FilNods[i]) << "\n"; 01835 } 01836 } 01837 } 01838 01839 inline void Domain::CalcReactions (Table & NodesReactions, SDPair & SumReactions) const 01840 { 01841 // resize tables 01842 String buf("Node"); 01843 for (size_t i=0; i<AllUKeys.Size(); ++i) 01844 { 01845 buf.Printf ("%s %s",buf.CStr(),AllUKeys[i].CStr()); 01846 SumReactions.Set (AllUKeys[i].CStr(), 0.0); 01847 } 01848 NodesReactions.SetZero (buf.CStr(), NodsWithPU.Size()); 01849 01850 // find reactions 01851 size_t k = 0; 01852 for (size_t i=0; i<NodsWithPU.Size(); ++i) 01853 { 01854 Node const * nod = NodsWithPU[i]; 01855 NodesReactions("Node", k) = nod->Vert.ID; 01856 std::map<String,double> R; 01857 nod->Reactions (R); 01858 for (std::map<String,double>::const_iterator it=R.begin(); it!=R.end(); ++it) 01859 { 01860 NodesReactions(it->first, k) = it->second; 01861 SumReactions[it->first] += it->second; 01862 } 01863 k++; 01864 } 01865 } 01866 01867 01868 }; // namespace FEM 01869 01870 #endif // MECHSYS_DOMAIN_H