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

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

dev_omp

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