source: XIOS/dev/XIOS_DEV_CMIP6/src/node/context.cpp @ 1316

Last change on this file since 1316 was 1316, checked in by ymipsl, 7 years ago

Modify registry configuration. The name of the context added automatically to the key will the same for client than for servers.

YM

  • 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: 64.3 KB
Line 
1#include "context.hpp"
2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
5
6#include "calendar_type.hpp"
7#include "duration.hpp"
8
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
12#include "node_type.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "timer.hpp"
17#include "memtrack.hpp"
18#include <limits>
19#include "server.hpp"
20
21namespace xios {
22
23  shared_ptr<CContextGroup> CContext::root;
24
25   /// ////////////////////// Définitions ////////////////////// ///
26
27   CContext::CContext(void)
28      : CObjectTemplate<CContext>(), CContextAttributes()
29      , calendar(), hasClient(false), hasServer(false)
30      , isPostProcessed(false), finalized(false)
31      , idServer_(), client(0), server(0)
32      , allProcessed(false), countChildCtx_(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)
38      , isPostProcessed(false), finalized(false)
39      , idServer_(), client(0), server(0)
40      , allProcessed(false), countChildCtx_(0)
41   { /* Ne rien faire de plus */ }
42
43   CContext::~CContext(void)
44   {
45     delete client;
46     delete server;
47     for (std::vector<CContextClient*>::iterator it = clientPrimServer.begin(); it != clientPrimServer.end(); it++)  delete *it;
48     for (std::vector<CContextServer*>::iterator it = serverPrimServer.begin(); it != serverPrimServer.end(); it++)  delete *it;
49
50   }
51
52   //----------------------------------------------------------------
53   //! Get name of context
54   StdString CContext::GetName(void)   { return (StdString("context")); }
55   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
56   ENodeType CContext::GetType(void)   { return (eContext); }
57
58   //----------------------------------------------------------------
59
60   /*!
61   \brief Get context group (context root)
62   \return Context root
63   */
64   CContextGroup* CContext::getRoot(void)
65   {
66      if (root.get()==NULL) root=shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
67      return root.get();
68   }
69
70   //----------------------------------------------------------------
71
72   /*!
73   \brief Get calendar of a context
74   \return Calendar
75   */
76   boost::shared_ptr<CCalendar> CContext::getCalendar(void) const
77   {
78      return (this->calendar);
79   }
80
81   //----------------------------------------------------------------
82
83   /*!
84   \brief Set a context with a calendar
85   \param[in] newCalendar new calendar
86   */
87   void CContext::setCalendar(boost::shared_ptr<CCalendar> newCalendar)
88   {
89      this->calendar = newCalendar;
90   }
91
92   //----------------------------------------------------------------
93   /*!
94   \brief Parse xml file and write information into context object
95   \param [in] node xmld node corresponding in xml file
96   */
97   void CContext::parse(xml::CXMLNode & node)
98   {
99      CContext::SuperClass::parse(node);
100
101      // PARSING POUR GESTION DES ENFANTS
102      xml::THashAttributes attributes = node.getAttributes();
103
104      if (attributes.end() != attributes.find("src"))
105      {
106         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
107         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
108            ERROR("void CContext::parse(xml::CXMLNode & node)",
109                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
110         if (!ifs.good())
111            ERROR("CContext::parse(xml::CXMLNode & node)",
112                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
113         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
114      }
115
116      if (node.getElementName().compare(CContext::GetName()))
117         DEBUG("Le noeud is wrong defined but will be considered as a context !");
118
119      if (!(node.goToChildElement()))
120      {
121         DEBUG("Le context ne contient pas d'enfant !");
122      }
123      else
124      {
125         do { // Parcours des contextes pour traitement.
126
127            StdString name = node.getElementName();
128            attributes.clear();
129            attributes = node.getAttributes();
130
131            if (attributes.end() != attributes.find("id"))
132            {
133              DEBUG(<< "Definition node has an id,"
134                    << "it will not be taking account !");
135            }
136
137#define DECLARE_NODE(Name_, name_)    \
138   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
139   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
140#define DECLARE_NODE_PAR(Name_, name_)
141#include "node_type.conf"
142
143            DEBUG(<< "The element \'"     << name
144                  << "\' in the context \'" << CContext::getCurrent()->getId()
145                  << "\' is not a definition !");
146
147         } while (node.goToNextElement());
148
149         node.goToParentElement(); // Retour au parent
150      }
151   }
152
153   //----------------------------------------------------------------
154   //! Show tree structure of context
155   void CContext::ShowTree(StdOStream & out)
156   {
157      StdString currentContextId = CContext::getCurrent() -> getId();
158      std::vector<CContext*> def_vector =
159         CContext::getRoot()->getChildList();
160      std::vector<CContext*>::iterator
161         it = def_vector.begin(), end = def_vector.end();
162
163      out << "<? xml version=\"1.0\" ?>" << std::endl;
164      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
165
166      for (; it != end; it++)
167      {
168         CContext* context = *it;
169         CContext::setCurrent(context->getId());
170         out << *context << std::endl;
171      }
172
173      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
174      CContext::setCurrent(currentContextId);
175   }
176
177
178   //----------------------------------------------------------------
179
180   //! Convert context object into string (to print)
181   StdString CContext::toString(void) const
182   {
183      StdOStringStream oss;
184      oss << "<" << CContext::GetName()
185          << " id=\"" << this->getId() << "\" "
186          << SuperClassAttribute::toString() << ">" << std::endl;
187      if (!this->hasChild())
188      {
189         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
190      }
191      else
192      {
193
194#define DECLARE_NODE(Name_, name_)    \
195   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
196   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
197#define DECLARE_NODE_PAR(Name_, name_)
198#include "node_type.conf"
199
200      }
201
202      oss << "</" << CContext::GetName() << " >";
203
204      return (oss.str());
205   }
206
207   //----------------------------------------------------------------
208
209   /*!
210   \brief Find all inheritace among objects in a context.
211   \param [in] apply (true) write attributes of parent into ones of child if they are empty
212                     (false) write attributes of parent into a new container of child
213   \param [in] parent unused
214   */
215   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
216   {
217#define DECLARE_NODE(Name_, name_)    \
218   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
219     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
220#define DECLARE_NODE_PAR(Name_, name_)
221#include "node_type.conf"
222   }
223
224   //----------------------------------------------------------------
225
226   //! Verify if all root definition in the context have child.
227   bool CContext::hasChild(void) const
228   {
229      return (
230#define DECLARE_NODE(Name_, name_)    \
231   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
232#define DECLARE_NODE_PAR(Name_, name_)
233#include "node_type.conf"
234      false);
235}
236
237   //----------------------------------------------------------------
238
239   void CContext::CleanTree(void)
240   {
241#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
242#define DECLARE_NODE_PAR(Name_, name_)
243#include "node_type.conf"
244   }
245   ///---------------------------------------------------------------
246
247   //! Initialize client side
248   void CContext::initClient(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtServer /*= 0*/)
249   {
250
251     hasClient = true;
252     MPI_Comm intraCommServer, interCommServer;
253     
254
255     if (CServer::serverLevel != 1)
256      // initClient is called by client
257     {
258       client = new CContextClient(this, intraComm, interComm, cxtServer);
259       if (cxtServer) // Attached mode
260       {
261         intraCommServer = intraComm;
262         interCommServer = interComm;
263       }
264       else
265       {
266         MPI_Comm_dup(intraComm, &intraCommServer);
267         comms.push_back(intraCommServer);
268         MPI_Comm_dup(interComm, &interCommServer);
269         comms.push_back(interCommServer);
270       }
271/* for registry take the id of client context */
272/* for servers, supress the _server_ from id  */
273       string contextRegistryId=getId() ;
274       size_t pos=contextRegistryId.find("_server_") ;
275       if (pos!=std::string::npos)  contextRegistryId=contextRegistryId.substr(0,pos) ;
276
277       registryIn=new CRegistry(intraComm);
278       registryIn->setPath(contextRegistryId) ;
279       if (client->clientRank==0) registryIn->fromFile("xios_registry.bin") ;
280       registryIn->bcastRegistry() ;
281       registryOut=new CRegistry(intraComm) ;
282       
283       registryOut->setPath(contextRegistryId) ;
284
285       server = new CContextServer(this, intraCommServer, interCommServer);
286     }
287     else
288     // initClient is called by primary server
289     {
290       clientPrimServer.push_back(new CContextClient(this, intraComm, interComm));
291       MPI_Comm_dup(intraComm, &intraCommServer);
292       comms.push_back(intraCommServer);
293       MPI_Comm_dup(interComm, &interCommServer);
294       comms.push_back(interCommServer);
295       serverPrimServer.push_back(new CContextServer(this, intraCommServer, interCommServer));
296     }
297   }
298
299   void CContext::setClientServerBuffer(CContextClient* contextClient)
300   {
301      // Estimated minimum event size for small events (10 is an arbitrary constant just for safety)
302      const size_t minEventSize = CEventClient::headerSize + getIdServer().size() + 10 * sizeof(int);
303
304      // Ensure there is at least some room for 20 of such events in the buffers
305      size_t minBufferSize = std::max(CXios::minBufferSize, 20 * minEventSize);
306
307#define DECLARE_NODE(Name_, name_)    \
308     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
309#define DECLARE_NODE_PAR(Name_, name_)
310#include "node_type.conf"
311#undef DECLARE_NODE
312#undef DECLARE_NODE_PAR
313
314     // Compute the buffer sizes needed to send the attributes and data corresponding to fields
315     std::map<int, StdSize> maxEventSize;
316     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize, contextClient);
317     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize, contextClient);
318
319     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
320     for (it = dataBufferSize.begin(); it != ite; ++it)
321       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
322
323     // Apply the buffer size factor, check that we are above the minimum buffer size and below the maximum size
324     ite = bufferSize.end();
325     for (it = bufferSize.begin(); it != ite; ++it)
326     {
327       it->second *= CXios::bufferSizeFactor;
328       if (it->second < minBufferSize) it->second = minBufferSize;
329       if (it->second > CXios::maxBufferSize) it->second = CXios::maxBufferSize;
330     }
331
332     // Leaders will have to send some control events so ensure there is some room for those in the buffers
333     if (contextClient->isServerLeader())
334     {
335       const std::list<int>& ranks = contextClient->getRanksServerLeader();
336       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
337       {
338         if (!bufferSize.count(*itRank))
339         {
340           bufferSize[*itRank] = minBufferSize;
341           maxEventSize[*itRank] = minEventSize;
342         }
343       }
344     }
345     contextClient->setBufferSize(bufferSize, maxEventSize);
346
347   }
348
349   //! Verify whether a context is initialized
350   bool CContext::isInitialized(void)
351   {
352     return hasClient;
353   }
354
355   void CContext::initServer(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtClient /*= 0*/)
356   {
357     hasServer=true;
358     server = new CContextServer(this,intraComm,interComm);
359
360/* for registry take the id of client context */
361/* for servers, supress the _server_ from id  */
362     string contextRegistryId=getId() ;
363     size_t pos=contextRegistryId.find("_server_") ;
364     if (pos!=std::string::npos)  contextRegistryId=contextRegistryId.substr(0,pos) ;
365       
366     registryIn=new CRegistry(intraComm);
367     registryIn->setPath(contextRegistryId) ;
368     if (server->intraCommRank==0) registryIn->fromFile("xios_registry.bin") ;
369     registryIn->bcastRegistry() ;
370     registryOut=new CRegistry(intraComm) ;
371     registryOut->setPath(contextRegistryId) ;
372
373     MPI_Comm intraCommClient, interCommClient;
374     if (cxtClient) // Attached mode
375     {
376       intraCommClient = intraComm;
377       interCommClient = interComm;
378     }
379     else
380     {
381       MPI_Comm_dup(intraComm, &intraCommClient);
382       comms.push_back(intraCommClient);
383       MPI_Comm_dup(interComm, &interCommClient);
384       comms.push_back(interCommClient);
385     }
386     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
387   }
388
389   //! Try to send the buffers and receive possible answers
390  bool CContext::checkBuffersAndListen(void)
391  {
392    bool clientReady, serverFinished;
393
394    // Only classical servers are non-blocking
395    if (CServer::serverLevel == 0)
396    {
397      client->checkBuffers();
398      bool hasTmpBufferedEvent = client->hasTemporarilyBufferedEvent();
399      if (hasTmpBufferedEvent)
400        hasTmpBufferedEvent = !client->sendTemporarilyBufferedEvent();
401      // Don't process events if there is a temporarily buffered event
402      return server->eventLoop(!hasTmpBufferedEvent);
403    }
404    else if (CServer::serverLevel == 1)
405    {
406      if (!finalized)
407        client->checkBuffers();
408      bool serverFinished = true;
409      if (!finalized)
410        serverFinished = server->eventLoop();
411      bool serverPrimFinished = true;
412      for (int i = 0; i < clientPrimServer.size(); ++i)
413      {
414        if (!finalized)
415          clientPrimServer[i]->checkBuffers();
416        if (!finalized)
417          serverPrimFinished *= serverPrimServer[i]->eventLoop();
418      }
419      return ( serverFinished && serverPrimFinished);
420    }
421
422    else if (CServer::serverLevel == 2)
423    {
424      client->checkBuffers();
425      return server->eventLoop();
426    }
427  }
428
429   //! Terminate a context
430   void CContext::finalize(void)
431   {
432     // Send registry upon calling the function the first time
433     if (countChildCtx_ == 0)
434       if (hasClient) sendRegistry() ;
435
436     // Client:
437     // (1) blocking send context finalize to its server
438     // (2) blocking receive context finalize from its server
439     // (3) some memory deallocations
440     if (CXios::isClient)
441     {
442       // Make sure that client (model) enters the loop only once
443       if (countChildCtx_ < 1)
444       {
445         ++countChildCtx_;
446
447         client->finalize();
448         while (client->havePendingRequests())
449            client->checkBuffers();
450
451         while (!server->hasFinished())
452           server->eventLoop();
453
454         if (hasServer) // Mode attache
455         {
456           closeAllFile();
457           registryOut->hierarchicalGatherRegistry() ;
458           if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
459         }
460
461         //! Deallocate client buffers
462         client->releaseBuffers();
463
464         //! Free internally allocated communicators
465         for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
466           MPI_Comm_free(&(*it));
467         comms.clear();
468
469         info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
470       }
471     }
472     else if (CXios::isServer)
473     {
474       // First context finalize message received from a model
475       // Send context finalize to its child contexts (if any)
476       if (countChildCtx_ == 0)
477         for (int i = 0; i < clientPrimServer.size(); ++i)
478           clientPrimServer[i]->finalize();
479
480       // (Last) context finalized message received
481       if (countChildCtx_ == clientPrimServer.size())
482       {
483         // Blocking send of context finalize message to its client (e.g. primary server or model)
484         client->finalize();
485         bool bufferReleased;
486         do
487         {
488           client->checkBuffers();
489           bufferReleased = !client->havePendingRequests();
490         } while (!bufferReleased);
491         finalized = true;
492
493         closeAllFile(); // Just move to here to make sure that server-level 1 can close files
494         if (hasServer && !hasClient)
495         {           
496           registryOut->hierarchicalGatherRegistry() ;
497           if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
498         }
499
500         //! Deallocate client buffers
501         client->releaseBuffers();
502         for (int i = 0; i < clientPrimServer.size(); ++i)
503           clientPrimServer[i]->releaseBuffers();
504
505         //! Free internally allocated communicators
506         for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
507           MPI_Comm_free(&(*it));
508         comms.clear();
509
510         info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
511       }
512
513       ++countChildCtx_;
514     }
515   }
516
517   //! Free internally allocated communicators
518   void CContext::freeComms(void)
519   {
520     for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
521       MPI_Comm_free(&(*it));
522     comms.clear();
523   }
524
525   //! Deallocate buffers allocated by clientContexts
526   void CContext::releaseClientBuffers(void)
527   {
528     client->releaseBuffers();
529     for (int i = 0; i < clientPrimServer.size(); ++i)
530       clientPrimServer[i]->releaseBuffers();
531   }
532
533   void CContext::postProcessingGlobalAttributes()
534   {
535     if (allProcessed) return; 
536     
537     // After xml is parsed, there are some more works with post processing
538     postProcessing();
539
540     // Check grid and calculate its distribution
541     checkGridEnabledFields();
542 
543     // Distribute files between secondary servers according to the data size
544     distributeFiles();
545
546     setClientServerBuffer(client);
547     for (int i = 0; i < clientPrimServer.size(); ++i)
548         setClientServerBuffer(clientPrimServer[i]);
549
550     if (hasClient)
551     {
552      // Send all attributes of current context to server
553      this->sendAllAttributesToServer();
554
555      // Send all attributes of current calendar
556      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
557
558      // We have enough information to send to server
559      // First of all, send all enabled files
560      sendEnabledFiles(this->enabledWriteModeFiles);
561      // We only use server-level 1 (for now) to read data
562      if (!hasServer)
563        sendEnabledFiles(this->enabledReadModeFiles);
564
565      // Then, send all enabled fields     
566      sendEnabledFieldsInFiles(this->enabledWriteModeFiles);
567      if (!hasServer)
568        sendEnabledFieldsInFiles(this->enabledReadModeFiles);
569
570      // Then, check whether we have domain_ref, axis_ref or scalar_ref attached to the enabled fields
571      // If any, so send them to server
572       sendRefDomainsAxisScalars(this->enabledWriteModeFiles);
573      if (!hasServer)
574        sendRefDomainsAxisScalars(this->enabledReadModeFiles);       
575
576       // Check whether enabled fields have grid_ref, if any, send this info to server
577      sendRefGrid(this->enabledFiles);
578      // This code may be useful in the future when we want to seperate completely read and write
579      // sendRefGrid(this->enabledWriteModeFiles);
580      // if (!hasServer)
581      //   sendRefGrid(this->enabledReadModeFiles);
582     
583      // A grid of enabled fields composed of several components which must be checked then their
584      // checked attributes should be sent to server
585      sendGridComponentEnabledFieldsInFiles(this->enabledFiles); // This code can be seperated in two (one for reading, another for writing)
586
587       // We have a xml tree on the server side and now, it should be also processed
588      sendPostProcessing();
589       
590      // Finally, we send information of grid itself to server
591      sendGridEnabledFieldsInFiles(this->enabledWriteModeFiles);       
592      if (!hasServer)
593        sendGridEnabledFieldsInFiles(this->enabledReadModeFiles);       
594     }
595     allProcessed = true;
596   }
597
598   void CContext::sendPostProcessingGlobalAttributes()
599   {
600      // Use correct context client to send message
601     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
602    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
603     for (int i = 0; i < nbSrvPools; ++i)
604     {
605       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
606       CEventClient event(getType(),EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES);
607
608       if (contextClientTmp->isServerLeader())
609       {
610         CMessage msg;
611         if (hasServer)
612           msg<<this->getIdServer(i);
613         else
614           msg<<this->getIdServer();
615         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
616         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
617           event.push(*itRank,1,msg);
618         contextClientTmp->sendEvent(event);
619       }
620       else contextClientTmp->sendEvent(event);
621     }
622   }
623
624   void CContext::recvPostProcessingGlobalAttributes(CEventServer& event)
625   {
626      CBufferIn* buffer=event.subEvents.begin()->buffer;
627      string id;
628      *buffer>>id;
629      get(id)->recvPostProcessingGlobalAttributes(*buffer);
630   }
631
632   void CContext::recvPostProcessingGlobalAttributes(CBufferIn& buffer)
633   {     
634      postProcessingGlobalAttributes();
635   }
636
637   /*!
638   \brief Close all the context defintion and do processing data
639      After everything is well defined on client side, they will be processed and sent to server
640   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
641   all necessary information to server, from which each server can build its own database.
642   Because the role of server is to write out field data on a specific netcdf file,
643   the only information that it needs is the enabled files
644   and the active fields (fields will be written onto active files)
645   */
646   void CContext::closeDefinition(void)
647   {
648    CTimer::get("Context : close definition").resume() ;
649    postProcessingGlobalAttributes();
650
651    if (hasClient) sendPostProcessingGlobalAttributes();
652
653    // There are some processings that should be done after all of above. For example: check mask or index
654    this->buildFilterGraphOfEnabledFields();
655   
656     if (hasClient && !hasServer)
657    {
658      buildFilterGraphOfFieldsWithReadAccess();
659    }
660   
661    checkGridEnabledFields();   
662
663    if (hasClient) this->sendProcessingGridOfEnabledFields();
664    if (hasClient) this->sendCloseDefinition();
665
666    // Nettoyage de l'arborescence
667    if (hasClient) CleanTree(); // Only on client side??
668
669    if (hasClient)
670    {
671      sendCreateFileHeader();
672      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
673    }
674    CTimer::get("Context : close definition").suspend() ;
675   }
676
677   void CContext::findAllEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
678   {
679     for (unsigned int i = 0; i < activeFiles.size(); i++)
680     (void)activeFiles[i]->getEnabledFields();
681   }
682
683   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
684   {
685      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
686        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
687   }
688
689   void CContext::sendGridComponentEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
690   {
691     int size = activeFiles.size();
692     for (int i = 0; i < size; ++i)
693     {       
694       activeFiles[i]->sendGridComponentOfEnabledFields();
695     }
696   }
697
698   /*!
699      Send active (enabled) fields in file from a client to others
700      \param [in] activeFiles files contains enabled fields to send
701   */
702   void CContext::sendGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
703   {
704     int size = activeFiles.size();
705     for (int i = 0; i < size; ++i)
706     {       
707       activeFiles[i]->sendGridOfEnabledFields();
708     }
709   }
710
711   void CContext::checkGridEnabledFields()
712   {
713     int size = enabledFiles.size();
714     for (int i = 0; i < size; ++i)
715     {
716       enabledFiles[i]->checkGridOfEnabledFields();       
717     }
718   }
719
720   /*!
721      Check grid of active (enabled) fields in file
722      \param [in] activeFiles files contains enabled fields whose grid needs checking
723   */
724   void CContext::checkGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
725   {
726     int size = activeFiles.size();
727     for (int i = 0; i < size; ++i)
728     {
729       activeFiles[i]->checkGridOfEnabledFields();       
730     }
731   }
732
733    /*!
734      Go up the hierachical tree via field_ref and do check of attributes of fields
735      This can be done in a client then all computed information will be sent from this client to others
736      \param [in] sendToServer Flag to indicate whether calculated information will be sent
737   */
738   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
739   {
740     int size = this->enabledFiles.size();
741     for (int i = 0; i < size; ++i)
742     {
743       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
744     }
745
746     for (int i = 0; i < size; ++i)
747     {
748       this->enabledFiles[i]->generateNewTransformationGridDest();
749     }
750   }
751
752    /*!
753      Go up the hierachical tree via field_ref and do check of attributes of fields.
754      The transformation can be done in this step.
755      All computed information will be sent from this client to others.
756      \param [in] sendToServer Flag to indicate whether calculated information will be sent
757   */
758   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
759   {
760     int size = this->enabledFiles.size();
761     for (int i = 0; i < size; ++i)
762     {
763       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
764     }
765   }
766
767   void CContext::buildFilterGraphOfEnabledFields()
768   {
769     int size = this->enabledFiles.size();
770     for (int i = 0; i < size; ++i)
771     {
772       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
773     }
774   }
775
776   void CContext::startPrefetchingOfEnabledReadModeFiles()
777   {
778     int size = enabledReadModeFiles.size();
779     for (int i = 0; i < size; ++i)
780     {
781        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
782     }
783   }
784
785   void CContext::checkPrefetchingOfEnabledReadModeFiles()
786   {
787     int size = enabledReadModeFiles.size();
788     for (int i = 0; i < size; ++i)
789     {
790        enabledReadModeFiles[i]->prefetchEnabledReadModeFieldsIfNeeded();
791     }
792   }
793
794  void CContext::findFieldsWithReadAccess(void)
795  {
796    fieldsWithReadAccess.clear();
797    const vector<CField*> allFields = CField::getAll();
798    for (size_t i = 0; i < allFields.size(); ++i)
799    {
800      CField* field = allFields[i];
801
802      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
803        field->read_access = true;
804      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
805        fieldsWithReadAccess.push_back(field);
806    }
807  }
808
809  void CContext::solveAllRefOfFieldsWithReadAccess()
810  {
811    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
812      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
813  }
814
815  void CContext::buildFilterGraphOfFieldsWithReadAccess()
816  {
817    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
818      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
819  }
820
821   void CContext::solveAllInheritance(bool apply)
822   {
823     // Résolution des héritages descendants (càd des héritages de groupes)
824     // pour chacun des contextes.
825      solveDescInheritance(apply);
826
827     // Résolution des héritages par référence au niveau des fichiers.
828      const vector<CFile*> allFiles=CFile::getAll();
829      const vector<CGrid*> allGrids= CGrid::getAll();
830
831      if (hasClient && !hasServer)
832      //if (hasClient)
833      {
834        for (unsigned int i = 0; i < allFiles.size(); i++)
835          allFiles[i]->solveFieldRefInheritance(apply);
836      }
837
838      unsigned int vecSize = allGrids.size();
839      unsigned int i = 0;
840      for (i = 0; i < vecSize; ++i)
841        allGrids[i]->solveDomainAxisRefInheritance(apply);
842
843   }
844
845   void CContext::findEnabledFiles(void)
846   {
847      const std::vector<CFile*> allFiles = CFile::getAll();
848      const CDate& initDate = calendar->getInitDate();
849
850      for (unsigned int i = 0; i < allFiles.size(); i++)
851         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
852         {
853            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
854            {
855              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
856              {
857                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
858                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
859                    <<"\" is less than the time step. File will not be written."<<endl;
860              }
861              else
862               enabledFiles.push_back(allFiles[i]);
863            }
864         }
865         else
866         {
867           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
868           {
869             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
870                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
871                 <<"\" is less than the time step. File will not be written."<<endl;
872           }
873           else
874             enabledFiles.push_back(allFiles[i]); // otherwise true by default
875         }
876
877      if (enabledFiles.size() == 0)
878         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
879               << getId() << "\" !");
880
881   }
882
883   void CContext::distributeFiles(void)
884   {
885     double eps=std::numeric_limits<double>::epsilon()*10 ;
886     
887     // If primary server
888     if (hasServer && hasClient)
889     {
890       int nbPools = clientPrimServer.size();
891
892       // (1) Find all enabled files in write mode
893       // for (int i = 0; i < this->enabledFiles.size(); ++i)
894       // {
895       //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
896       //    enabledWriteModeFiles.push_back(enabledFiles[i]);
897       // }
898
899       // (2) Estimate the data volume for each file
900       int size = this->enabledWriteModeFiles.size();
901       std::vector<std::pair<double, CFile*> > dataSizeMap;
902       double dataPerPool = 0;
903       int nfield=0 ;
904       for (size_t i = 0; i < size; ++i)
905       {
906         CFile* file = this->enabledWriteModeFiles[i];
907         StdSize dataSize=0;
908         std::vector<CField*> enabledFields = file->getEnabledFields();
909         size_t numEnabledFields = enabledFields.size();
910         for (size_t j = 0; j < numEnabledFields; ++j) dataSize += enabledFields[j]->getGlobalWrittenSize() ;
911
912         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
913         double dataSizeSec= dataSize/ outFreqSec;
914         nfield++ ;
915// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
916         dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
917         dataPerPool += dataSizeSec;
918       }
919       dataPerPool /= nbPools;
920       std::sort(dataSizeMap.begin(), dataSizeMap.end());
921
922       // (3) Assign contextClient to each enabled file
923
924       std::multimap<double,int> poolDataSize ;
925// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
926
927       int j;
928       double dataSize ;
929       for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
930             
931       for (int i = dataSizeMap.size()-1; i >= 0; --i)
932       {
933         dataSize=(*poolDataSize.begin()).first ;
934         j=(*poolDataSize.begin()).second ;
935         dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
936         dataSize+=dataSizeMap[i].first;
937         poolDataSize.erase(poolDataSize.begin()) ;
938         poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
939       }
940
941       for (std::multimap<double,int>:: iterator it=poolDataSize.begin() ; it!=poolDataSize.end(); ++it) info(30)<<"Load Balancing for servers (perfect=1) : "<<it->second<<" :  ratio "<<it->first*1./dataPerPool<<endl ;
942 
943       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
944       {
945         enabledReadModeFiles[i]->setContextClient(client);         
946       }
947     }
948     else
949     {
950       for (int i = 0; i < this->enabledFiles.size(); ++i)
951         enabledFiles[i]->setContextClient(client);
952     }
953   }
954
955   /*!
956      Find all files in write mode
957   */
958   void CContext::findEnabledWriteModeFiles(void)
959   {
960     int size = this->enabledFiles.size();
961     for (int i = 0; i < size; ++i)
962     {
963       if (enabledFiles[i]->mode.isEmpty() || 
964          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
965        enabledWriteModeFiles.push_back(enabledFiles[i]);
966     }
967   }
968
969   /*!
970      Find all files in read mode
971   */
972   void CContext::findEnabledReadModeFiles(void)
973   {
974     int size = this->enabledFiles.size();
975     for (int i = 0; i < size; ++i)
976     {
977       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
978        enabledReadModeFiles.push_back(enabledFiles[i]);
979     }
980   }
981
982   void CContext::closeAllFile(void)
983   {
984     std::vector<CFile*>::const_iterator
985            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
986
987     for (; it != end; it++)
988     {
989       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
990       (*it)->close();
991     }
992   }
993
994   /*!
995   \brief Dispatch event received from client
996      Whenever a message is received in buffer of server, it will be processed depending on
997   its event type. A new event type should be added in the switch list to make sure
998   it processed on server side.
999   \param [in] event: Received message
1000   */
1001   bool CContext::dispatchEvent(CEventServer& event)
1002   {
1003
1004      if (SuperClass::dispatchEvent(event)) return true;
1005      else
1006      {
1007        switch(event.type)
1008        {
1009           case EVENT_ID_CLOSE_DEFINITION :
1010             recvCloseDefinition(event);
1011             return true;
1012             break;
1013           case EVENT_ID_UPDATE_CALENDAR:
1014             recvUpdateCalendar(event);
1015             return true;
1016             break;
1017           case EVENT_ID_CREATE_FILE_HEADER :
1018             recvCreateFileHeader(event);
1019             return true;
1020             break;
1021           case EVENT_ID_POST_PROCESS:
1022             recvPostProcessing(event);
1023             return true;
1024            case EVENT_ID_SEND_REGISTRY:
1025             recvRegistry(event);
1026             return true;
1027             break;
1028            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
1029             recvPostProcessingGlobalAttributes(event);
1030             return true;
1031             break;
1032            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
1033             recvProcessingGridOfEnabledFields(event);
1034             return true;
1035             break;
1036           default :
1037             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
1038                    <<"Unknown Event");
1039           return false;
1040         }
1041      }
1042   }
1043
1044   //! Client side: Send a message to server to make it close
1045   void CContext::sendCloseDefinition(void)
1046   {
1047     // Use correct context client to send message
1048     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1049     for (int i = 0; i < nbSrvPools; ++i)
1050     {
1051       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1052       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1053       if (contextClientTmp->isServerLeader())
1054       {
1055         CMessage msg;
1056         if (hasServer)
1057           msg<<this->getIdServer(i);
1058         else
1059           msg<<this->getIdServer();
1060         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1061         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1062           event.push(*itRank,1,msg);
1063         contextClientTmp->sendEvent(event);
1064       }
1065       else contextClientTmp->sendEvent(event);
1066     }
1067   }
1068
1069   //! Server side: Receive a message of client announcing a context close
1070   void CContext::recvCloseDefinition(CEventServer& event)
1071   {
1072      CBufferIn* buffer=event.subEvents.begin()->buffer;
1073      string id;
1074      *buffer>>id;
1075      get(id)->closeDefinition();
1076   }
1077
1078   //! Client side: Send a message to update calendar in each time step
1079   void CContext::sendUpdateCalendar(int step)
1080   {
1081     // Use correct context client to send message
1082    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1083     for (int i = 0; i < nbSrvPools; ++i)
1084     {
1085       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1086       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
1087
1088         if (contextClientTmp->isServerLeader())
1089         {
1090           CMessage msg;
1091           if (hasServer)
1092             msg<<this->getIdServer(i)<<step;
1093           else
1094             msg<<this->getIdServer()<<step;
1095           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1096           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1097             event.push(*itRank,1,msg);
1098           contextClientTmp->sendEvent(event);
1099         }
1100         else contextClientTmp->sendEvent(event);
1101     }
1102   }
1103
1104   //! Server side: Receive a message of client annoucing calendar update
1105   void CContext::recvUpdateCalendar(CEventServer& event)
1106   {
1107      CBufferIn* buffer=event.subEvents.begin()->buffer;
1108      string id;
1109      *buffer>>id;
1110      get(id)->recvUpdateCalendar(*buffer);
1111   }
1112
1113   //! Server side: Receive a message of client annoucing calendar update
1114   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1115   {
1116      int step;
1117      buffer>>step;
1118      updateCalendar(step);
1119      if (hasClient && hasServer)
1120      {       
1121        sendUpdateCalendar(step);
1122      }
1123   }
1124
1125   //! Client side: Send a message to create header part of netcdf file
1126   void CContext::sendCreateFileHeader(void)
1127   {
1128     // Use correct context client to send message
1129     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1130     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1131     for (int i = 0; i < nbSrvPools; ++i)
1132     {
1133       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1134       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
1135
1136       if (contextClientTmp->isServerLeader())
1137       {
1138         CMessage msg;
1139         if (hasServer)
1140           msg<<this->getIdServer(i);
1141         else
1142           msg<<this->getIdServer();
1143         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1144         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1145           event.push(*itRank,1,msg) ;
1146         contextClientTmp->sendEvent(event);
1147       }
1148       else contextClientTmp->sendEvent(event);
1149     }
1150   }
1151
1152   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1153   void CContext::recvCreateFileHeader(CEventServer& event)
1154   {
1155      CBufferIn* buffer=event.subEvents.begin()->buffer;
1156      string id;
1157      *buffer>>id;
1158      get(id)->recvCreateFileHeader(*buffer);
1159   }
1160
1161   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1162   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1163   {
1164      if (!hasClient && hasServer) 
1165        createFileHeader();
1166   }
1167
1168   //! Client side: Send a message to do some post processing on server
1169   void CContext::sendProcessingGridOfEnabledFields()
1170   {
1171      // Use correct context client to send message
1172     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1173     for (int i = 0; i < nbSrvPools; ++i)
1174     {
1175       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1176       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
1177
1178       if (contextClientTmp->isServerLeader())
1179       {
1180         CMessage msg;
1181         if (hasServer)
1182           msg<<this->getIdServer(i);
1183         else
1184           msg<<this->getIdServer();
1185         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1186         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1187           event.push(*itRank,1,msg);
1188         contextClientTmp->sendEvent(event);
1189       }
1190       else contextClientTmp->sendEvent(event);
1191     }
1192   }
1193
1194   //! Server side: Receive a message to do some post processing
1195   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1196   {
1197      CBufferIn* buffer=event.subEvents.begin()->buffer;
1198      string id;
1199      *buffer>>id;     
1200   }
1201
1202   //! Client side: Send a message to do some post processing on server
1203   void CContext::sendPostProcessing()
1204   {
1205      // Use correct context client to send message
1206     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1207     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1208     for (int i = 0; i < nbSrvPools; ++i)
1209     {
1210       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1211       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1212       if (contextClientTmp->isServerLeader())
1213       {
1214         CMessage msg;
1215         if (hasServer)
1216           msg<<this->getIdServer(i);
1217         else
1218           msg<<this->getIdServer();
1219         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1220         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1221         event.push(*itRank,1,msg);
1222         contextClientTmp->sendEvent(event);
1223       }
1224       else contextClientTmp->sendEvent(event);
1225     }
1226   }
1227
1228   //! Server side: Receive a message to do some post processing
1229   void CContext::recvPostProcessing(CEventServer& event)
1230   {
1231      CBufferIn* buffer=event.subEvents.begin()->buffer;
1232      string id;
1233      *buffer>>id;
1234      get(id)->recvPostProcessing(*buffer);
1235   }
1236
1237   //! Server side: Receive a message to do some post processing
1238   void CContext::recvPostProcessing(CBufferIn& buffer)
1239   {
1240      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
1241      postProcessing();
1242   }
1243
1244   const StdString& CContext::getIdServer()
1245   {
1246      if (hasClient)
1247      {
1248        idServer_ = this->getId();
1249        idServer_ += "_server";
1250        return idServer_;
1251      }
1252      if (hasServer) return (this->getId());
1253   }
1254
1255   const StdString& CContext::getIdServer(const int i)
1256   {
1257     idServer_ = this->getId();
1258     idServer_ += "_server_";
1259     idServer_ += boost::lexical_cast<string>(i);
1260     return idServer_;
1261   }
1262
1263
1264   /*!
1265   \brief Do some simple post processings after parsing xml file
1266      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1267   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1268   which will be written out into netcdf files, are processed
1269   */
1270   void CContext::postProcessing()
1271   {
1272     if (isPostProcessed) return;
1273
1274      // Make sure the calendar was correctly created
1275      if (!calendar)
1276        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1277      else if (calendar->getTimeStep() == NoneDu)
1278        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
1279      // Calendar first update to set the current date equals to the start date
1280      calendar->update(0);
1281
1282      // Find all inheritance in xml structure
1283      this->solveAllInheritance();
1284
1285//      ShowTree(info(10));
1286
1287      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1288      // Warning: This must be done after solving the inheritance and before the rest of post-processing
1289      checkAxisDomainsGridsEligibilityForCompressedOutput();     
1290
1291      // Check if some automatic time series should be generated
1292      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
1293
1294      // The timeseries should only be prepared in client
1295      if (hasClient && !hasServer) prepareTimeseries();
1296
1297      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1298      findEnabledFiles();
1299      findEnabledWriteModeFiles();
1300      findEnabledReadModeFiles();
1301
1302      // For now, only read files with client and only one level server
1303      // if (hasClient && !hasServer) findEnabledReadModeFiles();     
1304
1305      // Find all enabled fields of each file     
1306      findAllEnabledFieldsInFiles(this->enabledWriteModeFiles);
1307      findAllEnabledFieldsInFiles(this->enabledReadModeFiles);
1308
1309      // For now, only read files with client and only one level server
1310      // if (hasClient && !hasServer)
1311      //   findAllEnabledFieldsInFiles(this->enabledReadModeFiles);     
1312
1313      if (hasClient && !hasServer)
1314      {
1315        initReadFiles();
1316        // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1317        this->readAttributesOfEnabledFieldsInReadModeFiles();
1318      }
1319
1320      // Only search and rebuild all reference objects of enable fields, don't transform
1321      this->solveOnlyRefOfEnabledFields(false);
1322
1323      // Search and rebuild all reference object of enabled fields, and transform
1324      this->solveAllRefOfEnabledFieldsAndTransform(false);
1325
1326      // Find all fields with read access from the public API
1327      if (hasClient && !hasServer) findFieldsWithReadAccess();
1328      // and solve the all reference for them
1329      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
1330
1331      isPostProcessed = true;
1332   }
1333
1334   /*!
1335    * Compute the required buffer size to send the attributes (mostly those grid related).
1336    *
1337    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1338    */
1339   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
1340   {
1341     std::map<int, StdSize> attributesSize;
1342
1343     if (hasClient)
1344     {
1345       size_t numEnabledFiles = this->enabledWriteModeFiles.size();
1346       for (size_t i = 0; i < numEnabledFiles; ++i)
1347       {
1348         CFile* file = this->enabledWriteModeFiles[i];
1349         // if (file->getContextClient() == contextClient)
1350         {
1351           std::vector<CField*> enabledFields = file->getEnabledFields();
1352           size_t numEnabledFields = enabledFields.size();
1353           for (size_t j = 0; j < numEnabledFields; ++j)
1354           {
1355             const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient);
1356             std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1357             for (; it != itE; ++it)
1358             {
1359               // If attributesSize[it->first] does not exist, it will be zero-initialized
1360               // so we can use it safely without checking for its existance
1361               if (attributesSize[it->first] < it->second)
1362                 attributesSize[it->first] = it->second;
1363
1364               if (maxEventSize[it->first] < it->second)
1365                 maxEventSize[it->first] = it->second;
1366             }
1367           }
1368         }
1369       }
1370
1371      // Not a good approach here, duplicate code
1372       if (!hasServer)
1373       {
1374         size_t numEnabledFiles = this->enabledReadModeFiles.size();
1375         for (size_t i = 0; i < numEnabledFiles; ++i)
1376         {
1377           CFile* file = this->enabledReadModeFiles[i]; 
1378           {
1379             std::vector<CField*> enabledFields = file->getEnabledFields();
1380             size_t numEnabledFields = enabledFields.size();
1381             for (size_t j = 0; j < numEnabledFields; ++j)
1382             {
1383               const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient);
1384               std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1385               for (; it != itE; ++it)
1386               {
1387                 // If attributesSize[it->first] does not exist, it will be zero-initialized
1388                 // so we can use it safely without checking for its existance
1389                 if (attributesSize[it->first] < it->second)
1390                   attributesSize[it->first] = it->second;
1391
1392                 if (maxEventSize[it->first] < it->second)
1393                   maxEventSize[it->first] = it->second;
1394               }
1395             }
1396           }
1397         }
1398       }
1399     }
1400
1401     return attributesSize;
1402   }
1403
1404   /*!
1405    * Compute the required buffer size to send the fields data.
1406    *
1407    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1408    */
1409   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
1410   {
1411     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
1412
1413     std::map<int, StdSize> dataSize;
1414
1415     // Find all reference domain and axis of all active fields
1416     size_t numEnabledFiles = this->enabledFiles.size();
1417     for (size_t i = 0; i < numEnabledFiles; ++i)
1418     {
1419       CFile* file = this->enabledFiles[i];
1420       if (file->getContextClient() == contextClient)
1421       {
1422         CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
1423
1424         if (fileMode == mode)
1425         {
1426           std::vector<CField*> enabledFields = file->getEnabledFields();
1427           size_t numEnabledFields = enabledFields.size();
1428           for (size_t j = 0; j < numEnabledFields; ++j)
1429           {
1430             // const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1431            const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1432             // for (size_t c = 0; c < mapSize.size(); ++c)
1433             // {
1434               std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1435               for (; it != itE; ++it)
1436               {
1437                 // If dataSize[it->first] does not exist, it will be zero-initialized
1438                 // so we can use it safely without checking for its existance
1439                 if (CXios::isOptPerformance)
1440                   dataSize[it->first] += it->second;
1441                 else if (dataSize[it->first] < it->second)
1442                   dataSize[it->first] = it->second;
1443
1444                 if (maxEventSize[it->first] < it->second)
1445                   maxEventSize[it->first] = it->second;
1446               }
1447             // }
1448           }
1449         }
1450       }
1451     }
1452
1453     return dataSize;
1454   }
1455
1456   //! Client side: Send infomation of active files (files are enabled to write out)
1457   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
1458   {
1459     int size = activeFiles.size();
1460
1461     // In a context, each type has a root definition, e.g: axis, domain, field.
1462     // Every object must be a child of one of these root definition. In this case
1463     // all new file objects created on server must be children of the root "file_definition"
1464     StdString fileDefRoot("file_definition");
1465     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1466
1467     for (int i = 0; i < size; ++i)
1468     {
1469       CFile* f = activeFiles[i];
1470       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1471       f->sendAllAttributesToServer(f->getContextClient());
1472       f->sendAddAllVariables(f->getContextClient());
1473     }
1474   }
1475
1476   //! Client side: Send information of active fields (ones are written onto files)
1477   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
1478   {
1479     int size = activeFiles.size();
1480     for (int i = 0; i < size; ++i)
1481     {
1482       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
1483     }
1484   }
1485
1486   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1487   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1488   {
1489     if (!hasClient) return;
1490
1491     const vector<CAxis*> allAxis = CAxis::getAll();
1492     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1493       (*it)->checkEligibilityForCompressedOutput();
1494
1495     const vector<CDomain*> allDomains = CDomain::getAll();
1496     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1497       (*it)->checkEligibilityForCompressedOutput();
1498
1499     const vector<CGrid*> allGrids = CGrid::getAll();
1500     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1501       (*it)->checkEligibilityForCompressedOutput();
1502   }
1503
1504   //! Client side: Prepare the timeseries by adding the necessary files
1505   void CContext::prepareTimeseries()
1506   {
1507     if (!hasClient) return;
1508
1509     const std::vector<CFile*> allFiles = CFile::getAll();
1510     for (size_t i = 0; i < allFiles.size(); i++)
1511     {
1512       CFile* file = allFiles[i];
1513
1514       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1515       for (size_t k = 0; k < vars.size(); k++)
1516       {
1517         CVariable* var = vars[k];
1518
1519         if (var->ts_target.isEmpty()
1520              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1521           fileVars.push_back(var);
1522
1523         if (!var->ts_target.isEmpty()
1524              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1525           fieldVars.push_back(var);
1526       }
1527
1528       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1529       {
1530         StdString fileNameStr("%file_name%") ;
1531         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1532         
1533         StdString fileName=file->getFileOutputName();
1534         size_t pos=tsPrefix.find(fileNameStr) ;
1535         while (pos!=std::string::npos)
1536         {
1537           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1538           pos=tsPrefix.find(fileNameStr) ;
1539         }
1540       
1541         const std::vector<CField*> allFields = file->getAllFields();
1542         for (size_t j = 0; j < allFields.size(); j++)
1543         {
1544           CField* field = allFields[j];
1545
1546           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1547           {
1548             CFile* tsFile = CFile::create();
1549             tsFile->duplicateAttributes(file);
1550
1551             // Add variables originating from file and targeted to timeserie file
1552             for (size_t k = 0; k < fileVars.size(); k++)
1553               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1554
1555           
1556             tsFile->name = tsPrefix + "_";
1557             if (!field->name.isEmpty())
1558               tsFile->name.get() += field->name;
1559             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1560               tsFile->name.get() += field->field_ref;
1561             else
1562               tsFile->name.get() += field->getId();
1563
1564             if (!field->ts_split_freq.isEmpty())
1565               tsFile->split_freq = field->ts_split_freq;
1566
1567             CField* tsField = tsFile->addField();
1568             tsField->field_ref = field->getId();
1569
1570             // Add variables originating from file and targeted to timeserie field
1571             for (size_t k = 0; k < fieldVars.size(); k++)
1572               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1573
1574             vars = field->getAllVariables();
1575             for (size_t k = 0; k < vars.size(); k++)
1576             {
1577               CVariable* var = vars[k];
1578
1579               // Add variables originating from field and targeted to timeserie field
1580               if (var->ts_target.isEmpty()
1581                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1582                 tsField->getVirtualVariableGroup()->addChild(var);
1583
1584               // Add variables originating from field and targeted to timeserie file
1585               if (!var->ts_target.isEmpty()
1586                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1587                 tsFile->getVirtualVariableGroup()->addChild(var);
1588             }
1589
1590             tsFile->solveFieldRefInheritance(true);
1591
1592             if (file->timeseries == CFile::timeseries_attr::exclusive)
1593               field->enabled = false;
1594           }
1595         }
1596
1597         // Finally disable the original file is need be
1598         if (file->timeseries == CFile::timeseries_attr::only)
1599          file->enabled = false;
1600       }
1601     }
1602   }
1603
1604   //! Client side: Send information of reference grid of active fields
1605   void CContext::sendRefGrid(const std::vector<CFile*>& activeFiles)
1606   {
1607     std::set<StdString> gridIds;
1608     int sizeFile = activeFiles.size();
1609     CFile* filePtr(NULL);
1610
1611     // Firstly, find all reference grids of all active fields
1612     for (int i = 0; i < sizeFile; ++i)
1613     {
1614       filePtr = activeFiles[i];
1615       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1616       int sizeField = enabledFields.size();
1617       for (int numField = 0; numField < sizeField; ++numField)
1618       {
1619         if (0 != enabledFields[numField]->getRelGrid())
1620           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1621       }
1622     }
1623
1624     // Create all reference grids on server side
1625     StdString gridDefRoot("grid_definition");
1626     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1627     std::set<StdString>::const_iterator it, itE = gridIds.end();
1628     for (it = gridIds.begin(); it != itE; ++it)
1629     {
1630       gridPtr->sendCreateChild(*it);
1631       CGrid::get(*it)->sendAllAttributesToServer();
1632       CGrid::get(*it)->sendAllDomains();
1633       CGrid::get(*it)->sendAllAxis();
1634       CGrid::get(*it)->sendAllScalars();
1635     }
1636   }
1637
1638   //! Client side: Send information of reference domain, axis and scalar of active fields
1639   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
1640   {
1641     std::set<StdString> domainIds, axisIds, scalarIds;
1642
1643     // Find all reference domain and axis of all active fields
1644     int numEnabledFiles = activeFiles.size();
1645     for (int i = 0; i < numEnabledFiles; ++i)
1646     {
1647       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
1648       int numEnabledFields = enabledFields.size();
1649       for (int j = 0; j < numEnabledFields; ++j)
1650       {
1651         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1652         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1653         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1654         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1655       }
1656     }
1657
1658     // Create all reference axis on server side
1659     std::set<StdString>::iterator itDom, itAxis, itScalar;
1660     std::set<StdString>::const_iterator itE;
1661
1662     StdString scalarDefRoot("scalar_definition");
1663     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1664     itE = scalarIds.end();
1665     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1666     {
1667       if (!itScalar->empty())
1668       {
1669         scalarPtr->sendCreateChild(*itScalar);
1670         CScalar::get(*itScalar)->sendAllAttributesToServer();
1671       }
1672     }
1673
1674     StdString axiDefRoot("axis_definition");
1675     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1676     itE = axisIds.end();
1677     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1678     {
1679       if (!itAxis->empty())
1680       {
1681         axisPtr->sendCreateChild(*itAxis);
1682         CAxis::get(*itAxis)->sendAllAttributesToServer();
1683       }
1684     }
1685
1686     // Create all reference domains on server side
1687     StdString domDefRoot("domain_definition");
1688     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1689     itE = domainIds.end();
1690     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1691     {
1692       if (!itDom->empty()) {
1693          domPtr->sendCreateChild(*itDom);
1694          CDomain::get(*itDom)->sendAllAttributesToServer();
1695       }
1696     }
1697   }
1698
1699   //! Update calendar in each time step
1700   void CContext::updateCalendar(int step)
1701   {
1702      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1703      calendar->update(step);
1704      info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1705#ifdef XIOS_MEMTRACK_LIGHT
1706      info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1707#endif
1708      //if (hasClient)
1709      if (hasClient && !hasServer) // For now we only use server level 1 to read data
1710      {
1711        checkPrefetchingOfEnabledReadModeFiles();
1712        garbageCollector.invalidate(calendar->getCurrentDate());
1713      }
1714   }
1715
1716   void CContext::initReadFiles(void)
1717   {
1718      vector<CFile*>::const_iterator it;
1719
1720      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
1721      {
1722         (*it)->initRead();
1723      }
1724   }
1725
1726   //! Server side: Create header of netcdf file
1727   void CContext::createFileHeader(void)
1728   {
1729      vector<CFile*>::const_iterator it;
1730
1731      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1732      // for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
1733      {
1734         (*it)->initWrite();
1735      }
1736   }
1737
1738   //! Get current context
1739   CContext* CContext::getCurrent(void)
1740   {
1741     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1742   }
1743
1744   /*!
1745   \brief Set context with an id be the current context
1746   \param [in] id identity of context to be set to current
1747   */
1748   void CContext::setCurrent(const string& id)
1749   {
1750     CObjectFactory::SetCurrentContextId(id);
1751     CGroupFactory::SetCurrentContextId(id);
1752   }
1753
1754  /*!
1755  \brief Create a context with specific id
1756  \param [in] id identity of new context
1757  \return pointer to the new context or already-existed one with identity id
1758  */
1759  CContext* CContext::create(const StdString& id)
1760  {
1761    CContext::setCurrent(id);
1762
1763    bool hasctxt = CContext::has(id);
1764    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1765    getRoot();
1766    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1767
1768#define DECLARE_NODE(Name_, name_) \
1769    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1770#define DECLARE_NODE_PAR(Name_, name_)
1771#include "node_type.conf"
1772
1773    return (context);
1774  }
1775
1776
1777     //! Server side: Receive a message to do some post processing
1778  void CContext::recvRegistry(CEventServer& event)
1779  {
1780    CBufferIn* buffer=event.subEvents.begin()->buffer;
1781    string id;
1782    *buffer>>id;
1783    get(id)->recvRegistry(*buffer);
1784  }
1785
1786  void CContext::recvRegistry(CBufferIn& buffer)
1787  {
1788    if (server->intraCommRank==0)
1789    {
1790      CRegistry registry(server->intraComm) ;
1791      registry.fromBuffer(buffer) ;
1792      registryOut->mergeRegistry(registry) ;
1793    }
1794  }
1795
1796  void CContext::sendRegistry(void)
1797  {
1798    registryOut->hierarchicalGatherRegistry() ;
1799
1800    // Use correct context client to send message
1801    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1802    for (int i = 0; i < nbSrvPools; ++i)
1803    {
1804      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1805      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1806        if (contextClientTmp->isServerLeader())
1807        {
1808           CMessage msg ;
1809           if (hasServer)
1810             msg<<this->getIdServer(i);
1811           else
1812             msg<<this->getIdServer();
1813           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
1814           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1815           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1816             event.push(*itRank,1,msg);
1817           contextClientTmp->sendEvent(event);
1818         }
1819         else contextClientTmp->sendEvent(event);
1820    }
1821  }
1822
1823  /*!
1824  * \fn bool CContext::isFinalized(void)
1825  * Context is finalized if it received context post finalize event.
1826  */
1827  bool CContext::isFinalized(void)
1828  {
1829    return finalized;
1830  }
1831
1832} // namespace xios
Note: See TracBrowser for help on using the repository browser.