diff --git a/arcane/src/arcane/core/CaseFunction2.h b/arcane/src/arcane/core/CaseFunction2.h new file mode 100644 index 000000000..2213ac62b --- /dev/null +++ b/arcane/src/arcane/core/CaseFunction2.h @@ -0,0 +1,116 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +/*---------------------------------------------------------------------------*/ +/* CaseFunction2.h (C) 2000-2023 */ +/* */ +/* Fonction du jeu de données avec type de valeur explicite. */ +/*---------------------------------------------------------------------------*/ +#ifndef ARCANE_CORE_CASEFUNCTION2_H +#define ARCANE_CORE_CASEFUNCTION2_H +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#include "arcane/utils/Real3.h" +#include "arcane/core/CaseFunction.h" + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +namespace Arcane +{ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/*! + * \internal + * \brief Implémentation de CaseFunction permettant de retourner directement + * la valeur associée à un paramètre sans passer par une référence. + * + * Cela est principalement utilisé pour simplifier les extensions C# en évitant + * les différentes surcharges de value(). + * + * Pour utiliser cette classe, il faut implémenter les méthodes 'valueAs*' + * pour les deux types d'argument \a Integer et \a Real et pour les + * différents types de retour possibles. + */ +class ARCANE_CORE_EXPORT CaseFunction2 +: public CaseFunction +{ + public: + + //! Construit une fonction du jeu de données. + explicit CaseFunction2(const CaseFunctionBuildInfo& cfbi) + : CaseFunction(cfbi) + {} + + protected: + + void value(Real param, Real& v) const override + { + v = valueAsReal(param); + } + void value(Real param, Integer& v) const override + { + v = valueAsInteger(param); + } + void value(Real param, bool& v) const override + { + v = valueAsBool(param); + } + void value(Real param, String& v) const override + { + v = valueAsString(param); + } + void value(Real param, Real3& v) const override + { + v = valueAsReal3(param); + } + void value(Integer param, Real& v) const override + { + v = valueAsReal(param); + } + void value(Integer param, Integer& v) const override + { + v = valueAsInteger(param); + } + void value(Integer param, bool& v) const override + { + v = valueAsBool(param); + } + void value(Integer param, String& v) const override + { + v = valueAsString(param); + } + void value(Integer param, Real3& v) const override + { + v = valueAsReal3(param); + } + + public: + + virtual Real valueAsReal(Real param) const = 0; + virtual Integer valueAsInteger(Real param) const = 0; + virtual bool valueAsBool(Real param) const = 0; + virtual String valueAsString(Real param) const = 0; + virtual Real3 valueAsReal3(Real param) const = 0; + + virtual Real valueAsReal(Integer param) const = 0; + virtual Integer valueAsInteger(Integer param) const = 0; + virtual bool valueAsBool(Integer param) const = 0; + virtual String valueAsString(Integer param) const = 0; + virtual Real3 valueAsReal3(Integer param) const = 0; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +} // namespace Arcane + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#endif diff --git a/arcane/src/arcane/core/InterfaceImpl.cc b/arcane/src/arcane/core/InterfaceImpl.cc index a30e86985..f915f9de2 100644 --- a/arcane/src/arcane/core/InterfaceImpl.cc +++ b/arcane/src/arcane/core/InterfaceImpl.cc @@ -93,6 +93,7 @@ #include "arcane/core/IPhysicalUnitConverter.h" #include "arcane/core/IPhysicalUnit.h" #include "arcane/core/IStandardFunction.h" +#include "arcane/core/CaseFunction2.h" #include "arcane/core/IServiceAndModuleFactoryMng.h" #include "arcane/core/IGhostLayerMng.h" #include "arcane/core/IMeshUniqueIdMng.h" diff --git a/arcane/src/arcane/core/srcs.cmake b/arcane/src/arcane/core/srcs.cmake index b149cdb43..7c2240c29 100644 --- a/arcane/src/arcane/core/srcs.cmake +++ b/arcane/src/arcane/core/srcs.cmake @@ -393,6 +393,7 @@ set(ARCANE_ORIGINAL_SOURCES CaseDatasetSource.h CaseFunction.cc CaseFunction.h + CaseFunction2.h CaseOptions.h CaseOptionServiceImpl.h CaseOptionTypes.h diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index d9b1a21ba..5c386f54d 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -695,6 +695,7 @@ if (ARCANE_HAS_DOTNET_TESTS) if (ARCANE_HAS_TASKS) arcane_add_csharp_test_sequential(hydro_cs_task testSimpleHydroCS-1.arc -m 15 -K 4) endif() + arcane_add_csharp_test_sequential(casefunction_cs testCaseFunctionModule-1.arc) endif() arcane_add_test_parallel(loadbalance_test1 testLoadBalanceHydro-MeshPartitionerTester.arc 4 -m 30) diff --git a/arcane/src/arcane/tests/CaseFunctionTester.axl b/arcane/src/arcane/tests/CaseFunctionTester.axl new file mode 100644 index 000000000..fc9d471fb --- /dev/null +++ b/arcane/src/arcane/tests/CaseFunctionTester.axl @@ -0,0 +1,19 @@ + + + + + Module de test des 'ICaseFunction'. + + + + + Fonction f(x) -> x * 2.0 + + + Fonction f(x) -> x * 3.0 + + + Fonction f(x,position) -> x * normL2(position) + + + diff --git a/arcane/src/arcane/tests/CaseFunctionTesterModule.cc b/arcane/src/arcane/tests/CaseFunctionTesterModule.cc new file mode 100644 index 000000000..6d89e7eeb --- /dev/null +++ b/arcane/src/arcane/tests/CaseFunctionTesterModule.cc @@ -0,0 +1,196 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +/*---------------------------------------------------------------------------*/ +/* CaseFunctionTesterModule.cc (C) 2000-2023 */ +/* */ +/* Module de test des 'CaseFunction'. */ +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#include "arcane/core/StandardCaseFunction.h" +#include "arcane/core/ITimeLoopMng.h" +#include "arcane/core/TimeLoopEntryPointInfo.h" +#include "arcane/core/TimeLoop.h" +#include "arcane/core/IMesh.h" + +#include "arcane/tests/CaseFunctionTester_axl.h" + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +namespace ArcaneTest +{ +using namespace Arcane; +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/*! + * \brief Module de test des 'ICaseFunction'. + */ +class CaseFunctionTesterModule +: public ArcaneCaseFunctionTesterObject +{ + public: + + explicit CaseFunctionTesterModule(const ModuleBuildInfo& mbi); + + public: + + static void staticInitialize(ISubDomain* sd); + + public: + + VersionInfo versionInfo() const override { return Arcane::VersionInfo(0, 1, 0); } + + public: + + void init(); + void loop(); + + private: +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ARCANE_DEFINE_STANDARD_MODULE(CaseFunctionTesterModule, CaseFunctionTester); + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +namespace +{ + class StandardFuncTest + : public StandardCaseFunction + , public IBinaryMathFunctor + { + public: + + StandardFuncTest(const CaseFunctionBuildInfo& bi) + : StandardCaseFunction(bi) + {} + + public: + + virtual IBinaryMathFunctor* getFunctorRealReal3ToReal() + { + return this; + } + virtual Real apply(Real r, Real3 r3) + { + return r + r3.normL2(); + } + }; + +} // namespace + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +CaseFunctionTesterModule:: +CaseFunctionTesterModule(const ModuleBuildInfo& mbi) +: ArcaneCaseFunctionTesterObject(mbi) +{ + addEntryPoint(this, "Init", + &CaseFunctionTesterModule::init, IEntryPoint::WInit); + addEntryPoint(this, "Loop", + &CaseFunctionTesterModule::loop); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void CaseFunctionTesterModule:: +staticInitialize(ISubDomain* sd) +{ + ITimeLoopMng* tlm = sd->timeLoopMng(); + ITimeLoop* time_loop = tlm->createTimeLoop("CaseFunctionTester"); + + { + List clist; + clist.add(TimeLoopEntryPointInfo("CaseFunctionTester.Init")); + time_loop->setEntryPoints(ITimeLoop::WInit, clist); + } + + { + List clist; + clist.add(TimeLoopEntryPointInfo("CaseFunctionTester.Loop")); + time_loop->setEntryPoints(ITimeLoop::WComputeLoop, clist); + } + + { + StringList clist; + clist.add("CaseFunctionTester"); + time_loop->setRequiredModulesName(clist); + } + + tlm->registerTimeLoop(time_loop); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void CaseFunctionTesterModule:: +loop() +{ + if (m_global_iteration() > 10) + subDomain()->timeLoopMng()->stopComputeLoop(true); + + // Temps de début d'itération auquel sont calculées les valeurs des fonctions + Real global_time = m_global_old_time(); + Int32 global_iter = m_global_iteration(); + + { + Real v1 = options()->realTimeMultiply2.value(); + Real expected_v1 = global_time * 2.0; + info() << "Function: real-time-multiply-2: " << v1; + if (!math::isNearlyEqual(v1, expected_v1)) + ARCANE_FATAL("Bad (1) value v={0} expected={1}", v1, expected_v1); + } + { + int v1 = options()->intIterMultiply3.value(); + int expected_v1 = global_iter * 3; + info() << "Function: int-iter-multiply-3: " << v1; + if (v1 != expected_v1) + ARCANE_FATAL("Bad (2) value v={0} expected={1}", v1, expected_v1); + } + { + ICaseFunction* opt_function = options()->realNormL2.function(); + IStandardFunction* scf = options()->realNormL2.standardFunction(); + if (!scf) + ARCANE_FATAL("No standard case function for option 'real-norml2'"); + auto* functor = scf->getFunctorRealReal3ToReal(); + if (!functor) + ARCANE_FATAL("Standard function '{0}' is not convertible to f(Real,Real3) -> Real", opt_function->name()); + + VariableNodeReal3& node_coord = defaultMesh()->nodesCoordinates(); + ENUMERATE_ (Node, inode, allNodes()) { + Real3 coord = node_coord[inode]; + Real v1 = functor->apply(global_time, coord); + Real expected_v1 = global_time * coord.normL2(); + info() << "Function: real-norml2: " << v1; + if (!math::isNearlyEqual(v1, expected_v1)) + ARCANE_FATAL("Bad (3) value v={0} expected={1}", v1, expected_v1); + } + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void CaseFunctionTesterModule:: +init() +{ + m_global_deltat.assign(1.5); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +} // End namespace ArcaneTest + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/tests/DotNetCaseFunctionProvider.cs b/arcane/src/arcane/tests/DotNetCaseFunctionProvider.cs index 2d9902e0f..e71d9404b 100644 --- a/arcane/src/arcane/tests/DotNetCaseFunctionProvider.cs +++ b/arcane/src/arcane/tests/DotNetCaseFunctionProvider.cs @@ -12,15 +12,38 @@ using IntegerArrayView = Arcane.Int32ArrayView; #endif -[Arcane.Service("DotNetCaseFunctionProvider",typeof(Arcane.ICaseFunctionProvider))] -public class DotNetCaseFunctionProvider : Arcane.ICaseFunctionProvider_WrapperService +namespace ArcaneTest { - public DotNetCaseFunctionProvider(ServiceBuildInfo bi) : base(bi) + [Arcane.Service("DotNetCaseFunctionProvider",typeof(Arcane.ICaseFunctionProvider))] + public class DotNetCaseFunctionProvider : Arcane.ICaseFunctionProvider_WrapperService { + public DotNetCaseFunctionProvider(ServiceBuildInfo bi) : base(bi) + { + } + + public override void RegisterCaseFunctions(ICaseMng cm) + { + Console.WriteLine("REGISTER C# CASE_FUNCTION_PROVIDER"); + Arcane.CaseFunctionLoader.LoadCaseFunction(cm,typeof(MyTestCaseFunction)); + } } - public override void RegisterCaseFunctions(ICaseMng cm) + public class MyTestCaseFunction { - Console.WriteLine("REGISTER C# CASE_FUNCTION_PROVIDER"); + public Real FuncTimeMultiply2(Real x) + { + Console.WriteLine("FuncTimeMultiply2 x={0}",x); + return x * 2.0; + } + public int FuncIterMultiply3(int x) + { + Console.WriteLine("FuncIterMultiply3 x={0}",x); + return x * 3; + } + public Real FuncStandardRealReal3NormL2(Real x,Real3 position) + { + Console.WriteLine("FuncStandardNormL2 x={0} position={1}",x,position); + return x * System.Math.Sqrt(position.x*position.x + position.y*position.y + position.z*position.z); + } } } diff --git a/arcane/src/arcane/tests/srcs.cmake b/arcane/src/arcane/tests/srcs.cmake index 1c7d0463b..8ed72cb96 100644 --- a/arcane/src/arcane/tests/srcs.cmake +++ b/arcane/src/arcane/tests/srcs.cmake @@ -6,6 +6,7 @@ set(ARCANE_SOURCES ParticleUnitTest.cc TestUnitTest.cc CaseFunctionUnitTest.cc + CaseFunctionTesterModule.cc CaseOptionsTesterModule.cc ParallelTesterModule.cc SubMeshTestModule.cc @@ -83,6 +84,7 @@ set(AXL_FILES CheckpointTester SimpleHydro ScriptTester + CaseFunctionTester CaseOptionsTester ParallelTester SubMeshTest diff --git a/arcane/tests/testCaseFunctionModule-1.arc b/arcane/tests/testCaseFunctionModule-1.arc new file mode 100644 index 000000000..910cda31e --- /dev/null +++ b/arcane/tests/testCaseFunctionModule-1.arc @@ -0,0 +1,19 @@ + + + + Test Arcane 1 + Test Arcane 1 + CaseFunctionTester + + + + 422 + + + + 1.5 + 1 + 1 + + + diff --git a/arcane/tools/wrapper/core/ArcaneSwigCore.i b/arcane/tools/wrapper/core/ArcaneSwigCore.i index e8326adb3..2804eb020 100644 --- a/arcane/tools/wrapper/core/ArcaneSwigCore.i +++ b/arcane/tools/wrapper/core/ArcaneSwigCore.i @@ -35,7 +35,7 @@ using namespace Arcane::Accelerator; #define SWIG_DISPOSE csdispose #define SWIG_DISPOSE_DERIVED csdispose_derived -namespace Arcane +namespace Arccore { class IFunctor; namespace Internal @@ -43,6 +43,14 @@ namespace Arcane class ExternalRef; } } +namespace Arcane +{ + using Arccore::IFunctor; + namespace Internal + { + using Arccore::Internal::ExternalRef; + } +} #define ARCCORE_DECLARE_REFERENCE_COUNTED_CLASS(a) diff --git a/arcane/tools/wrapper/core/ArcaneSwigCoreInclude.h b/arcane/tools/wrapper/core/ArcaneSwigCoreInclude.h index 9b992854c..fedce17a0 100644 --- a/arcane/tools/wrapper/core/ArcaneSwigCoreInclude.h +++ b/arcane/tools/wrapper/core/ArcaneSwigCoreInclude.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2022 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* ArcaneSwigCoreInclude.h (C) 2000-2022 */ +/* ArcaneSwigCoreInclude.h (C) 2000-2023 */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -61,6 +61,7 @@ #include "arcane/CaseOptionsMulti.h" #include "arcane/CaseOptionService.h" #include "arcane/StandardCaseFunction.h" +#include "arcane/CaseFunction2.h" #include "arcane/ICaseOptions.h" #include "arcane/ICaseMng.h" #include "arcane/ICaseFunctionProvider.h" diff --git a/arcane/tools/wrapper/core/ArrayView.i b/arcane/tools/wrapper/core/ArrayView.i index cc1fa0028..40b5135e7 100644 --- a/arcane/tools/wrapper/core/ArrayView.i +++ b/arcane/tools/wrapper/core/ArrayView.i @@ -11,6 +11,11 @@ /*---------------------------------------------------------------------------*/ // On ne peut pas inclure 'arcane/utils/UtilsTypes.h' car SWIG (3.0.12) ne // semble pas bien gérer 'using' des classes de Arccore. +namespace Arccore +{ + template class IFunctorWithArgumentT; +} + namespace Arcane { template class ArrayView; @@ -35,8 +40,6 @@ namespace Arcane template class Collection; template class List; - template class IFunctorWithArgumentT; - template class EventObservable; template class EventObserver; diff --git a/arcane/tools/wrapper/core/CMakeLists.txt b/arcane/tools/wrapper/core/CMakeLists.txt index f09ac77f3..d3d664dd9 100644 --- a/arcane/tools/wrapper/core/CMakeLists.txt +++ b/arcane/tools/wrapper/core/CMakeLists.txt @@ -31,6 +31,7 @@ set(ARCANE_SWIG_CORE_CSHARP_FILES ArcaneSimpleExecutor AssemblyLoaderHelper CaseOptionMultiEnumT + CaseFunction Debug ExternalRef EntryPoint diff --git a/arcane/tools/wrapper/core/CaseOption.i b/arcane/tools/wrapper/core/CaseOption.i index 3cdcd0879..6d27554e2 100644 --- a/arcane/tools/wrapper/core/CaseOption.i +++ b/arcane/tools/wrapper/core/CaseOption.i @@ -23,6 +23,7 @@ namespace Arcane %feature("director") Arcane::ICaseOptionServiceContainer; %feature("director") Arcane::StandardCaseFunction; %feature("director") Arcane::CaseFunction; +%feature("director") Arcane::CaseFunction2; %feature("director") Arcane::CaseOptionComplexValue; %ignore Arcane::ICaseFunction::value; @@ -62,6 +63,7 @@ namespace Arcane %include arcane/core/ICaseFunction.h %include arcane/core/CaseFunction.h %include arcane/core/StandardCaseFunction.h +%include arcane/core/CaseFunction2.h %include arcane/core/ICaseFunctionProvider.h /*---------------------------------------------------------------------------*/ diff --git a/arcane/tools/wrapper/core/DotNetObject.i b/arcane/tools/wrapper/core/DotNetObject.i index 1867c78fb..da6089eed 100644 --- a/arcane/tools/wrapper/core/DotNetObject.i +++ b/arcane/tools/wrapper/core/DotNetObject.i @@ -1,5 +1,5 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- -%typemap(cscode) Arcane::Internal::ExternalRef +%typemap(cscode) Arccore::Internal::ExternalRef %{ internal delegate void DestroyDelegate(IntPtr handle); @@ -20,9 +20,9 @@ } %} -%typemap(csclassmodifiers) Arcane::Internal::ExternalRef "public partial class" +%typemap(csclassmodifiers) Arccore::Internal::ExternalRef "public partial class" // La classe 'ExternaRef' est dans 'arccore/base' -namespace Arcane::Internal +namespace Arccore::Internal { class ExternalRef { diff --git a/arcane/tools/wrapper/core/ItemPairGroup.i b/arcane/tools/wrapper/core/ItemPairGroup.i index 4ee60e43d..55b54ff2c 100644 --- a/arcane/tools/wrapper/core/ItemPairGroup.i +++ b/arcane/tools/wrapper/core/ItemPairGroup.i @@ -79,4 +79,4 @@ namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -%template(ItemPairGroupCustomFunctor) Arcane::IFunctorWithArgumentT; +%template(ItemPairGroupCustomFunctor) Arccore::IFunctorWithArgumentT; diff --git a/arcane/tools/wrapper/core/Service.i b/arcane/tools/wrapper/core/Service.i index 06edbf1af..3ec1218c6 100644 --- a/arcane/tools/wrapper/core/Service.i +++ b/arcane/tools/wrapper/core/Service.i @@ -16,7 +16,7 @@ %rename BasicModule BasicModule_INTERNAL; -%typemap(cscode) Arcane::IFunctor %{ +%typemap(cscode) Arccore::IFunctor %{ public delegate void FunctorDelegate(); private FunctorDelegate m_functor; public FunctorDelegate Functor { get { return m_functor; } } @@ -138,7 +138,7 @@ %include arcane/core/BasicModule.h %include arcane/core/IEntryPoint.h -namespace Arcane +namespace Arccore { class IFunctor { diff --git a/arcane/tools/wrapper/core/csharp/CaseFunction.cs b/arcane/tools/wrapper/core/csharp/CaseFunction.cs new file mode 100644 index 000000000..9516455ba --- /dev/null +++ b/arcane/tools/wrapper/core/csharp/CaseFunction.cs @@ -0,0 +1,450 @@ +//----------------------------------------------------------------------------- +// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +using System; +using System.Reflection; +using System.Collections.Generic; + +#if ARCANE_64BIT +using Integer = System.Int64; +#else +using Integer = System.Int32; +#endif +using Real = System.Double; + +namespace Arcane +{ + public class CaseFunctionLoader + { + static List m_case_functions; + + /*! + * \brief Charge les 'CaseFunction' issues de la classe \a class_type. + * + * Toutes les méthodes publiques de \a class_type dont le prototype correspond + * à une \a CaseFunction sont considérées comme des fonctions du jeu de données. + * + * Par exemple: + * \code + * double func1(int); + * int func2(double); + * \endcode + * + * Les méthodes trouvées sont ajoutées à \a case_mng + */ + public static void LoadCaseFunction(ICaseMng case_mng,Type class_type) + { + if (class_type==null) + return; + + ConstructorInfo ci = class_type.GetConstructor(new Type[0]); + object o = ci.Invoke(null); + + TraceAccessor Trace = new TraceAccessor(case_mng.TraceMng()); + + // TODO: utile actuellement pour conserver une référence mais il faudrait ensuite + // supprimer + if (m_case_functions==null) + m_case_functions = new List(); + + List current_functions = new List(); + + //ICaseMng cm = sd.CaseMng(); + BindingFlags flags = BindingFlags.Public|BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.DeclaredOnly; + MethodInfo[] methods = class_type.GetMethods(flags); + + foreach(MethodInfo method in methods){ + string func_name = method.Name; + Trace.Info(String.Format("FOUND METHOD name={0}",func_name)); + var cfbi = new CaseFunctionBuildInfo(case_mng.TraceMng(),func_name); + ICaseFunction ucf = UserCaseFunction.Create(Trace,o,method,cfbi); + if (ucf==null) + ucf = UserStandardCaseFunction.Create(Trace,o,method,cfbi); + if (ucf!=null) + current_functions.Add(ucf); + else{ + string msg = $"User function '{func_name}' is invalid."+ + " Valid prototypes are f(Real,Real|Real3) -> Real|Real3 or f(Real|Integer) -> Real|Integer|bool"; + throw new ApplicationException(msg); + } + } + foreach(ICaseFunction cf in current_functions){ + case_mng.AddFunction(cf); + m_case_functions.Add(cf); + } + } + } + + //! Function f(Real,Real) -> Real + class RealRealToRealFunctor : IRealRealToRealMathFunctor + { + delegate Real MyDelegate(Real a,Real b); + MyDelegate m_delegate; + + public RealRealToRealFunctor(object o,MethodInfo method) + { + m_delegate = (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate),o,method); + } + public override Real Apply(Real a,Real b) + { + return m_delegate(a,b); + } + public override void Apply(RealConstArrayView a,RealConstArrayView b,RealArrayView out_v) + { + for (int i=0; i Real + class RealReal3ToRealFunctor : IRealReal3ToRealMathFunctor + { + delegate Real MyDelegate(Real a,Real3 b); + MyDelegate m_delegate; + + public RealReal3ToRealFunctor(object o,MethodInfo method) + { + m_delegate = (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate),o,method); + } + public override Real Apply(Real a,Real3 b) + { + return m_delegate(a,b); + } + public override void Apply(RealConstArrayView a,Real3ConstArrayView b,RealArrayView out_v) + { + for (int i=0; i Real3 + class RealRealToReal3Functor : IRealRealToReal3MathFunctor + { + delegate Real3 MyDelegate(Real a,Real b); + MyDelegate m_delegate; + + public RealRealToReal3Functor(object o,MethodInfo method) + { + m_delegate = (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate),o,method); + } + public override Real3 Apply(Real a,Real b) + { + return m_delegate(a,b); + } + public override void Apply(RealConstArrayView a,RealConstArrayView b,Real3ArrayView out_v) + { + for (int i=0; i Real3 + class RealReal3ToReal3Functor : IRealReal3ToReal3MathFunctor + { + delegate Real3 MyDelegate(Real a,Real3 b); + MyDelegate m_delegate; + + public RealReal3ToReal3Functor(object o,MethodInfo method) + { + m_delegate = (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate),o,method); + } + public override Real3 Apply(Real a,Real3 b) + { + return m_delegate(a,b); + } + public override void Apply(RealConstArrayView a,Real3ConstArrayView b,Real3ArrayView out_v) + { + for (int i=0; i {3}",method_name,param1_type,param2_type,return_type)); + + // Créé l'instance correspondante au type de la fonction retournée. + if (return_type==real_type && param1_type==real_type && param2_type==real_type){ + trace.Info("Found f(Real,Real) -> Real"); + var v = new RealRealToRealFunctor(o,method); + return new UserStandardCaseFunction(v,cfbi); + } + + if (return_type==real_type && param1_type==real_type && param2_type==real3_type){ + trace.Info("Found f(Real,Real3) -> Real"); + var v = new RealReal3ToRealFunctor(o,method); + return new UserStandardCaseFunction(v,cfbi); + } + + if (return_type==real3_type && param1_type==real_type && param2_type==real_type){ + trace.Info("Found f(Real,Real) -> Real3"); + var v = new RealRealToReal3Functor(o,method); + return new UserStandardCaseFunction(v,cfbi); + } + + if (return_type==real3_type && param1_type==real_type && param2_type==real3_type){ + trace.Info("Found f(Real,Real3) -> Real3"); + var v = new RealReal3ToReal3Functor(o,method); + return new UserStandardCaseFunction(v,cfbi); + } + return null; + } + + public override IRealRealToRealMathFunctor GetFunctorRealRealToReal() + { + return m_rr_to_r; + } + + public override IRealRealToReal3MathFunctor GetFunctorRealRealToReal3() + { + return m_rr_to_r3; + } + + public override IRealReal3ToRealMathFunctor GetFunctorRealReal3ToReal() + { + return m_rr3_to_r; + } + + public override IRealReal3ToReal3MathFunctor GetFunctorRealReal3ToReal3() + { + return m_rr3_to_r3; + } + } + + /*! + * \brief Représente une fonction du type table de marche + * + * Pour l'instant on a uniquement le support des fonctions + * avec le prototype suivant: f(Real|Integer) -> Real|Integer|Bool. + */ + class UserCaseFunction : Arcane.CaseFunction2 + { + delegate double RealToRealDelegate(double v); + delegate double IntegerToRealDelegate(int v); + delegate int RealToIntegerDelegate(double v); + delegate int IntegerToIntegerDelegate(int v); + delegate bool RealToBoolDelegate(double v); + delegate bool IntegerToBoolDelegate(int v); + + RealToRealDelegate m_real_to_real_delegate; + IntegerToRealDelegate m_integer_to_real_delegate; + + RealToIntegerDelegate m_real_to_integer_delegate; + IntegerToIntegerDelegate m_integer_to_integer_delegate; + + RealToBoolDelegate m_real_to_bool_delegate; + IntegerToBoolDelegate m_integer_to_bool_delegate; + + public UserCaseFunction(Arcane.CaseFunctionBuildInfo cfbi) : base(cfbi) + { + } + + public override double ValueAsReal(double v) + { + if (m_real_to_real_delegate!=null) + return m_real_to_real_delegate(v); + if (m_real_to_integer_delegate!=null) + return (double)m_real_to_integer_delegate(v); + if (m_integer_to_integer_delegate!=null) + return (double)m_integer_to_integer_delegate((int)v); + if (m_integer_to_real_delegate!=null) + return m_integer_to_integer_delegate((int)v); + throw new ApplicationException("Bad type for user function. Should be convertible to f(Real) -> Real"); + } + + public override int ValueAsInteger(double v) + { + if (m_real_to_integer_delegate!=null) + return m_real_to_integer_delegate(v); + if (m_integer_to_integer_delegate!=null) + return m_integer_to_integer_delegate((int)v); + if (m_real_to_real_delegate!=null) + return (int)m_real_to_real_delegate(v); + if (m_integer_to_real_delegate!=null) + return (int)m_integer_to_integer_delegate((int)v); + throw new ApplicationException("Bad type for user function. Should be convertible to f(Real) -> int"); + } + + public override bool ValueAsBool(double v) + { + if (m_real_to_bool_delegate!=null) + return m_real_to_bool_delegate(v); + if (m_integer_to_bool_delegate!=null) + return m_integer_to_bool_delegate((int)v); + throw new ApplicationException("Bad type for user function. Should be convertible to f(Real) -> bool"); + } + + public override double ValueAsReal(int v) + { + if (m_integer_to_real_delegate!=null) + return m_integer_to_integer_delegate(v); + if (m_real_to_real_delegate!=null) + return m_real_to_real_delegate((double)v); + if (m_integer_to_integer_delegate!=null) + return (double)m_integer_to_integer_delegate(v); + if (m_real_to_integer_delegate!=null) + return (double)m_real_to_integer_delegate(v); + throw new ApplicationException("Bad type for user function. Should be convertible to f(int) -> Real"); + } + + public override int ValueAsInteger(int v) + { + if (m_integer_to_integer_delegate!=null) + return m_integer_to_integer_delegate(v); + if (m_real_to_integer_delegate!=null) + return m_real_to_integer_delegate((double)v); + throw new ApplicationException("Bad type for user function. Should be convertible to f(int) -> int"); + } + + public override bool ValueAsBool(int v) + { + if (m_integer_to_bool_delegate!=null) + return m_integer_to_bool_delegate(v); + if (m_real_to_bool_delegate!=null) + return m_real_to_bool_delegate((double)v); + throw new ApplicationException("Bad type for user function. Should be convertible to f(int) -> bool"); + } + + public override Real3 ValueAsReal3(int v) + { + throw new NotSupportedException(); + } + + public override string ValueAsString(int v) + { + throw new NotSupportedException(); + } + + public override Real3 ValueAsReal3(Real v) + { + throw new NotSupportedException(); + } + + public override string ValueAsString(Real v) + { + throw new NotSupportedException(); + } + + public static UserCaseFunction Create(TraceAccessor trace, object o,MethodInfo method,CaseFunctionBuildInfo cfbi) + { + string method_name = method.Name; + ParameterInfo[] method_params = method.GetParameters(); + int nb_param = method_params.Length; + + if (nb_param!=1) + return null; + + Type real_type = typeof(double); + Type integer_type = typeof(int); + Type bool_type = typeof(bool); + Type return_type = method.ReturnType; + Type param1_type = method_params[0].ParameterType; + + trace.Info(String.Format("METHOD_INFO={0} f({1}) -> {2}",method_name,param1_type,return_type)); + + // Créé l'instance correspondante au type de la fonction retournée + + if (return_type==real_type && param1_type==real_type){ + trace.Info("Found f(Real) -> Real"); + cfbi.m_param_type = ICaseFunction.eParamType.ParamReal; + cfbi.m_value_type = ICaseFunction.eValueType.ValueReal; + var v = new UserCaseFunction(cfbi); + v.m_real_to_real_delegate = (RealToRealDelegate)Delegate.CreateDelegate(typeof(RealToRealDelegate),o,method); + return v; + } + + if (return_type==real_type && param1_type==integer_type){ + trace.Info("Found f(int) -> Real"); + cfbi.m_param_type = ICaseFunction.eParamType.ParamInteger; + cfbi.m_value_type = ICaseFunction.eValueType.ValueReal; + var v = new UserCaseFunction(cfbi); + v.m_integer_to_real_delegate = (IntegerToRealDelegate)Delegate.CreateDelegate(typeof(IntegerToRealDelegate),o,method); + return v; + } + + if (return_type==integer_type && param1_type==real_type){ + trace.Info("Found f(Real) -> int"); + cfbi.m_param_type = ICaseFunction.eParamType.ParamReal; + cfbi.m_value_type = ICaseFunction.eValueType.ValueInteger; + var v = new UserCaseFunction(cfbi); + v.m_real_to_integer_delegate = (RealToIntegerDelegate)Delegate.CreateDelegate(typeof(RealToIntegerDelegate),o,method); + return v; + } + + if (return_type==integer_type && param1_type==integer_type){ + trace.Info("Found f(int) -> int"); + cfbi.m_param_type = ICaseFunction.eParamType.ParamInteger; + cfbi.m_value_type = ICaseFunction.eValueType.ValueInteger; + var v = new UserCaseFunction(cfbi); + v.m_integer_to_integer_delegate = (IntegerToIntegerDelegate)Delegate.CreateDelegate(typeof(IntegerToIntegerDelegate),o,method); + return v; + } + + if (return_type==bool_type && param1_type==real_type){ + trace.Info("Found f(Real) -> bool"); + cfbi.m_param_type = ICaseFunction.eParamType.ParamReal; + cfbi.m_value_type = ICaseFunction.eValueType.ValueBool; + var v = new UserCaseFunction(cfbi); + v.m_real_to_bool_delegate = (RealToBoolDelegate)Delegate.CreateDelegate(typeof(RealToBoolDelegate),o,method); + return v; + } + + if (return_type==bool_type && param1_type==integer_type){ + trace.Info("Found f(int) -> bool"); + cfbi.m_param_type = ICaseFunction.eParamType.ParamInteger; + cfbi.m_value_type = ICaseFunction.eValueType.ValueBool; + var v = new UserCaseFunction(cfbi); + v.m_integer_to_bool_delegate = (IntegerToBoolDelegate)Delegate.CreateDelegate(typeof(IntegerToBoolDelegate),o,method); + return v; + } + + return null; + + } + } +} +