Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
ArcaneBasicVerifierService.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* ArcaneBasicVerifierService.cc (C) 2000-2024 */
9/* */
10/* Variable comparison service. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ITraceMng.h"
15#include "arcane/utils/FatalErrorException.h"
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/StringBuilder.h"
18#include "arcane/utils/ValueConvert.h"
19
20#include "arcane/core/IParallelMng.h"
21#include "arcane/core/VariableCollection.h"
22#include "arcane/core/IVariableUtilities.h"
23#include "arcane/core/VerifierService.h"
24#include "arcane/core/ItemGroup.h"
25#include "arcane/core/IVariableMng.h"
26#include "arcane/core/IVariable.h"
27#include "arcane/core/ISubDomain.h"
29#include "arcane/core/IData.h"
30#include "arcane/core/internal/IVariableInternal.h"
31
32#include "arcane/std/internal/BasicReader.h"
33#include "arcane/std/internal/BasicWriter.h"
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38namespace Arcane
39{
40using namespace Arcane::impl;
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45class ArcaneBasicVerifierService
46: public VerifierService
47{
48 class GroupFinder
50 {
51 public:
52
53 GroupFinder(IVariableMng* vm)
54 : m_variable_mng(vm)
55 {}
56 ItemGroup getWantedGroup(VariableMetaData* vmd) override
57 {
58 String full_name = vmd->fullName();
59 IVariable* var = m_variable_mng->findVariableFullyQualified(full_name);
60 if (!var)
61 ARCANE_FATAL("Variable '{0}' not found");
62 return var->itemGroup();
63 }
64
65 private:
66
67 IVariableMng* m_variable_mng;
68 };
69
70 public:
71
72 explicit ArcaneBasicVerifierService(const ServiceBuildInfo& sbi)
73 : VerifierService(sbi)
74 {
75 }
76
77 public:
78
79 void build() override {}
80 void writeReferenceFile() override;
81 void doVerifFromReferenceFile(bool parallel_sequential, bool compare_ghost) override;
82
83 protected:
84
85 void _setFormatVersion(Int32 v)
86 {
87 m_wanted_format_version = v;
88 }
89
90 private:
91
92 String m_full_file_name;
93 Int32 m_wanted_format_version = 1;
94
95 private:
96
97 void _computeFullFileName(bool is_read)
98 {
99 ARCANE_UNUSED(is_read);
101 //m_full_file_name = fileName();
102 const String& sub_dir = subDir();
103 if (!sub_dir.empty()) {
104 s += "/";
105 s += sub_dir;
106 }
107 m_full_file_name = s;
108 }
109 void _doVerifHash(BasicReader* reader, const VariableCollection& variables);
110 void _writeReferenceFile(const String& file_name);
111};
112
113/*---------------------------------------------------------------------------*/
114/*---------------------------------------------------------------------------*/
115
116void ArcaneBasicVerifierService::
117_writeReferenceFile(const String& file_name)
118{
119 ISubDomain* sd = subDomain();
120 IParallelMng* pm = sd->parallelMng();
121 IVariableMng* vm = sd->variableMng();
122 auto open_mode = BasicReaderWriterCommon::OpenModeTruncate;
123 // For now, use version 1
124 // Starting from January 2019, it is possible to use version 2 or 3
125 // because the C# comparator supports this version.
126 Int32 version = m_wanted_format_version;
127 bool want_parallel = pm->isParallel();
128 ScopedPtrT<BasicWriter> verif(new BasicWriter(sd->application(), pm, file_name,
129 open_mode, version, want_parallel));
130 if (compareMode() == eCompareMode::HashOnly)
131 verif->setSaveValues(false);
132
133 verif->initialize();
134
135 // In parallel, since writing requires communication between subdomains,
136 // it is essential that all PEs have the same variables. We filter them to
137 // ensure this.
138 VariableCollection used_variables = vm->usedVariables();
139 if (pm->isParallel()) {
140 bool dump_not_common = true;
141 VariableCollection filtered_variables = vm->utilities()->filterCommonVariables(pm, used_variables, dump_not_common);
142 vm->writeVariables(verif.get(), filtered_variables);
143 }
144 else {
145 vm->writeVariables(verif.get(), used_variables);
146 }
147}
148
149/*---------------------------------------------------------------------------*/
150/*---------------------------------------------------------------------------*/
151
154{
155 _computeFullFileName(false);
156 String dir_name = platform::getFileDirName(m_full_file_name);
157 platform::recursiveCreateDirectory(m_full_file_name);
158 _writeReferenceFile(m_full_file_name);
159}
160
161/*---------------------------------------------------------------------------*/
162/*---------------------------------------------------------------------------*/
163
165doVerifFromReferenceFile(bool parallel_sequential, bool compare_ghost)
166{
167 ISubDomain* sd = subDomain();
168 IParallelMng* pm = sd->parallelMng();
169 IVariableMng* vm = subDomain()->variableMng();
170 ITraceMng* tm = sd->traceMng();
171 _computeFullFileName(true);
172 bool want_parallel = pm->isParallel();
173 Ref<BasicReader> reader = makeRef(new BasicReader(sd->application(), pm, A_NULL_RANK, m_full_file_name, want_parallel));
174 reader->initialize();
175 GroupFinder group_finder(vm);
176 reader->setItemGroupFinder(&group_finder);
177
178 VariableList read_variables;
179 _getVariables(read_variables, parallel_sequential);
180
181 // In parallel, since reading requires communication between subdomains,
182 // it is essential that all PEs have the same variables. We filter them to
183 // ensure this.
184 if (pm->isParallel()) {
185 IVariableMng* vm = sd->variableMng();
186 bool dump_not_common = true;
187 VariableCollection filtered_variables = vm->utilities()->filterCommonVariables(pm, read_variables, dump_not_common);
188 read_variables = filtered_variables;
189 }
190
191 tm->info() << "Checking (" << m_full_file_name << ")";
192 reader->beginRead(read_variables);
193 if (compareMode() == eCompareMode::Values)
194 _doVerif(reader.get(), read_variables, compare_ghost);
195 if (compareMode() == eCompareMode::HashOnly)
196 _doVerifHash(reader.get(), read_variables);
197 reader->endRead();
198}
199
200/*---------------------------------------------------------------------------*/
201/*---------------------------------------------------------------------------*/
202namespace
203{
204 String
205 _getHashValueOrNull(const std::map<String, String>& comparison_hash_map, const String& name)
206 {
207 auto x = comparison_hash_map.find(name);
208 if (x != comparison_hash_map.end())
209 return x->second;
210 return {};
211 }
212} // namespace
213
214void ArcaneBasicVerifierService::
215_doVerifHash(BasicReader* ref_reader, const VariableCollection& variables)
216{
217 ISubDomain* sd = subDomain();
218 IParallelMng* pm = sd->parallelMng();
219 bool is_master = pm->isMasterIO();
220 const bool want_parallel = pm->isParallel();
221
222 info() << "Check Verif Hash";
223 // Retrieves the hash calculation algorithm
224 IHashAlgorithm* ref_compare_hash_algo = ref_reader->comparisonHashAlgorithm();
225 if (!ref_compare_hash_algo)
226 // TODO: check if we should do nothing or signal an error.
227 return;
228
229 // Calculates the hash of the current variable values
230 std::map<String, String> current_comparison_hash_map;
231 ParallelDataWriterList parallel_data_writers;
232 info() << "DoVerifHash";
233 for (VariableCollection::Enumerator ivar(variables); ++ivar;) {
234 IVariable* var = *ivar;
235 Ref<IData> allocated_data;
236 IData* data = var->data();
237 // In parallel, sort entities by increasing uniqueId().
238 // In sequential mode, this is always the case.
239 // NOTE: for now we use the global IParallelMng but we should
240 // check if we should not use the one associated with the
241 // current variable's mesh \a var.
242 if (want_parallel) {
243 // In parallel, only compare variables on entities
244 ItemGroup group = var->itemGroup();
245 if (group.null())
246 continue;
247 Ref<ParallelDataWriter> writer = parallel_data_writers.getOrCreateWriter(group);
248 allocated_data = writer->getSortedValues(data);
249 data = allocated_data.get();
250 }
251 String hash_string = var->_internalApi()->computeComparisonHashCollective(ref_compare_hash_algo, data);
252 if (!hash_string.empty())
253 current_comparison_hash_map.try_emplace(var->fullName(), hash_string);
254 }
255
256 std::map<String, String> ref_comparison_hash_map;
257 ref_reader->fillComparisonHash(ref_comparison_hash_map);
258 if (is_master) {
259 Int32 nb_variable = 0;
260 Int32 nb_compared = 0;
261 Int32 nb_different = 0;
262 for (VariableCollection::Enumerator ivar(variables); ++ivar;) {
263 IVariable* var = *ivar;
264 String var_full_name = var->fullName();
265 ++nb_variable;
266 String ref_hash = _getHashValueOrNull(ref_comparison_hash_map, var_full_name);
267 String current_hash = _getHashValueOrNull(current_comparison_hash_map, var_full_name);
268 if (!ref_hash.empty() && !current_hash.empty()) {
269 ++nb_compared;
270 if (ref_hash != current_hash) {
271 info() << "Different hash ref_hash=" << ref_hash << " current=" << current_hash
272 << " var=" << var_full_name;
273 ++nb_different;
274 }
275 else
276 info(4) << "Found Hash hash=" << ref_hash << " var=" << var_full_name;
277 }
278 }
279 info() << "NbVariable=" << nb_variable << " nb_compared=" << nb_compared << " nb_different=" << nb_different;
280 }
281}
282
283/*---------------------------------------------------------------------------*/
284/*---------------------------------------------------------------------------*/
285
286/*---------------------------------------------------------------------------*/
287/*---------------------------------------------------------------------------*/
288
289class ArcaneBasicVerifierService2
290: public ArcaneBasicVerifierService
291{
292 public:
293
294 explicit ArcaneBasicVerifierService2(const ServiceBuildInfo& sbi)
295 : ArcaneBasicVerifierService(sbi)
296 {
297 }
298};
299
300/*---------------------------------------------------------------------------*/
301/*---------------------------------------------------------------------------*/
302
303class ArcaneBasicVerifierServiceV3
304: public ArcaneBasicVerifierService
305{
306 public:
307
308 explicit ArcaneBasicVerifierServiceV3(const ServiceBuildInfo& sbi)
309 : ArcaneBasicVerifierService(sbi)
310 {
311 _setFormatVersion(3);
312 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_VERIF_HASHONLY", true)) {
313 bool use_hash = (v.value() != 0);
314 info() << "ArcaneBasicVerifierServiceV3: using hash?=" << use_hash;
316 }
317 }
318};
319
320/*---------------------------------------------------------------------------*/
321/*---------------------------------------------------------------------------*/
322
324 ServiceProperty("ArcaneBasicVerifier2", ST_SubDomain),
326
328 ServiceProperty("ArcaneBasicVerifier3", ST_SubDomain),
330
331/*---------------------------------------------------------------------------*/
332/*---------------------------------------------------------------------------*/
333
334} // End namespace Arcane
335
336/*---------------------------------------------------------------------------*/
337/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
This file contains the various service factories and macros for registering services.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro to declare an interface when registering a service.
void build() override
Build-level construction of the service.
void doVerifFromReferenceFile(bool parallel_sequential, bool compare_ghost) override
Performs the verification from the reference file.
void writeReferenceFile() override
Writes the reference file.
Template class for converting a type.
virtual ITraceMng * traceMng() const =0
Trace manager.
Interface of the parallelism manager for a subdomain.
virtual bool isMasterIO() const =0
true if the instance is a master I/O manager.
virtual bool isParallel() const =0
Returns true if the execution is parallel.
Interface of the subdomain manager.
Definition ISubDomain.h:75
virtual IApplication * application()=0
Application.
virtual IParallelMng * parallelMng()=0
Returns the parallelism manager.
virtual IVariableMng * variableMng()=0
Returns the variable manager.
virtual TraceMessage info()=0
Stream for an information message.
virtual String computeComparisonHashCollective(IHashAlgorithm *hash_algo, IData *sorted_data)=0
Calculates the comparison hash for the variable.
Variable manager interface.
virtual IVariableUtilities * utilities() const =0
Interface of associated utility functions.
virtual VariableCollection usedVariables()=0
List of used variables.
virtual void writeVariables(IDataWriter *writer, IVariableFilter *filter=0)=0
Writes the variables.
virtual VariableCollection filterCommonVariables(IParallelMng *pm, VariableCollection input_variables, bool dump_not_common)=0
Filters common variables between multiple ranks.
Interface of a variable.
Definition IVariable.h:40
virtual String fullName() const =0
Full variable name (with family prefix).
virtual IData * data()=0
Data associated with the variable.
virtual ItemGroup itemGroup() const =0
Associated mesh group.
virtual IVariableInternal * _internalApi()=0
Internal Arcane API.
Interface of the data verification service between two executions.
@ HashOnly
Compares only the hashes of the values.
Mesh entity group.
Definition ItemGroup.h:51
bool null() const
true means the group is the null group
Definition ItemGroup.h:75
InstanceType * get() const
Associated instance or nullptr if none.
Reference to an instance.
Structure containing the information to create a service.
Service creation properties.
Unicode character string constructor.
bool empty() const
True if the string is empty (null or "").
Definition String.cc:317
TraceMessage info() const
Flow for an information message.
Metadata on a variable.
String fullName() const
Full name of the variable.
String fileName() const override
Name of the file containing the reference values.
virtual void _getVariables(VariableList variables, bool parallel_sequential)
Fills the list of variables that need to be reread in variables.
void setCompareMode(eCompareMode v) override
Desired comparison type.
String subDir() const override
Name of the file containing the reference values.
Interface to find the group associated with a variable based on this metadata.
Definition BasicReader.h:45
void fillComparisonHash(std::map< String, String > &comparison_hash_map)
Fills the argument with pairs (variable_name, hash_value).
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro for registering a service.
String getFileDirName(const String &file_name)
Returns the directory name of a file.
bool recursiveCreateDirectory(const String &dir_name)
Create a directory.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
@ ST_SubDomain
The service is used at the subdomain level.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.
std::int32_t Int32
Signed integer type of 32 bits.