Blogs about Jazz

Blogs > Jazz Team Blog >

Under the hood: Detect budget to cost estimation discrepancies using Rational Engineering Lifecycle Manager

Tags: ,

Part 3b of “Using Rational Engineering Lifecycle Manager to answer hard Systems Engineering questions” blog series

Preamble: Our users have been asking us for more practical examples about how to unleash the power of linked lifecycle data in Rational Engineering Lifecycle Manager (RELM), so we have decided to kick off a blog series on the Jazz Team Blog to answer some of your most pressing questions! All of the examples that we will be providing in this blog series were created with problems IBM System Engineering domain users encounter, so many SSE customers will find these examples very relevant to their own process, and will be able to easily adapt the proposed solutions to their own needs. In previous blogs and postings related to RELM, members of our team explained the conceptual value of linked data, as well as provided overview of the Systems & Software Engineering (SSE) solution along with deployment tips, so you may want to start there if you are new to RELM and SSE.

Creating a RELM view: Cost violations

The goal of this exercise is to create a couple of RELM views which highlight estimations that surpass budget. The views will show requirements and the tasks which implement the requirements, where the sum of the estimation on the tasks exceed the allowed budget of the requirement.

For more background info on this, please check out the parent posting “Detect budget to cost estimation discrepancies using Rational Engineering Lifecycle Manager“.

The scenario we chose for this session is a bit advanced. It includes retrieving data from custom fields called Requirement and Change Request.  It uses aggregate functions in the query. In this session I also plan to show how to customize the UI types used in the view to display any information you like.

The first of the two views we build is My Cost Violations. It considers those tasks that are assigned to me and are considered a cost violation.

In this example, the logged in user has one task assigned which has an estimation of $3000. There is a requirement that specifies a budget of $6000. The requirement is implemented by 3 tasks. The combined estimation of the tasks is $10000, which is well over the budget. In this case, even though the task assigned to this user alone is below the budget amount, together they are over the budget and contribute to a cost violation.

We will start with a blank view in RELM and add couple of containers, a container for each type of element we want to display. We will use the Container – Grid Layout type container, as we want a simple list of nodes as opposed to a collapsible list. For collapsible list, use Container – Tree Layout. We will change Number of Columns for the container to 1, so that we get the nodes stacked in a single column as seen in the picture above.

After adding the first container and a Text title to the View, it should look like the screen below.

The container requires a query. Here we want to create a query that will give us a list of requirements that incur cost violations with one or more of the tasks assigned to the current user. Since we cannot hardcode it to any single user, we want to use that as a parameter to the query. We want to use the parameter of type Current User.

Now, here is the query.

PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rm: <http://open-services.net/ns/rm#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rtc_custom: <http://jazz.net/xmlns/prod/jazz/rtc/ext/1.0/>

SELECT ?resource  ?title ?shortTitle ?type ?BudgetAmount
WHERE {
	{
		SELECT ?resource ?title ?type (?req_estimation AS ?BudgetAmount)
		 (SUM(?cr_estimation) AS ?TotalEstimation)
    		WHERE {
			?resource
				dcterms:title ?title ;
		               	a ?type;
				?custom_estimation_field ?req_estimation_0 ;
				rm:implementedBy ?changeRequest .

			?custom_estimation_field
				rdfs:label "Cost Estimation" .

			OPTIONAL {
			?changeRequest
				rtc_custom:CostEstimation2 ?cr_estimation_0 .
			}

			{
				SELECT ?resource
				WHERE {
					?resource
						rm:implementedBy ?cr.

        	   				?cr
						dcterms:contributor <$currUser.uri$> .
				}
			}

			BIND (if( !bound(?req_estimation_0), 0, ?req_estimation_0) AS ?req_estimation)
			BIND (if( !bound(?cr_estimation_0), 0, ?cr_estimation_0) AS ?cr_estimation)

			FILTER (?type = rm:Requirement)

	    	}
		GROUP BY ?resource ?title ?type ?req_estimation
	}

	BIND( SUBSTR(str(?title), 1, 50) AS ?shortTitle )

	FILTER (?BudgetAmount < ?TotalEstimation)
}

Notice <$currUser.uri$> in the query. This will get replaced with the URI of the current user.

“Cost Estimation” is not part of “Requirement” or “Change Request”, out of the box. So, for our data, we added custom fields to both Requirement and Change Request. As you can see in the query, I am looking for a field with label “Cost Estimation” on “Requirement”. On “Change Request”, I am looking for a predicate <http://jazz.net/xmlns/prod/jazz/rtc/ext/1.0/CostEstimation2>, as specified during the creation of that custom field.

Add a query to the view and select the query for our container. This should display any matching requirement in the view. If you hover on the node, you will get the OSLC preview.

Note: In the parent blog, we talked about the sample data we are using for these exercises. Needless to say, the output you see here are from that data on our server.

Now add another container to the View for Tasks and use the following query.

PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rm: <http://open-services.net/ns/rm#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rtc_custom: <http://jazz.net/xmlns/prod/jazz/rtc/ext/1.0/>

SELECT ?resource  ?title ?shortTitle ?type ?EstimationAmount ?highlight
WHERE {
	?requirement_url
		rm:implementedBy ?resource .

	?resource
		dcterms:title ?title ;
	      	a ?type.

	OPTIONAL{
	?resource
		rtc_custom:CostEstimation2 ?cr_estimation_1 .
	}

	OPTIONAL{
	?resource
		dcterms:contributor <$currUser.uri$> ;
		dcterms:contributor ?assigned_to_me .
	}

	BIND (if( !bound(?cr_estimation_1), 0, ?cr_estimation_1) AS ?EstimationAmount)
	BIND (if( bound(?assigned_to_me), "yes", "no") AS ?highlight)

    {
    SELECT ?requirement_url
    WHERE {
	{
		SELECT ?requirement_url (?req_estimation AS ?BudgetAmount)
		 (SUM(?cr_estimation) AS ?TotalEstimation)
    		WHERE {
			?requirement_url
		               	a rm:Requirement;
				?custom_estimation_field ?req_estimation_0 ;
				rm:implementedBy ?changeRequest .

			?custom_estimation_field
				rdfs:label "Cost Estimation" .

			OPTIONAL {
			?changeRequest
				rtc_custom:CostEstimation2 ?cr_estimation_0 .
			}

			{
				SELECT ?requirement_url
				WHERE {
					?requirement_url
						rm:implementedBy ?cr.

					?cr
						dcterms:contributor <$currUser.uri$> .
				}
			}

			BIND (if( !bound(?req_estimation_0), 0, ?req_estimation_0) AS ?req_estimation)
			BIND (if( !bound(?cr_estimation_0), 0, ?cr_estimation_0) AS ?cr_estimation)
	    	}
	    	GROUP BY ?requirement_url ?req_estimation
	}

	FILTER (?BudgetAmount < ?TotalEstimation)
    }
    }
    BIND( SUBSTR(str(?title), 1, 50) AS ?shortTitle )

}

As you might have noticed, I was lazy to write this query from scratch. So I took the query used in the previous container and put that inside as a sub query. In the outer part of the query, I am finding the tasks which implement those requirements. This query works, however it can certainly be improved for performance.

Notice that, in the query, I am setting a property called ‘highlight’ to ‘yes’ if the task is assigned to the current user. We will see that in use shortly.

The link used between “Requirement” and “Task” is “ImplimentedBy”. Add it from the Connections section of page properties. The view should look like this one now.

In this view, it will be useful to show the budget amount for “Requirement” and the estimated amount for “Tasks”. To do that you can customize the UI types in use.

There is an out of the box UI type named “requirementNode”. Let’s make a duplicate of that and call it “requirementNodeWithBudget”.

Add a ‘Text” under Shapes to display static text, “Budget ($)”

Change the height of UI type to “45” so that the text we added will be visible. The preview may not get updated immediately when you make changes to the attributes. If you exit out of this window and open it again, it will be refreshed.

Next, we want to display the amount, which is not static text, but a property returned by the query. So, I added a property called “amount” with value ${BudgetAmout}, which is a property returned by the query. Then, I added a text shape to display the amount in the UI.

The UI type is all set to display the budget amount. Now all that we have to do is use this new UI type in the node that is in use.

With that the view looks like this.

Similarly I added another UI type and used that for change request.

What is missing now is that there is no indication about which tasks are assigned to the current user. Recall in our query, we have a property called “highlight” and we set its value to yes/no based on whether it is assigned to current user or not. Now, let’s create two node types and call them “HighlightedArtifact” and “NormalArtifact”. Add a condition for the nodes and use the same property from the query.

Also, set an appropriate fill color.

At this point the view should look like this.

Look and Feel

RELM allows you to use different types of nodes and UI types in your view. Basically, with UI type you can define the shape you want to display and specify what text to appear where. A node uses a UI type. Node allows you to specify a condition that determines when the node will be used in the view, among other things.

As you saw earlier in the article, “HighlightedArtifact” and “NormalArtifiact” are two examples of Nodes. The property/value combination we specified there determines when those nodes will be used in the view.

You can override many of the settings in the node that you inherit from the UI type.

In the screen below, I changed the width and height to 200 and 50 respectively. Then I changed the fill property as seen in the inset. That gives a red gradient box for “HighlightedArtifiact”.

In this same way, I updated other nodes in the view to get the final look and feel.

That completes the first of the two views we wanted to build.

The next view we want to build is “Cost Violations (by user name)”. For this view, instead of checking for cost violations for logged in user, we want to check for any user by their user name.

The only main difference between this view and the previous view we built is the parameter to the view. So, as a first step, let’s duplicate the view.

Then rename the view and change the parameter.

Notice the type is set to default, and I provided a text value ‘Pete’, one of the users in the system.

Since the parameter is now a simple text value containing the user name, I need to make slight change in my queries.

Query for the requirements is:

PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rm: <http://open-services.net/ns/rm#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rtc_custom: <http://jazz.net/xmlns/prod/jazz/rtc/ext/1.0/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

SELECT ?resource  ?title ?shortTitle ?type ?BudgetAmount
WHERE {
	{
		SELECT ?resource ?title ?type (?req_estimation AS ?BudgetAmount)
		 (SUM(?cr_estimation) AS ?TotalEstimation)
    		WHERE {
			?resource
				dcterms:title ?title ;
		               	a ?type;
				?custom_estimation_field ?req_estimation_0 ;
				rm:implementedBy ?changeRequest .

			?custom_estimation_field
				rdfs:label "Cost Estimation" .

			OPTIONAL {
			?changeRequest
				rtc_custom:CostEstimation2 ?cr_estimation_0 .
			}

			{
				SELECT ?resource
				WHERE {
					?resource
						rm:implementedBy ?cr.

        	   				?cr
						dcterms:contributor ?contributor .

        	   				?contributor
						foaf:name "${currUser}" .				}
			}

			BIND (if( !bound(?req_estimation_0), 0, ?req_estimation_0) AS ?req_estimation)
			BIND (if( !bound(?cr_estimation_0), 0, ?cr_estimation_0) AS ?cr_estimation)

			FILTER (?type = rm:Requirement)

	    	}
		GROUP BY ?resource ?title ?type ?req_estimation
	}

	BIND( SUBSTR(str(?title), 1, 50) AS ?shortTitle )

	FILTER (?BudgetAmount < ?TotalEstimation)
}

And query for the tasks is:

PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rm: <http://open-services.net/ns/rm#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rtc_custom: <http://jazz.net/xmlns/prod/jazz/rtc/ext/1.0/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

SELECT ?resource  ?title ?shortTitle ?type ?EstimationAmount ?highlight
WHERE {
	?requirement_url
		rm:implementedBy ?resource .

	?resource
		dcterms:title ?title ;
	      	a ?type.

	OPTIONAL{
	?resource
		rtc_custom:CostEstimation2 ?cr_estimation_1 .
	}

	OPTIONAL{
	?resource
		dcterms:contributor ?contributor ;
		dcterms:contributor ?assigned_to_me .

	?contributor
		foaf:name "${currUser}" .
	}

	BIND (if( !bound(?cr_estimation_1), 0, ?cr_estimation_1) AS ?EstimationAmount)
	BIND (if( bound(?assigned_to_me), "yes", "no") AS ?highlight)

    {
    SELECT ?requirement_url
    WHERE {
	{
		SELECT ?requirement_url (?req_estimation AS ?BudgetAmount)
		 (SUM(?cr_estimation) AS ?TotalEstimation)
    		WHERE {
			?requirement_url
		               	a rm:Requirement;
				?custom_estimation_field ?req_estimation_0 ;
				rm:implementedBy ?changeRequest .

			?custom_estimation_field
				rdfs:label "Cost Estimation" .

			OPTIONAL {
			?changeRequest
				rtc_custom:CostEstimation2 ?cr_estimation_0 .
			}

			{
				SELECT ?requirement_url
				WHERE {
					?requirement_url
						rm:implementedBy ?cr.

					?cr
						dcterms:contributor ?contributor .

					?contributor
						foaf:name "${currUser}" .
				}
			}

			BIND (if( !bound(?req_estimation_0), 0, ?req_estimation_0) AS ?req_estimation)
			BIND (if( !bound(?cr_estimation_0), 0, ?cr_estimation_0) AS ?cr_estimation)
	    	}
	    	GROUP BY ?requirement_url ?req_estimation
	}

	FILTER (?BudgetAmount < ?TotalEstimation)
    }
    }
    BIND( SUBSTR(str(?title), 1, 50) AS ?shortTitle )

}

That’s all. With those changes, the view should be like this.

Conclusion

In this session we created couple of RELM views to highlight situations where estimations surpass the planned budget. The first one showed “My Cost Violations”, showing cost violations for the current user. The second view was a slight variation of the first one, which shows cost violations for any given user.

In this exercise you also saw how to use UI types and nodes to show any details in your view in any way you choose.

Ubaidu Peediakkal
Systems and Software Engineering (SSE) Solution Architect