/// <summary>
        /// Saves a time-step to the database's persistent memory.
        /// </summary>
        /// <param name="_tsi">Contains Id etc.</param>
        public void SaveTimestep(TimestepInfo _tsi)
        {
            using (var tr = new FuncTrace())
            {
                if (!(_tsi.ID.Equals(Guid.Empty) && _tsi.StorageID.Equals(Guid.Empty)))
                {
                    throw new ArgumentException("Timestep is already saved in database");
                }
                var fields  = _tsi.Fields.ToArray();
                var GridDat = fields[0].GridDat;

                {
                    List <DGField> FieldsFlatten = new List <DGField>();
                    TimestepInfo.FlattenHierarchy(FieldsFlatten, fields);
                    foreach (var f in FieldsFlatten)
                    {
                        if (!object.ReferenceEquals(f.GridDat, GridDat))
                        {
                            throw new ArgumentException("mismatch in GridData object.");
                        }

                        if (!fields.Contains(f, (a, b) => object.ReferenceEquals(a, b)))
                        {
                            // here, we ensure that the 'fields' -- list is complete, i.e.
                            // that the flatten hierarchy contains no field which is not already a memeber of 'fields'.
                            // The purpose is e.g. to prevent saving an XDG field without the required level-set field.
                            throw new ArgumentException(
                                      "Unable to save timestep: field '" + f.Identification
                                      + "', which is required by at least one of the"
                                      + " given fields, must also be contained in the"
                                      + " given list of fields.",
                                      "_tsi");
                        }
                    }
                }

                // build vector
                // ============
                int J           = GridDat.iLogicalCells.NoOfLocalUpdatedCells;
                var vec         = new CellFieldDataSet[J];
                var _fields     = fields.ToArray();
                int NF          = _fields.Length;
                var Permutation = GridDat.CurrentGlobalIdPermutation.Values;
                for (int j = 0; j < J; j++)
                { // loop over cells
                    vec[j]          = new CellFieldDataSet();
                    vec[j].GlobalID = Permutation[j];
                    //vec[j].DGCoordinateData = new CellFieldDataSet.CellFieldData[NF];
                    for (int idxF = 0; idxF < NF; idxF++)
                    { // loop over fields
                        var      field  = _fields[idxF];
                        int      N      = field.Basis.GetLength(j);
                        double[] Coords = new double[N];
                        for (int n = 0; n < N; n++)
                        {
                            Coords[n] = field.Coordinates[j, n];
                        }
                        //vec[j].DGCoordinateData[idxF] = new CellFieldDataSet.CellFieldData() {
                        //    Data = Coords
                        //};
                        vec[j].AppendDGCoordinates(Coords);
                        Debug.Assert(ArrayTools.ListEquals(Coords, vec[j].GetDGCoordinates(idxF)));
                    }
                }

                // Save dg coordinates
                // ===================
                Guid VectorGuid = Driver.SaveVector(vec);
                _tsi.StorageID = VectorGuid;


                // Save state object
                // =================
                _tsi.ID = Guid.NewGuid().MPIBroadcast(0);
                Exception e = null;
                if (MyRank == 0)
                {
                    try
                    {
                        //tsi = new TimestepInfo(physTime, currentSession, TimestepNo, fields, VectorGuid);
                        using (var s = fsDriver.GetTimestepStream(true, _tsi.ID))
                        {
                            Driver.Serialize(s, _tsi, typeof(TimestepInfo));
                            s.Close();
                        }
                    }
                    catch (Exception ee)
                    {
                        e = ee;
                        Console.Error.WriteLine(ee.GetType().Name + " on rank " + MyRank + " saving time-step " + _tsi.TimeStepNumber + ": " + ee.Message);
                        Console.Error.WriteLine(ee.StackTrace);
                    }
                }
                e.ExceptionBcast();

                // log session
                // ===========
                SessionInfo currentSession = (SessionInfo)(_tsi.Session); // hack
                if (MyRank == 0)
                {
                    try
                    {
                        currentSession.LogTimeStep(_tsi.ID);
                    }
                    catch (Exception ee)
                    {
                        e = ee;
                        Console.Error.WriteLine(ee.GetType().Name + " on rank " + MyRank + " saving time-step " + _tsi.TimeStepNumber + ": " + ee.Message);
                        Console.Error.WriteLine(ee.StackTrace);
                    }
                }
                e.ExceptionBcast();

                _tsi.Database = currentSession.Database;
            }
        }