singleMember adds a single member from the supplied dimension to the calculation shape.
singleMember(Dimension d, String mbr).
Consider the following example:
"Beginning Inventory Units" = "Ending Inventory Units"[previous(Manufacturing)] Required[level(Week)] = if(isNull("Schedule Required"), "MRP Receipts"[lead(Manufacturing, ComponentMetrics.leadTime / 7)], "Schedule Required") "Demand Units Avg"[level(Week)] = avg("Demand Units"[sibling(Manufacturing)])
In this example:
The shape functions, previous, level, lead, and sibling:
Are used with a location operator, and share some commonality in their signature and implementation
Return a Dimension instance that tells the location operator on which dimension to qualify
Are evaluated at compile-time and at runtime.
"MRP Receipts"[lead(Manufacturing, ComponentMetrics.leadTime / 7)] calculates the lead time value only at runtime. Even though the lead time value is not know until runtime, it is crucial to know the cell locations on with the measure Required is based so that Integrated Operational Planning can calculate MRP Recipts before calculating Required.
The following shape function example calculates the leaf-level members of a dimension. Returning the dimension at the end of the call is used to generate the location collections.
The following example shows how to handle parameters whose values are not determined at compile time.
public static Dimension leaves(Dimension d) throws ISException { VariableShape varShape = ctx.getVariableShape(); CalcOdometer denseShape = varShape.getDenseShape(); Slice sparseShape = varShape.getSparseShape(); DimensionType dtype = d.getType(); if (dtype.equals(DimensionType.SPARSE)) { if (sparseShape == null) throw new ISException("populating for sparse dimension, "+d.getName()+ " is not allowed"); MemberSet mset = sparseShape.locate(d); Iterator mbrs = d.getMemberAccessor().getMemberIterator(); while (mbrs.hasNext()) { Member m = (Member)mbrs.next(); if (!d.hasDependents(m)) { mset.add(m); } } } else { Iterator mbrs = d.getMemberAccessor().getMemberIterator(); while (mbrs.hasNext()) { Member m = (Member)mbrs.next(); if (!d.hasDependents(m)) { denseShape.addMember(m); } } } return d; } public static Dimension lead(Hierarchy h, double leadBy) throws ISException { Location current = ctx.getVariableShape().getCurrentLocation(); int offset = (int)Math.round(leadBy); Member [] mbrs = current.getMembers(); Dimension d = h.getDimension(); int idx = Location.getDimIndex(mbrs, d); Member startMbr = mbrs[idx]; HierarchyNode node = h.getHierarchyNode(startMbr); Level[] levels = h.getLevels(); int levelIndex = node.getLevel(); long numOfMembersAtLowerLevels = 0; for (int i = levels.length-1; i > levelIndex; i--) { numOfMembersAtLowerLevels += levels[i].getMemberCount(); } long membersAtThisLevel = levels[levelIndex].getMemberCount(); MemberSet sparseMemberSet = null; CalcOdometer denseShape = null; Member offsetMember = null; if (d.getType().equals(DimensionType.SPARSE)) { Slice sparseShape = ctx.getVariableShape().getSparseShape(); sparseMemberSet = sparseShape.locate(d); } else { denseShape = ctx.getVariableShape().getDenseShape(); } if (ctx.isAtCompileTime() && ctx.hasDynamicParameters()) { long lowerBound = numOfMembersAtLowerLevels; long upperBound = numOfMembersAtLowerLevels + membersAtThisLevel - 1; long currentDepID = startMbr.getDependencyID(); if (goForward) { for (long k = currentDepID; k <= upperBound; k++) { offsetMember = d.findMemberByDependencyID(k); if (offsetMember != null) { if (sparseMemberSet != null) sparseMemberSet.add(offsetMember); else if (denseShape != null) denseShape.addMember(offsetMember); } } } else { for (long k = lowerBound; k <= currentDepID; k++) { offsetMember = d.findMemberByDependencyID(k); if (offsetMember != null) { if (sparseMemberSet != null) sparseMemberSet.add(offsetMember); else if (denseShape != null) denseShape.addMember(offsetMember); } } } return d; } if (offset == 0) { offsetMember = startMbr; } else { long dependentID = startMbr.getDependencyID()+offset; boolean isvalid = true; if (dependentID < numOfMembersAtLowerLevels) { dependentID = numOfMembersAtLowerLevels; isvalid = false; } else if (dependentID >= numOfMembersAtLowerLevels + membersAtThisLevel) { dependentID = numOfMembersAtLowerLevels + membersAtThisLevel - 1; isvalid = false; } if (isvalid) offsetMember = d.findMemberByDependencyID(dependentID); } if (offsetMember != null) { if (sparseMemberSet != null) sparseMemberSet.add(offsetMember); else if (denseShape != null) denseShape.addMember(offsetMember); } return d; }