Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
CaseMng.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/* CaseMng.cc (C) 2000-2025 */
9/* */
10/* Class managing dataset options. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/List.h"
16#include "arcane/utils/ValueConvert.h"
17#include "arcane/utils/Deleter.h"
18#include "arcane/utils/StringBuilder.h"
19#include "arcane/utils/ITraceMng.h"
20#include "arcane/utils/TraceAccessor.h"
21#include "arcane/utils/FatalErrorException.h"
22#include "arcane/utils/OStringStream.h"
23#include "arcane/utils/ScopedPtr.h"
24#include "arcane/utils/ApplicationInfo.h"
25#include "arcane/utils/NotImplementedException.h"
26#include "arcane/utils/CriticalSection.h"
27#include "arcane/utils/CommandLineArguments.h"
28#include "arcane/utils/internal/ParameterListWithCaseOption.h"
29
30#include "arcane/core/ISubDomain.h"
31#include "arcane/core/IApplication.h"
32#include "arcane/core/IParallelMng.h"
33#include "arcane/core/IParallelSuperMng.h"
34#include "arcane/core/ICaseMng.h"
35#include "arcane/core/IModule.h"
36#include "arcane/core/CaseOptions.h"
37#include "arcane/core/XmlNode.h"
38#include "arcane/core/XmlNodeList.h"
39#include "arcane/core/XmlNodeIterator.h"
40#include "arcane/core/ICaseDocument.h"
41#include "arcane/core/ICaseFunctionProvider.h"
42#include "arcane/core/CaseNodeNames.h"
43#include "arcane/core/ISession.h"
44#include "arcane/core/CaseTable.h"
45#include "arcane/core/IMainFactory.h"
46#include "arcane/core/IIOMng.h"
47#include "arcane/core/ServiceFinder2.h"
48#include "arcane/core/ObservablePool.h"
49#include "arcane/core/ICaseDocumentVisitor.h"
50#include "arcane/core/ServiceBuilder.h"
51#include "arcane/core/internal/ICaseMngInternal.h"
52
53#include "arcane/impl/CaseDocumentLangTranslator.h"
54
55/*---------------------------------------------------------------------------*/
56/*---------------------------------------------------------------------------*/
57
58namespace Arcane
59{
60
61/*---------------------------------------------------------------------------*/
62/*---------------------------------------------------------------------------*/
63
64extern "C++" std::unique_ptr<ICaseDocumentVisitor>
65createPrintCaseDocumentVisitor(ITraceMng* tm, const String& lang);
66
67extern "C++" ICaseDocumentFragment*
68arcaneCreateCaseDocumentFragment(ITraceMng* tm, IXmlDocumentHolder* document);
69
70/*---------------------------------------------------------------------------*/
71/*---------------------------------------------------------------------------*/
72
76class CaseMng
78, public ICaseMng
79, public ICaseMngInternal
80, public TraceAccessor
81{
83
84 private:
85
86 class OptionsReader
87 {
88 public:
89
90 OptionsReader(ICaseMng*) {}
91 void read(bool is_phase1);
92 void addOption(ICaseOptions* o) { m_options.add(o); }
93
94 private:
95
97 void _read(bool is_phase1);
99 };
100
101 private:
102
103 class ErrorInfo
104 {
105 public:
106
107 explicit ErrorInfo(const String& error_message)
108 : m_has_error(true)
109 , m_error_message(error_message)
110 {}
111 ErrorInfo()
112 : m_has_error(false)
113 {}
114
115 public:
116
117 bool hasError() const { return m_has_error; }
118 const String& errorMessage() const { return m_error_message; }
119
120 private:
121
122 bool m_has_error;
123 String m_error_message;
124 };
125
129 class CaseOptionsFilterUsed
130 {
131 public:
132
133 explicit CaseOptionsFilterUsed(const CaseOptionsList& opt_list)
134 : m_begin(opt_list.begin())
135 , m_end(opt_list.end())
136 {}
137
138 public:
139
140 auto begin() const { return m_begin; }
141 auto end() const { return m_end; }
142 void operator++()
143 {
144 bool do_continue = true;
145 do {
146 ++m_begin;
147 if (m_begin >= m_end)
148 return;
149 ICaseOptions* co = *m_begin;
150 IModule* md = co->caseModule();
151 do_continue = (md && !md->used());
152 } while (do_continue);
153 }
154
155 private:
156
157 CaseOptionsList::const_iterator m_begin;
158 CaseOptionsList::const_iterator m_end;
159 };
160
161 public:
162
163 explicit CaseMng(ISubDomain*);
164 ~CaseMng() override;
165
166 public:
167
169 IMeshMng* meshMng() const override { return m_sub_domain->meshMng(); }
170 ISubDomain* subDomain() override { return m_sub_domain; }
171 IApplication* application() override { return m_sub_domain->application(); }
172 IPhysicalUnitSystem* physicalUnitSystem() const override { return m_sub_domain->physicalUnitSystem(); }
173 ICaseDocument* caseDocument() override { return m_case_document.get(); }
175 {
177 if (doc)
178 return doc->fragment();
179 return nullptr;
180 }
181 ICaseDocument* readCaseDocument(const String& filename, ByteConstArrayView bytes) override;
182
183 void readFunctions() override;
184 void readOptions(bool is_phase1) override;
185 void printOptions() override;
186 void registerOptions(ICaseOptions*) override;
187 void unregisterOptions(ICaseOptions*) override;
188 ICaseFunction* findFunction(const String& name) const override;
189 void updateOptions(Real current_time, Real current_deltat, Integer current_iteration) override;
190 CaseFunctionCollection functions() override { return m_functions; }
191
192 void removeFunction(ICaseFunction* func, bool dofree) override;
193 void removeFunction(ICaseFunction* func) override;
194 void addFunction(ICaseFunction* func) override
195 {
196 addFunction(makeRef(func));
197 }
198 void addFunction(Ref<ICaseFunction> func) override;
199
201
202 void setTreatWarningAsError(bool v) override { m_treat_warning_as_error = v; }
203 bool isTreatWarningAsError() const override { return m_treat_warning_as_error; }
204
205 void setAllowUnkownRootElelement(bool v) override { m_allow_unknown_root_element = v; }
206 bool isAllowUnkownRootElelement() const override { return m_allow_unknown_root_element; }
207
209 {
210 return m_observables[type];
211 }
212
213 Ref<ICaseFunction> findFunctionRef(const String& name) const;
214
215 Ref<ICaseMng> toReference() override { return makeRef<ICaseMng>(this); }
216
217 ICaseMngInternal* _internalImpl() override { return this; }
218
220
221 void internalReadOneOption(ICaseOptions* opt, bool is_phase1) override;
223 {
224 return arcaneCreateCaseDocumentFragment(traceMng(), document);
225 }
226 const ParameterListWithCaseOption& parameters() const { return m_parameters; }
228
229 public:
230
231 String msgClassName() const { return "CaseMng"; }
232
233 private:
234
236 ScopedPtrT<ICaseDocument> m_case_document;
237 CaseFunctionList m_functions;
239 List<CaseOptionBase*> m_options_with_function;
240 bool m_treat_warning_as_error = false;
241 bool m_allow_unknown_root_element = true;
244 bool m_is_function_read = false;
245 Ref<ICaseFunctionDotNetProvider> m_dotnet_provider;
246 ParameterListWithCaseOption m_parameters;
247
248 private:
249
250 ErrorInfo _readOneTable(const XmlNode& func_elem);
251 ErrorInfo _checkValidFunction(const XmlNode& func_elem, CaseFunctionBuildInfo& cfbi);
252 void _readOptions(bool is_phase1);
253 void _readFunctions();
254 void _readCaseDocument(const String& filename, ByteConstArrayView bytes);
255 void _printErrors(ICaseDocumentFragment* doc, bool is_phase1);
256 void _checkTranslateDocument();
257 void _removeFunction(ICaseFunction* func, bool do_delete);
259 ICaseDocument* _noNullCaseDocument()
260 {
261 ICaseDocument* doc = m_case_document.get();
263 return doc;
264 }
265 void _readOneDotNetFunction(const String& assembly_name, const String& class_name);
266};
267
268/*---------------------------------------------------------------------------*/
269/*---------------------------------------------------------------------------*/
270
271void CaseMng::OptionsReader::
272read(bool is_phase1)
273{
274 _read(is_phase1);
275 if (is_phase1)
277}
278
279/*---------------------------------------------------------------------------*/
280/*---------------------------------------------------------------------------*/
281
282void CaseMng::OptionsReader::
283_read(bool is_phase1)
284{
285 auto read_phase = (is_phase1) ? eCaseOptionReadPhase::Phase1 : eCaseOptionReadPhase::Phase2;
286 for (ICaseOptions* co : m_options) {
287 co->read(read_phase);
288 }
289}
290
291/*---------------------------------------------------------------------------*/
292/*---------------------------------------------------------------------------*/
293
294void CaseMng::OptionsReader::
295_searchInvalidOptions()
296{
297 // Searches for dataset elements that do not correspond to a known option.
298 XmlNodeList invalid_elems;
299 for (ICaseOptions* co : m_options)
300 co->addInvalidChildren(invalid_elems);
301}
302
303/*---------------------------------------------------------------------------*/
304/*---------------------------------------------------------------------------*/
305
306CaseMng::
307CaseMng(ISubDomain* sub_domain)
308: TraceAccessor(sub_domain->traceMng())
309, m_sub_domain(sub_domain)
310, m_treat_warning_as_error(false)
311{
312 if (!platform::getEnvironmentVariable("ARCANE_STRICT_CASEOPTION").null())
313 m_treat_warning_as_error = true;
314
317
318 // Recopies the command line arguments in \a m_parameters that
319 // might override the dataset values
320 m_parameters.addParameters(sub_domain->application()->applicationInfo().commandLineArguments().parameters());
321}
322
323/*---------------------------------------------------------------------------*/
324/*---------------------------------------------------------------------------*/
325
326CaseMng::
327~CaseMng()
328{
329}
330
331/*---------------------------------------------------------------------------*/
332/*---------------------------------------------------------------------------*/
333
334/*---------------------------------------------------------------------------*/
335/*---------------------------------------------------------------------------*/
336
337extern "C++" ICaseMng*
338arcaneCreateCaseMng(ISubDomain* mng)
339{
340 return new CaseMng(mng);
341}
342
343/*---------------------------------------------------------------------------*/
344/*---------------------------------------------------------------------------*/
345
347readOptions(bool is_phase1)
348{
349 Trace::Setter mci(traceMng(), msgClassName());
350
351 ICaseDocumentFragment* doc = _noNullCaseDocument()->fragment();
352 if (is_phase1)
353 info() << "Reading the input data (phase1): language '"
354 << doc->language() << "', "
355 << m_case_options_list.count() << " input data.";
356 else
357 info() << "Reading the input data (phase2)";
358
359 if (is_phase1) {
361 }
362
363 if (is_phase1)
365
366 // Notifies the start of reading options.
367 if (is_phase1)
368 m_observables[eCaseMngEventType::BeginReadOptionsPhase1]->notifyAllObservers();
369 else
370 m_observables[eCaseMngEventType::BeginReadOptionsPhase2]->notifyAllObservers();
371
372 _readOptions(is_phase1);
373 _printErrors(doc, is_phase1);
374
375 _checkTranslateDocument();
376}
377
378/*---------------------------------------------------------------------------*/
379/*---------------------------------------------------------------------------*/
380
381void CaseMng::
382_checkTranslateDocument()
383{
384 // If requested, writes a file containing the translation in the specified language
385 // of each data set element.
386 String tr_lang = platform::getEnvironmentVariable("ARCANE_TRANSLATE_CASEDOCUMENT");
387 if (!tr_lang.null()) {
388 info() << "Generating translation for case file to lang=" << tr_lang;
390 String convert_string = translator.translate(this, tr_lang);
391 {
392 std::ofstream ofile("convert_info.txt");
393 convert_string.writeBytes(ofile);
394 }
395 }
396}
397
398/*---------------------------------------------------------------------------*/
399/*---------------------------------------------------------------------------*/
400
401void CaseMng::
402_printErrors(ICaseDocumentFragment* doc, bool is_phase1)
403{
404 //ICaseDocumentFragment* doc = _noNullCaseDocument()->fragment();
405
406 // Displays warnings but only during phase 2 to have
407 // them all at once (some warnings are only generated during phase 2)
408 if (!m_treat_warning_as_error) {
409 if (!is_phase1) {
410 if (doc->hasWarnings()) {
411 OStringStream ostr;
412 doc->printWarnings(ostr());
413 pwarning() << "The input data are not coherent:\n\n"
414 << ostr.str();
415 }
416 }
417 }
418 bool has_error = doc->hasError();
419 if (doc->hasWarnings() && m_treat_warning_as_error && !is_phase1)
420 has_error = true;
421
422 if (has_error) {
423 OStringStream ostr;
424 if (m_treat_warning_as_error && doc->hasWarnings())
425 doc->printWarnings(ostr());
426 doc->printErrors(ostr());
427 ARCANE_FATAL("Input data are invalid:\n\n{0}", ostr.str());
428 }
429}
430
431/*---------------------------------------------------------------------------*/
432/*---------------------------------------------------------------------------*/
433
436{
438 return;
439
440 Trace::Setter mci(traceMng(), msgClassName());
441
442 // Registers the services providing the functions
443 {
445 ISubDomain* sd = subDomain();
446 FinderType finder(sd->application(), sd);
447 const Array<FinderType::FactoryType*>& factories = finder.factories();
448 info() << "NB_CASE_FUNCTION_PROVIDER_FACTORY = " << factories.size();
449 for (const auto& factory : factories) {
450 auto cfp = factory->createServiceReference(ServiceBuildInfoBase(sd));
451 if (cfp.get()) {
452 info() << "FOUND CASE FUNCTION PROVIDER (V2)!";
453 cfp->registerCaseFunctions(this);
454 }
455 }
456 }
457
458 _readFunctions();
459
460 m_is_function_read = true;
461}
462
463/*---------------------------------------------------------------------------*/
464/*---------------------------------------------------------------------------*/
465
468{
469 Trace::Setter mci(traceMng(), msgClassName());
470
471 log() << "Register case option <" << co->rootTagName() << ">";
472 m_case_options_list.add(co);
473}
474
475/*---------------------------------------------------------------------------*/
476/*---------------------------------------------------------------------------*/
477
480{
481 m_case_options_list.remove(co);
482}
483
484/*---------------------------------------------------------------------------*/
485/*---------------------------------------------------------------------------*/
486
487void CaseMng::
488_readFunctions()
489{
490 bool has_error = false;
491
492 // Reading functions
493
494 ICaseDocumentFragment* doc = _noNullCaseDocument()->fragment();
495 XmlNode case_root_elem = doc->rootElement();
496
497 CaseNodeNames* cnn = doc->caseNodeNames();
498
499 // Retrieves the list of walk tables.
500 XmlNode funcs_elem = case_root_elem.child(cnn->functions);
501 XmlNodeList functions_elem = funcs_elem.children();
502
503 String ustr_table(cnn->function_table);
504 String ustr_script(cnn->function_script);
505
506 if (functions_elem.empty())
507 return;
508
509 for (XmlNode node : functions_elem) {
510 bool is_bad = false;
511 if (node.type() != XmlNode::ELEMENT)
512 continue;
513 if (node.isNamed(ustr_table)) {
514 ErrorInfo err_info = _readOneTable(node);
515 if (err_info.hasError()) {
516 is_bad = true;
517 String table_name = node.attrValue(cnn->name_attribute);
518 if (table_name.null())
519 error() << " Error in element '" << node.xpathFullName() << "' : "
520 << err_info.errorMessage();
521 else
522 error() << " Error in table named '" << table_name << "' : "
523 << err_info.errorMessage();
524 }
525 }
526 else if (node.isNamed("external-assembly")) {
527 String assembly_name = node.expectedChild("assembly-name").value();
528 String class_name = node.expectedChild("class-name").value();
529 _readOneDotNetFunction(assembly_name, class_name);
530 }
531 else
532 warning() << "Unknown node in functions: " << node.xpathFullName();
533 has_error |= is_bad;
534 }
535
536 if (has_error)
537 ARCANE_FATAL("Error while reading the functions");
538
539 // Displays information about the number of tables and their number
540 // of elements
541 log() << "Number of functions: " << m_functions.count();
542 for (auto& icf_ref : m_functions) {
543 auto table = dynamic_cast<CaseTable*>(icf_ref.get());
544 if (table)
545 log() << "Table <" << table->name() << "> own "
546 << table->nbElement() << " element(s)";
547 }
548}
549
550/*---------------------------------------------------------------------------*/
551/*---------------------------------------------------------------------------*/
552
553CaseMng::ErrorInfo CaseMng::
554_checkValidFunction(const XmlNode& func_elem, CaseFunctionBuildInfo& cfbi)
555{
556 CaseNodeNames* cnn = caseDocument()->caseNodeNames();
557
558 String func_name = func_elem.attrValue(cnn->name_attribute);
559 if (func_name.null())
560 return ErrorInfo(String::format("missing attribute '{0}'", cnn->name_attribute));
561
562 cfbi.m_name = func_name;
563 if (findFunction(func_name))
564 return ErrorInfo(String::format("function '{0}' is defined several times", func_name));
565
566 String param_name = func_elem.attrValue(cnn->function_parameter);
567 if (param_name.null())
568 return ErrorInfo(String::format("missing attribute '{0}'", cnn->function_parameter));
569
570 String value_name = func_elem.attrValue(cnn->function_value);
571 if (value_name.null())
572 return ErrorInfo(String::format("missing attribute '{0}'", cnn->function_value));
573
574 String comul_name = func_elem.attrValue("comul");
575 String transform_x_name = func_elem.attrValue("comul-x");
576
577 cfbi.m_transform_param_func = transform_x_name;
578 cfbi.m_transform_value_func = comul_name;
579
580 String ustr_time(cnn->time_type);
581 String ustr_iteration(cnn->iteration_type);
582
583 String ustr_real(cnn->real_type);
584 String ustr_real3(cnn->real3_type);
585 String ustr_bool(cnn->bool_type);
586 String ustr_integer(cnn->integer_type);
587 String ustr_string(cnn->string_type);
588
589 UniqueArray<String> valid_param_strs = { ustr_time, ustr_real, ustr_iteration, ustr_integer };
590
591 // Checks that the specified parameter type is correct (real or integer)
593 if (param_name == ustr_time || param_name == ustr_real)
594 param_type = ICaseFunction::ParamReal;
595 else if (param_name == ustr_iteration || param_name == ustr_integer)
596 param_type = ICaseFunction::ParamInteger;
597 if (param_type == ICaseFunction::ParamUnknown) {
598 return ErrorInfo(String::format("invalid value '{0}' for attribute '{1}'. Valid values are '{2}'.",
599 param_name, cnn->function_parameter, String::join(", ", valid_param_strs)));
600 }
601 cfbi.m_param_type = param_type;
602
603 UniqueArray<String> valid_value_strs = { ustr_real, ustr_real3, ustr_integer, ustr_bool, ustr_string };
604
605 // Checks that the specified value type is correct (real or integer)
607 if (value_name == ustr_real)
608 value_type = ICaseFunction::ValueReal;
609 if (value_name == ustr_integer)
610 value_type = ICaseFunction::ValueInteger;
611 if (value_name == ustr_bool)
612 value_type = ICaseFunction::ValueBool;
613 if (value_name == ustr_string)
614 value_type = ICaseFunction::ValueString;
615 if (value_name == ustr_real3)
616 value_type = ICaseFunction::ValueReal3;
617 if (value_type == ICaseFunction::ValueUnknown)
618 return ErrorInfo(String::format("invalid value '{0}' for attribute '{1}'. Valid values are '{2}'.",
619 value_name, cnn->function_value, String::join(", ", valid_value_strs)));
620 cfbi.m_value_type = value_type;
621
622 // Checks if there is a 'deltat-coef' element and if so, retrieves its value.
623 String deltat_coef_str = func_elem.attrValue(cnn->function_deltat_coef);
624 Real deltat_coef = 0.0;
625 if (!deltat_coef_str.null()) {
626 if (builtInGetValue(deltat_coef, deltat_coef_str))
627 return ErrorInfo(String::format("Invalid value '{0}' for attribute '{1}. Can not convert to 'Real' type",
628 deltat_coef_str, cnn->function_deltat_coef));
629 cfbi.m_deltat_coef = deltat_coef;
630 info() << "Coefficient deltat for the function '" << func_name << "' = " << cfbi.m_deltat_coef;
631 }
632
633 return ErrorInfo();
634}
635
636/*---------------------------------------------------------------------------*/
637/*---------------------------------------------------------------------------*/
638
639CaseMng::ErrorInfo CaseMng::
640_readOneTable(const XmlNode& func_elem)
641{
642 CaseFunctionBuildInfo cfbi(traceMng());
643
644 ErrorInfo err_info = _checkValidFunction(func_elem, cfbi);
645 if (err_info.hasError())
646 return err_info;
647
648 CaseNodeNames* cnn = caseDocument()->caseNodeNames();
649
650 String ustr_constant(cnn->function_constant);
651 String ustr_linear(cnn->function_linear);
652 String ustr_value(cnn->function_value);
653
654 String interpolation_name = func_elem.attrValue(cnn->function_interpolation);
655 if (interpolation_name.null())
656 return ErrorInfo(String::format("missing attribute '{0}'", cnn->function_interpolation));
657
658 // Checks that the specified curve type is correct
660 if (interpolation_name == ustr_constant)
661 interpolation_type = CaseTable::CurveConstant;
662 else if (interpolation_name == ustr_linear)
663 interpolation_type = CaseTable::CurveLinear;
664 if (interpolation_type == CaseTable::CurveUnknown) {
665 return ErrorInfo(String::format("Invalid value for attribute '{0}'. Valid values are '{1}' or '{2}'",
666 cnn->function_interpolation, ustr_constant, ustr_linear));
667 }
668
669 // Retrieves the list of function values
670 XmlNodeList func_value_list = func_elem.children(ustr_value);
671 Integer nb_func_value = func_value_list.size();
672 if (nb_func_value == 0)
673 return ErrorInfo("The table has no values");
674
675 auto func = new CaseTable(cfbi, interpolation_type);
677
678 Integer value_index = 0;
679
680 String ustr_x("x");
681 String ustr_y("y");
682 for (const auto& i : func_value_list) {
683 String param_str = i.child(ustr_x).value();
684 String value_str = i.child(ustr_y).value();
685 param_str = String::collapseWhiteSpace(param_str);
686 value_str = String::collapseWhiteSpace(value_str);
687 if (param_str.null())
688 return ErrorInfo(String::format("index={0} element <x> is missing", value_index));
689 if (value_str.null())
690 return ErrorInfo(String::format("index={0} element <y> is missing", value_index));
691
692 CaseTable::eError error_number = func->appendElement(param_str, value_str);
693 // TODO: ADD DOC IN THE DATA DOCUMENT about this information.
694 if (error_number != CaseTable::ErrNo) {
695 String message = "No info";
696 switch (error_number) {
698 message = String::format("parameter '{0}' can not be converted to the 'param' type of the table", param_str);
699 break;
701 message = String::format("value '{0}' can not be converted to the 'value' type of the table", value_str);
702 break;
704 message = "<x> lesser than previous <x>";
705 break;
707 message = "<x> greater than next <x>";
708 break;
710 message = "bad interval";
711 break;
712 case CaseTable::ErrNo:
713 // Should never happen
714 ARCANE_FATAL("Internal Error");
715 }
716 return ErrorInfo(String::format("index={0} : {1}", value_index, message));
717 }
718 ++value_index;
719 }
720 return ErrorInfo();
721}
722
723/*---------------------------------------------------------------------------*/
724/*---------------------------------------------------------------------------*/
725
726void CaseMng::
727_readOneDotNetFunction(const String& assembly_name, const String& class_name)
728{
729 // If it hasn't been done yet, load the '.Net' service which will register
730 // the functions
731 if (!m_dotnet_provider.get()) {
732 ServiceBuilder<ICaseFunctionDotNetProvider> sb(subDomain());
733 m_dotnet_provider = sb.createReference("ArcaneDefaultDotNetCaseFunctionProvider", SB_AllowNull);
734 if (!m_dotnet_provider.get())
735 ARCANE_FATAL("Can not create '.Net' case function provider. Check that the '.Net' runtime is loaded.");
736 }
737
738 m_dotnet_provider->registerCaseFunctions(this, assembly_name, class_name);
739}
740
741/*---------------------------------------------------------------------------*/
742/*---------------------------------------------------------------------------*/
743
749{
750 ICaseDocument* doc = _noNullCaseDocument();
751 ICaseDocumentFragment* doc_fragment = doc->fragment();
752 // Searches for data set elements that do not correspond to a known option.
753 XmlNodeList invalid_elems;
755 co->addInvalidChildren(invalid_elems);
756
757 // Searches for root elements that do not correspond to an option
758
759 // Temporarily, for compatibility reasons, allows unused root elements.
760 if (!platform::getEnvironmentVariable("ARCANE_ALLOW_UNKNOWN_ROOT_ELEMENT").null())
761 m_allow_unknown_root_element = true;
762
763 String arcane_element_name = doc->arcaneElement().name();
764 String function_element_name = doc->functionsElement().name();
765 XmlNodeList mesh_elements = doc->meshElements();
766 String mesh_element_name;
767 if (mesh_elements.size() > 0)
768 mesh_element_name = mesh_elements[0].name();
769 for (XmlNode node : doc_fragment->rootElement()) {
770 if (node.type() != XmlNode::ELEMENT)
771 continue;
772 String name = node.name();
773 if (name == "comment")
774 continue;
775 if (name == arcane_element_name || name == function_element_name)
776 continue;
777 if (!mesh_element_name.null() && name == mesh_element_name)
778 continue;
779 bool is_found = false;
781 if (co->rootTagName() == name) {
782 is_found = true;
783 break;
784 }
785 }
786 if (!is_found) {
787 if (m_allow_unknown_root_element)
788 pwarning() << "-- Unknown root option '" << node.xpathFullName() << "'";
789 else
790 invalid_elems.add(node);
791 }
792 }
793
794 if (!doc_fragment->hasError()) {
795 if (!invalid_elems.empty()) {
796 for (XmlNode xnode : invalid_elems) {
797 perror() << "-- Unknown root option '" << xnode.xpathFullName() << "'";
798 }
799 pfatal() << "Unknown root option(s) in the input data. "
800 << "You can put these options inside <comment> tags to remove this error";
801 }
802 }
803}
804
805/*---------------------------------------------------------------------------*/
806/*---------------------------------------------------------------------------*/
807
808void CaseMng::
809_readOptions(bool is_phase1)
810{
811 auto read_phase = (is_phase1) ? eCaseOptionReadPhase::Phase1 : eCaseOptionReadPhase::Phase2;
812 for (ICaseOptions* co : CaseOptionsFilterUsed(m_case_options_list)) {
813 co->read(read_phase);
814 }
815
816 if (is_phase1) {
818 }
819
820 if (!is_phase1) {
821 // Searches for options using functions.
822 m_options_with_function.clear();
823 UniqueArray<CaseOptionBase*> col;
824 for (ICaseOptions* co : CaseOptionsFilterUsed(m_case_options_list)) {
825 co->deepGetChildren(col);
826 }
827 for (CaseOptionBase* co : col) {
828 if (co->function()) {
829 m_options_with_function.add(co);
830 }
831 }
832 }
833}
834
835/*---------------------------------------------------------------------------*/
836/*---------------------------------------------------------------------------*/
837
840{
841 String lang = _noNullCaseDocument()->fragment()->language();
842
843 auto v = createPrintCaseDocumentVisitor(traceMng(), lang);
844 info() << "-----------------------------------------------------";
845 info();
846 info() << "Input data values:";
847 // By default, uses the historical display mechanism so that users do not
848 // have too many display differences with new versions of Arcane.
849 // TODO: verify that the new display is identical to the old for most options.
850 const bool use_old = true;
852 if (use_old)
853 co->printChildren(lang, 0);
854 else
855 co->visit(v.get());
856 }
857
858 info() << "-----------------------------------------------------";
859}
860
861/*---------------------------------------------------------------------------*/
862/*---------------------------------------------------------------------------*/
863
865updateOptions(Real current_time, Real current_deltat, Integer current_iteration)
866{
867 Trace::Setter mci(traceMng(), msgClassName());
868
869 for (CaseOptionBase* co : m_options_with_function) {
870 ICaseFunction* cf = co->function();
871 Real deltat_coef = cf->deltatCoef();
872 Real t = current_time;
873 if (!math::isZero(deltat_coef)) {
874 Real to_add = deltat_coef * current_deltat;
875 t += to_add;
876 }
877 co->updateFromFunction(t, current_iteration);
878 }
879}
880
881/*---------------------------------------------------------------------------*/
882/*---------------------------------------------------------------------------*/
883
884Ref<ICaseFunction> CaseMng::
885findFunctionRef(const String& name) const
886{
887 for (auto& func_ref : m_functions)
888 if (func_ref->name() == name)
889 return func_ref;
890 return {};
891}
892
893/*---------------------------------------------------------------------------*/
894/*---------------------------------------------------------------------------*/
895
897findFunction(const String& name) const
898{
899 return findFunctionRef(name).get();
900}
901
902/*---------------------------------------------------------------------------*/
903/*---------------------------------------------------------------------------*/
904
907{
908 _removeFunction(func, false);
909}
910
911/*---------------------------------------------------------------------------*/
912/*---------------------------------------------------------------------------*/
913
915removeFunction(ICaseFunction* func, bool do_free)
916{
917 _removeFunction(func, do_free);
918}
919
920/*---------------------------------------------------------------------------*/
921/*---------------------------------------------------------------------------*/
922
923void CaseMng::
924_removeFunction(ICaseFunction* func, bool do_delete)
925{
926 // Plus utilisé depuis qu'on utilise un compte de référence.
927 ARCANE_UNUSED(do_delete);
928 Integer index = 0;
929 bool is_found = false;
930 for (auto& f : m_functions) {
931 if (f.get() == func) {
932 is_found = true;
933 break;
934 }
935 ++index;
936 }
937 if (is_found) {
938 m_functions.removeAt(index);
939 }
940}
941
942/*---------------------------------------------------------------------------*/
943/*---------------------------------------------------------------------------*/
944
947{
948 m_functions.add(func);
949}
950
951/*---------------------------------------------------------------------------*/
952/*---------------------------------------------------------------------------*/
953
955readCaseDocument(const String& filename, ByteConstArrayView case_bytes)
956{
958 {
959 // For now, reads in the critical section because it causes
960 // certain crashes sometimes (to be studied)
961 CriticalSection cs(sm->threadMng());
962 _readCaseDocument(filename, case_bytes);
963 }
964 return m_case_document.get();
965}
966
967/*---------------------------------------------------------------------------*/
968/*---------------------------------------------------------------------------*/
969
970void CaseMng::
971_readCaseDocument(const String& filename, ByteConstArrayView case_bytes)
972{
973 if (m_case_document.get())
974 // Already read...
975 return;
976
978 IIOMng* io_mng = m_sub_domain->parallelMng()->ioMng();
979 String printed_filename = filename;
980
981 IXmlDocumentHolder* case_doc = io_mng->parseXmlBuffer(case_bytes, filename);
982 if (!case_doc) {
983 info() << "XML Memory File:";
984 info() << filename;
985 pfatal() << "Failed to analyze the input data " << printed_filename;
986 }
987
988 m_case_document = app->mainFactory()->createCaseDocument(app, case_doc);
989
990 CaseNodeNames* cnn = caseDocument()->caseNodeNames();
991
992 String code_name = app->applicationInfo().codeName();
993 XmlNode root_elem = m_case_document->fragment()->rootElement();
994 if (root_elem.name() != cnn->root) {
995 pfatal() << "The root element <" << root_elem.name() << "> has to be <" << cnn->root << ">";
996 }
997
998 if (root_elem.attrValue(cnn->code_name) != code_name) {
999 pfatal() << "The file is not a case of code '" << code_name << "'";
1000 }
1001
1002 String case_codeversion = root_elem.attrValue(cnn->code_version);
1003 String code_version(app->majorAndMinorVersionStr());
1004 String code_version2(app->mainVersionStr());
1005 if (case_codeversion != code_version && case_codeversion != code_version2) {
1006 if (!m_sub_domain->session()->checkIsValidCaseVersion(case_codeversion))
1007 pfatal() << "The version number of the file (" << case_codeversion
1008 << ") doesn't match the version of the code '"
1009 << code_name << "' (" << code_version << ").";
1010 }
1011}
1012
1013/*---------------------------------------------------------------------------*/
1014/*---------------------------------------------------------------------------*/
1015
1017internalReadOneOption(ICaseOptions* opt, bool is_phase1)
1018{
1020 ICaseDocumentFragment* doc = opt->caseDocumentFragment();
1022 if (is_phase1)
1024 OptionsReader reader(this);
1025 reader.addOption(opt);
1026 reader.read(is_phase1);
1027 XmlNodeList invalid_elems;
1028 opt->addInvalidChildren(invalid_elems);
1029 _printErrors(doc, is_phase1);
1030}
1031
1032/*---------------------------------------------------------------------------*/
1033/*---------------------------------------------------------------------------*/
1034
1035} // End namespace Arcane
1036
1037/*---------------------------------------------------------------------------*/
1038/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ARCCORE_DEFINE_REFERENCE_COUNTED_INCLASS_METHODS()
Macro to define methods managing counters of references.
Integer size() const
Number of elements in the vector.
bool empty() const
Capacity (number of allocated elements) of the vector.
const String & codeName() const
Returns the name of the calculation code linked to the application.
Base class for 1D data vectors.
void add(ConstReferenceType val)
Adds element val to the end of the array.
Class managing the translation of a dataset into another language.
Information to build an instance of CaseFunction.
Case manager.
Definition CaseMng.cc:81
void internalReadOneOption(ICaseOptions *opt, bool is_phase1) override
Implementation via ICaseMngInternal.
Definition CaseMng.cc:1017
void setAllowUnkownRootElelement(bool v) override
Sets the permission for unknown elements at the document root.
Definition CaseMng.cc:205
void readOptions(bool is_phase1) override
Reads the dataset options corresponding to the used modules.
Definition CaseMng.cc:347
CaseFunctionList m_functions
List of functions.
Definition CaseMng.cc:237
bool m_is_function_read
Indicates if functions have already been read.
Definition CaseMng.cc:244
IObservable * observable(eCaseMngEventType type) override
Observable on the instance.
Definition CaseMng.cc:208
IApplication * application() override
Associated application.
Definition CaseMng.cc:171
void printOptions() override
Prints the option values.
Definition CaseMng.cc:839
ISubDomain * subDomain() override
Sub-domain manager.
Definition CaseMng.cc:170
bool isTreatWarningAsError() const override
Indicates whether warnings in the dataset should be treated as errors and cause the code to stop.
Definition CaseMng.cc:203
bool isAllowUnkownRootElelement() const override
Indicates whether unknown elements at the document root are allowed.
Definition CaseMng.cc:206
ISubDomain * m_sub_domain
Sub-domain manager.
Definition CaseMng.cc:235
void registerOptions(ICaseOptions *) override
Registers a list of dataset options.
Definition CaseMng.cc:467
ICaseFunction * findFunction(const String &name) const override
Returns the function by name name or nullptr if none exists.
Definition CaseMng.cc:897
const ParameterListWithCaseOption & parameters() const
List of parameters that can override the dataset.
Definition CaseMng.cc:226
ITraceMng * traceMng() override
Trace manager.
Definition CaseMng.cc:168
void unregisterOptions(ICaseOptions *) override
Unregisters a list of dataset options.
Definition CaseMng.cc:479
void removeFunction(ICaseFunction *func, bool dofree) override
Deletes a function.
Definition CaseMng.cc:915
ICaseDocumentFragment * createDocumentFragment(IXmlDocumentHolder *document) override
Creates a fragment.
Definition CaseMng.cc:222
CaseOptionsList m_case_options_list
List of case options.
Definition CaseMng.cc:238
void setTreatWarningAsError(bool v) override
Sets the way warnings are treated.
Definition CaseMng.cc:202
CaseOptionsCollection blocks() const override
Collection of option blocks.
Definition CaseMng.cc:200
void updateOptions(Real current_time, Real current_deltat, Integer current_iteration) override
Updates the options based on a time-marching table.
Definition CaseMng.cc:865
IMeshMng * meshMng() const override
Associated mesh manager.
Definition CaseMng.cc:169
CaseFunctionCollection functions() override
Returns the list of tables.
Definition CaseMng.cc:190
IPhysicalUnitSystem * physicalUnitSystem() const override
Associated unit system.
Definition CaseMng.cc:172
ICaseDocument * readCaseDocument(const String &filename, ByteConstArrayView bytes) override
Reads the XML document of the dataset.
Definition CaseMng.cc:955
ICaseDocument * caseDocument() override
XML document of the dataset (can be null if no dataset).
Definition CaseMng.cc:173
ICaseMngInternal * _internalImpl() override
Internal implementation.
Definition CaseMng.cc:217
void _searchInvalidOptions()
Searches for invalid data set options.
Definition CaseMng.cc:748
void readFunctions() override
Reads the dataset tables.
Definition CaseMng.cc:435
ICaseDocumentFragment * caseDocumentFragment() override
Fragment of the XML Document associated with the dataset (can be null if no dataset).
Definition CaseMng.cc:174
void addFunction(ICaseFunction *func) override
Adds the function func.
Definition CaseMng.cc:194
XML node names of an Arcane dataset.
Base class for a data set option.
eCurveType
Type of the table curve.
Definition CaseTable.h:65
@ CurveUnknown
Unknown curve type.
Definition CaseTable.h:66
@ CurveLinear
Piecewise linear curve.
Definition CaseTable.h:68
@ CurveConstant
Piecewise constant curve.
Definition CaseTable.h:67
eError
Types of errors returned by the class.
Definition CaseTable.h:48
@ ErrCanNotConvertParamToRightType
Indicates that converting the parameter to the desired type is impossible.
Definition CaseTable.h:53
@ ErrBadRange
Indicates that an element index is not valid.
Definition CaseTable.h:51
@ ErrNotGreaterThanPrevious
Indicates that the parameter is not greater than the previous one.
Definition CaseTable.h:57
@ ErrNotLesserThanNext
Indicates that the parameter is not less than the next one.
Definition CaseTable.h:59
@ ErrCanNotConvertValueToRightType
Indicates that converting the value to the desired type is impossible.
Definition CaseTable.h:55
Critical section in multi-thread.
Application interface.
virtual IMainFactory * mainFactory() const =0
Main factory.
virtual String mainVersionStr() const =0
Main application version number (without beta).
virtual String majorAndMinorVersionStr() const =0
Major and minor version number in M.m format.
virtual IParallelSuperMng * parallelSuperMng()=0
Supervisory parallelism manager.
virtual const ApplicationInfo & applicationInfo() const =0
Executable information.
Interface of a part of a dataset.
virtual CaseNodeNames * caseNodeNames()=0
Returns the instance containing the names of XML nodes by language.
virtual XmlNode rootElement()=0
Returns the root element.
virtual String language() const =0
Language used in the dataset.
virtual void clearErrorsAndWarnings()=0
Clears the recorded error and warning messages.
Interface of a class managing an XML document of the dataset.
virtual XmlNode functionsElement()=0
Returns the root element of the functions.
virtual const XmlNodeList & meshElements()=0
Returns the root element of the mesh information.
virtual XmlNode arcaneElement()=0
Returns the information element for Arcane.
virtual ICaseDocumentFragment * fragment()=0
Fragment corresponding to this document.
virtual CaseNodeNames * caseNodeNames()=0
Returns the instance containing the names of XML nodes by language.
Interface of a dataset function.
virtual Real deltatCoef() const =0
Value of the deltat multiplier coefficient.
eParamType
Type of a function parameter.
@ ParamUnknown
Unknown parameter type.
@ ParamReal
Real type parameter.
@ ParamInteger
Integer type parameter.
eValueType
Type of a function value.
@ ValueReal3
'Real3' type value
@ ValueUnknown
Unknown value type.
@ ValueInteger
Integer type value.
@ ValueString
String type value.
@ ValueReal
Real type value.
@ ValueBool
Boolean type value.
Internal part of ICaseMng.
Case manager interface.
Definition ICaseMng.h:57
Interface for a list of data set options.
virtual IModule * caseModule() const =0
Returns the associated module or nullptr if none exists.
virtual String rootTagName() const =0
Name of the element in the data set language.
Interface of the input/output manager.
Definition IIOMng.h:37
virtual IXmlDocumentHolder * parseXmlBuffer(Span< const Byte > buffer, const String &name)=0
Reads and parses the XML file contained in the buffer buffer.
virtual ICaseDocument * createCaseDocument(IApplication *)=0
Creates an instance of a case document.
Mesh manager interface.
Definition IMeshMng.h:41
Interface of a module.
Definition IModule.h:40
virtual bool used() const =0
true if the module is used.
virtual IIOMng * ioMng() const =0
I/O manager.
Abstract class of the parallelism supervisor.
virtual IThreadMng * threadMng() const =0
Thread manager.
Interface of a unit system.
Interface of the subdomain manager.
Definition ISubDomain.h:75
virtual IApplication * application()=0
Application.
virtual IParallelMng * parallelMng()=0
Returns the parallelism manager.
Manager of a DOM document.
Implementation of a collection of elements in vector form.
List of observables.
Parameter list with information to override dataset options.
T * get() const
Returns the object referenced by the instance.
Definition Ptr.h:122
Reference to an instance.
static ThatClass create(InstanceType *t)
Creates a reference from the instance t.
Thread-safe implementation of a reference counter.
Encapsulation of an automatically destructing pointer.
Definition ScopedPtr.h:44
Information for creating a service.
Utility class to find one or more services implementing the InterfaceType interface.
bool null() const
Returns true if the string is null.
Definition String.cc:306
void writeBytes(std::ostream &o) const
Writes the string in UTF-8 format to the stream o.
Definition String.cc:1247
static String collapseWhiteSpace(const String &rhs)
Performs whitespace character normalization.
Definition String.cc:454
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage pfatal() const
Flow for a parallel fatal error message.
TraceMessage log() const
Flow for a log message.
TraceMessage info() const
Flow for an information message.
TraceMessage error() const
Flow for an error message.
TraceMessage warning() const
Flow for a warning message.
ITraceMng * traceMng() const
Trace manager.
TraceMessage perror() const
TraceMessage pwarning() const
1D data vector with value semantics (STL style).
List of nodes of a DOM tree.
Definition XmlNodeList.h:36
Node of a DOM tree.
Definition XmlNode.h:51
XmlNode child(const String &name) const
Child node of this node with name name.
Definition XmlNode.cc:73
XmlNodeList children(const String &name) const
Set of child nodes of this node having the name name.
Definition XmlNode.cc:102
@ ELEMENT
The node is an Element.
Definition XmlNode.h:87
String name() const
Node name.
Definition XmlNode.cc:141
bool isZero(const BuiltInProxy< _Type > &a)
Tests if a value is exactly equal to zero.
String getEnvironmentVariable(const String &name)
Environment variable named name.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
@ SB_AllowNull
Allows the service to be absent.
eCaseOptionReadPhase
Reading phases.
eCaseMngEventType
Types of events supported by ICaseMng.
Definition ICaseMng.h:39
@ BeginReadOptionsPhase2
Event generated before reading options in phase 2.
Definition ICaseMng.h:43
@ BeginReadOptionsPhase1
Event generated before reading options in phase 1.
Definition ICaseMng.h:41
Int32 Integer
Type representing an integer.
List< ICaseOptions * > CaseOptionsList
Array of dataset options.
Collection< ICaseOptions * > CaseOptionsCollection
Collection of dataset options.
double Real
Type representing a real number.
ConstArrayView< Byte > ByteConstArrayView
C equivalent of a 1D array of characters.
Definition UtilsTypes.h:476
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.