Using Waterobjects.NET for SewerCAD

  Product(s): Bentley SewerCAD
  Environment: N\A


Original Author:

Kris Culin, Senior Software Engineer, Bentley Systems


This simple guide will take you through the steps for:

  • Opening a SewerCAD hydraulic model
  • Editing some RTK data
  • Computing the model
  • Getting some results.

The assumption is made with this guide that you have a good grasp on using C# and a general idea of how the Municipal Framework is setup. More information on waterobjects.NET and the Bentley Developer Network can be found here:


Opening the Hydraulic Model

To successfully open SewerCAD projects you need instances of two of the primary classes.  The ApplicationModel and ParentFormUIModel.

Create the ApplicationDescription:

IApplicationDescription description = ProductizationLibrary.NewSewerCADApplicationDescription(Assembly.GetExecutingAssembly().GetName().Version, LicensePlatformType.Standalone, Assembly.GetExecutingAssembly().GetName().Version.ToString());

Note:  To quickly add missing using statements, put the cursor over the class that cannot be found.  Press CTRL + period and you will get a little menu that pops up.  Choose the option that adds the using statement at the top of your class file.  If that option is not available, then the reference itself is not yet added to your project.

Create the ApplicationModel for SewerCAD:

StormSewerProductApplicationModel applicationModel = new StormSewerProductApplicationModel(new string[] {}, description);

Create the ParentFormModel:

StormSewerProductParentFormModel parentFormModel = new StormSewerProductParentFormModel(applicationModel);

Create the ParentFormUIModel:

AlabamaParentFormUIModel parentFormUIModel = new
AlabamaParentFormUIModel(parentFormModel, false);

//Make sure you call this after creating the ParentFormUIModel


Now you are at the point where you can open a project, modify data, compute and check results.  Everything you need has been created in the last few steps.

However, before we get to that you also need to make sure the IUserInterface has been properly set.  A lot of the functionality will depend on IUserInterface being available and not null.

To achieve this, create a Form in your project and implement IUserInterface.  The most important part of the interface is the OwnerWindow property.  Simply use “return this” for the getter.

public object OwnerWindow
get { return this; }

Then do the following:

parentFormModel.SetCOMUserInterface(new FakeParentForm());

//FakeParentForm is the name of the Form that was added.  However, you can use whatever name you want.

To open your project, do this:

parentFormUIModel.OpenFileWithSpecifiedExtension(filename, false);

“filename” is the variable that contains the full path and filename of the file you want to open. 

Get the project and hold on to it.  It will contain information and access that you will need.

IDomainProject project = parentFormModel.CurrentGraphicalProject;

Editing RTK Data

To edit the RTK data you need the ID of an RTK table.  This guide assumes that there are catchments in the model that was opened and that all catchments use the RTK Unit Hydrograph and that RTK Tables have been assigned.

First, get the catchment manager:

IDomainElementManager catchmentManager = project.DomainDataSet.DomainElementManager((int)DomainElementType.CatchmentElementManager);

Now, get all the IDs but we really need just the first one.

HmIDCollection elementIDs = catchmentManager.ElementIDs();
Int catchmentID = elementIDs[0];

There are 3 different “sets” of RTK values:  Slow, moderate and rapid.  Therefore, there are nine (9) different fields.  Each of the fields have a different name.  All nine fields are unitized but with different dimensions.  It is suggested you familiarize yourself with this information via the SewerCAD UI before continuing.

Before we get the RTK values, we need the ID of the RTK Table.

ReferenceField rtkSetIDField = new ReferenceField(catchmentManager.DomainElementField(StandardFieldName.RTKUnitHydrographType_RTKSetID, StandardAlternativeTypeName.Hydrologic) as IEditField);
Int RTKSetID = (int)rtkSetIDField.GetValue(catchmentID);

Now we have the ID of the RTK Table.  Get the fields from the RTK Table manager, and use the RTKSetID with the Get/SetValue calls.

This guide will show you how to get to the Slow RTK fields.  It is very similar code to get to the Moderate and Rapid RTK fields.

ISupportElementManager rtkSetManager =

IUnitizedField slowRField = rtkSetManager.SupportElementField(StandardFieldName.RTKSet_SlowInfiltrationR) as IUniziedField

IUnitizedField slowTField = rtkSetManager.SupportElementField(StandardFieldName.RTKSet_SlowInfiltrationT) as IUnitizedField;

IUnitizedField slowKField = rtkSetManager.SupportElementField(StandardFieldName.RTKSet_SlowInfiltrationK) as IUnitizedField;

Once you have all nine fields, you can hold on to them for the lifetime of the project being opened.  Once you close the project and reopen a project, the fields need to be retrieved again.  The same applies to the rtkSetIDField from the catchment manager as well.

Computing the Model

To compute the model is pretty simple.  This approach assumes that the scenario you would like to compute is active (set as current).  It also assumes it is using the GVF-Pressure solver.


Calling the above will automatically show the calculation summary when the computation is complete.  If you want to suppress this, then you will need to take a different approach for computing the scenario.

ModelingElementCollection scenarios = new ModelingElementCollection();


By using the batch run action, it will compute the scenario you added to the scenarios list but it will suppress the opening of the calculation summary.

Obtaining Results

Once the scenario is computed, you can now check the results.

There are different ways of getting results.  You can get the flows for all conduits in the model for a specific time step.  This is returned in an IHmIDToDoubleDictionary keyed by Conduit ID and the value being the flow in the working unit for the field.  Or you can get the flow values over time for a specific conduit ID.  This returns a double array and represents the flows at each time step computed for the calculation (index starting at 0).

For this part I will assume you know the ID of the conduit you want to check and the value is stored in the variable conduitID.

To get the flow values over time, do the following:

IDomainElementManager conduitManager = project.DomainDataSet.DomainElementManager((int)DomainElementType.ConduitElementManager);IResultTimeVariantField flowField = conduitManager.ResultField(StandardResultRecordName.BasicFlowResults_Flow,

StandardCalculationOptionFieldName.GVFPressureEngine, StandardResultRecordName.BasicFlowResults) as IResultTimeVariantField;

Flows over time:

double[] flows = (double[])flowField.GetValuesOverTime(conduitID, project.DomainDataSet.ScenarioManager.ActiveScenarioID);

Flow for a specific time step of 5.  The actual time for timeStepIndex 5 depends on the output increment and whether or not the scenario has pressure elements that could compute at “non-standard” time increments or what are called” intermediate” time steps.

double flow = (double)flowField.GetValue(conduitID, project.DomainDataSet.ScenarioManager.ActiveScenarioID, 5);

Keep in mind that the flow value will be in the working unit for the field.  By default this is also the storage unit of the field unless it is changed.  The working unit stays the same until it is changed or the field is retrieved again from the manager.  The storage unit for this field is CubicFeetPerSecond (a.k.a. cfs).

Closing the Project

When your program closes you need to make sure that the project that was opened is closed properly and that the parentFormModel and parentFormUIModel are properly disposed.

To close the project without saving:

//The following ensures you are not prompted to save.

If you instead want to save your project, then do this:


Make sure you make the following call when your main form closes to end the application: