#include "ANSCUSTOMPY.h" #include #include using json = nlohmann::json; namespace fs = std::filesystem; namespace py = pybind11; namespace { using ThreadLocalModelMap = std::unordered_map>; ThreadLocalModelMap& GetThreadLocalState() { thread_local ThreadLocalModelMap threadState; return threadState; } } std::string CustomParametersToJson(const ANSCENTER::Params& params) { json root; // ROI_Config for (const auto& cfg : params.ROI_Config) { json j; j["Rectangle"] = cfg.Rectangle; j["Polygon"] = cfg.Polygon; j["Line"] = cfg.Line; j["MinItems"] = cfg.MinItems; j["MaxItems"] = cfg.MaxItems; j["Name"] = cfg.Name; j["ROI-Match"] = cfg.ROIMatch; root["ROI_Config"].push_back(j); } // ROI_Options for (const auto& opt : params.ROI_Options) { root["ROI_Options"].push_back(opt); } // Parameters for (const auto& param : params.Parameters) { json j; j["Name"] = param.Name; j["DataType"] = param.DataType; j["NoOfdecimals"] = param.NoOfDecimals; j["MaxValue"] = param.MaxValue; j["MinValue"] = param.MinValue; j["StartValue"] = param.StartValue; j["ListItems"] = param.ListItems; j["DefaultValue"] = param.DefaultValue; j["Value"] = param.Value; root["Parameters"].push_back(j); } // ROI_Values for (const auto& rv : params.ROI_Values) { json j; j["ROI-Match"] = rv.ROIMatch; for (const auto& pt : rv.ROIPoints) { j["ROIPoints"].push_back({ {"x", pt.x}, {"y", pt.y} }); } j["Option"] = rv.Option; j["Name"] = rv.Name; j["OriginalImageSize"] = rv.OriginalImageSize; root["ROI_Values"].push_back(j); } // Convert to compact JSON string (no whitespace) std::string jsonString = root.dump(); // dump() without indent = compact return jsonString; } namespace ANSCENTER { std::once_flag PythonRuntime::initFlag; std::unique_ptr PythonRuntime::instance = nullptr; std::atomic PythonRuntime::_isInitialized{ false }; std::atomic PythonRuntime::shuttingDown{ false }; std::mutex PythonRuntime::_instanceMutex; std::mutex ANSCUSTOMPY::_globalInstancesMutex; std::unordered_set ANSCUSTOMPY::_globalInstances; std::atomic ANSCUSTOMPY::globalInstanceCounter{ 1 }; // Declare GetPythonRuntime as a friend function of PythonRuntime PythonRuntime& GetPythonRuntime(const std::wstring& pythonHome); PythonRuntime& GetPythonRuntime(const std::wstring& pythonHome) { std::call_once(PythonRuntime::initFlag, [&]() { std::lock_guard lock(PythonRuntime::_instanceMutex); PythonRuntime::instance = std::unique_ptr(new PythonRuntime(pythonHome)); }); return *PythonRuntime::instance; } PythonRuntime::PythonRuntime(const std::wstring& home) : pythonHome(home) { InitializeInterpreter(); } bool PythonRuntime::IsInitialized() { return _isInitialized.load(std::memory_order_acquire) && Py_IsInitialized(); } void PythonRuntime::InitializeInterpreter() { if (!pythonHome.empty()) { #pragma warning(push) #pragma warning(disable : 4996) Py_SetPythonHome(pythonHome.c_str()); #pragma warning(pop) } py::initialize_interpreter(); _isInitialized.store(true, std::memory_order_release); PatchPythonStreamsSafe(); } void PythonRuntime::PatchPythonStreamsSafe() { try { py::exec(R"( import sys, io class DummyStream(io.StringIO): def write(self, txt): pass def flush(self): pass if sys.stdout is None or not hasattr(sys.stdout, "write"): sys.stdout = DummyStream() if sys.stderr is None or not hasattr(sys.stderr, "write"): sys.stderr = DummyStream() )"); } catch (const py::error_already_set& e) { std::cerr << "[PatchPythonStreamsSafe] Python error: " << e.what() << std::endl; } } void PythonRuntime::AddToSysPath(const std::string& path) { if (!IsInitialized()) { std::cerr << "[PythonRuntime::AddToSysPath] Interpreter not initialized!\n"; return; } py::gil_scoped_acquire gil; py::module_ sys = py::module_::import("sys"); sys.attr("path").attr("insert")(0, path); } void PythonRuntime::Shutdown() { std::lock_guard lock(_instanceMutex); if (shuttingDown.exchange(true)) return; if (_isInitialized.load(std::memory_order_acquire)) { try { py::gil_scoped_acquire gil; py::module::import("gc").attr("collect")(); } catch (...) { std::cerr << "[PythonRuntime::Shutdown] GC failed (ignored)." << std::endl; } try { py::finalize_interpreter(); } catch (...) { std::cerr << "[PythonRuntime::Shutdown] finalize_interpreter failed." << std::endl; } _isInitialized.store(false, std::memory_order_release); } instance.reset(); } /// /// /// Initializes the ANSCUSTOMPY model with the given parameters. /// ANSCUSTOMPY::ANSCUSTOMPY() { _instanceId = globalInstanceCounter.fetch_add(1, std::memory_order_relaxed); _destroyed = false; _isInitialized = false; } ANSCUSTOMPY::~ANSCUSTOMPY() { try { if (PythonRuntime::IsInitialized()) Destroy(); } catch (...) { std::cerr << "[~ANSCUSTOMPY] Exception during destruction." << std::endl; } } void ANSCUSTOMPY::RegisterSelf() { { std::lock_guard lock(_globalInstancesMutex); _globalInstances.insert(this); } auto& threadState = GetThreadLocalState(); if (!_wrapper || !_wrapper->modelFactory) return; if (threadState.find(_instanceId) == threadState.end()) { if (_wrapper && _wrapper->modelFactory) { py::gil_scoped_acquire gil; auto newWrapper = std::make_shared(); newWrapper->modelFactory = _wrapper->modelFactory; newWrapper->map[0] = std::make_shared(_wrapper->modelFactory()); threadState[_instanceId] = newWrapper; } } } void ANSCUSTOMPY::UnregisterSelf() { std::lock_guard lock(_globalInstancesMutex); _globalInstances.erase(this); } void ANSCUSTOMPY::ClearThreadState() { auto& threadState = GetThreadLocalState(); auto it = threadState.find(_instanceId); if (it != threadState.end()) { if (PythonRuntime::IsInitialized()) { py::gil_scoped_acquire gil; it->second->map.clear(); } else { it->second->map.clear(); } threadState.erase(it); } } bool ANSCUSTOMPY::EnsureModelReady(const std::string& methodName) { if (!_isInitialized || _destroyed || !PythonRuntime::IsInitialized()) { return false; } //auto& threadState = GetThreadLocalState(); //if (threadState.find(_instanceId) == threadState.end()) { // if (_wrapper && _wrapper->modelFactory) { // py::gil_scoped_acquire gil; // auto newWrapper = std::make_shared(); // newWrapper->modelFactory = _wrapper->modelFactory; // newWrapper->map[0] = std::make_shared(_wrapper->modelFactory()); // threadState[_instanceId] = newWrapper; // } // else { // return false; // } //} return true; } py::object ANSCUSTOMPY::GetThreadLocalModel() { auto& threadState = GetThreadLocalState(); auto it = threadState.find(_instanceId); if (_destroyed || it == threadState.end() || !it->second) { return py::none(); } auto& modelMap = it->second->map; auto modelIt = modelMap.find(0); if (modelIt == modelMap.end()) { py::gil_scoped_acquire gil; auto obj = it->second->modelFactory(); if (obj.is_none()) return py::none(); auto wrapped = std::make_shared(obj); modelMap[0] = wrapped; return *wrapped; } return *modelIt->second; } bool ANSCUSTOMPY::Destroy() { //std::lock_guard lock(_mutex); if (_destroyed) return true; _destroyed = true; ClearThreadState(); UnregisterSelf(); return true; } void ANSCUSTOMPY::SafeShutdownAll(bool waitForShutdown) { std::unordered_set instancesCopy; { std::lock_guard lock(_globalInstancesMutex); instancesCopy = _globalInstances; } for (ANSCUSTOMPY* instance : instancesCopy) { if (instance) { try { instance->ClearThreadState(); instance->Destroy(); } catch (...) { std::cerr << "[SafeShutdownAll] Destroy failed." << std::endl; } } } std::this_thread::sleep_for(std::chrono::milliseconds(300)); auto shutdownFunc = []() { try { std::this_thread::sleep_for(std::chrono::milliseconds(300)); int retry = 0; while (!ANSCUSTOMPY::_globalInstances.empty() && retry++ < 100) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } if (PythonRuntime::IsInitialized()) { py::gil_scoped_acquire gil; py::module::import("gc").attr("collect")(); PythonRuntime::Shutdown(); } } catch (...) { std::cerr << "[SafeShutdownAll] Shutdown failed." << std::endl; } }; if (waitForShutdown) shutdownFunc(); else std::thread(shutdownFunc).detach(); } bool ANSCUSTOMPY::InitializePythonModel(const std::string& moduleName, const std::string& fullPath) { if (!PythonRuntime::IsInitialized()) { _logger.LogError("[InitializePythonModel] Python error:\n", "Python interpreter is not initialized.", __FILE__, __LINE__); return false; } py::gil_scoped_acquire gil; try { py::exec("import logging; logging.getLogger('ultralytics').setLevel(logging.CRITICAL)", py::globals()); py::dict locals; std::ostringstream code; code << "import importlib.util\n" << "spec = importlib.util.spec_from_file_location('" << moduleName << "', r'" << fullPath << "')\n" << "mod = importlib.util.module_from_spec(spec)\n" << "spec.loader.exec_module(mod)\n"; py::exec(code.str(), py::globals(), locals); py::object mod = locals["mod"]; py::object modelClass = mod.attr("ANSModel"); auto& threadState = GetThreadLocalState(); auto& wrapper = threadState[_instanceId]; // ensure per-thread-per-instance if (!wrapper) wrapper = std::make_shared(); wrapper->modelFactory = [modelClass]() { py::gil_scoped_acquire gil; py::object instance = modelClass(); return instance;}; _wrapper = wrapper; // Store for main thread access too return true; } catch (const py::error_already_set& e) { PyErr_Print(); _logger.LogFatal("InitializePythonModel", std::string("Python error: ") + e.what(), __FILE__, __LINE__); return false; } } bool ANSCUSTOMPY::Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap) { //std::lock_guard lock(_mutex); try { // Step 1: Base model init bool result = ANSODBase::Initialize(licenseKey, modelConfig, modelZipFilePath, modelZipPassword, labelMap); if (!result) return false; _modelConfig = modelConfig; _modelConfig.inpHeight = 640; _modelConfig.inpWidth = 640; if (_modelConfig.modelMNSThreshold < 0.2) _modelConfig.modelMNSThreshold = 0.5; if (_modelConfig.modelConfThreshold < 0.2) _modelConfig.modelConfThreshold = 0.5; // Step 2: Validate model folder if (_modelFolder.empty()) { _logger.LogError("ANSCUSTOMPY::Initialize", "_modelFolder is not set.", __FILE__, __LINE__); return false; } // Step 3: Set Python Home std::wstring pythonHome; const fs::path sharedPython = "C:/ProgramData/ANSCENTER/Python311"; const fs::path sharedDll = sharedPython / "python311.dll"; if (fs::exists(sharedDll)) { pythonHome = sharedPython.wstring(); } else { pythonHome = (fs::path(_modelFolder) / "python_env").wstring(); } // Step 4: Initialize Python and sys.path auto& runtime = GetPythonRuntime(pythonHome); runtime.AddToSysPath(_modelFolder); // Step 5: Load Python model class from unique module //_scriptPath = _modelFolder + "/ansinfer.py"; _scriptPath = fs::path(_modelFolder).append("ansinfer.py").string(); _moduleName = "ansinfer_" + std::to_string(_instanceId); if (!InitializePythonModel(_moduleName, _scriptPath)) { _logger.LogError("ANSCUSTOMPY::Initialize", "Failed to load Python model.", __FILE__, __LINE__); return false; } // Step 6: Load class names _classFilePath = CreateFilePath(_modelFolder, "classes.names"); std::ifstream isValidFileName(_classFilePath); if (!isValidFileName) { _logger.LogDebug("ANSCUSTOMPY::LoadModel. Load classes from string", _classFilePath, __FILE__, __LINE__); LoadClassesFromString(); } else { _logger.LogDebug("ANSCUSTOMPY::LoadModel. Load classes from file", _classFilePath, __FILE__, __LINE__); LoadClassesFromFile(); } labelMap.clear(); if (!_classes.empty()) labelMap = VectorToCommaSeparatedString(_classes); _destroyed = false; _isInitialized = true; RegisterSelf(); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSCUSTOMPY::Initialize", e.what(), __FILE__, __LINE__); return false; } } bool ANSCUSTOMPY::LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword) { //std::lock_guard lock(_mutex); try { // Step 0: Assign unique instance ID if (!ANSODBase::LoadModel(modelZipFilePath, modelZipPassword)) return false; if (_modelFolder.empty()) { _logger.LogError("ANSCUSTOMPY::LoadModel", "_modelFolder is not set.", __FILE__, __LINE__); return false; } // Step 3: Set Python home std::wstring pythonHome; const fs::path sharedPython = "C:/ProgramData/ANSCENTER/Python311"; const fs::path sharedDll = sharedPython / "python311.dll"; if (fs::exists(sharedDll)) { pythonHome = sharedPython.wstring(); } else { pythonHome = (fs::path(_modelFolder) / "python_env").wstring(); } // Step 4: Initialize Python and sys.path auto& runtime = GetPythonRuntime(pythonHome); runtime.AddToSysPath(_modelFolder); // Step 5: Load Python model class from unique module //_scriptPath = _modelFolder + "/ansinfer.py"; _scriptPath = fs::path(_modelFolder).append("ansinfer.py").string(); _moduleName = "ansinfer_" + std::to_string(_instanceId); if (!InitializePythonModel(_moduleName, _scriptPath)) { _logger.LogError("ANSCUSTOMPY::LoadModel", "Failed to load Python model.", __FILE__, __LINE__); return false; } _destroyed = false; _isInitialized = true; RegisterSelf(); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSCUSTOMPY::LoadModel", e.what(), __FILE__, __LINE__); return false; } } bool ANSCUSTOMPY::LoadModelFromFolder(std::string licenseKey, ModelConfig modelConfig, std::string modelName, std::string className, const std::string& modelFolder, std::string& labelMap) { //std::lock_guard lock(_mutex); try { // Step 0: Assign unique instance ID early if (!ANSODBase::LoadModelFromFolder(licenseKey, modelConfig, modelName, className, modelFolder, labelMap)) return false; _modelConfig = modelConfig; _modelConfig.inpHeight = 640; _modelConfig.inpWidth = 640; if (_modelConfig.modelMNSThreshold < 0.2) _modelConfig.modelMNSThreshold = 0.5; if (_modelConfig.modelConfThreshold < 0.2) _modelConfig.modelConfThreshold = 0.5; // Step 2: Validate model folder if (_modelFolder.empty()) { _logger.LogError("ANSCUSTOMPY::Initialize", "_modelFolder is not set.", __FILE__, __LINE__); return false; } // Step 3: Set Python home std::wstring pythonHome; const fs::path sharedPython = "C:/ProgramData/ANSCENTER/Python311"; const fs::path sharedDll = sharedPython / "python311.dll"; if (fs::exists(sharedDll)) { pythonHome = sharedPython.wstring(); } else { pythonHome = (fs::path(_modelFolder) / "python_env").wstring(); } // Step 4: Initialize Python and sys.path auto& runtime = GetPythonRuntime(pythonHome); runtime.AddToSysPath(_modelFolder); // Step 5: Load Python model class from unique module //_scriptPath = _modelFolder + "/ansinfer.py"; _scriptPath = fs::path(_modelFolder).append("ansinfer.py").string(); _moduleName = "ansinfer_" + std::to_string(_instanceId); if (!InitializePythonModel(_moduleName, _scriptPath)) { _logger.LogError("ANSCUSTOMPY::Initialize", "Failed to load Python model.", __FILE__, __LINE__); return false; } // Step 6: Load class labels _classFilePath = CreateFilePath(_modelFolder, "classes.names"); std::ifstream isValidFileName(_classFilePath); if (!isValidFileName) { _logger.LogDebug("ANSCUSTOMPY::LoadModel", "Load classes from string", __FILE__, __LINE__); LoadClassesFromString(); } else { _logger.LogDebug("ANSCUSTOMPY::LoadModel", "Load classes from file", __FILE__, __LINE__); LoadClassesFromFile(); } labelMap.clear(); if (!_classes.empty()) labelMap = VectorToCommaSeparatedString(_classes); _destroyed = false; _isInitialized = true; RegisterSelf(); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSCUSTOMPY::LoadModelFromFolder", e.what(), __FILE__, __LINE__); return false; } } std::vector ANSCUSTOMPY::RunInference(const cv::Mat& input) { return RunInference(input, "CustomPyCam"); } std::vector ANSCUSTOMPY::RunInference(const cv::Mat& input, const std::string& camera_id) { std::vector results; if (!_isInitialized) { _logger.LogError("ANSCUSTOMPY::RunInference", "Model is not initialized.", __FILE__, __LINE__); return results; } if (!_licenseValid) { _logger.LogError("ANSCUSTOMPY::RunInference", "Invalid License", __FILE__, __LINE__); return results; } if (input.empty()) { _logger.LogError("ANSCUSTOMPY::RunInference", "Input image is empty.", __FILE__, __LINE__); return results; } try { std::string jsonStr = RunPythonInferenceFromMat(input); if (!jsonStr.empty()) { results = ANSUtilityHelper::GetDetectionsFromString(jsonStr); } else { _logger.LogWarn("ANSCUSTOMPY::RunInference", "Empty JSON result from Python inference.", __FILE__, __LINE__); } } catch (const std::exception& e) { _logger.LogFatal("ANSCUSTOMPY::RunInference", e.what(), __FILE__, __LINE__); } return results; } std::string ANSCUSTOMPY::RunPythonInferenceFromMat(const cv::Mat& image) { if (!EnsureModelReady("RunPythonInferenceFromMat")) return ""; if (image.empty()) return ""; try { py::object model = GetThreadLocalModel(); if (model.is_none()) { _logger.LogError("ANSCUSTOMPY::RunPythonInferenceFromMat", "Model is None.", __FILE__, __LINE__); return ""; } py::gil_scoped_acquire gil; if (!py::hasattr(model, "run_inference")) { _logger.LogError("ANSCUSTOMPY::RunPythonInferenceFromMat", "Model has no 'run_inference' method.", __FILE__, __LINE__); return ""; } py::bytes image_bytes(reinterpret_cast(image.data), image.total() * image.elemSize()); py::object result = model.attr("run_inference")(image_bytes, image.cols, image.rows, image.channels()); return result.cast(); } catch (const py::error_already_set& e) { PyErr_Print(); _logger.LogFatal("RunPythonInferenceFromMat", e.what(), __FILE__, __LINE__); return ""; } catch (const std::exception& e) { _logger.LogFatal("RunPythonInferenceFromMat", e.what(), __FILE__, __LINE__); return ""; } } bool ANSCUSTOMPY::OptimizeModel(bool fp16, std::string& optimizedModelFolder) { if (!EnsureModelReady("OptimizeModel")) return false; try { py::object model = GetThreadLocalModel(); if (model.is_none()) { _logger.LogError("ANSCUSTOMPY::OptimizeModel", "Model is None.", __FILE__, __LINE__); return false; } py::gil_scoped_acquire gil; if (!py::hasattr(model, "model_optimize")) { _logger.LogError("ANSCUSTOMPY::OptimizeModel", "Python model has no method 'model_optimize'.", __FILE__, __LINE__); return false; } py::object result; try { result = model.attr("model_optimize")(fp16); } catch (const py::error_already_set& e) { PyErr_Print(); _logger.LogFatal("ANSCUSTOMPY::OptimizeModel", std::string("Exception in 'model_optimize': ") + e.what(), __FILE__, __LINE__); return false; } if (result.is_none()) { _logger.LogError("ANSCUSTOMPY::OptimizeModel", "Python 'model_optimize' returned None.", __FILE__, __LINE__); return false; } if (!py::isinstance(result)) { _logger.LogError("ANSCUSTOMPY::OptimizeModel", "Unexpected return type from 'model_optimize'. Expected bool.", __FILE__, __LINE__); return false; } bool success = result.cast(); if (success) { optimizedModelFolder = fs::path(_scriptPath).parent_path().string(); } return success; } catch (const py::error_already_set& e) { PyErr_Print(); _logger.LogFatal("ANSCUSTOMPY::OptimizeModel", e.what(), __FILE__, __LINE__); return false; } catch (const std::exception& e) { _logger.LogFatal("ANSCUSTOMPY::OptimizeModel", e.what(), __FILE__, __LINE__); return false; } } bool ANSCUSTOMPY::ConfigureParameters(Params& param) { if (!EnsureModelReady("ConfigureParamaters")) return false; try { py::object model = GetThreadLocalModel(); if (model.is_none()) { _logger.LogError("ANSCUSTOMPY::ConfigureParamaters", "Model is None.", __FILE__, __LINE__); return false; } py::gil_scoped_acquire gil; if (!py::hasattr(model, "configureParameters")) { _logger.LogError("ANSCUSTOMPY::ConfigureParamaters", "Python model missing 'configureParameters' method.", __FILE__, __LINE__); return false; } py::object result; try { result = model.attr("configureParameters")(); } catch (const py::error_already_set& e) { PyErr_Print(); _logger.LogFatal("ANSCUSTOMPY::ConfigureParamaters", std::string("Exception in 'configureParameters': ") + e.what(), __FILE__, __LINE__); return false; } if (result.is_none()) { _logger.LogError("ANSCUSTOMPY::ConfigureParamaters", "Returned None from Python method.", __FILE__, __LINE__); return false; } if (!py::isinstance(result)) { _logger.LogError("ANSCUSTOMPY::ConfigureParamaters", "Expected Python string return from 'configureParameters'.", __FILE__, __LINE__); return false; } std::string jsonStr = result.cast(); if (jsonStr.empty()) { _logger.LogError("ANSCUSTOMPY::ConfigureParamaters", "Empty JSON string returned from Python.", __FILE__, __LINE__); return false; } param = ANSUtilityHelper::ParseCustomParameters(jsonStr); return true; } catch (const py::error_already_set& e) { PyErr_Print(); _logger.LogFatal("ANSCUSTOMPY::ConfigureParamaters", e.what(), __FILE__, __LINE__); return false; } catch (const std::exception& e) { _logger.LogFatal("ANSCUSTOMPY::ConfigureParamaters", e.what(), __FILE__, __LINE__); return false; } } bool ANSCUSTOMPY::SetParameters(const Params& param) { if (!EnsureModelReady("SetParamaters")) return false; try { std::string jsonStr = CustomParametersToJson(param); if (jsonStr.empty()) { _logger.LogError("ANSCUSTOMPY::SetParamaters", "Serialized parameter string is empty.", __FILE__, __LINE__); return false; } py::object model = GetThreadLocalModel(); if (model.is_none()) { _logger.LogError("ANSCUSTOMPY::SetParamaters", "Model is None.", __FILE__, __LINE__); return false; } py::gil_scoped_acquire gil; if (!py::hasattr(model, "setParameters")) { _logger.LogError("ANSCUSTOMPY::SetParamaters", "Python model has no method 'setParameters'.", __FILE__, __LINE__); return false; } py::object result; try { result = model.attr("setParameters")(jsonStr); } catch (const py::error_already_set& e) { PyErr_Print(); _logger.LogFatal("ANSCUSTOMPY::SetParamaters", std::string("Exception in 'setParameters': ") + e.what(), __FILE__, __LINE__); return false; } if (result.is_none()) { _logger.LogError("ANSCUSTOMPY::SetParamaters", "Python method returned None.", __FILE__, __LINE__); return false; } if (!py::isinstance(result)) { _logger.LogError("ANSCUSTOMPY::SetParamaters", "Python method returned non-boolean type.", __FILE__, __LINE__); return false; } return result.cast(); } catch (const py::error_already_set& e) { PyErr_Print(); _logger.LogFatal("ANSCUSTOMPY::SetParamaters", std::string("Python error: ") + e.what(), __FILE__, __LINE__); return false; } catch (const std::exception& e) { _logger.LogFatal("ANSCUSTOMPY::SetParamaters", e.what(), __FILE__, __LINE__); return false; } } }