Workflow for using a plugin function

  1. Include the header files in your source file.
    Every plugin function must contain a header file inclusion directive, which contains definitions for the API methods.
    #include <CaeUtils_Exp_IMaterial.hxx>
    #include <CaeUtils_Exp_IContext.hxx>
    #include <CaeUtils_Exp_IScalarValue.hxx>
    #include <CaeUtils_Exp_ITableValue.hxx>
    #include <CaeUtils_Exp_IFieldValue.hxx>
    #include <CaeUtils_Exp_IReturnValue.hxx>
    #include <CaeUtils_Exp_IFunctionDefinition.hxx>
    #include <CaeUtils_Exp_IRegistrar.hxx>
    #include <CaeUtils_Exp_PluginVersion.hxx>
  2. Define the default values for function arguments.
    You can provide default values for function arguments that are automatically assigned by the compiler if you do not provide a value for the argument with default value.
    const double UNDEF_VALUE = -1.33e33;
    const UGS::CaeUtils::Exp::DefValue DEFAULTS = { UNDEF_VALUE, 0, NULL, false };
  3. Initialize your plugin functions.
    Simcenter 3D calls the Initialize_Versioned function and the thermal solver calls the Initialize function to load the plugin functions. For your convenience, you can write the AddFunctions function to list all your plugin functions, as shown on the following example.
    {
        void AddFunctions(IRegistrar* pReg);
    }
    
    #ifdef _WIN32
    extern "C" __declspec(dllexport) void Initialize(UGS::CaeUtils::Exp::IRegistrar* pReg)
    #else
    extern "C" void Initialize(UGS::CaeUtils::Exp::IRegistrar* pReg)
    #endif
    {
        AddFunctions(pReg);
    }
    #ifdef _WIN32
    extern "C" __declspec(dllexport) void Initialize_Versioned(UGS::CaeUtils::Exp::IRegistrar* pReg, int nVersionNumber)
    #else
    extern "C" void Initialize_Versioned(UGS::CaeUtils::Exp::IRegistrar* pReg, int nVersionNumber)
    #endif
    {
        AddFunctions(pReg);
        //
        // Enumerate the caeexpeval version numbers and static_assert if there is a mismatch.
        //
        // Including this code snippet will ensure that there is no mismatch between compiler and expeval versions.
        //
    #ifdef _WIN32
    #if (_MSC_VER == 1900)
        const int myVersionNumber = 110003;
        static_assert(myVersionNumber == caeExpEvalVersion, "CaeExpEval library and compiler version mismatch. Requires Visual Studio 2015, MSC_VER 14.0");
    #elif (_MSC_VER == 1800)
        const int myVersionNumber = 110002;
        static_assert(myVersionNumber == caeExpEvalVersion, "CaeExpEval library and compiler version mismatch. Requires Visual Studio 2013, MSC_VER 12.0");
    #endif
    #endif
    
    }
  4. Initialize thermal solver functions.
    If you use the thermal solver functions in your plugin, the thermal solver calls the TMGUserInitialize function to pass a pointer to the GetTMGFunction function. You can find the list of all available functions and their pointers in the [installation_path]\tmg\include\maya\expeval_utils\AdditionalFunctions.h. You need to include the AdditionalFunctions.h file in the beginning of your source file.

    You can also initialize all other pointers using pGetTMGFunction defined in the AdditionalFunctions.h. This example shows how to initialize the GetAreaBC method.

    #ifdef _WIN32
    extern "C" __declspec(dllexport) void TMGUserInitialize(void* pGetTMGFunc)
    #else
    extern "C" void TMGUserInitialize(void* pGetTMGFunc)
    #endif
    {
        // Generic function to get access to solver function
        pGetTMGFunction = (GetTMGFunctionPointer)pGetTMGFunc;
        pGetAreaBC = (GetAreaBCPointer)pGetTMGFunction(getAreaBCString);
    }

    Examples on how to access the additional thermal solver functions are described under each thermal solver API method definition.

  5. Define your plugin function.
    The following example shows how to define the HTCCustom() plugin function using Simcenter 3D methods, that computes a heat transfer coefficient, h, as follows:

    • Pr is the Prandtl number.
    • k is the fluid conductivity.
    • r is the radius.
    • μ is the fluid viscosity.
    • cp is the fluid specific heat.
    void HTCCustom(const IContext* pContext, const ArgData* pArgs, IReturnValue* pRet)
        {
        double result = 0.0;
        const IMaterial* pMaterial = pContext->GetFluidMaterial();
        if (!pMaterial)
        {
             pRet->SetDouble(result);
             pRet->SetErrorMsg("The fluid material is not defined while calling HTCCustom plugin function.");
             return;
        }
        bool boolResult = true;
        // Properties of the fluid material
        double fluidTemperature = 0.0;
        boolResult = pContext->GetFluidTemp(&fluidTemperature);
        if (!boolResult)
        {
            pRet->SetDouble(result);
            pRet->SetErrorMsg("The fluid material temperature is not defined while calling HTCCustom plugin function.");
            return;
        }
        double fluidPressure = 0.0;
        boolResult = pContext->GetFluidPressure(&fluidPressure);
        if (!boolResult)
        {
            pRet->SetDouble(result);
            pRet->SetErrorMsg("The fluid material pressure is not defined while calling HTCCustom plugin function.");
            return;
        }
        double fluidConductivity = pMaterial->GetThermalConductivity(fluidTemperature, fluidPressure);
        if (fluidConductivity == 0.0)
        {
            pRet->SetDouble(result);
            pRet->SetErrorMsg("The fluid material thermal conductivity equals 0 while calling HTCCustom plugin function.");
            return;
        }
        double fluidViscosity = 0.0;
        const IScalarValue* pScalar = pMaterial->GetScalarProperty("DynamicVisc");
        if (pScalar)
            fluidViscosity = pScalar->GetValue();
        else
        {
            const IFieldValue* pField = pMaterial->GetFieldProperty("DynamicVisc");
            if (pField)
            {
                std::vector<double> temperatures(1);
                temperatures[0] = fluidTemperature;
                double* viscosities = pField->GetInterpolatedValue(temperatures);
                fluidViscosity = viscosities[0];
                delete[] viscosities;
            }
        }
        if (fluidViscosity == 0.0)
        {
            pRet->SetDouble(result);
            pRet->SetErrorMsg("The fluid material dynamic viscosity equals 0 or not defined while calling HTCCustom plugin function.");
            return;
        }
        double fluidSpecificHeat = pMaterial->GetSpecificHeat(fluidTemperature, fluidPressure);
        if (fluidSpecificHeat == 0.0)
        {
            pRet->SetDouble(result);
            pRet->SetErrorMsg("The fluid material specific heat equals 0 while calling HTCCustom plugin function.");
            return;
        } 
            double radius = 0.0;
        boolResult = pContext->GetRadius(&radius);
        double prandtlNumber = fluidViscosity * fluidSpecificHeat / fluidConductivity;
        if (radius != 0.0)
        result = prandtlNumber * fluidConductivity / radius;       
     
       // Put 1 if you want to printout information for debugging purposes
    #if 0
            std::cout << std::endl;
            std::cout << "Fluid Viscosity: " << fluidViscosity << std::endl;
            std::cout << "Fluid Temperature: " << fluidTemperature << std::endl;
            std::cout << "Fluid Conductivity: " << fluidConductivity << std::endl;
            std::cout << "Fluid Specific Heat: " << fluidSpecificHeat << std::endl;
            std::cout << "Radius: " << radius << std::endl;
            std::cout << "Prandtl Number: " << prandtlNumber << std::endl;
            std::cout << "Result: " << result << std::endl;
            
    #endif
            pRet->SetDouble(result);
     }
    
  6. Register your HTCCCustom() plugin function.
    You can register and add your plugin function, using the AddFunction method.
      void AddHTCCustom(IRegistrar* pReg)
        {
            Measure meas;
            meas.Set(1, 0, -3, 0, 0, 0, -1, 0, 0);
            IFunctionDefinition* pFunc = pReg->AddFunction(
                 // Name of the function used in BC
                 "HTCCustom",
                 // Long description
                 "Return heat transfer coefficient from a free disc with turbulent flow",
                 // Unit dimension for the value returned
                 meas,
                 // Return value data type
                TYP_DBL,
                 // Name for unit dimension returned
                "Heat transfer coefficient",
                 // Pointer of the implemented function from the Step 6.
                &HTCCustom);
    
           }
    Note:
    When you add your function, you must specify the unit dimensions of the physical quantity that is returned by your function using the Set method.
  7. Add your plugin function to the source code.
    Use AddFunctions, which is described in step 3, to add your plugin function to the structure of the source code.
    // Go through the list of all supported functions and add them
    void AddFunctions(IRegistrar* pReg)
    {
            AddHTCCustom(pReg);
    }
  8. Compile the source code.
    Compile the source code for your plugin function using the build_windows.cmd or build_linux.com scripts to generate a .dll file for Windows or .so file for Linux. Edit the scripts to specify the correct compiler and the name of the plugin and for any other modifications.

    You can find a sample compilation script in the [installation_path]\nxcae_extras\tmg\plugin_examples\thermal_solver\ExpressionsShell folder. For Windows, you can find the Visual Studio 2017 project already set up for this example in the [installation_path]\nxcae_extras\tmg\plugin_examples\thermal_solver\ExpressionsVC2017 folder.

    Make sure that the version of your local compiler is identical to the version of the compiler used in the script. For a list of the compiler versions, see Supported compilers.

  9. Use your plugin function in a Simcenter 3D thermal model.
    For information on how to specify plugin functions in expressions for your boundary conditions, see Specify a thermal plugin function in the Simcenter 3D Online help.