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

Last change on this file since 801 was 775, checked in by mhnguyen, 9 years ago

Implementing the reading of attributes of an axis from a file

+) 3d grid can be read directly from a file
+) Clean some redundant codes
+) Add new attribute declaration that allows to output only desired attributes

Test
+) On Curie
+) test_remap passes and result is correct

  • 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: 37.8 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::solveAllRefOfEnabledFields(bool sendToServer)
456   {
457     int size = this->enabledFiles.size();
458     for (int i = 0; i < size; ++i)
459     {
460       this->enabledFiles[i]->solveAllRefOfEnabledFields(sendToServer);
461     }
462   }
463
464   void CContext::buildFilterGraphOfEnabledFields()
465   {
466     int size = this->enabledFiles.size();
467     for (int i = 0; i < size; ++i)
468     {
469       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
470     }
471   }
472
473   void CContext::startPrefetchingOfEnabledReadModeFiles()
474   {
475     int size = enabledReadModeFiles.size();
476     for (int i = 0; i < size; ++i)
477     {
478        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
479     }
480   }
481
482   void CContext::checkPrefetchingOfEnabledReadModeFiles()
483   {
484     int size = enabledReadModeFiles.size();
485     for (int i = 0; i < size; ++i)
486     {
487        enabledReadModeFiles[i]->prefetchEnabledReadModeFieldsIfNeeded();
488     }
489   }
490
491  void CContext::findFieldsWithReadAccess(void)
492  {
493    fieldsWithReadAccess.clear();
494    const vector<CField*> allFields = CField::getAll();
495    for (size_t i = 0; i < allFields.size(); ++i)
496    {
497      CField* field = allFields[i];
498
499      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
500        field->read_access = true;
501      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
502        fieldsWithReadAccess.push_back(field);
503    }
504  }
505
506  void CContext::solveAllRefOfFieldsWithReadAccess()
507  {
508    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
509      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
510  }
511
512  void CContext::buildFilterGraphOfFieldsWithReadAccess()
513  {
514    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
515      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
516  }
517
518   void CContext::solveAllInheritance(bool apply)
519   {
520     // Résolution des héritages descendants (càd des héritages de groupes)
521     // pour chacun des contextes.
522      solveDescInheritance(apply);
523
524     // Résolution des héritages par référence au niveau des fichiers.
525      const vector<CFile*> allFiles=CFile::getAll();
526      const vector<CGrid*> allGrids= CGrid::getAll();
527
528     //if (hasClient && !hasServer)
529      if (hasClient)
530      {
531        for (unsigned int i = 0; i < allFiles.size(); i++)
532          allFiles[i]->solveFieldRefInheritance(apply);
533      }
534
535      unsigned int vecSize = allGrids.size();
536      unsigned int i = 0;
537      for (i = 0; i < vecSize; ++i)
538        allGrids[i]->solveDomainAxisRefInheritance(apply);
539
540   }
541
542   void CContext::findEnabledFiles(void)
543   {
544      const std::vector<CFile*> allFiles = CFile::getAll();
545
546      for (unsigned int i = 0; i < allFiles.size(); i++)
547         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
548         {
549            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
550               enabledFiles.push_back(allFiles[i]);
551         }
552         else enabledFiles.push_back(allFiles[i]); // otherwise true by default
553
554
555      if (enabledFiles.size() == 0)
556         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
557               << getId() << "\" !");
558   }
559
560   void CContext::findEnabledReadModeFiles(void)
561   {
562     int size = this->enabledFiles.size();
563     for (int i = 0; i < size; ++i)
564     {
565       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
566        enabledReadModeFiles.push_back(enabledFiles[i]);
567     }
568   }
569
570   void CContext::closeAllFile(void)
571   {
572     std::vector<CFile*>::const_iterator
573            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
574
575     for (; it != end; it++)
576     {
577       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
578       (*it)->close();
579     }
580   }
581
582   /*!
583   \brief Dispatch event received from client
584      Whenever a message is received in buffer of server, it will be processed depending on
585   its event type. A new event type should be added in the switch list to make sure
586   it processed on server side.
587   \param [in] event: Received message
588   */
589   bool CContext::dispatchEvent(CEventServer& event)
590   {
591
592      if (SuperClass::dispatchEvent(event)) return true;
593      else
594      {
595        switch(event.type)
596        {
597           case EVENT_ID_CLOSE_DEFINITION :
598             recvCloseDefinition(event);
599             return true;
600             break;
601           case EVENT_ID_UPDATE_CALENDAR:
602             recvUpdateCalendar(event);
603             return true;
604             break;
605           case EVENT_ID_CREATE_FILE_HEADER :
606             recvCreateFileHeader(event);
607             return true;
608             break;
609           case EVENT_ID_POST_PROCESS:
610             recvPostProcessing(event);
611             return true;
612            case EVENT_ID_SEND_REGISTRY:
613             recvRegistry(event);
614             return true;
615            break;
616
617           default :
618             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
619                    <<"Unknown Event");
620           return false;
621         }
622      }
623   }
624
625   //! Client side: Send a message to server to make it close
626   void CContext::sendCloseDefinition(void)
627   {
628     CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
629     if (client->isServerLeader())
630     {
631       CMessage msg;
632       msg<<this->getIdServer();
633       const std::list<int>& ranks = client->getRanksServerLeader();
634       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
635         event.push(*itRank,1,msg);
636       client->sendEvent(event);
637     }
638     else client->sendEvent(event);
639   }
640
641   //! Server side: Receive a message of client announcing a context close
642   void CContext::recvCloseDefinition(CEventServer& event)
643   {
644
645      CBufferIn* buffer=event.subEvents.begin()->buffer;
646      string id;
647      *buffer>>id;
648      get(id)->closeDefinition();
649   }
650
651   //! Client side: Send a message to update calendar in each time step
652   void CContext::sendUpdateCalendar(int step)
653   {
654     if (!hasServer)
655     {
656       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
657       if (client->isServerLeader())
658       {
659         CMessage msg;
660         msg<<this->getIdServer()<<step;
661         const std::list<int>& ranks = client->getRanksServerLeader();
662         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
663           event.push(*itRank,1,msg);
664         client->sendEvent(event);
665       }
666       else client->sendEvent(event);
667     }
668   }
669
670   //! Server side: Receive a message of client annoucing calendar update
671   void CContext::recvUpdateCalendar(CEventServer& event)
672   {
673      CBufferIn* buffer=event.subEvents.begin()->buffer;
674      string id;
675      *buffer>>id;
676      get(id)->recvUpdateCalendar(*buffer);
677   }
678
679   //! Server side: Receive a message of client annoucing calendar update
680   void CContext::recvUpdateCalendar(CBufferIn& buffer)
681   {
682      int step;
683      buffer>>step;
684      updateCalendar(step);
685   }
686
687   //! Client side: Send a message to create header part of netcdf file
688   void CContext::sendCreateFileHeader(void)
689   {
690     CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
691     if (client->isServerLeader())
692     {
693       CMessage msg;
694       msg<<this->getIdServer();
695       const std::list<int>& ranks = client->getRanksServerLeader();
696       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
697         event.push(*itRank,1,msg) ;
698       client->sendEvent(event);
699     }
700     else client->sendEvent(event);
701   }
702
703   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
704   void CContext::recvCreateFileHeader(CEventServer& event)
705   {
706      CBufferIn* buffer=event.subEvents.begin()->buffer;
707      string id;
708      *buffer>>id;
709      get(id)->recvCreateFileHeader(*buffer);
710   }
711
712   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
713   void CContext::recvCreateFileHeader(CBufferIn& buffer)
714   {
715      createFileHeader();
716   }
717
718   //! Client side: Send a message to do some post processing on server
719   void CContext::sendPostProcessing()
720   {
721     if (!hasServer)
722     {
723       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
724       if (client->isServerLeader())
725       {
726         CMessage msg;
727         msg<<this->getIdServer();
728         const std::list<int>& ranks = client->getRanksServerLeader();
729         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
730           event.push(*itRank,1,msg);
731         client->sendEvent(event);
732       }
733       else client->sendEvent(event);
734     }
735   }
736
737   //! Server side: Receive a message to do some post processing
738   void CContext::recvPostProcessing(CEventServer& event)
739   {
740      CBufferIn* buffer=event.subEvents.begin()->buffer;
741      string id;
742      *buffer>>id;
743      get(id)->recvPostProcessing(*buffer);
744   }
745
746   //! Server side: Receive a message to do some post processing
747   void CContext::recvPostProcessing(CBufferIn& buffer)
748   {
749      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
750      postProcessing();
751   }
752
753   const StdString& CContext::getIdServer()
754   {
755      if (hasClient)
756      {
757        idServer_ = this->getId();
758        idServer_ += "_server";
759        return idServer_;
760      }
761      if (hasServer) return (this->getId());
762   }
763
764   /*!
765   \brief Do some simple post processings after parsing xml file
766      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
767   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
768   which will be written out into netcdf files, are processed
769   */
770   void CContext::postProcessing()
771   {
772     if (isPostProcessed) return;
773
774      // Make sure the calendar was correctly created
775      if (!calendar)
776        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
777      else if (calendar->getTimeStep() == NoneDu)
778        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
779      // Calendar first update to set the current date equals to the start date
780      calendar->update(0);
781
782      // Find all inheritance in xml structure
783      this->solveAllInheritance();
784
785      // Check if some axis, domains or grids are eligible to for compressed indexed output.
786      // Warning: This must be done after solving the inheritance and before the rest of post-processing
787      checkAxisDomainsGridsEligibilityForCompressedOutput();
788
789      // Check if some automatic time series should be generated
790      // Warning: This must be done after solving the inheritance and before the rest of post-processing
791      prepareTimeseries();
792
793      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
794      this->findEnabledFiles();
795      this->findEnabledReadModeFiles();
796
797      // Find all enabled fields of each file
798      this->findAllEnabledFields();
799      this->findAllEnabledFieldsInReadModeFiles();
800
801     if (hasClient && !hasServer)
802     {
803      // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
804      this->readAttributesOfEnabledFieldsInReadModeFiles();
805     }
806      // Search and rebuild all reference object of enabled fields
807      this->solveAllRefOfEnabledFields(false);
808
809      // Find all fields with read access from the public API
810      findFieldsWithReadAccess();
811      // and solve the all reference for them
812      solveAllRefOfFieldsWithReadAccess();
813
814      isPostProcessed = true;
815   }
816
817   std::map<int, StdSize> CContext::getAttributesBufferSize()
818   {
819     std::map<int, StdSize> attributesSize;
820
821     size_t numEnabledFiles = this->enabledFiles.size();
822     for (size_t i = 0; i < numEnabledFiles; ++i)
823     {
824       CFile* file = this->enabledFiles[i];
825
826       std::vector<CField*> enabledFields = file->getEnabledFields();
827       size_t numEnabledFields = enabledFields.size();
828       for (size_t j = 0; j < numEnabledFields; ++j)
829       {
830         const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize();
831         std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
832         for (; it != itE; ++it)
833         {
834           // If attributesSize[it->first] does not exist, it will be zero-initialized
835           // so we can use it safely without checking for its existance
836           if (attributesSize[it->first] < it->second)
837             attributesSize[it->first] = it->second;
838         }
839       }
840     }
841
842     return attributesSize;
843   }
844
845   std::map<int, StdSize> CContext::getDataBufferSize()
846   {
847     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
848
849     std::map<int, StdSize> dataSize;
850
851     // Find all reference domain and axis of all active fields
852     size_t numEnabledFiles = this->enabledFiles.size();
853     for (size_t i = 0; i < numEnabledFiles; ++i)
854     {
855       CFile* file = this->enabledFiles[i];
856       CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
857
858       if (fileMode == mode)
859       {
860         std::vector<CField*> enabledFields = file->getEnabledFields();
861         size_t numEnabledFields = enabledFields.size();
862         for (size_t j = 0; j < numEnabledFields; ++j)
863         {
864           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize();
865           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
866           for (; it != itE; ++it)
867           {
868             // If dataSize[it->first] does not exist, it will be zero-initialized
869             // so we can use it safely without checking for its existance
870             if (CXios::isOptPerformance)
871               dataSize[it->first] += it->second;
872             else if (dataSize[it->first] < it->second)
873               dataSize[it->first] = it->second;
874           }
875         }
876       }
877     }
878
879     return dataSize;
880   }
881
882   //! Client side: Send infomation of active files (files are enabled to write out)
883   void CContext::sendEnabledFiles()
884   {
885     int size = this->enabledFiles.size();
886
887     // In a context, each type has a root definition, e.g: axis, domain, field.
888     // Every object must be a child of one of these root definition. In this case
889     // all new file objects created on server must be children of the root "file_definition"
890     StdString fileDefRoot("file_definition");
891     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
892
893     for (int i = 0; i < size; ++i)
894     {
895       cfgrpPtr->sendCreateChild(this->enabledFiles[i]->getId());
896       this->enabledFiles[i]->sendAllAttributesToServer();
897       this->enabledFiles[i]->sendAddAllVariables();
898     }
899   }
900
901   //! Client side: Send information of active fields (ones are written onto files)
902   void CContext::sendEnabledFields()
903   {
904     int size = this->enabledFiles.size();
905     for (int i = 0; i < size; ++i)
906     {
907       this->enabledFiles[i]->sendEnabledFields();
908     }
909   }
910
911   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
912   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
913   {
914     if (!hasClient) return;
915
916     const vector<CAxis*> allAxis = CAxis::getAll();
917     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
918       (*it)->checkEligibilityForCompressedOutput();
919
920     const vector<CDomain*> allDomains = CDomain::getAll();
921     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
922       (*it)->checkEligibilityForCompressedOutput();
923
924     const vector<CGrid*> allGrids = CGrid::getAll();
925     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
926       (*it)->checkEligibilityForCompressedOutput();
927   }
928
929   //! Client side: Prepare the timeseries by adding the necessary files
930   void CContext::prepareTimeseries()
931   {
932     if (!hasClient) return;
933
934     const std::vector<CFile*> allFiles = CFile::getAll();
935     for (size_t i = 0; i < allFiles.size(); i++)
936     {
937       CFile* file = allFiles[i];
938
939       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
940       {
941         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : file->getFileOutputName();
942
943         const std::vector<CField*> allFields = file->getAllFields();
944         for (size_t j = 0; j < allFields.size(); j++)
945         {
946           CField* field = allFields[j];
947
948           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
949           {
950             CFile* tsFile = CFile::create();
951             tsFile->duplicateAttributes(file);
952
953             tsFile->name = tsPrefix + "_";
954             if (!field->name.isEmpty())
955               tsFile->name.get() += field->name;
956             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
957               tsFile->name.get() += field->field_ref;
958             else
959               tsFile->name.get() += field->getId();
960
961             if (!field->ts_split_freq.isEmpty())
962               tsFile->split_freq = field->ts_split_freq;
963
964             CField* tsField = tsFile->addField();
965             tsField->field_ref = field->getId();
966
967             tsFile->solveFieldRefInheritance(true);
968
969             if (file->timeseries == CFile::timeseries_attr::exclusive)
970               field->enabled = false;
971           }
972         }
973
974         // Finally disable the original file is need be
975         if (file->timeseries == CFile::timeseries_attr::only)
976          file->enabled = false;
977       }
978     }
979   }
980
981   //! Client side: Send information of reference grid of active fields
982   void CContext::sendRefGrid()
983   {
984     std::set<StdString> gridIds;
985     int sizeFile = this->enabledFiles.size();
986     CFile* filePtr(NULL);
987
988     // Firstly, find all reference grids of all active fields
989     for (int i = 0; i < sizeFile; ++i)
990     {
991       filePtr = this->enabledFiles[i];
992       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
993       int sizeField = enabledFields.size();
994       for (int numField = 0; numField < sizeField; ++numField)
995       {
996         if (0 != enabledFields[numField]->getRelGrid())
997           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
998       }
999     }
1000
1001     // Create all reference grids on server side
1002     StdString gridDefRoot("grid_definition");
1003     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1004     std::set<StdString>::const_iterator it, itE = gridIds.end();
1005     for (it = gridIds.begin(); it != itE; ++it)
1006     {
1007       gridPtr->sendCreateChild(*it);
1008       CGrid::get(*it)->sendAllAttributesToServer();
1009       CGrid::get(*it)->sendAllDomains();
1010       CGrid::get(*it)->sendAllAxis();
1011     }
1012   }
1013
1014
1015   //! Client side: Send information of reference domain and axis of active fields
1016   void CContext::sendRefDomainsAxis()
1017   {
1018     std::set<StdString> domainIds;
1019     std::set<StdString> axisIds;
1020
1021     // Find all reference domain and axis of all active fields
1022     int numEnabledFiles = this->enabledFiles.size();
1023     for (int i = 0; i < numEnabledFiles; ++i)
1024     {
1025       std::vector<CField*> enabledFields = this->enabledFiles[i]->getEnabledFields();
1026       int numEnabledFields = enabledFields.size();
1027       for (int j = 0; j < numEnabledFields; ++j)
1028       {
1029         const std::pair<StdString, StdString>& prDomAxisId = enabledFields[j]->getRefDomainAxisIds();
1030         if ("" != prDomAxisId.first) domainIds.insert(prDomAxisId.first);
1031         if ("" != prDomAxisId.second) axisIds.insert(prDomAxisId.second);
1032       }
1033     }
1034
1035     // Create all reference axis on server side
1036     std::set<StdString>::iterator itDom, itAxis;
1037     std::set<StdString>::const_iterator itE;
1038
1039     StdString axiDefRoot("axis_definition");
1040     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1041     itE = axisIds.end();
1042     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1043     {
1044       if (!itAxis->empty())
1045       {
1046         axisPtr->sendCreateChild(*itAxis);
1047         CAxis::get(*itAxis)->sendAllAttributesToServer();
1048       }
1049     }
1050
1051     // Create all reference domains on server side
1052     StdString domDefRoot("domain_definition");
1053     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1054     itE = domainIds.end();
1055     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1056     {
1057       if (!itDom->empty()) {
1058          domPtr->sendCreateChild(*itDom);
1059          CDomain::get(*itDom)->sendAllAttributesToServer();
1060       }
1061     }
1062   }
1063
1064   //! Update calendar in each time step
1065   void CContext::updateCalendar(int step)
1066   {
1067      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1068      calendar->update(step);
1069      info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1070
1071      if (hasClient)
1072      {
1073        //checkPrefetchingOfEnabledReadModeFiles();
1074        garbageCollector.invalidate(calendar->getCurrentDate());
1075      }
1076   }
1077
1078   //! Server side: Create header of netcdf file
1079   void CContext::createFileHeader(void )
1080   {
1081      vector<CFile*>::const_iterator it;
1082
1083      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1084      {
1085         (*it)->initFile();
1086      }
1087   }
1088
1089   //! Get current context
1090   CContext* CContext::getCurrent(void)
1091   {
1092     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1093   }
1094
1095   /*!
1096   \brief Set context with an id be the current context
1097   \param [in] id identity of context to be set to current
1098   */
1099   void CContext::setCurrent(const string& id)
1100   {
1101     CObjectFactory::SetCurrentContextId(id);
1102     CGroupFactory::SetCurrentContextId(id);
1103   }
1104
1105  /*!
1106  \brief Create a context with specific id
1107  \param [in] id identity of new context
1108  \return pointer to the new context or already-existed one with identity id
1109  */
1110  CContext* CContext::create(const StdString& id)
1111  {
1112    CContext::setCurrent(id);
1113
1114    bool hasctxt = CContext::has(id);
1115    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1116    getRoot();
1117    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1118
1119#define DECLARE_NODE(Name_, name_) \
1120    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1121#define DECLARE_NODE_PAR(Name_, name_)
1122#include "node_type.conf"
1123
1124    return (context);
1125  }
1126
1127
1128
1129     //! Server side: Receive a message to do some post processing
1130  void CContext::recvRegistry(CEventServer& event)
1131  {
1132    CBufferIn* buffer=event.subEvents.begin()->buffer;
1133    string id;
1134    *buffer>>id;
1135    get(id)->recvRegistry(*buffer);
1136  }
1137
1138  void CContext::recvRegistry(CBufferIn& buffer)
1139  {
1140    if (server->intraCommRank==0)
1141    {
1142      CRegistry registry(server->intraComm) ;
1143      registry.fromBuffer(buffer) ;
1144      registryOut->mergeRegistry(registry) ;
1145    }
1146  }
1147
1148  void CContext::sendRegistry(void)
1149  {
1150    registryOut->hierarchicalGatherRegistry() ;
1151
1152    CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1153    if (client->isServerLeader())
1154    {
1155       CMessage msg ;
1156       msg<<this->getIdServer();
1157       if (client->clientRank==0) msg<<*registryOut ;
1158       const std::list<int>& ranks = client->getRanksServerLeader();
1159       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1160         event.push(*itRank,1,msg);
1161       client->sendEvent(event);
1162     }
1163     else client->sendEvent(event);
1164  }
1165
1166} // namespace xios
Note: See TracBrowser for help on using the repository browser.