[4216] | 1 | /*
|
---|
| 2 | * \file Elements.c
|
---|
| 3 | * \brief: implementation of the Elements class, derived from DataSet class
|
---|
| 4 | */
|
---|
| 5 |
|
---|
[12706] | 6 | /*Headers: {{{*/
|
---|
[4216] | 7 | #ifdef HAVE_CONFIG_H
|
---|
[9320] | 8 | #include <config.h>
|
---|
[4216] | 9 | #else
|
---|
| 10 | #error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
|
---|
| 11 | #endif
|
---|
| 12 |
|
---|
| 13 | #include <vector>
|
---|
| 14 | #include <functional>
|
---|
| 15 | #include <algorithm>
|
---|
| 16 | #include <iostream>
|
---|
| 17 |
|
---|
| 18 | #include "./DataSet.h"
|
---|
| 19 | #include "../shared/shared.h"
|
---|
| 20 | #include "../include/include.h"
|
---|
| 21 | #include "../EnumDefinitions/EnumDefinitions.h"
|
---|
| 22 |
|
---|
| 23 | using namespace std;
|
---|
| 24 | /*}}}*/
|
---|
| 25 |
|
---|
| 26 | /*Object constructors and destructor*/
|
---|
[12706] | 27 | /*FUNCTION Elements::Elements(){{{*/
|
---|
[4216] | 28 | Elements::Elements(){
|
---|
[10522] | 29 | enum_type=MeshElementsEnum;
|
---|
[4216] | 30 | return;
|
---|
| 31 | }
|
---|
| 32 | /*}}}*/
|
---|
[12706] | 33 | /*FUNCTION Elements::~Elements(){{{*/
|
---|
[4216] | 34 | Elements::~Elements(){
|
---|
| 35 | return;
|
---|
| 36 | }
|
---|
| 37 | /*}}}*/
|
---|
| 38 |
|
---|
| 39 | /*Object management*/
|
---|
[12706] | 40 | /*FUNCTION Elements::Configure{{{*/
|
---|
[6411] | 41 | void Elements::Configure(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){
|
---|
| 42 |
|
---|
| 43 | vector<Object*>::iterator object;
|
---|
| 44 | Element* element=NULL;
|
---|
| 45 |
|
---|
| 46 | for ( object=objects.begin() ; object < objects.end(); object++ ){
|
---|
| 47 |
|
---|
[13975] | 48 | element=dynamic_cast<Element*>((*object));
|
---|
[6411] | 49 | element->Configure(elements,loads,nodes,materials,parameters);
|
---|
| 50 |
|
---|
| 51 | }
|
---|
| 52 |
|
---|
| 53 | }
|
---|
| 54 | /*}}}*/
|
---|
[12706] | 55 | /*FUNCTION Elements::ProcessResultsUnits{{{*/
|
---|
[6372] | 56 | void Elements::ProcessResultsUnits(void){
|
---|
| 57 |
|
---|
| 58 | //Process results to be output in the correct units
|
---|
[6411] | 59 | for(int i=0;i<this->Size();i++){
|
---|
[13975] | 60 | Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
|
---|
[6372] | 61 | element->ProcessResultsUnits();
|
---|
| 62 | }
|
---|
| 63 | }
|
---|
| 64 | /*}}}*/
|
---|
[12706] | 65 | /*FUNCTION Elements::DeleteResults{{{*/
|
---|
[6372] | 66 | void Elements::DeleteResults(void){
|
---|
[13975] | 67 |
|
---|
[6411] | 68 | for (int i=0;i<this->Size();i++){
|
---|
[13975] | 69 | Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
|
---|
[6372] | 70 | element->DeleteResults();
|
---|
| 71 | }
|
---|
| 72 | }
|
---|
| 73 | /*}}}*/
|
---|
[12706] | 74 | /*FUNCTION Elements::ResultsToPatch{{{*/
|
---|
[6372] | 75 | Patch* Elements::ResultsToPatch(void){
|
---|
| 76 |
|
---|
| 77 | /*output: */
|
---|
| 78 | Patch* patch=NULL;
|
---|
| 79 |
|
---|
| 80 | /*intermediary: */
|
---|
| 81 | int i;
|
---|
| 82 | int count;
|
---|
| 83 | int numrows;
|
---|
| 84 | int numvertices;
|
---|
| 85 | int numnodes;
|
---|
| 86 | int max_numvertices;
|
---|
| 87 | int max_numnodes;
|
---|
| 88 | int element_numvertices;
|
---|
| 89 | int element_numrows;
|
---|
| 90 | int element_numnodes;
|
---|
| 91 |
|
---|
| 92 | /*We are going to extract from the results within the elements, the desired results , and create a table
|
---|
| 93 | * of patch information, that will hold, for each element that computed the result that
|
---|
| 94 | * we desire, the enum_type of the result, the step and time, the id of the element, the interpolation type, the vertices ids, and the values
|
---|
| 95 | * at the nodes (could be different from the vertices). This will be used for visualization purposes.
|
---|
| 96 | * For example, we could build the following patch table, for velocities:
|
---|
| 97 | *
|
---|
| 98 | 1. on a Beam element, Vx, at step 1, time .5, element id 1, interpolation type P0 (constant), vertices ids 1 and 2, one constant value 4.5
|
---|
| 99 | VxEnum 1 .5 1 P0 1 2 4.5 NaN NaN
|
---|
| 100 | 2. on a Tria element, Vz, at step 2, time .8, element id 2, interpolation type P1 (linear), vertices ids 1 3 and 4, with values at 3 nodes 4.5, 3.2, 2.5
|
---|
| 101 | VzEnum 2 .8 2 P1 1 3 4 4.5 3.2 2.5
|
---|
| 102 | * ... etc ...
|
---|
| 103 | *
|
---|
| 104 | * So what do we need to build the table: the maximum number of vertices included in the table,
|
---|
| 105 | * and the maximum number of nodal values, as well as the number of rows. Once we have that,
|
---|
| 106 | * we ask the elements to fill their own row in the table, by looping on the elememnts.
|
---|
| 107 | *
|
---|
| 108 | * We will use the Patch object, which will store all of the information needed, and will be able
|
---|
| 109 | * to output itself to disk on its own. See object/Patch.h for format of this object.*/
|
---|
[13975] | 110 |
|
---|
[6372] | 111 | /*First, determine maximum number of vertices, nodes, and number of results: */
|
---|
| 112 | numrows=0;
|
---|
| 113 | numvertices=0;
|
---|
| 114 | numnodes=0;
|
---|
| 115 |
|
---|
| 116 | for(i=0;i<this->Size();i++){
|
---|
| 117 |
|
---|
[13975] | 118 | Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
|
---|
[6372] | 119 | element->PatchSize(&element_numrows,&element_numvertices,&element_numnodes);
|
---|
| 120 |
|
---|
| 121 | numrows+=element_numrows;
|
---|
| 122 | if(element_numvertices>numvertices)numvertices=element_numvertices;
|
---|
| 123 | if(element_numnodes>numnodes)numnodes=element_numnodes;
|
---|
| 124 | }
|
---|
| 125 |
|
---|
| 126 | /*Synchronize across cluster, so as to not end up with different sizes for each patch on each cpu: */
|
---|
[12330] | 127 | #ifdef _HAVE_MPI_
|
---|
[13975] | 128 | MPI_Reduce (&numvertices,&max_numvertices,1,MPI_INT,MPI_MAX,0,IssmComm::GetComm() );
|
---|
| 129 | MPI_Bcast(&max_numvertices,1,MPI_INT,0,IssmComm::GetComm());
|
---|
[6372] | 130 | numvertices=max_numvertices;
|
---|
| 131 |
|
---|
[13975] | 132 | MPI_Reduce (&numnodes,&max_numnodes,1,MPI_INT,MPI_MAX,0,IssmComm::GetComm() );
|
---|
| 133 | MPI_Bcast(&max_numnodes,1,MPI_INT,0,IssmComm::GetComm());
|
---|
[6372] | 134 | numnodes=max_numnodes;
|
---|
| 135 | #endif
|
---|
| 136 |
|
---|
| 137 | /*Ok, initialize Patch object: */
|
---|
| 138 | patch=new Patch(numrows,numvertices,numnodes);
|
---|
| 139 |
|
---|
| 140 | /*Now, go through elements, and fill the Patch object: */
|
---|
| 141 | count=0;
|
---|
| 142 | for(i=0;i<this->Size();i++){
|
---|
[13975] | 143 | Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
|
---|
[6372] | 144 | element->PatchFill(&count,patch);
|
---|
| 145 | }
|
---|
| 146 |
|
---|
| 147 | return patch;
|
---|
| 148 | }
|
---|
| 149 | /*}}}*/
|
---|
[12706] | 150 | /*FUNCTION Elements::SetCurrentConfiguration{{{*/
|
---|
[6411] | 151 | void Elements::SetCurrentConfiguration(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){
|
---|
| 152 |
|
---|
| 153 | vector<Object*>::iterator object;
|
---|
| 154 | Element* element=NULL;
|
---|
| 155 |
|
---|
| 156 | for ( object=objects.begin() ; object < objects.end(); object++ ){
|
---|
| 157 |
|
---|
[13975] | 158 | element=dynamic_cast<Element*>((*object));
|
---|
[6411] | 159 | element->SetCurrentConfiguration(elements,loads,nodes,materials,parameters);
|
---|
| 160 |
|
---|
| 161 | }
|
---|
| 162 |
|
---|
| 163 | }
|
---|
| 164 | /*}}}*/
|
---|
[12706] | 165 | /*FUNCTION Elements::ToResults{{{*/
|
---|
[11027] | 166 | void Elements::ToResults(Results* results,Parameters* parameters){
|
---|
[6411] | 167 |
|
---|
[13975] | 168 | int my_rank;
|
---|
| 169 | int num_procs;
|
---|
[9878] | 170 |
|
---|
[13975] | 171 | Patch *patch = NULL;
|
---|
| 172 | int *resultsenums = NULL;
|
---|
| 173 | int *resultssizes = NULL;
|
---|
| 174 | int *resultssteps = NULL;
|
---|
| 175 | IssmDouble *resultstimes = NULL;
|
---|
| 176 | IssmDouble *vector_serial = NULL;
|
---|
| 177 | Vector<IssmDouble> *vector = NULL;
|
---|
| 178 | bool io_gather;
|
---|
| 179 | bool results_as_patches;
|
---|
| 180 | int numberofvertices ,numberofelements;
|
---|
| 181 | int numberofresults ,vectorsize;
|
---|
| 182 | int rank;
|
---|
| 183 | int minrank;
|
---|
[6411] | 184 |
|
---|
[13975] | 185 | /*recover my_rank:*/
|
---|
| 186 | my_rank=IssmComm::GetRank();
|
---|
| 187 | num_procs=IssmComm::GetSize();
|
---|
| 188 |
|
---|
[6411] | 189 | /*Recover parameters: */
|
---|
[9622] | 190 | parameters->FindParam(&io_gather,SettingsIoGatherEnum);
|
---|
[10981] | 191 | parameters->FindParam(&results_as_patches,SettingsResultsAsPatchesEnum);
|
---|
[9874] | 192 | parameters->FindParam(&numberofvertices,MeshNumberofverticesEnum);
|
---|
[11027] | 193 | parameters->FindParam(&numberofelements,MeshNumberofelementsEnum);
|
---|
[6411] | 194 |
|
---|
[10981] | 195 | if(!results_as_patches){
|
---|
[9874] | 196 | /*No patch here, we prepare vectors*/
|
---|
[6411] | 197 |
|
---|
[11239] | 198 | /*Get rank of first cpu that has results*/
|
---|
[12330] | 199 | #ifdef _HAVE_MPI_
|
---|
[11239] | 200 | if(this->Size()) rank=my_rank;
|
---|
| 201 | else rank=num_procs;
|
---|
[13975] | 202 | MPI_Allreduce (&rank,&minrank,1,MPI_INT,MPI_MIN,IssmComm::GetComm());
|
---|
[12330] | 203 | #else
|
---|
| 204 | minrank=my_rank;
|
---|
| 205 | #endif
|
---|
[11239] | 206 |
|
---|
[11027] | 207 | /*see what the first element of this partition has in stock (this is common to all partitions)*/
|
---|
[11239] | 208 | if(my_rank==minrank){
|
---|
[13395] | 209 | if(this->Size()==0) _error_("Cannot write results because there is no element??");
|
---|
[13975] | 210 | Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(0));
|
---|
[11027] | 211 | element->ListResultsInfo(&resultsenums,&resultssizes,&resultstimes,&resultssteps,&numberofresults);
|
---|
| 212 | }
|
---|
[12330] | 213 | #ifdef _HAVE_MPI_
|
---|
[13975] | 214 | MPI_Bcast(&numberofresults,1,MPI_DOUBLE,minrank,IssmComm::GetComm());
|
---|
[12330] | 215 | #endif
|
---|
[11239] | 216 |
|
---|
[11027] | 217 | /*Get out if there is no results. Otherwise broadcast info*/
|
---|
| 218 | if(!numberofresults) return;
|
---|
[12330] | 219 | #ifdef _HAVE_MPI_
|
---|
[11239] | 220 | if(my_rank!=minrank){
|
---|
[12706] | 221 | resultsenums=xNew<int>(numberofresults);
|
---|
| 222 | resultssizes=xNew<int>(numberofresults);
|
---|
| 223 | resultstimes=xNew<IssmDouble>(numberofresults);
|
---|
| 224 | resultssteps=xNew<int>(numberofresults);
|
---|
[11027] | 225 | }
|
---|
[13975] | 226 | MPI_Bcast(resultsenums,numberofresults,MPI_INT,minrank,IssmComm::GetComm());
|
---|
| 227 | MPI_Bcast(resultssizes,numberofresults,MPI_INT,minrank,IssmComm::GetComm());
|
---|
| 228 | MPI_Bcast(resultstimes,numberofresults,MPI_DOUBLE,minrank,IssmComm::GetComm());
|
---|
| 229 | MPI_Bcast(resultssteps,numberofresults,MPI_INT,minrank,IssmComm::GetComm());
|
---|
[12330] | 230 | #endif
|
---|
[11027] | 231 |
|
---|
[9874] | 232 | /*Loop over all results and get nodal vector*/
|
---|
| 233 | for(int i=0;i<numberofresults;i++){
|
---|
| 234 |
|
---|
| 235 | /*Get vector for result number i*/
|
---|
[11027] | 236 | if(resultssizes[i]==P1Enum) vectorsize=numberofvertices;
|
---|
| 237 | else if(resultssizes[i]==P0Enum) vectorsize=numberofelements;
|
---|
[13395] | 238 | else _error_("Unkown result size: " << EnumToStringx(resultssizes[i]));
|
---|
| 239 | vector=new Vector<IssmDouble>(vectorsize);
|
---|
[11027] | 240 |
|
---|
[9874] | 241 | for(int j=0;j<this->Size();j++){
|
---|
[13975] | 242 | Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(j));
|
---|
[12630] | 243 | element->GetVectorFromResults(vector,i,resultsenums[i],resultssizes[i]);
|
---|
[9874] | 244 | }
|
---|
[11995] | 245 | vector->Assemble();
|
---|
[9874] | 246 |
|
---|
| 247 | /*Serialize and add to results*/
|
---|
[11995] | 248 | vector_serial=vector->ToMPISerial();
|
---|
[9878] | 249 | if(my_rank==0){
|
---|
[9879] | 250 | /*No need to add this vector for all cpus*/
|
---|
[13395] | 251 | #ifdef _HAVE_ADOLC_
|
---|
| 252 | IssmPDouble* vector_serial_passive=xNew<IssmPDouble>(vectorsize);
|
---|
| 253 | for(int k=0;k<vectorsize;k++)vector_serial_passive[k]=reCast<IssmPDouble>(vector_serial[k]);
|
---|
| 254 | results->AddObject(new GenericExternalResult<double*>(results->Size()+1,resultsenums[i],vector_serial_passive,vectorsize,1,resultssteps[i],resultstimes[i]));
|
---|
| 255 | xDelete<IssmPDouble>(vector_serial_passive);
|
---|
| 256 | #else
|
---|
| 257 | results->AddObject(new GenericExternalResult<double*>(results->Size()+1,resultsenums[i],vector_serial,vectorsize,1,resultssteps[i],resultstimes[i]));
|
---|
| 258 | #endif
|
---|
[9878] | 259 | }
|
---|
[9874] | 260 |
|
---|
| 261 | /*clean up*/
|
---|
[11995] | 262 | xdelete(&vector);
|
---|
[12706] | 263 | xDelete<IssmDouble>(vector_serial);
|
---|
[9874] | 264 | }
|
---|
| 265 | }
|
---|
| 266 | else{
|
---|
| 267 | /*create patch object out of all results in this dataset: */
|
---|
| 268 | patch=this->ResultsToPatch();
|
---|
| 269 |
|
---|
| 270 | /*Gather onto master cpu 0, if needed: */
|
---|
| 271 | if(io_gather)patch->Gather();
|
---|
[6411] | 272 |
|
---|
[9874] | 273 | /*create result object and add to results dataset:*/
|
---|
| 274 | if (patch->maxvertices && patch->maxnodes){
|
---|
[13395] | 275 | results->AddObject(new GenericExternalResult<int>(results->Size()+1,PatchVerticesEnum,patch->maxvertices,1,0));
|
---|
| 276 | results->AddObject(new GenericExternalResult<int>(results->Size()+1,PatchNodesEnum, patch->maxnodes,1,0));
|
---|
| 277 | #ifdef _HAVE_ADOLC_
|
---|
| 278 | IssmPDouble* values_passive=xNew<IssmPDouble>(patch->numrows*patch->numcols);
|
---|
| 279 | for(int k=0;k<(patch->numrows*patch->numcols);k++)values_passive[k]=reCast<IssmPDouble>(patch->values[k]);
|
---|
| 280 | results->AddObject(new GenericExternalResult<double*>(results->Size()+1,PatchEnum, values_passive,patch->numrows,patch->numcols,1,0));
|
---|
| 281 | xDelete<IssmPDouble>(values_passive);
|
---|
| 282 | #else
|
---|
| 283 | results->AddObject(new GenericExternalResult<double*>(results->Size()+1,PatchEnum, patch->values,patch->numrows,patch->numcols,1,0));
|
---|
| 284 | #endif
|
---|
[9874] | 285 | }
|
---|
[6411] | 286 | }
|
---|
| 287 |
|
---|
| 288 | /*Free ressources:*/
|
---|
[12706] | 289 | xDelete<int>(resultsenums);
|
---|
| 290 | xDelete<int>(resultssizes);
|
---|
| 291 | xDelete<int>(resultssteps);
|
---|
| 292 | xDelete<IssmDouble>(resultstimes);
|
---|
[6411] | 293 | delete patch;
|
---|
| 294 | }
|
---|
| 295 | /*}}}*/
|
---|
[13975] | 296 | /*FUNCTION Elements::MaxNumNodes{{{*/
|
---|
| 297 | int Elements::MaxNumNodes(void){
|
---|
| 298 |
|
---|
| 299 | int max=0;
|
---|
| 300 | int allmax;
|
---|
| 301 | int numnodes=0;
|
---|
| 302 |
|
---|
| 303 | /*Now go through all elements, and get how many nodes they own, unless they are clone nodes: */
|
---|
| 304 | for(int i=0;i<this->Size();i++){
|
---|
| 305 |
|
---|
| 306 | Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
|
---|
| 307 | numnodes=element->GetNumberOfNodes();
|
---|
| 308 | if(numnodes>max)max=numnodes;
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | /*Grab max of all cpus: */
|
---|
| 312 | #ifdef _HAVE_MPI_
|
---|
| 313 | MPI_Allreduce((void*)&max,(void*)&allmax,1,MPI_INT,MPI_MAX,IssmComm::GetComm());
|
---|
| 314 | max=allmax;
|
---|
| 315 | #endif
|
---|
| 316 |
|
---|
| 317 | return max;
|
---|
| 318 | }
|
---|
| 319 | /*}}}*/
|
---|
[12706] | 320 | /*FUNCTION Elements::NumberOfElements{{{*/
|
---|
[7089] | 321 | int Elements::NumberOfElements(void){
|
---|
| 322 |
|
---|
[13975] | 323 | int local_nelem;
|
---|
[7089] | 324 | int numberofelements;
|
---|
| 325 |
|
---|
| 326 | local_nelem=this->Size();
|
---|
[12330] | 327 | #ifdef _HAVE_MPI_
|
---|
[13975] | 328 | MPI_Allreduce ( (void*)&local_nelem,(void*)&numberofelements,1,MPI_INT,MPI_SUM,IssmComm::GetComm());
|
---|
[7089] | 329 | #else
|
---|
[12330] | 330 | numberofelements=local_nelem;
|
---|
[7089] | 331 | #endif
|
---|
| 332 |
|
---|
| 333 | return numberofelements;
|
---|
| 334 | }
|
---|
| 335 | /*}}}*/
|
---|
[12706] | 336 | /*FUNCTION Elements::InputCopy{{{*/
|
---|
[8967] | 337 | void Elements::InputDuplicate(int input_enum,int output_enum){
|
---|
| 338 |
|
---|
[9211] | 339 | for(int i=0;i<this->Size();i++){
|
---|
[13975] | 340 | Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
|
---|
[8967] | 341 | element->InputDuplicate(input_enum,output_enum);
|
---|
| 342 | }
|
---|
| 343 | }
|
---|
| 344 | /*}}}*/
|
---|