source: XIOS/dev/branch_yushan/src/node/context.cpp @ 1087

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

save modif from local. context_init/finalize OK

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