public void LoadMorphologicalUnitData()
        {
            Units.Clear();

            // Loop over the sorted list of mask values IN ASCENDING DIRECTIONAL ORDER
            foreach (KeyValuePair <int, Tuple <string, string> > maskValue in ((GCDCore.Project.Masks.DirectionalMask)BS.Mask).SortedFieldValues)
            {
                // Only able to create a morphological unit if this mask item appears in budget seg
                if (BS.Classes.ContainsKey(maskValue.Value.Item1))
                {
                    BudgetSegregationClass bsc = BS.Classes[maskValue.Value.Item1];

                    MorphologicalUnit mu = new MorphologicalUnit(bsc.Name);
                    mu.VolErosion    = bsc.Statistics.ErosionThr.GetVolume(ProjectManager.Project.CellArea, ProjectManager.Project.Units);
                    mu.VolErosionErr = bsc.Statistics.ErosionErr.GetVolume(ProjectManager.Project.CellArea, ProjectManager.Project.Units);

                    mu.VolDeposition    = bsc.Statistics.DepositionThr.GetVolume(ProjectManager.Project.CellArea, ProjectManager.Project.Units);
                    mu.VolDepositionErr = bsc.Statistics.DepositionErr.GetVolume(ProjectManager.Project.CellArea, ProjectManager.Project.Units);

                    Units.Add(mu);
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////////////////
            // Uncomment next line to clear the morph unit data and load the debug data
#if DEBUG
            LoadFeshieData();
#endif
            ////////////////////////////////////////////////////////////////////////////////////////////////////

            // Add the total row
            Units.Add(new MorphologicalUnit("Reach Total", true));
        }
        public void ImposeBoundaryCondition(FluxDirection eDir, MorphologicalUnit unit, Volume boundaryVol)
        {
            // Make sure to remove any existing boundary condition flux
            ResetFluxes();

            // Update all units with the new flux as the reach input
            UpdateFluxes(eDir, unit, boundaryVol);
        }
        private void UpdateFluxes(FluxDirection eDir, MorphologicalUnit boundaryUnit, Volume boundaryFlux)
        {
            BoundaryFluxDirection = eDir;
            BoundaryFluxUnit      = boundaryUnit;
            BoundaryFlux          = boundaryFlux;
            ReachInputFlux        = boundaryFlux - (eDir == FluxDirection.Input ? boundaryUnit.VolIn : boundaryUnit.VolOut);

            // Add back in the VolOut for the minimum flux cell (or the whole reach if there was no min flux cell)
            Units[0].VolIn            = -1 * Units[0].VolChange + ReachInputFlux;
            Units[0].VolOut           = Units[0].VolIn + Units[0].VolChange;
            Units[0].CumulativeVolume = Units[0].VolChange;

            // Recalculate the VolOut for each downstream unit now we know the reach input flux
            for (int i = 1; i < Units.Count; i++)
            {
                Units[i].VolIn            = Units[i - 1].VolOut;
                Units[i].VolOut           = Units[i].VolIn - Units[i].VolChange;
                Units[i].CumulativeVolume = Units[i - 1].CumulativeVolume + Units[i].VolChange;
            }

            // Loop over all units and recalc the erosion and deposition.
            MorphologicalUnit muTotal = Units.Last();

            muTotal.VolErosion       = new Volume(0);
            muTotal.VolErosionErr    = new Volume(0);
            muTotal.VolDeposition    = new Volume(0);
            muTotal.VolDepositionErr = new Volume(0);
            foreach (MorphologicalUnit unit in Units)
            {
                muTotal.VolErosion       += unit.VolErosion;
                muTotal.VolErosionErr    += unit.VolErosionErr;
                muTotal.VolDeposition    += unit.VolDeposition;
                muTotal.VolDepositionErr += unit.VolDepositionErr;
            }

            muTotal.VolIn            = Units[0].VolIn;
            muTotal.VolOut           = Units[Units.Count - 1].VolOut;
            muTotal.CumulativeVolume = Units[Units.Count - 1].CumulativeVolume;

            CalculateWork();
        }
        public void ImposeMinimumFlux()
        {
            // Make sure that the reach is reset with zero boundary condition flux
            ResetFluxes();

            MorphologicalUnit minFluxUnit = null;

            // Find the first unit with positive volume change
            if (Units.Where(x => !x.IsTotal).Any(x => x.VolChange >= new Volume(0)))
            {
                minFluxUnit = Units.Where(x => !x.IsTotal).First(x => x.VolChange >= new Volume(0));
            }
            else
            {
                // No positive change, so find the least negative change
                minFluxUnit = Units.Where(x => !x.IsTotal).OrderByDescending(x => x.VolChange).First();
            }

            // Update the reach fluxes with the min flux volume
            UpdateFluxes(FluxDirection.Output, minFluxUnit, new Volume(0));
        }
        public void SaveExcelSpreadsheet()
        {
            //get template and throw error if it doesnt exists
            FileInfo template = new FileInfo(Path.Combine(ProjectManager.ExcelTemplatesFolder.FullName, "Morphological.xml"));

            if (!template.Exists)
            {
                throw new Exception("The GCD morphological approach spreadsheet template cannot be found at " + template.FullName);
            }

            // Verify if file already exists and if so, can it be deleted and replaced
            if (Spreadsheet.Exists)
            {
                // Will throw exception if locked
                IsFileLocked(Spreadsheet);

                Spreadsheet.Delete();
            }

            //setup ExcelXMLDocument which does the heavy lifting of updating the XML
            ExcelXMLDocument xmlExcelDoc = new ExcelXMLDocument(template.FullName);

            //loop through all the units and update spreadsheet
            for (int UnitIndex = 0; UnitIndex < (Units.Count - 1); UnitIndex++)
            {
                MorphologicalUnit unit = Units[UnitIndex];

                //get values and write to dictionary to update named ranges in spreadsheet
                Dictionary <string, string> dicStatValues = new Dictionary <string, string>();
                dicStatValues.Add("TemplateRowName", unit.Name);
                dicStatValues.Add("VolumeErosion", unit.VolErosion.CubicMeters.ToString());
                dicStatValues.Add("VolumeErosionError", unit.VolErosionErr.CubicMeters.ToString());
                dicStatValues.Add("VolumeDeposition", unit.VolDeposition.CubicMeters.ToString());
                dicStatValues.Add("VolumeDepositionError", unit.VolDepositionErr.CubicMeters.ToString());

                //clone or update template row
                if (UnitIndex > 0)
                {
                    xmlExcelDoc.CloneRow("ReachName", UnitIndex, dicStatValues);
                }
                else
                {
                    xmlExcelDoc.UpdateRow("ReachName", dicStatValues);
                }
            }

            //The formulas in the first row is different from the remaining rows, so they need to be update
            //Results match the UI
            string InitialVInformula = "=" + BoundaryFlux.CubicMeters + "-RC[-3]";

            xmlExcelDoc.SetFormula("InitialVIn", InitialVInformula);

            string InitialVOutformula = "=RC[-4]+RC[-1]";

            xmlExcelDoc.SetFormula("InitialVOut", InitialVOutformula);

            string InitialVCumulativeformula = "=RC[-6]";

            xmlExcelDoc.SetFormula("InitialVCumulative", InitialVCumulativeformula);

            //Set duration adn porosity values in spreadsheet
            xmlExcelDoc.SetNamedCellValue("FlowDuration", CompetentDuration.Hours.ToString());
            xmlExcelDoc.SetNamedCellValue("Porosity", Porosity.ToString());

            //cells should be formatted with black, single weight top and bottom border
            CellStyle oCellStyle = new CellStyle();

            oCellStyle.TopBorder.Weight    = 1;
            oCellStyle.TopBorder.Color     = "#000000";
            oCellStyle.BottomBorder.Weight = 1;
            oCellStyle.BottomBorder.Color  = "#000000";

            //loop through all cells and format
            for (int i = 0; i < (Units.Count - 2); i++)
            {
                xmlExcelDoc.FormatRow("ReachName", i, oCellStyle);
            }

            //save output
            //xml cant be saved using the easier readable format with line breaks between nodes
            //because it mangles the header with subscript. Excel interprets the line breaks as new lines in the cell
            string xml = xmlExcelDoc.GetXML();

            File.WriteAllText(Spreadsheet.FullName, xml);
        }