source: XIOS/dev/branch_openmp/src/node/context.cpp @ 1328

Last change on this file since 1328 was 1328, checked in by yushan, 6 years ago

dev_omp

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