Personal tools
You are here: Home Community Help Center Reference Manuals RiskAnalytics Developer's Guide Components

Components

Note: Return to reference manual view.

WORK IN PROGRESS: IT technical issue to develop components and models.

1. Conventions

Conventions make a developers life easier by reducing the amount of code to be written and increasing the readableness. In RiskAnalytics conventions are used to generate the user interface and database schema.

1.1. Naming convention

Beside clean code and higher readableness naming convention, increase coding speed in modern IDE (integrated development environment) as code completion is supported.

A component may have several properties. There exist four prefixes to be used:

  • parm: whenever a variable name starts with parm. It is displayed on the parameterization user interface automatically.
  • in: all in variables of type PacketList receive packets from other components
  • out: all out variables of type PacketList send packets to other components. It is displayed on the result template user interface and optionally on the result page automatically.
  • sub: a component may have sub components. Their name has to start with sub.

Remark: If a component is written in Java, variables starting with any of these prefixes need a public setter and getter method.

1.2. Grouping of Components and Parameters in the GUI

The order in which you write the parameters, out channels and sub components in a component determines the order in the GUI.

RiskAnalytics comes with a powerful way of deriving a default user interface for all models, components and its parameters - a model or component developer does not have to write any GUI code. Yet he can group the parameters.

The order in which subcomponents, parameters and out channels in a component are displayed is the order in which they appear in the corresponding code.

Example of a Model and its Visualization in the Parameter View

class PodraModel extends Model {
    DynamicUnderwritingSegments underwriting
    DynamicClaimsGenerators claimsGenerators
    DynamicDependencies correlations
    DynamicMultipleDependencies eventCorrelations
    DynamicConfigurableLobs linesOfBusiness
    MultiLineDynamicReinsuranceProgram reinsuranceProgram
...
}

 Component Order

 

 

2. Component

Basics explained using an example.

Advice

Try to keep components simple; a component should do one thing and not many things. This makes it easier to test it and it also increases the chances that such a components can be re-used.

If we think of a model as a directed graph, components are the nodes in such a graph. The edges are wired out and in properties.

Concept

The method doCalculation is executed once only per iteration and period. No loops are possible for a component.

Execution is triggered by the framework: If all wired in channels have received their information doCalculation is executed. Afterwards the packets prepared in the out channels is sent to following components.

Step by step example

We create a component providing a premium value to other components. The premium will be the product of number of policies and the price per policy parameter.

  1. Create a new Groovy or Java class in the corresponding package. (Line 1, 5)
    (Domain classes can be found in src/groovy/org/pillarone/modelling/domain)
  2. The class has to extend org.pillarone.riskanalytics.core.components.Component (Line 2, 5)
  3. The class has two parameters parmNumberOfPolicy and parmPricePerPolicy (Line 6, 7) The order in which the parameters are defined is also the order how they will be displayed in the UI. If parameters are inherited from superclasses, the parameters of the superclass are displayed first.
  4. The class has an output channel outPremium (Line 8) in order to send premium information to other components.
  5. Premium has to be calculated (Line 10), wrapped in a packet and added to the output channel (Line 11)
 1: package org.pillarone.modelling.domain.underwriting

 2: import org.pillarone.modelling.components.Component
 3: import org.pillarone.modelling.packets.PacketList
 4: import org.pillarone.modelling.packets.Premium
 
 5: class PremiumCalculation extends Component {

 6:   double parmNumberOfPolicy
 7:   double parmPricePerPolicy

 8:   PacketList<Premium> outPremium = new PacketList(Premium)

 9:   void doCalculation() {
10:       double premium = parmNumberOfPolicy * parmPricePerPolicy
11:       outPremium << new Premium(value: premium)
12:     }
13: }

Let's say we want another component providing index information which influences the price per policy. In order to cover this use case we write a component with extended functionality:

  1. Add an additional input channel inIndex (Line 5)
  2. Adjust the premium calculation: build the product of all received indices (Line 8 - 10) and adjust the price per policy accordingly (Line 11)

 

 1: package org.pillarone.modelling.domain.underwriting

 2: import org.pillarone.modelling.packets.PacketList
 3: import org.pillarone.modelling.packets.Index
 
 4: class PremiumCalculationWithIndex extends PremiumCalculation {

 5:   PacketList<Index> inIndex = new PacketList(Index)

 6:   void doCalculation() {
 7:       double level = 1.0
 8:       for (Index idx in inIndex) {
 9:           level *= idx.value
10:       }
11:       double pricePerPolicy = parmPricePerPolicy * level
12:       double premium = parmNumberOfPolicy * pricePerPolicy
13:       outPremium << new Premium(value: premium)
14:     }
15: } 

For the sake of completeness the following listings contain the Index and Premium classes:

 1: package org.pillarone.modelling.packets
 
 2: class Premium extends Packet {
 3:   double value
 4: }


 1: package org.pillarone.modelling.packets
 
 2: class Index extends Packet {
 3:   double value
 4: }

3. Composed Component

To avoid modelers always starting from scratch, the concept of composed components allows to define building blocks containing several components. Typical building blocks may be lines of business, reinsurance program, ... Somehow a composed component is very similar to a model but can't be executed.

Step by step example

We create a component composed of a frequency and claims size generator.

  1. Create a new Groovy class in the corresponding package (Line 1, 2).
    (Domain classes can be found in src/groovy/org/pillarone/modelling/domain)
    Remark: Composed components have to be defined in a Groovy class as wiring would not work with a Java class in the current implementation.
  2. The class has to extend org.pillarone.riskanalytics.core.components.ComposedComponent (Line 2)
  3. The class has two sub components subFrequencyGenerator and subClaimsGenerator. Make sure all sub components name start with sub! If you forget to add sub, they won't be displayed in any of the user interfaces. (Line 3, 4)
  4. The class has an output channel outClaims (Line 5) in order to send claims to other components such as claims development or reinsurance contracts.
  5. Sub components have to be instantiated in the constructor and not in the declaration! (Line 7, 8)
  6. As this composed component doesn't have any in channels, we have to define which component is executed first in doCalculation() (Line 11).
    Remark: As composed components contain no additional business logic, it is not necessary to implement doCalculation() always as this is the case for components.
  7. Each composed component has to implement the abstract wire() method. Wiring between the sub components is done similar to the wiring in models. (Line 14-16). As sub components are nested we have to make sure that the information required outside the composed component is replicated. This is done with the so called PortReplicatorCategory (Line 17-19).
    Remark: Using the PortReplicatorCategory the properties on the left and right side have to be either in or out properties, whereas for WireCategory the left side property has to be an in and the right side an out property.
 1: package org.pillarone.modelling.domain.generators.claims

    ...

 2: class FrequencyClaimsGenerator extends ComposedComponent {

 3:    FrequencyGenerator subFrequencyGenerator
 4:    SingleClaimsGenerator subClaimsGenerator

 5:    PacketList<Claim> outClaims = new PacketList(Claim)

 6:    FrequencyClaimsGenerator() {
 7:       subFrequencyGenerator = new FrequencyGenerator()
 8:       subClaimsGenerator = new SingleClaimsGenerator()
 9:    }

10:    public void doCalculation() {
11:       subFrequencyGenerator.start()
12:    }

13:    public void wire() {
14:        WiringUtils.use(WireCategory) {
15:            subClaimsGenerator.inClaimCount = subFrequencyGenerator.outFrequency
16:        }
17:        WiringUtils.use(PortReplicatorCategory) {
18:            this.outClaims = subClaimsGenerator.outClaims
19:        }
20:    }
21: }

Calibration of the frequency and claims generator can be done proportional to the number of policies or the premium written. In order to enable this possibility in the composed component too and additional input channel is required.

  1. The class has an input channel inUnderwritingInfo (Line 3)
  2. If an input channel is wired, the default behaviour can be used by omitting doCalculation() at all or calling super.doCalculation() (Line 13). In this example omitting the method doCalculation() is not recommended as it is not possible to assure that inUnderwritingInfo is connected in all use cases.
    Remark: As it is not mandatory to wire all channels, the method isReceiverWired(inUnderwritingInfo) (Line 12) is implement in Component and returns true if any out channel is connected to inUnderwritingInfo.
  3. Finally it is necessary to provide the underwriting information to the frequency and claims generator using the closure PortReplicatorCategory to wire them.
 1: package org.pillarone.modelling.domain.generators.claims

    ...

 2: class FrequencyClaimsGenerator extends ComposedComponent {

 3:    PacketList<UnderwritingInfo> inUnderwritingInfo = new PacketList(UnderwritingInfo)

 4:    FrequencyGenerator subFrequencyGenerator
 5:    SingleClaimsGenerator subClaimsGenerator

 6:    PacketList<Claim> outClaims = new PacketList(Claim)

 7:    FrequencyClaimsGenerator() {
 8:       subFrequencyGenerator = new FrequencyGenerator()
 9:       subClaimsGenerator = new SingleClaimsGenerator()
10:    }

11:    public void doCalculation() {
12:        if (isReceiverWired(inUnderwritingInfo)) {
13:            super.doCalculation()
14:        } else {
15:            subFrequencyGenerator.start()
16:        }
17:    }

18:    public void wire() {
19:        WiringUtils.use(WireCategory) {
20:            subClaimsGenerator.inClaimCount = subFrequencyGenerator.outFrequency
21:        }
22:        WiringUtils.use(PortReplicatorCategory) {
23:            this.outClaims = subClaimsGenerator.outClaims
24:        }
25:        if (isReceiverWired(inUnderwritingInfo)) {
26:            WiringUtils.use(PortReplicatorCategory) {
27:                subFrequencyGenerator.inUnderwritingInfo = this.inUnderwritingInfo
28:                subClaimsGenerator.inUnderwritingInfo = this.inUnderwritingInfo
29:            }
30:        }
31:    }
32: }

4. Dynamically Composed Component

Composed components consisting of a flexible number of subcomponents, all of which must be of the same type. The number of subcomponents is defined with the parameterization. According the available records in a database the same number of subcomponents are instantiated.

Concept

  • A dynamic composed component is similar to a composed component in the sense that it contains components and different in the sense that it contains a flexible number of a component of a specific type. The type of these component has to be defined in the function
    abstract Component getDefaultSubComponent()
  • Currently all sub components have the same generic name.
  • The wire() and doCalculation() methods follow exactly the same concepts as for a composed component.
  • The abstract class DynamicComposedComponent handles adding, removing, naming and other checks for all derived class. The components are administered using a list of component called componentList.
  • This concepts enables a data driven modelling. The PODRA modell actually contains six void containers (underwriting, claims generators, correlations, event correlations, lines of business and reinsurance program). As the wiring itself is fix such models typically include several filter components for allocation.
    The drawback of such models are the lower performance and the higher risk of parameterization errors.

Step by step example

We create a dynamically composed component containing reinsurance contracts.

  1. Create a new Groovy class in the corresponding package (Line 1, 2).
    (Domain classes can be found in src/groovy/org/pillarone/modelling/domain)
    Composed components have to be defined in a Groovy class as wiring would not work with a Java class in the current implementation.
  2. The class has to extend org.pillarone.riskanalytics.core.components.DynamicComposedComponent (Line 2)
  3. The DynamicReinsuranceProgram has an arbitrary number of ReinsuranceContract. Their default instantiation is defined in getDefaultSubComponent(). The method is called whenever an application user right clicks on the reinsurance program and adds a new contract.
  4. Finally it is necessary to define the default name (Line 12-14).
 1: package org.pillarone.modelling.domain.reinsurance.programs

    ...

 2: class DynamicReinsuranceProgram extends DynamicComposedComponent {

    ...

 3:   public ReinsuranceContract getDefaultSubComponent() {
 4:       ReinsuranceContract newContract = new ReinsuranceContract(
 5:           parmInuringPriority: 0,
 6:           parmContractStrategy: 
 7:               ReinsuranceContractStrategyFactory.getContractStrategy(
 8:                   ReinsuranceContractType.TRIVIAL, [:]))
 9:       newContract.name = getName(newContract)
10:       return newContract
11:   }

12:   protected String getDynamicComponentName() {
13:       "contract"
14:   }

       ...

The wire() method of the DynamicReinsuranceProgram looks rather complicated. The complexity is related with the fact, that the inuring priority parameter of the contracts allows the application user to define any order of the contracts. Furthermore merger components are required to make sure contracts get the correct net information if several contracts have the same inuring priority. The complexity is not related to the concept of dynamic composed components.

5. Multiple Calculation Phases

Whenever a reallocation is needed it is unavoidable to have loops in a model graph. There are specific composed components containing components being executed in different phases.

The concept and implementation is relatively new. The API is not yet stable. The current implementation allows to phases. It is used to reallocate ceded and net claims and underwriting information to lines of business in order to display resulting gross, ceded and net figures in one place.

 

Example implementation is ConfigurableLob.

 

  • org.pillarone.riskanalytics.core.components.MultipleCalculationPhaseComposedComponent
  • org.pillarone.riskanalytics.core.components.MultiPhaseDynamicComposedComponent

6. Testing

Verify that the component yields correct results.

In order to verify that a component yields correct results, you need to have reference implementation that does the same calculation. The parameters used as input and the output from the reference calculation are then used in a test case.

 

Step by step example

 

 also include executing the test case

Document Actions