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

Last change on this file since 1330 was 1330, checked in by oabramkina, 6 years ago

Adding buffer evaluation in case of reading.

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