source: XIOS/dev/dev_trunk_omp/src/node/context.cpp @ 1646

Last change on this file since 1646 was 1646, checked in by yushan, 5 years ago

branch merged with trunk @1645. arch file (ep&mpi) added for ADA

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