MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/fem/domain.h
Go to the documentation of this file.
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("%s  =>  %g\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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines