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

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

branch merged with trunk @1155

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