source: XIOS/dev/branch_yushan_merged/src/node/context.cpp @ 1157

Last change on this file since 1157 was 1157, checked in by yushan, 7 years ago

branch re-merged with trunk @1156

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 43.9 KB
Line 
1#include "context.hpp"
2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
5
6#include "calendar_type.hpp"
7#include "duration.hpp"
8
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
12#include "node_type.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "timer.hpp"
17#include "memtrack.hpp"
18
19namespace xios {
20
21  //shared_ptr<CContextGroup> CContext::root;
22  shared_ptr<CContextGroup> * CContext::root_ptr = 0;
23
24   /// ////////////////////// Dfinitions ////////////////////// ///
25
26   CContext::CContext(void)
27      : CObjectTemplate<CContext>(), CContextAttributes()
28      , calendar(), hasClient(false), hasServer(false), isPostProcessed(false), finalized(false)
29      , idServer_(), client(0), server(0)
30   { /* Ne rien faire de plus */ }
31
32   CContext::CContext(const StdString & id)
33      : CObjectTemplate<CContext>(id), CContextAttributes()
34      , calendar(), hasClient(false), hasServer(false), isPostProcessed(false), finalized(false)
35      , idServer_(), client(0), server(0)
36   { /* Ne rien faire de plus */ }
37
38   CContext::~CContext(void)
39   {
40     delete client;
41     delete server;
42   }
43
44   //----------------------------------------------------------------
45   //! Get name of context
46   StdString CContext::GetName(void)   { return (StdString("context")); }
47   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
48   ENodeType CContext::GetType(void)   { return (eContext); }
49
50   //----------------------------------------------------------------
51
52   /*!
53   \brief Get context group (context root)
54   \return Context root
55   */
56   CContextGroup* CContext::getRoot(void)
57   {
58      //if (root.get()==NULL) root=shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
59      //return root.get();
60
61      //static shared_ptr<CContextGroup> *root_ptr;
62      if(root_ptr == 0) //root_ptr = new shared_ptr<CContextGroup>;
63      // if (root_ptr->get()==NULL)
64      root_ptr = new shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
65      return root_ptr->get();
66   }
67
68   //----------------------------------------------------------------
69
70   /*!
71   \brief Get calendar of a context
72   \return Calendar
73   */
74   boost::shared_ptr<CCalendar> CContext::getCalendar(void) const
75   {
76      return (this->calendar);
77   }
78
79   //----------------------------------------------------------------
80
81   /*!
82   \brief Set a context with a calendar
83   \param[in] newCalendar new calendar
84   */
85   void CContext::setCalendar(boost::shared_ptr<CCalendar> newCalendar)
86   {
87      this->calendar = newCalendar;
88   }
89
90   //----------------------------------------------------------------
91   /*!
92   \brief Parse xml file and write information into context object
93   \param [in] node xmld node corresponding in xml file
94   */
95   void CContext::parse(xml::CXMLNode & node)
96   {
97      CContext::SuperClass::parse(node);
98
99      // PARSING POUR GESTION DES ENFANTS
100      xml::THashAttributes attributes = node.getAttributes();
101
102      if (attributes.end() != attributes.find("src"))
103      {
104         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
105         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
106            ERROR("void CContext::parse(xml::CXMLNode & node)",
107                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
108         if (!ifs.good())
109            ERROR("CContext::parse(xml::CXMLNode & node)",
110                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
111         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
112      }
113
114      if (node.getElementName().compare(CContext::GetName()))
115         DEBUG("Le noeud is wrong defined but will be considered as a context !");
116
117      if (!(node.goToChildElement()))
118      {
119         DEBUG("Le context ne contient pas d'enfant !");
120      }
121      else
122      {
123         do { // Parcours des contextes pour traitement.
124
125            StdString name = node.getElementName();
126            attributes.clear();
127            attributes = node.getAttributes();
128
129            if (attributes.end() != attributes.find("id"))
130            {
131              DEBUG(<< "Definition node has an id,"
132                    << "it will not be taking account !");
133            }
134
135#define DECLARE_NODE(Name_, name_)    \
136   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
137   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
138#define DECLARE_NODE_PAR(Name_, name_)
139#include "node_type.conf"
140
141            DEBUG(<< "The element \'"     << name
142                  << "\' in the context \'" << CContext::getCurrent()->getId()
143                  << "\' is not a definition !");
144
145         } while (node.goToNextElement());
146
147         node.goToParentElement(); // Retour au parent
148      }
149   }
150
151   //----------------------------------------------------------------
152   //! Show tree structure of context
153   void CContext::ShowTree(StdOStream & out)
154   {
155      StdString currentContextId = CContext::getCurrent() -> getId();
156      std::vector<CContext*> def_vector =
157         CContext::getRoot()->getChildList();
158      std::vector<CContext*>::iterator
159         it = def_vector.begin(), end = def_vector.end();
160
161      out << "<? xml version=\"1.0\" ?>" << std::endl;
162      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
163
164      for (; it != end; it++)
165      {
166         CContext* context = *it;
167         CContext::setCurrent(context->getId());
168         out << *context << std::endl;
169      }
170
171      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
172      CContext::setCurrent(currentContextId);
173   }
174
175
176   //----------------------------------------------------------------
177
178   //! Convert context object into string (to print)
179   StdString CContext::toString(void) const
180   {
181      StdOStringStream oss;
182      oss << "<" << CContext::GetName()
183          << " id=\"" << this->getId() << "\" "
184          << SuperClassAttribute::toString() << ">" << std::endl;
185      if (!this->hasChild())
186      {
187         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrmentation
188      }
189      else
190      {
191
192#define DECLARE_NODE(Name_, name_)    \
193   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
194   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
195#define DECLARE_NODE_PAR(Name_, name_)
196#include "node_type.conf"
197
198      }
199
200      oss << "</" << CContext::GetName() << " >";
201
202      return (oss.str());
203   }
204
205   //----------------------------------------------------------------
206
207   /*!
208   \brief Find all inheritace among objects in a context.
209   \param [in] apply (true) write attributes of parent into ones of child if they are empty
210                     (false) write attributes of parent into a new container of child
211   \param [in] parent unused
212   */
213   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
214   {
215#define DECLARE_NODE(Name_, name_)    \
216   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
217     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
218#define DECLARE_NODE_PAR(Name_, name_)
219#include "node_type.conf"
220   }
221
222   //----------------------------------------------------------------
223
224   //! Verify if all root definition in the context have child.
225   bool CContext::hasChild(void) const
226   {
227      return (
228#define DECLARE_NODE(Name_, name_)    \
229   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
230#define DECLARE_NODE_PAR(Name_, name_)
231#include "node_type.conf"
232      false);
233}
234
235   //----------------------------------------------------------------
236
237   void CContext::CleanTree(void)
238   {
239#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
240#define DECLARE_NODE_PAR(Name_, name_)
241#include "node_type.conf"
242   }
243   ///---------------------------------------------------------------
244
245   //! Initialize client side
246   void CContext::initClient(ep_lib::MPI_Comm intraComm, ep_lib::MPI_Comm interComm, CContext* cxtServer /*= 0*/)
247   {
248     hasClient=true;
249     client = new CContextClient(this, intraComm, interComm, cxtServer);
250
251     int tmp_rank;
252     MPI_Comm_rank(intraComm, &tmp_rank);
253     MPI_Barrier(intraComm);
254     
255
256     registryIn=new CRegistry(intraComm);
257     registryIn->setPath(getId()) ;
258     if (client->clientRank==0) registryIn->fromFile("xios_registry.bin") ;
259     registryIn->bcastRegistry() ;
260
261     registryOut=new CRegistry(intraComm) ;
262     registryOut->setPath(getId()) ;
263
264     ep_lib::MPI_Comm intraCommServer, interCommServer;
265     if (cxtServer) // Attached mode
266     {
267       intraCommServer = intraComm;
268       interCommServer = interComm;
269     }
270     else
271     {
272       MPI_Comm_dup(intraComm, &intraCommServer);
273       comms.push_back(intraCommServer);
274       MPI_Comm_dup(interComm, &interCommServer);
275       comms.push_back(interCommServer);
276     }
277     server = new CContextServer(this,intraCommServer,interCommServer);
278   }
279
280   void CContext::setClientServerBuffer()
281   {
282     size_t minBufferSize = CXios::minBufferSize;
283#define DECLARE_NODE(Name_, name_)    \
284     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
285#define DECLARE_NODE_PAR(Name_, name_)
286#include "node_type.conf"
287#undef DECLARE_NODE
288#undef DECLARE_NODE_PAR
289
290     std::map<int, StdSize> maxEventSize;
291     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize);
292     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize);
293
294     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
295     for (it = dataBufferSize.begin(); it != ite; ++it)
296       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
297
298     ite = bufferSize.end();
299     for (it = bufferSize.begin(); it != ite; ++it)
300     {
301       it->second *= CXios::bufferSizeFactor;
302       if (it->second < minBufferSize) it->second = minBufferSize;
303     }
304
305     // We consider that the minimum buffer size is also the minimum event size
306     ite = maxEventSize.end();
307     for (it = maxEventSize.begin(); it != ite; ++it)
308       if (it->second < minBufferSize) it->second = minBufferSize;
309
310     if (client->isServerLeader())
311     {
312       const std::list<int>& ranks = client->getRanksServerLeader();
313       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
314         if (!bufferSize.count(*itRank)) bufferSize[*itRank] = maxEventSize[*itRank] = minBufferSize;
315     }
316
317     client->setBufferSize(bufferSize, maxEventSize);
318   }
319
320   //! Verify whether a context is initialized
321   bool CContext::isInitialized(void)
322   {
323     return hasClient;
324   }
325
326   //! Initialize server
327   void CContext::initServer(ep_lib::MPI_Comm intraComm, ep_lib::MPI_Comm interComm, CContext* cxtClient /*= 0*/)
328   {
329     hasServer=true;
330     server = new CContextServer(this,intraComm,interComm);
331
332     registryIn=new CRegistry(intraComm);
333     registryIn->setPath(getId()) ;
334     if (server->intraCommRank==0) registryIn->fromFile("xios_registry.bin") ;
335     registryIn->bcastRegistry() ;
336     registryOut=new CRegistry(intraComm) ;
337     registryOut->setPath(getId()) ;
338
339     ep_lib::MPI_Comm intraCommClient, interCommClient;
340     if (cxtClient) // Attached mode
341     {
342       intraCommClient = intraComm;
343       interCommClient = interComm;
344     }
345     else
346     {
347       MPI_Comm_dup(intraComm, &intraCommClient);
348       comms.push_back(intraCommClient);
349       MPI_Comm_dup(interComm, &interCommClient);
350       comms.push_back(interCommClient);
351     }
352     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
353   }
354
355   //! Try to send the buffers and receive possible answers
356   bool CContext::checkBuffersAndListen(void)
357   {
358     client->checkBuffers();
359
360     bool hasTmpBufferedEvent = client->hasTemporarilyBufferedEvent();
361     if (hasTmpBufferedEvent)
362       hasTmpBufferedEvent = !client->sendTemporarilyBufferedEvent();
363
364     // Don't process events if there is a temporarily buffered event
365     return server->eventLoop(!hasTmpBufferedEvent);
366   }
367
368   //! Terminate a context
369   void CContext::finalize(void)
370   {
371      if (!finalized)
372      {
373        finalized = true;
374        if (hasClient) sendRegistry() ;
375        client->finalize();
376        while (!server->hasFinished())
377        {
378          server->eventLoop();
379        }
380
381        if (hasServer)
382        {
383          closeAllFile();
384          registryOut->hierarchicalGatherRegistry() ;
385          if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
386        }
387
388        for (std::list<ep_lib::MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
389          MPI_Comm_free(&(*it));
390        comms.clear();
391      }
392   }
393
394   /*!
395   \brief Close all the context defintion and do processing data
396      After everything is well defined on client side, they will be processed and sent to server
397   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
398   all necessary information to server, from which each server can build its own database.
399   Because the role of server is to write out field data on a specific netcdf file,
400   the only information that it needs is the enabled files
401   and the active fields (fields will be written onto active files)
402   */
403   void CContext::closeDefinition(void)
404   {
405     CTimer::get("Context : close definition").resume() ;
406     // There is nothing client need to send to server
407     if (hasClient)
408     {
409       // After xml is parsed, there are some more works with post processing
410       postProcessing();
411     }
412     setClientServerBuffer();
413
414     if (hasClient && !hasServer)
415     {
416      // Send all attributes of current context to server
417      this->sendAllAttributesToServer();
418
419      // Send all attributes of current calendar
420      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
421
422      // We have enough information to send to server
423      // First of all, send all enabled files
424       sendEnabledFiles();
425
426      // Then, send all enabled fields
427       sendEnabledFields();
428
429      // At last, we have all info of domain and axis, then send them
430       sendRefDomainsAxis();
431
432      // After that, send all grid (if any)
433       sendRefGrid();
434    }
435
436    // We have a xml tree on the server side and now, it should be also processed
437    if (hasClient && !hasServer) sendPostProcessing();
438
439    // There are some processings that should be done after all of above. For example: check mask or index
440    if (hasClient)
441    {
442      this->buildFilterGraphOfEnabledFields();
443      buildFilterGraphOfFieldsWithReadAccess();
444      this->solveAllRefOfEnabledFields(true);
445    }
446
447    // Now tell server that it can process all messages from client
448    if (hasClient && !hasServer) this->sendCloseDefinition();
449
450    // Nettoyage de l'arborescence
451    if (hasClient && !hasServer) CleanTree(); // Only on client side??
452
453    if (hasClient)
454    {
455      sendCreateFileHeader();
456
457      startPrefetchingOfEnabledReadModeFiles();
458    }
459    CTimer::get("Context : close definition").suspend() ;
460   }
461
462   void CContext::findAllEnabledFields(void)
463   {
464     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
465     (void)this->enabledFiles[i]->getEnabledFields();
466   }
467
468   void CContext::findAllEnabledFieldsInReadModeFiles(void)
469   {
470     for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
471     (void)this->enabledReadModeFiles[i]->getEnabledFields();
472   }
473
474   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
475   {
476      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
477        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
478   }
479
480   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
481   {
482     int size = this->enabledFiles.size();
483     for (int i = 0; i < size; ++i)
484     {
485       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
486     }
487
488     for (int i = 0; i < size; ++i)
489     {
490       this->enabledFiles[i]->generateNewTransformationGridDest();
491     }
492   }
493
494   void CContext::solveAllRefOfEnabledFields(bool sendToServer)
495   {
496     int size = this->enabledFiles.size();
497     for (int i = 0; i < size; ++i)
498     {
499       this->enabledFiles[i]->solveAllRefOfEnabledFields(sendToServer);
500     }
501   }
502
503   void CContext::buildFilterGraphOfEnabledFields()
504   {
505     int size = this->enabledFiles.size();
506     for (int i = 0; i < size; ++i)
507     {
508       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
509     }
510   }
511
512   void CContext::startPrefetchingOfEnabledReadModeFiles()
513   {
514     int size = enabledReadModeFiles.size();
515     for (int i = 0; i < size; ++i)
516     {
517        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
518     }
519   }
520
521   void CContext::checkPrefetchingOfEnabledReadModeFiles()
522   {
523     int size = enabledReadModeFiles.size();
524     for (int i = 0; i < size; ++i)
525     {
526        enabledReadModeFiles[i]->prefetchEnabledReadModeFieldsIfNeeded();
527     }
528   }
529
530  void CContext::findFieldsWithReadAccess(void)
531  {
532    fieldsWithReadAccess.clear();
533    const vector<CField*> allFields = CField::getAll();
534    for (size_t i = 0; i < allFields.size(); ++i)
535    {
536      CField* field = allFields[i];
537
538      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
539        field->read_access = true;
540      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
541        fieldsWithReadAccess.push_back(field);
542    }
543  }
544
545  void CContext::solveAllRefOfFieldsWithReadAccess()
546  {
547    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
548      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
549  }
550
551  void CContext::buildFilterGraphOfFieldsWithReadAccess()
552  {
553    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
554      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
555  }
556
557   void CContext::solveAllInheritance(bool apply)
558   {
559     // Rsolution des hritages descendants (cd des hritages de groupes)
560     // pour chacun des contextes.
561      solveDescInheritance(apply);
562
563     // Rsolution des hritages par rfrence au niveau des fichiers.
564      const vector<CFile*> allFiles=CFile::getAll();
565      const vector<CGrid*> allGrids= CGrid::getAll();
566
567     //if (hasClient && !hasServer)
568      if (hasClient)
569      {
570        for (unsigned int i = 0; i < allFiles.size(); i++)
571          allFiles[i]->solveFieldRefInheritance(apply);
572      }
573
574      unsigned int vecSize = allGrids.size();
575      unsigned int i = 0;
576      for (i = 0; i < vecSize; ++i)
577        allGrids[i]->solveDomainAxisRefInheritance(apply);
578
579   }
580
581   void CContext::findEnabledFiles(void)
582   {
583      const std::vector<CFile*> allFiles = CFile::getAll();
584      const CDate& initDate = calendar->getInitDate();
585
586      for (unsigned int i = 0; i < allFiles.size(); i++)
587         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est dfini.
588         {
589            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fix  vrai.
590            {
591              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
592              {
593                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
594                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
595                    <<"\" is less than the time step. File will not be written."<<endl;
596              }
597              else
598               enabledFiles.push_back(allFiles[i]);
599            }
600         }
601         else
602         {
603           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
604           {
605             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
606                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
607                 <<"\" is less than the time step. File will not be written."<<endl;
608           }
609           else
610             enabledFiles.push_back(allFiles[i]); // otherwise true by default
611         }
612
613      if (enabledFiles.size() == 0)
614         DEBUG(<<"Aucun fichier ne va tre sorti dans le contexte nomm \""
615               << getId() << "\" !");
616   }
617
618   void CContext::findEnabledReadModeFiles(void)
619   {
620     int size = this->enabledFiles.size();
621     for (int i = 0; i < size; ++i)
622     {
623       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
624        enabledReadModeFiles.push_back(enabledFiles[i]);
625     }
626   }
627
628   void CContext::closeAllFile(void)
629   {
630     std::vector<CFile*>::const_iterator
631            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
632
633     for (; it != end; it++)
634     {
635       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
636       (*it)->close();
637     }
638   }
639
640   /*!
641   \brief Dispatch event received from client
642      Whenever a message is received in buffer of server, it will be processed depending on
643   its event type. A new event type should be added in the switch list to make sure
644   it processed on server side.
645   \param [in] event: Received message
646   */
647   bool CContext::dispatchEvent(CEventServer& event)
648   {
649
650      if (SuperClass::dispatchEvent(event)) return true;
651      else
652      {
653        switch(event.type)
654        {
655           case EVENT_ID_CLOSE_DEFINITION :
656             recvCloseDefinition(event);
657             return true;
658             break;
659           case EVENT_ID_UPDATE_CALENDAR:
660             recvUpdateCalendar(event);
661             return true;
662             break;
663           case EVENT_ID_CREATE_FILE_HEADER :
664             recvCreateFileHeader(event);
665             return true;
666             break;
667           case EVENT_ID_POST_PROCESS:
668             recvPostProcessing(event);
669             return true;
670            case EVENT_ID_SEND_REGISTRY:
671             recvRegistry(event);
672             return true;
673            break;
674
675           default :
676             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
677                    <<"Unknown Event");
678           return false;
679         }
680      }
681   }
682
683   //! Client side: Send a message to server to make it close
684   void CContext::sendCloseDefinition(void)
685   {
686     CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
687     if (client->isServerLeader())
688     {
689       CMessage msg;
690       msg<<this->getIdServer();
691       const std::list<int>& ranks = client->getRanksServerLeader();
692       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
693         event.push(*itRank,1,msg);
694       client->sendEvent(event);
695     }
696     else client->sendEvent(event);
697   }
698
699   //! Server side: Receive a message of client announcing a context close
700   void CContext::recvCloseDefinition(CEventServer& event)
701   {
702
703      CBufferIn* buffer=event.subEvents.begin()->buffer;
704      string id;
705      *buffer>>id;
706      get(id)->closeDefinition();
707   }
708
709   //! Client side: Send a message to update calendar in each time step
710   void CContext::sendUpdateCalendar(int step)
711   {
712     if (!hasServer)
713     {
714       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
715       if (client->isServerLeader())
716       {
717         CMessage msg;
718         msg<<this->getIdServer()<<step;
719         const std::list<int>& ranks = client->getRanksServerLeader();
720         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
721           event.push(*itRank,1,msg);
722         client->sendEvent(event);
723       }
724       else client->sendEvent(event);
725     }
726   }
727
728   //! Server side: Receive a message of client annoucing calendar update
729   void CContext::recvUpdateCalendar(CEventServer& event)
730   {
731      CBufferIn* buffer=event.subEvents.begin()->buffer;
732      string id;
733      *buffer>>id;
734      get(id)->recvUpdateCalendar(*buffer);
735   }
736
737   //! Server side: Receive a message of client annoucing calendar update
738   void CContext::recvUpdateCalendar(CBufferIn& buffer)
739   {
740      int step;
741      buffer>>step;
742      updateCalendar(step);
743   }
744
745   //! Client side: Send a message to create header part of netcdf file
746   void CContext::sendCreateFileHeader(void)
747   {
748     CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
749     if (client->isServerLeader())
750     {
751       CMessage msg;
752       msg<<this->getIdServer();
753       const std::list<int>& ranks = client->getRanksServerLeader();
754       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
755         event.push(*itRank,1,msg) ;
756       client->sendEvent(event);
757     }
758     else client->sendEvent(event);
759   }
760
761   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
762   void CContext::recvCreateFileHeader(CEventServer& event)
763   {
764      CBufferIn* buffer=event.subEvents.begin()->buffer;
765      string id;
766      *buffer>>id;
767      get(id)->recvCreateFileHeader(*buffer);
768   }
769
770   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
771   void CContext::recvCreateFileHeader(CBufferIn& buffer)
772   {
773      createFileHeader();
774   }
775
776   //! Client side: Send a message to do some post processing on server
777   void CContext::sendPostProcessing()
778   {
779     if (!hasServer)
780     {
781       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
782       if (client->isServerLeader())
783       {
784         CMessage msg;
785         msg<<this->getIdServer();
786         const std::list<int>& ranks = client->getRanksServerLeader();
787         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
788           event.push(*itRank,1,msg);
789         client->sendEvent(event);
790       }
791       else client->sendEvent(event);
792     }
793   }
794
795   //! Server side: Receive a message to do some post processing
796   void CContext::recvPostProcessing(CEventServer& event)
797   {
798      CBufferIn* buffer=event.subEvents.begin()->buffer;
799      string id;
800      *buffer>>id;
801      get(id)->recvPostProcessing(*buffer);
802   }
803
804   //! Server side: Receive a message to do some post processing
805   void CContext::recvPostProcessing(CBufferIn& buffer)
806   {
807      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
808      postProcessing();
809   }
810
811   const StdString& CContext::getIdServer()
812   {
813      if (hasClient)
814      {
815        idServer_ = this->getId();
816        idServer_ += "_server";
817        return idServer_;
818      }
819      if (hasServer) return (this->getId());
820   }
821
822   /*!
823   \brief Do some simple post processings after parsing xml file
824      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
825   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
826   which will be written out into netcdf files, are processed
827   */
828   void CContext::postProcessing()
829   {
830     int myRank;
831     MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
832
833     if (isPostProcessed) return;
834
835      // Make sure the calendar was correctly created
836      if (!calendar)
837        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
838      else if (calendar->getTimeStep() == NoneDu)
839        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
840      // Calendar first update to set the current date equals to the start date
841      calendar->update(0);
842
843      // Find all inheritance in xml structure
844      this->solveAllInheritance();
845
846      // Check if some axis, domains or grids are eligible to for compressed indexed output.
847      // Warning: This must be done after solving the inheritance and before the rest of post-processing
848      checkAxisDomainsGridsEligibilityForCompressedOutput();
849
850      // Check if some automatic time series should be generated
851      // Warning: This must be done after solving the inheritance and before the rest of post-processing
852      prepareTimeseries();
853
854      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers  sortir.
855      this->findEnabledFiles();
856      this->findEnabledReadModeFiles();
857
858      // Find all enabled fields of each file
859      this->findAllEnabledFields();
860      this->findAllEnabledFieldsInReadModeFiles();
861
862     if (hasClient && !hasServer)
863     {
864      // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
865      this->readAttributesOfEnabledFieldsInReadModeFiles();
866     }
867
868      // Only search and rebuild all reference objects of enable fields, don't transform
869      this->solveOnlyRefOfEnabledFields(false);
870
871      // Search and rebuild all reference object of enabled fields
872      this->solveAllRefOfEnabledFields(false);
873
874      // Find all fields with read access from the public API
875      findFieldsWithReadAccess();
876      // and solve the all reference for them
877      solveAllRefOfFieldsWithReadAccess();
878
879      isPostProcessed = true;
880   }
881
882   /*!
883    * Compute the required buffer size to send the attributes (mostly those grid related).
884    *
885    * \param maxEventSize [in/out] the size of the bigger event for each connected server
886    */
887   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize)
888   {
889     std::map<int, StdSize> attributesSize;
890
891     if (hasClient)
892     {
893       size_t numEnabledFiles = this->enabledFiles.size();
894       for (size_t i = 0; i < numEnabledFiles; ++i)
895       {
896         CFile* file = this->enabledFiles[i];
897
898         std::vector<CField*> enabledFields = file->getEnabledFields();
899         size_t numEnabledFields = enabledFields.size();
900         for (size_t j = 0; j < numEnabledFields; ++j)
901         {
902           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize();
903           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
904           for (; it != itE; ++it)
905           {
906             // If attributesSize[it->first] does not exist, it will be zero-initialized
907             // so we can use it safely without checking for its existance
908             if (attributesSize[it->first] < it->second)
909               attributesSize[it->first] = it->second;
910
911             if (maxEventSize[it->first] < it->second)
912               maxEventSize[it->first] = it->second;
913           }
914         }
915       }
916     }
917
918     return attributesSize;
919   }
920
921   /*!
922    * Compute the required buffer size to send the fields data.
923    *
924    * \param maxEventSize [in/out] the size of the bigger event for each connected server
925    */
926   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize)
927   {
928     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
929
930     std::map<int, StdSize> dataSize;
931
932     // Find all reference domain and axis of all active fields
933     size_t numEnabledFiles = this->enabledFiles.size();
934     for (size_t i = 0; i < numEnabledFiles; ++i)
935     {
936       CFile* file = this->enabledFiles[i];
937       CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
938
939       if (fileMode == mode)
940       {
941         std::vector<CField*> enabledFields = file->getEnabledFields();
942         size_t numEnabledFields = enabledFields.size();
943         for (size_t j = 0; j < numEnabledFields; ++j)
944         {
945           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize();
946           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
947           for (; it != itE; ++it)
948           {
949             // If dataSize[it->first] does not exist, it will be zero-initialized
950             // so we can use it safely without checking for its existance
951             if (CXios::isOptPerformance)
952               dataSize[it->first] += it->second;
953             else if (dataSize[it->first] < it->second)
954               dataSize[it->first] = it->second;
955
956             if (maxEventSize[it->first] < it->second)
957               maxEventSize[it->first] = it->second;
958           }
959         }
960       }
961     }
962
963     return dataSize;
964   }
965
966   //! Client side: Send infomation of active files (files are enabled to write out)
967   void CContext::sendEnabledFiles()
968   {
969     int size = this->enabledFiles.size();
970
971     // In a context, each type has a root definition, e.g: axis, domain, field.
972     // Every object must be a child of one of these root definition. In this case
973     // all new file objects created on server must be children of the root "file_definition"
974     StdString fileDefRoot("file_definition");
975     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
976
977     for (int i = 0; i < size; ++i)
978     {
979       cfgrpPtr->sendCreateChild(this->enabledFiles[i]->getId());
980       this->enabledFiles[i]->sendAllAttributesToServer();
981       this->enabledFiles[i]->sendAddAllVariables();
982     }
983   }
984
985   //! Client side: Send information of active fields (ones are written onto files)
986   void CContext::sendEnabledFields()
987   {
988     int size = this->enabledFiles.size();
989     for (int i = 0; i < size; ++i)
990     {
991       this->enabledFiles[i]->sendEnabledFields();
992     }
993   }
994
995   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
996   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
997   {
998     if (!hasClient) return;
999
1000     const vector<CAxis*> allAxis = CAxis::getAll();
1001     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1002       (*it)->checkEligibilityForCompressedOutput();
1003
1004     const vector<CDomain*> allDomains = CDomain::getAll();
1005     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1006       (*it)->checkEligibilityForCompressedOutput();
1007
1008     const vector<CGrid*> allGrids = CGrid::getAll();
1009     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1010       (*it)->checkEligibilityForCompressedOutput();
1011   }
1012
1013   //! Client side: Prepare the timeseries by adding the necessary files
1014   void CContext::prepareTimeseries()
1015   {
1016     if (!hasClient) return;
1017
1018     const std::vector<CFile*> allFiles = CFile::getAll();
1019     for (size_t i = 0; i < allFiles.size(); i++)
1020     {
1021       CFile* file = allFiles[i];
1022
1023       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1024       for (size_t k = 0; k < vars.size(); k++)
1025       {
1026         CVariable* var = vars[k];
1027
1028         if (var->ts_target.isEmpty()
1029              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1030           fileVars.push_back(var);
1031
1032         if (!var->ts_target.isEmpty()
1033              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1034           fieldVars.push_back(var);
1035       }
1036
1037       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1038       {
1039         StdString fileNameStr("%file_name%") ;
1040         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1041         
1042         StdString fileName=file->getFileOutputName();
1043         size_t pos=tsPrefix.find(fileNameStr) ;
1044         while (pos!=std::string::npos)
1045         {
1046           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1047           pos=tsPrefix.find(fileNameStr) ;
1048         }
1049       
1050         const std::vector<CField*> allFields = file->getAllFields();
1051         for (size_t j = 0; j < allFields.size(); j++)
1052         {
1053           CField* field = allFields[j];
1054
1055           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1056           {
1057             CFile* tsFile = CFile::create();
1058             tsFile->duplicateAttributes(file);
1059
1060             // Add variables originating from file and targeted to timeserie file
1061             for (size_t k = 0; k < fileVars.size(); k++)
1062               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1063
1064           
1065             tsFile->name = tsPrefix + "_";
1066             if (!field->name.isEmpty())
1067               tsFile->name.get() += field->name;
1068             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1069               tsFile->name.get() += field->field_ref;
1070             else
1071               tsFile->name.get() += field->getId();
1072
1073             if (!field->ts_split_freq.isEmpty())
1074               tsFile->split_freq = field->ts_split_freq;
1075
1076             CField* tsField = tsFile->addField();
1077             tsField->field_ref = field->getId();
1078
1079             // Add variables originating from file and targeted to timeserie field
1080             for (size_t k = 0; k < fieldVars.size(); k++)
1081               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1082
1083             vars = field->getAllVariables();
1084             for (size_t k = 0; k < vars.size(); k++)
1085             {
1086               CVariable* var = vars[k];
1087
1088               // Add variables originating from field and targeted to timeserie field
1089               if (var->ts_target.isEmpty()
1090                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1091                 tsField->getVirtualVariableGroup()->addChild(var);
1092
1093               // Add variables originating from field and targeted to timeserie file
1094               if (!var->ts_target.isEmpty()
1095                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1096                 tsFile->getVirtualVariableGroup()->addChild(var);
1097             }
1098
1099             tsFile->solveFieldRefInheritance(true);
1100
1101             if (file->timeseries == CFile::timeseries_attr::exclusive)
1102               field->enabled = false;
1103           }
1104         }
1105
1106         // Finally disable the original file is need be
1107         if (file->timeseries == CFile::timeseries_attr::only)
1108          file->enabled = false;
1109       }
1110     }
1111   }
1112
1113   //! Client side: Send information of reference grid of active fields
1114   void CContext::sendRefGrid()
1115   {
1116     std::set<StdString> gridIds;
1117     int sizeFile = this->enabledFiles.size();
1118     CFile* filePtr(NULL);
1119
1120     // Firstly, find all reference grids of all active fields
1121     for (int i = 0; i < sizeFile; ++i)
1122     {
1123       filePtr = this->enabledFiles[i];
1124       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1125       int sizeField = enabledFields.size();
1126       for (int numField = 0; numField < sizeField; ++numField)
1127       {
1128         if (0 != enabledFields[numField]->getRelGrid())
1129           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1130       }
1131     }
1132
1133     // Create all reference grids on server side
1134     StdString gridDefRoot("grid_definition");
1135     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1136     std::set<StdString>::const_iterator it, itE = gridIds.end();
1137     for (it = gridIds.begin(); it != itE; ++it)
1138     {
1139       gridPtr->sendCreateChild(*it);
1140       CGrid::get(*it)->sendAllAttributesToServer();
1141       CGrid::get(*it)->sendAllDomains();
1142       CGrid::get(*it)->sendAllAxis();
1143       CGrid::get(*it)->sendAllScalars();
1144     }
1145   }
1146
1147
1148   //! Client side: Send information of reference domain and axis of active fields
1149   void CContext::sendRefDomainsAxis()
1150   {
1151     std::set<StdString> domainIds, axisIds, scalarIds;
1152
1153     // Find all reference domain and axis of all active fields
1154     int numEnabledFiles = this->enabledFiles.size();
1155     for (int i = 0; i < numEnabledFiles; ++i)
1156     {
1157       std::vector<CField*> enabledFields = this->enabledFiles[i]->getEnabledFields();
1158       int numEnabledFields = enabledFields.size();
1159       for (int j = 0; j < numEnabledFields; ++j)
1160       {
1161         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1162         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1163         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1164         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1165       }
1166     }
1167
1168     // Create all reference axis on server side
1169     std::set<StdString>::iterator itDom, itAxis, itScalar;
1170     std::set<StdString>::const_iterator itE;
1171
1172     StdString scalarDefRoot("scalar_definition");
1173     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1174     itE = scalarIds.end();
1175     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1176     {
1177       if (!itScalar->empty())
1178       {
1179         scalarPtr->sendCreateChild(*itScalar);
1180         CScalar::get(*itScalar)->sendAllAttributesToServer();
1181       }
1182     }
1183
1184     StdString axiDefRoot("axis_definition");
1185     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1186     itE = axisIds.end();
1187     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1188     {
1189       if (!itAxis->empty())
1190       {
1191         axisPtr->sendCreateChild(*itAxis);
1192         CAxis::get(*itAxis)->sendAllAttributesToServer();
1193       }
1194     }
1195
1196     // Create all reference domains on server side
1197     StdString domDefRoot("domain_definition");
1198     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1199     itE = domainIds.end();
1200     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1201     {
1202       if (!itDom->empty()) {
1203          domPtr->sendCreateChild(*itDom);
1204          CDomain::get(*itDom)->sendAllAttributesToServer();
1205       }
1206     }
1207   }
1208
1209   //! Update calendar in each time step
1210   void CContext::updateCalendar(int step)
1211   {
1212      calendar->update(step);
1213#ifdef XIOS_MEMTRACK_LIGHT
1214      #pragma omp critical (_output)
1215      info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1216#endif
1217
1218      if (hasClient)
1219      {
1220        checkPrefetchingOfEnabledReadModeFiles();
1221        garbageCollector.invalidate(calendar->getCurrentDate());
1222      }
1223   }
1224
1225   //! Server side: Create header of netcdf file
1226   void CContext::createFileHeader(void )
1227   {
1228      vector<CFile*>::const_iterator it;
1229
1230      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1231      {
1232         (*it)->initFile();
1233      }
1234   }
1235
1236   //! Get current context
1237   CContext* CContext::getCurrent(void)
1238   {
1239     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1240   }
1241
1242   /*!
1243   \brief Set context with an id be the current context
1244   \param [in] id identity of context to be set to current
1245   */
1246   void CContext::setCurrent(const string& id)
1247   {
1248     CObjectFactory::SetCurrentContextId(id);
1249     CGroupFactory::SetCurrentContextId(id);
1250   }
1251
1252  /*!
1253  \brief Create a context with specific id
1254  \param [in] id identity of new context
1255  \return pointer to the new context or already-existed one with identity id
1256  */
1257  CContext* CContext::create(const StdString& id)
1258  {
1259    CContext::setCurrent(id);
1260
1261    bool hasctxt = CContext::has(id);
1262    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1263    getRoot();
1264    //if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1265    if (!hasctxt) CGroupFactory::AddChild(*root_ptr, context->getShared());
1266
1267#define DECLARE_NODE(Name_, name_) \
1268    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1269#define DECLARE_NODE_PAR(Name_, name_)
1270#include "node_type.conf"
1271
1272    return (context);
1273  }
1274
1275
1276
1277     //! Server side: Receive a message to do some post processing
1278  void CContext::recvRegistry(CEventServer& event)
1279  {
1280    CBufferIn* buffer=event.subEvents.begin()->buffer;
1281    string id;
1282    *buffer>>id;
1283    get(id)->recvRegistry(*buffer);
1284  }
1285
1286  void CContext::recvRegistry(CBufferIn& buffer)
1287  {
1288    if (server->intraCommRank==0)
1289    {
1290      CRegistry registry(server->intraComm) ;
1291      registry.fromBuffer(buffer) ;
1292      registryOut->mergeRegistry(registry) ;
1293    }
1294  }
1295
1296  void CContext::sendRegistry(void)
1297  {
1298    registryOut->hierarchicalGatherRegistry() ;
1299
1300    CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1301    if (client->isServerLeader())
1302    {
1303       CMessage msg ;
1304       msg<<this->getIdServer();
1305       if (client->clientRank==0) msg<<*registryOut ;
1306       const std::list<int>& ranks = client->getRanksServerLeader();
1307       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1308         event.push(*itRank,1,msg);
1309       client->sendEvent(event);
1310     }
1311     else client->sendEvent(event);
1312  }
1313
1314} // namespace xios
Note: See TracBrowser for help on using the repository browser.