source: XIOS/trunk/src/node/context.cpp @ 823

Last change on this file since 823 was 823, checked in by mhnguyen, 8 years ago

Implementing grid destination clone in case of two grid source

+) Clone attributes of grid destination as well as its transformation
+) Clean some redundant codes

Test
+) All tests pass

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