source: XIOS2/trunk/src/node/context.cpp

Last change on this file was 2615, checked in by ymipsl, 4 months ago
  • Permit now usage of contex_group into xml file for more modularity
  • Src path is now relative to parent file, except if path is an absolute path

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