private void pEntropyRun_implant(int numberOfCases, string csvFile, bool useThreads)
    {
        reset();
        clearAbortFlagFunc?.Invoke();
        string emailString;

        bool simState = entropyRunCore(numberOfCases, row: 0, col: 0, csvFile, useThreads, tileHandling: false, implantMode: true, doPASearch: false);

        switch (simState)
        {
        case false:
            emailString = "Implant run aborted";
            break;

        default:
            emailString = "Implant run completed";
            break;
        }
        // Assume user error if perJob is set and not onCompletion.
        // We'll use simulationSettings here just because legacy put the settings there and it's the easiest option.
        if (commonVars.getNonSimulationSettings().emailOnCompletion&& numberOfCases > 1)
        {
            Email.Send(commonVars.getNonSimulationSettings().host, commonVars.getNonSimulationSettings().port, commonVars.getNonSimulationSettings().ssl, emailString, lastSimResultsOverview, commonVars.getNonSimulationSettings().emailAddress, commonVars.getNonSimulationSettings().emailPwd);
        }

        if (numberOfCases > 1)
        {
            implantResultPackage.getMeanAndStdDev();
            updateStatus?.Invoke(lastSimResultsOverview);
        }

        postSimUIFunc?.Invoke();
    }
 private void pUpdatePreview(SimResultPackage resultPackage)
 {
     if (Monitor.IsEntered(varianceContext.previewLock))
     {
         updatePreview(resultPackage.getPreviewResult().getSimShapes(), resultPackage.getPreviewResult().getPreviewShapes(),
                       resultPackage.getPreviewResult().getPoints(), resultPackage.getMeanAndStdDev());
     }
 }
    private void entropyRunCore_implant_singleThread(bool previewMode, int numberOfCases)
    {
        const int numberOfResultsFields = 1;
        // Let's sample this
        const int sampleRate = 100;

        setSampler_implant(numberOfCases, previewMode);
        sampler_implant.sample(false);
        sw.Start();

        implantResultPackage = new SimResultPackage(ref varianceContext.implantPreviewLock, numberOfCases, numberOfResultsFields);
        sw.Reset();
        for (int i = 0; i < numberOfCases; i++)
        {
            sw.Start();
            currentProgress = i + 1;
            try
            {
                // Get the results from the implant calc engine.
                ChaosSettings_implant cs = sampler_implant.getSample(i);
                implantResultPackage.Add(entropyEval_implant(cs));

                if (numberOfCases == 1 || currentProgress % sampleRate == 0)
                {
                    // Update the preview configuration.
                    if (implantResultPackage.getImplantResult(i).isValid())
                    {
                        if (numberOfCases > 1)
                        {
                            try
                            {
                                resultString = implantResultPackage.getMeanAndStdDev();
                            }
                            catch (Exception)
                            {
                                // Non-critical if an exception is raised. Ignore and carry on.
                            }
                        }
                        else
                        {
                            // Need to workaround some oddness here. The .ToString() calls below seemed to turn "0.0" into blanks.
                            string tmp = Convert.ToDouble(implantResultPackage.getImplantResult(i).getResult()).ToString("0.##");
                            resultString += tmp + ",";

                            tmp           = Convert.ToDouble(implantResultPackage.getImplantResult(i).getMin()).ToString("0.##");
                            resultString += tmp + ",";

                            tmp           = Convert.ToDouble(implantResultPackage.getImplantResult(i).getMax()).ToString("0.##");
                            resultString += tmp;
                        }
                        updateImplantSimUIFunc?.Invoke(false, implantResultPackage, resultString);
                    }
                    // Force redraw. We could use the progress bar to repaint, though.
                    // Note that this is an ugly hack to also ensure we collect stop button presses.
                    forceImplantRepaintFunc?.Invoke();
                }
            }
            catch (Exception)
            {
                // Reject the case - something happened.
            }
            // Nudge progress bar.
            if (numberOfCases > 1)
            {
                timeOfFlight_implant(sw.Elapsed.TotalSeconds);
                stepProgress?.Invoke();
            }

            // Check if user cancelled.
            if (abortRunFunc == null)
            {
                continue;
            }

            abortRunFunc();
            if (!commonVars.runAbort)
            {
                continue;
            }

            sw.Stop();
            implantResultPackage.setState(false);
            commonVars.runAbort = false; // reset state to allow user to abort save of results.
            break;
        }

        implantResultPackage.setRunTime(sw.Elapsed.TotalSeconds);
        sw.Stop();
    }