public void ProcessOneRange(object state)
            {
                JobSetup jobSetup = (JobSetup)state;
                Index3   min      = jobSetup.output.MinIJK;
                Index3   max      = jobSetup.output.MaxIJK;
                Index3   size     = max - min + 1;
                int      ni       = size.I;
                int      nj       = size.J;
                int      nk       = size.K;

                try
                {
                    Index3 idx = new Index3();
                    PetrelLogger.InfoOutputWindow("ToArray " + min.ToString() + "," + max.ToString());
                    float[,,] data = null;
                    lock (jobSetup)
                    {
                        data = jobSetup.output.ToArray();
                    }
                    PetrelLogger.InfoOutputWindow("Setting " + min.ToString() + "," + max.ToString());
                    Random rd = new Random();
                    for (int i = 0; i < ni; i++)
                    {
                        idx.I = min.I + i;
                        for (int j = 0; j < nj; j++)
                        {
                            idx.J = min.J + j;
                            for (int k = 0; k < nk; k++)
                            {
                                idx.K = min.K + k;
                                float a = (float)rd.NextDouble() * 10000;
                                data[idx.I - min.I, idx.J - min.J, idx.K - min.K] = a;
                                //data[idx.I, idx.J, idx.K] = a;
                            }
                        }

                        //Interlocked.Increment(ref _availableWorkers);
                        //Interlocked.Increment(ref _completedThreads);
                        //data = null;
                        //GC.Collect();
                    }
                    bool canceled;
                    lock (_cancelThreadLock)
                    {
                        canceled = _cancelThread;
                    }
                    lock (jobSetup)
                    {
                        if (jobSetup.output != null)
                        {
                            if (!canceled)
                            {
                                PetrelLogger.InfoOutputWindow("CopyFrom " + min.ToString() + "," + max.ToString());
                                jobSetup.output.CopyFrom(data);
                                jobSetup.output.Dispose();
                                PetrelLogger.InfoOutputWindow("Disposed ");
                                PetrelLogger.InfoOutputWindow("Committed");
                            }
                        }
                    }
                    Interlocked.Increment(ref _availableWorkers);
                    Interlocked.Increment(ref _completedThreads);
                    data = null;
                    GC.Collect();
                }
                catch (Exception e)
                {
                    PetrelLogger.InfoOutputWindow("Exception in thread " + min.ToString() + "," + max.ToString() + ": " + e.Message);
                    Interlocked.Increment(ref _availableWorkers);
                    Interlocked.Increment(ref _completedThreads);
                }
            }
            public override void ExecuteSimple()
            {
                /* PetrelLogger.InfoOutputWindow(string.Format("Well Log: {0},Grid: {1}",
                 *   arguments.NovozhentsevWellLog.Name,
                 *   arguments.NovozhentsevGrid.Name));
                 * PetrelLogger.InfoOutputWindow("Runtime contex: "+ context.GetType().FullName
                 *   );*/

                Property prop  = null;
                int      count = 0;

                // все действия по изменению данных строго внутри транзакции
                using (ITransaction trans = DataManager.NewTransaction())//объект удалением которого будет  с#
                {
                    // запрашиваем исключительный доступ к свойствам сетки
                    trans.Lock(arguments.NovozhentsevGrid.PropertyCollection);//подождать пока
                    // создаем новое свойство и задаем его имя
                    prop      = arguments.NovozhentsevGrid.PropertyCollection.CreateProperty(arguments.NovozhentsevWellLog.WellLogVersion.Template);
                    prop.Name = string.Format("{0} ({1}) upscaled", arguments.NovozhentsevWellLog.Name, arguments.NovozhentsevWellLog.Borehole.Description.Name);
                    arguments.NovozhentsevResultProperty = prop;
                    // получаем перечислитель замеров каротажки в явном виде
                    IEnumerator <WellLogSample> enumSamples = arguments.NovozhentsevWellLog.Samples.GetEnumerator();                                                      //<> generic type тип элемента коллекции нумератор которой имеет этот тип,итератор
                    // получаем доступ к штатному сервису Petrel:
                    IPillarGridIntersectionService pgIntersection = CoreSystem.GetService <IPillarGridIntersectionService>();                                             //статический метод пиллар- пилоны -вид сетки
                    // получаем траекторию скважины в виде линии и запрашиваем список пересечений этой линии с ячейками сетки
                    IPolyline3 polyline = arguments.NovozhentsevWellLog.Borehole.Trajectory.Polyline;                                                                     //
                    IEnumerable <SegmentCellIntersection> intersectionsegments = pgIntersection.GetPillarGridPolylineIntersections(arguments.NovozhentsevGrid, polyline); //набор пересечений полилайна с сеткой грида/коллекция
                    // проходим в цикле по найденным точкам пересечения
                    SegmentCellIntersection enteringSegment = new SegmentCellIntersection();
                    SegmentCellIntersection leavingSegment;
                    double enteringMD = double.NaN;//measure depth, true vertical depth
                    double leavingMD  = double.NaN;
                    bool   FirstTime  = true;
                    foreach (SegmentCellIntersection segment in intersectionsegments)
                    {
                        // на первой итерации нужно только инициализировать внутренние переменные
                        if (FirstTime)
                        {
                            FirstTime       = false;
                            enteringSegment = segment;
                            enteringMD      = arguments.NovozhentsevWellLog.Borehole.Transform(arguments.NovozhentsevGrid.Domain, segment.IntersectionPoint.Z, Domain.MD);//домен - система координат, отсчета
                            // проматываем цикл по замерам, пока не дойдем до нужной глубины
                            while (enumSamples.MoveNext())
                            {
                                if (enumSamples.Current.MD >= enteringMD)
                                {
                                    break;
                                }
                            }
                            continue;
                        }
                        leavingSegment = segment;
                        // находим измеренные глубины точек пересечения вдоль ствола скважины
                        enteringMD = arguments.NovozhentsevWellLog.Borehole.Transform(arguments.NovozhentsevGrid.Domain, enteringSegment.IntersectionPoint.Z, Domain.MD);
                        leavingMD  = arguments.NovozhentsevWellLog.Borehole.Transform(arguments.NovozhentsevGrid.Domain, leavingSegment.IntersectionPoint.Z, Domain.MD);
                        // находим индекс ячейки
                        Index3 cellIndex = enteringSegment.EnteringCell;
                        float  avg       = float.NaN;
                        // если текущее значение глубины замера внутри текущей ячейки
                        if (enumSamples.Current.MD <= leavingMD)
                        {
                            int   numSamples = 1;
                            float total      = enumSamples.Current.Value;
                            // вручную проматываем замеры каротажной кривой в этой ячейке
                            while (enumSamples.MoveNext())
                            {
                                if (enumSamples.Current.MD <= leavingMD)
                                {
                                    numSamples++;
                                    total += enumSamples.Current.Value;
                                }
                                else
                                {
                                    break;
                                }
                            }
                            // теперь вычисляем усредненное значение свойства
                            avg = (float)(total / numSamples);
                            PetrelLogger.InfoOutputWindow(string.Format("сell= {0}, value={1} ({2})", cellIndex.ToString(), avg, prop.Description.Name));
                            prop[cellIndex] = avg;
                            count++;
                            enteringSegment = leavingSegment;
                        }
                        // и записываем его в новое свойство сетки
                    }
                    // если проблем нет, следующая строчка создаст наше свойство
                    arguments.NovozhentsevNumCells = count;
                    trans.Commit();
                }


                // TODO: Implement the workstep logic here.
            }