Professional Documents
Culture Documents
lgf
created by Vadim Kalinin on Jun 9, 2014 12:55 PM, last modified by Vadim Kalinin on Sep 11, 2015
1:36 PM
http://scn.sap.com/docs/DOC-55628
Purpose of default.lgf:
To perform calculations triggered by user data send by some input schedule or journal. It can be also launched (if
user selects the option) at the end of some standard DM chains (Copy, Move, Import, etc..).
For DM chains like DEFAULT_FORMULAS used to run scripts the default.lgf is NOT triggered.
Scope of default.lgf
When launched the default.lgf will receive scope as a combination of all members of all dimensions of data sent by
user.
Example:
Dimension: DIM1
Members: D1M1, D1M2
Dimension: DIM2
The user decided to change value in the cells marked with yellow to 2:
It means, that some extra combinations of members will be processed by default.lgf, not only changed data.
General rules:
2. Use *IS criteria in *WHEN/*ENDWHEN loop to select members for some calculations.
Sample:
*XDIM_MEMBERSET SOMEDIM=%SOMEDIM_SET%
*WHEN SOMEDIM
*WHEN SOMEDIM
*IS MEMBER1 // fixed member - condition to perform calculations in REC
*REC(...)
*ENDWHEN
3. *XDIM_FILTER can be used sometimes to narrow the scope, but the benefit of filtering against *IS is not
clear.
Example:
*XDIM_MEMBERSET ACCOUNT=%ACCOUNT_SET%
// Filter is reset, %ACCOUNT_SET% contains original scope
*WHEN ACCOUNT
*IS *
*REC(EXPRESSION=%VALUE%+2) // +2 for ACC1,ACC2,ACC3
*ENDWHEN
ACC1: 4
ACC2: 6
ACC3: 3
You also have to be on some recent SP level for *XDIM_FILTER to work correctly (read notes - search on
"XDIM_FILTER")
And store the Result in some member, then you have to write N *WHEN/*ENDWHEN loops to prevent aggregation if
more then 1 member is in scope. Without multiple loops the result will be multiplied M times, where M is number of
different members sent by input form simultaneously.
*WHEN SomeDim
*IS Member1
*REC(EXPRESSION=%VALUE%*[SomeDim].[Member2]*[SomeDim].[Member3],SomeDim=ResultMember)
*ENDWHEN
*WHEN SomeDim
*IS Member2
*REC(EXPRESSION=%VALUE%*[SomeDim].[Member1]*[SomeDim].[Member3],SomeDim=ResultMember)
*ENDWHEN
*WHEN SomeDim
*IS Member3
*REC(EXPRESSION=%VALUE%*[SomeDim].[Member1]*[SomeDim].[Member1],SomeDim=ResultMember)
*ENDWHEN
In this example the REC line can be the same for all 3 loops (%VALUE% can be replaced by direct member
reference):
*REC(EXPRESSION=[SomeDim].[Member1]*[SomeDim].[Member2]*[SomeDim].[Member3],SomeDim=ResultMember)
In some cases for simple formula like multiplication of 2 members (price * qty), but with long list of members,
LOOKUP can be used:
Then we can add for dimension SomeDim properties: MULT, RESULT and TYPE and fill it:
ID
MULT
RESULT
TYPE
Price1
Qty1
Amount1
Price
Price2
Qty2
Amount2
Price
Price3
Qty3
Amount3
Price
Price4
Qty4
Amount4
Price
Qty1
Price1
Amount1
Qty
Qty2
Price2
Amount2
Qty
Qty3
Price3
Amount3
Qty
Qty4
Price4
Amount4
Qty
*LOOKUP SameModel
*DIM M:SomeDim=SomeDim.MULT //Get member ID stored in property MULT
*DIM MEASURES=PERIODIC //The default storage type of SameModel
*ENDLOOKUP
*WHEN SomeDim.TYPE
*IS %T%
*REC(EXPRESSION=%VALUE%*LOOKUP(M),SomeDim=SomeDim.RESULT)
*ENDWHEN
*NEXT
*FOR/NEXT Loops
In general long and nested *FOR/*NEXT loops have to be avoided due to terrible performance. In most cases instead
of *FOR/NEXT loops some property can be created and used in the script code.
Sometimes it looks as a good idea to store some value in a property and to use it in calculations. Actually it's a bad
idea - you can't directly reference the property value in the expression, you have to use some %VAR% and long
*FOR/*NEXT loop. Always store values in SIGNEDDATA, may be use some dummy members.
The calculations in default.lgf use different sign conversion logic with ACCTYPE then the script run by DM package.
As a result the same script can produce different results as a default.lgf and as a script in DM package.
For default.lgf (BPC NW 10) all values read in the script scope are sign coverted based on ACCTYPE property and
the result of EXPRESSION calculation is also sign converted based on ACCTYPE property of the target account:
Example:
ID
ACCTYPE
INC
EXP
INC
default.lgf
*WHEN ACCOUNT
*IS A
*REC(EXPRESSION=%VALUE%+[ACCOUNT].[B],ACCOUNT=C)
*ENDWHEN
A: 5
B: 10
A: -5
B: 10
Calculations:
C: 15
The same script launched by DM package (BPC NW 10) will not have any sign conversions, all calculations will be
done with SGNEDDATA values:
-5 + 10 = 5
C: -5
*DESTINATION_APP
If it's required to send data to the different model the *DESTINATION_APP statement can be used in default.lgf.
Sign conversion logic is also applicable to writing data using *DESTINATION_APP.
The same rules are applicable to *WHEN/*ENDWHEN loop after the *DESTINATION_APP (by the way, in BPC NW
10 *DESTINATION_APP statement is valid only to the next *WHEN/*ENDWHEN loop, have to be repeated before
each *WHEN/*ENDWHEN sending data to other application (in BPC NW 7.5 all *WHEN/*ENDWHEN loops after
single *DESTINATION_APP will write to target cube).
If some dimension is missing in the destination model *SKIP_DIM=SomeDim have to be used. But the issue can be
in the following case:
SourceModel:
DimMissingInTarget: Member1, Member2, ..., MemberN (base) - having root parent All
SomeDim: Mem1, Mem2, ... - dimension in both Source and Target
TargetModel:
SomeDim: Mem1, Mem2, ... - dimension in both Source and Target
If some of Member1, Member2, ..., MemberN is changed in SourceModel the result of All have to be transferred to
TargetModel
*DESTINATION_APP=TargetModel
*SKIP_DIM=DimMissingInTarget
*WHEN DimMissingInTarget
*IS %M%
*WHEN SomeDim //SomeDim - dimension existing both in Source and Target
*IS Mem1,Mem2,... //some list of members of SomeDim changed by user and to be transferred to
TargetModel
*REC(EXPRESSION=[DimMissingInTarget].[All]) //Parent All value is used!
*ENDWHEN
*ENDWHEN
*NEXT
Another option for this particular case is to explicitely scope the scipped dimension with *XDIM_MEMBERSET:
*XDIM_MEMBERSET DimMissingInTarget=<ALL>
*DESTINATION_APP=TargetModel
*SKIP_DIM=DimMissingInTarget
But in this case you have to put this code at the end of the default.lgf or restore original scope for
DimMissingInTarget:
It's also possible to call Custom Logic BADI in default.lgf to perform some calculations that are not easy or even not
possible to implement using script logic. The badi have to work with the current scope and can contain some fixed
parameters.
Example:
*START_BADI SOMEBADI
QUERY=ON //to get records from the current scope
WRITE=ON //to use default write to cube
DEBUG=OFF
SOMEPARAM=SOMEFIXEDVALUE
...
*END_BADI // Script scope will be reset to initial script scope here if changed before
...
RUNLOGIC_PH BADI
It's also possible to use RUNLOGIC_PH BADI (How To Implement the RUNLOGIC_PH Keyword in SAP... | SCN)
to speed up some calculations using CHANGED parameter. For example - single change of price have to recalculate
values in multiple entities and multiple time periods.
*START_BADI RUNLOGIC_PH
QUERY=OFF
WRITE=ON
LOGIC = CALLED_LOGIC.LGF
APPSET = SameEnvironment
APP = SameModel
DIMENSION ENTITY=BAS(ALLENTITIES)
DIMENSION SomeDim=%Somedim_SET% //script initial scope
...
CHANGED=ENTITY
The same functionality can be achieved by Write Back BADI - perform calculations triggered by user input. The
details are described here: Calculations in Write Back BADI - Default.lgf R... | SCN
The significant difference between Write Back BADI and default.lgf is that Write Back BADI will receive data sent by
user before it's stored in the cube and only sent values will be processed.
B.R. Vadim
Benjamin Tan
We have a situation where we want to do some calculations for selective time periods based on
Category. A property of Category STARTMONTH contains the value "001","002" etc, to indicate the
starting period. An example below shows if the STARTMONTH is "003", then All months from March will
be copied from Source Accounts to Target accounts; likewise, if STARTMONTH is "005", then all months
from May will be copied over. If executed through DM, the selections of period can be passed on. But
for default logic, is there a way to dynamically scope the time periods?
Thanks in advance,
Ben
Ans:
But what a strange idea to perform copy of months in default.lgf?? Default.lgf works with data sent by user. If user
sent some value what do you want to do?
Vadim