This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

WaterObjects questions

My task is to add demand data from the SQL server to WaterGEMS model using WaterObjects.NET.

I have the DataTable with 2 columns: Customer Label and Demand. I need to programmatically create a child scenario and add (or update) an alternative demand from DataTable to Customers in a model mapped by Label.
From the very laconic WaterObjects.NET programming guide and the examples it’s very difficult to understand how to perform this task.

Let’s start with creating the scenario: to add a Domain element:

IDomainElementManager domainElementManager = dataSet.DomainElementManager(domainElementType.Id);

but how to get domainElementType.Id for child alternative(scenario) ?

How to find DomainElement (Customer) by Field (Label)?

I would be very grateful for the help

Parents
  • Hi Otonas,

    Data for scenario's is stored in alternatives. A scenario is basically a fixed set of alternatives (active topology, physical, demand, etc). For your tooling to work, you would first need to copy the demands from your DataTable to a new demand alternative. The coding for a new demand alternative can be found in the Loadbuilder example included with the progreamming guide. It uses a LoadBuildNodeResult object which was produced earlier by the loadbuilder tool, you should change the references to this object to your datatable instead. Also, in the foreach loop you should retrieve the customer watergems id based on its label (I dont have the coding for that I'm afraid, I usually only use watergems id's, but I think there should be a function/easy way to do this).

    #code#

    String alternativeName = "ExampleAlternativeName";

    int newAlternativeId = 0;
    IAlternative newAlternative = null;

    newAlternativeId = (ActiveDomainDataSet.AlternativeManager((int)AlternativeType.DemandAlternative)).Add();
    newAlternative = (IAlternative)((ActiveDomainDataSet.AlternativeManager((int)AlternativeType.DemandAlternative)).Element(newAlternativeId));
    newAlternative.Label = alternativeName;

    IDomainElementManager demandNodeManager = ActiveDomainDataSet.DomainElementManager(StandardDomainElementTypeName.IdahoDemandNode);

    ICrossElementFieldListManager crossElementDemandManager = demandNodeManager.CrossElementFieldListManager
    (StandardFieldName.DemandCollection, StandardAlternativeName.Demand, newAlternativeId, new SortContextCollection(), new FilterContextCollection());

    IEditField baseFlowField = (IEditField)(crossElementDemandManager.Field(StandardFieldName.DemandCollection_BaseFlow));
    ((IUnitizedField)baseFlowField).WorkingUnitIndex = m_result.FlowUnit;

    foreach (LoadBuildNodeResult anoderesult in m_result.NodeResults)
    {
    int aintNodeId = anoderesult.NodeID;
    if (newAlternative.Manager.DomainDataSet.Exists(aintNodeId))
    {
    int demandIndex = -1;
    foreach (LoadBuildDemandResultPair aresultLoad in anoderesult.DemandResults)
    {
    if (aresultLoad != null)
    {
    crossElementDemandManager.ActiveElementID = anoderesult.NodeID;
    demandIndex = crossElementDemandManager.Add();
    baseFlowField.SetValue(demandIndex, aresultLoad.Demand);
    }
    }
    }
    }

    #endcode#

    I've got no experience creating new scenario's and change it's alternatives, but you might give this a try (I have not checked this in Visual Studio):

    #code#

    int newscenarioid = ActiveDomainDataSet.ScenarioManager.Add();
    IScenario childscenario = (IScenario)ActiveDomainDataSet.ScenarioManager.Element(newscenarioid);
    childscenario.ParentID = 2; #assign the correct parent id to the new scenario

    childscenario.Label = "new scenario label";

    childscenario.AlternativeID((int)AlternativeType.DemandAlternative, newAlternativeId); #change the demand alternative of the scenario to the previously created alternative 

    #endcode#

  • Thank you, great ! The new Scenario and the newAlternative are created. Then I set the active scenario:

    #code

    adataset.ScenarioManager.ActiveScenarioID = newScenarioId;

    #endcode

    Note: when I open this modified model in WaterGEMS, the selected scenario is the one that was chosen earlier, not the new. Why?

    The next step is to initialize crossElementDemandManager: 

    #code

    CrossElementFieldListManager crossElementDemandManager = demandNodeManager.CrossElementFieldListManager
    (StandardFieldName.DemandCollection, StandardAlternativeName.Demand, newAlternativeId, new SortContextCollection(), new FilterContextCollection());

    IEditField baseFlowField = (IEditField)(crossElementDemandManager.Field(StandardFieldName.DemandCollection_BaseFlow));

    #endcode

    OK. The next line is unclear to me whether this is nessesary in my case . What is WorkingUnitIndex ?

    #code

    ((IUnitizedField)baseFlowField).WorkingUnitIndex = m_result.FlowUnit;

    #endcode

    The main problem is when I try to set a Demand for a customer:

    #code

    int aintNodeId = anoderesult.NodeID; // what is this Id in my case? CustomerId ?

    int aintNodeId = 118099; //for example

    if (newAlternative.Manager.DomainDataSet.Exists(aintNodeId)) //returns true
    {
    int demandIndex = -1;

    crossElementDemandManager.ActiveElementID = aintNodeId;
    demandIndex = crossElementDemandManager.Add(); }

    #endcode

    I'm getting an error: System.ArgumentException: 'Value does not fall within the expected range.'

  • For some reason the inheritance for the patterns and the Associated Elements does not happen. In a new alternative the Pattern is set to Fixed, and the Associated Element is empty

  • Try commenting this line out (I know I said it was important, but it might be interfering in this case):

    newScenario.MakeAlternativeLocal((int)AlternativeType.DemandAlternative);

    Instead, try using the MakeInherited method on newScenario (same parameter).

    Kris

  • I'm trying the MakeInherited method but anyway the new alternative doesn't inherit  the Patterns and the Associated Elements. A method needs to be developed to transfer from the Base alternative. 

  • Try this:

    if (!scLabels.Contains(yearMonth)) //if scenario with Label yearMonth doesn't exists, create the new
    {
    	int newScenarioId = domainDataSet.ScenarioManager.Add();
    
    	IScenario newScenario = (IScenario)domainDataSet.ScenarioManager.Element(newScenarioId);
    
    	// I am setting the parent of the new scenario to the Base scenario
    	newScenario.ParentID = scBaseId;
    	newScenario.Label = yearMonth;
    
    	// Now set the active scenario to the new scenario
    	domainDataSet.ScenarioManager.ActiveScenarioID = newScenario.Id;
    
    	int baseAlternativeID = 0;
    	foreach (IAlternative baseAlternative in domainDataSet.AlternativeManager((int)AlternativeType.DemandAlternative).BaseElements())
    	{
    		if (baseAlternative.Label == "Base Demand")
    		{
    			baseAlternativeID = baseAlternative.Id;
    			break;
    		}
    	}
    
    	int newAlternativeId = (domainDataSet.AlternativeManager((int)AlternativeType.DemandAlternative)).Add(baseAlternativeID);
    	IAlternative newAlternative = (IAlternative)domainDataSet.AlternativeManager((int)AlternativeType.DemandAlternative).Element(newAlternativeId);
    	newAlternative.Label = yearMonth;
    
    	newScenario.AlternativeID((int)AlternativeType.DemandAlternative, newAlternativeId);
    
    	// Make the demand alternative local so that edits are specific to this alternative (VERY important)
    	newScenario.MakeAlternativeLocal((int)AlternativeType.DemandAlternative);
    }
    

    I verified this code is working.  After the creation of the child scenario and child demand alternative, any changes made to the demand field on the customer meter will be applied only to the new demand alternative.  If you skip over any customer ids, then it will use the data from the parent.

    Here is some code that assigns a different demand and pattern to the customer meters in the model I created (which has 5 patterns and 5 customer meters):

    ISupportElementManager patternManager = domainDataSet.SupportElementManager((int)SupportElementType.IdahoPatternElementManager);
    HmIDCollection patternIDs = patternManager.ElementIDs();
    
    IDomainElementManager customerMeterManager = domainDataSet.DomainElementManager((int)DomainElementType.CustomerNodeElementManager);
    IEditField demandField = customerMeterManager.DomainElementField(StandardFieldName.Demand_BaseFlow, StandardAlternativeName.Demand) as IEditField;
    ((IUnitizedField)demandField).WorkingUnitIndex = UnitConversionManager.UnitIndex.GPM;
    IEditField patternIDField = new ReferenceField(customerMeterManager.DomainElementField(StandardFieldName.Demand_DemandPattern, StandardAlternativeName.Demand) as IEditField);
    
    HmIDCollection customerIDs = customerMeterManager.ElementIDs();
    customerIDs.ReverseInPlace();
    
    int patternIndex = 0;
    foreach (var id in customerIDs)
    {
    	int patternID = patternIDs[patternIndex];
    	demandField.SetValue(id, Convert.ToDouble(patternID));
    	patternIDField.SetValue(id, patternID);
    	++patternIndex;
    }
    
    DisposeLibrary.SafeDispose(ref customerIDs);
    

    You could modify the above code so it skips over customer ids if they match a certain criteria - like if the customer id is divisible by 2, skip over it.  Then when you open the model in WaterGEMS and edit the child alternative you'll see that those customer meters modified will have the Is Local flag checked (the "*" column) and those where you skipped the customer meter will have it unchecked and show the value from the parent.

    The first code block is using the MakeAlternativeLocal method.

    Kris

    Answer Verified By: Sushma Choure 

  • Great! It works like a charm! Thank you very much again!  It would have been impossible for me to do this without your help!

Reply Children
No Data