All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opengamma.strata.calc.runner.CalculationTasks Maven / Gradle / Ivy

/*
 * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.strata.calc.runner;

import static com.opengamma.strata.collect.Guavate.toImmutableList;

import java.lang.invoke.MethodHandles;
import java.util.List;

import org.joda.beans.ImmutableBean;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaBean;
import org.joda.beans.TypedMetaBean;
import org.joda.beans.gen.BeanDefinition;
import org.joda.beans.gen.PropertyDefinition;
import org.joda.beans.impl.light.LightMetaBean;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import com.opengamma.strata.basics.CalculationTarget;
import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.basics.ResolvableCalculationTarget;
import com.opengamma.strata.calc.CalculationRules;
import com.opengamma.strata.calc.CalculationRunner;
import com.opengamma.strata.calc.Column;
import com.opengamma.strata.calc.Measure;
import com.opengamma.strata.calc.ReportingCurrency;
import com.opengamma.strata.calc.marketdata.MarketDataRequirements;
import com.opengamma.strata.calc.marketdata.MarketDataRequirementsBuilder;
import com.opengamma.strata.collect.Messages;

/**
 * The tasks that will be used to perform the calculations.
 * 

* This captures the targets, columns and tasks that define the result grid. * Each task can be executed to produce the result. Applications will typically * use {@link CalculationRunner} or {@link CalculationTaskRunner} to execute the tasks. */ @BeanDefinition(style = "light") public final class CalculationTasks implements ImmutableBean { /** * The targets that calculations will be performed on. *

* The result of the calculations will be a grid where each row is taken from this list. */ @PropertyDefinition(validate = "notEmpty") private final List targets; /** * The columns that will be calculated. *

* The result of the calculations will be a grid where each column is taken from this list. */ @PropertyDefinition(validate = "notEmpty") private final List columns; /** * The tasks that perform the individual calculations. *

* The results can be visualized as a grid, with a row for each target and a column for each measure. * Each task can calculate the result for one or more cells in the grid. */ @PropertyDefinition(validate = "notEmpty") private final List tasks; //------------------------------------------------------------------------- /** * Obtains an instance from a set of targets, columns and rules. *

* The targets will typically be trades. * The columns represent the measures to calculate. *

* Any target that implements {@link ResolvableCalculationTarget} will result in a failed task. * * @param rules the rules defining how the calculation is performed * @param targets the targets for which values of the measures will be calculated * @param columns the columns that will be calculated * @return the calculation tasks */ public static CalculationTasks of( CalculationRules rules, List targets, List columns) { return of(rules, targets, columns, ReferenceData.empty()); } /** * Obtains an instance from a set of targets, columns and rules, resolving the targets. *

* The targets will typically be trades and positions. * The columns represent the measures to calculate. *

* The targets will be resolved if they implement {@link ResolvableCalculationTarget}. * * @param rules the rules defining how the calculation is performed * @param targets the targets for which values of the measures will be calculated * @param columns the columns that will be calculated * @param refData the reference data to use to resolve the targets * @return the calculation tasks */ public static CalculationTasks of( CalculationRules rules, List targets, List columns, ReferenceData refData) { // create columns that are a combination of the column overrides and the defaults // this is done once as it is the same for all targets List effectiveColumns = columns.stream() .map(column -> column.combineWithDefaults(rules.getReportingCurrency(), rules.getParameters())) .collect(toImmutableList()); // loop around the targets, then the columns, to build the tasks ImmutableList.Builder taskBuilder = ImmutableList.builder(); for (int rowIndex = 0; rowIndex < targets.size(); rowIndex++) { CalculationTarget target = resolveTarget(targets.get(rowIndex), refData); // find the applicable function, resolving the target if necessary CalculationFunction fn = target instanceof UnresolvableTarget ? UnresolvableTargetCalculationFunction.INSTANCE : rules.getFunctions().getFunction(target); // create the tasks List targetTasks = createTargetTasks(target, rowIndex, fn, effectiveColumns); taskBuilder.addAll(targetTasks); } // calculation tasks holds the original user-specified columns, not the derived ones return new CalculationTasks(taskBuilder.build(), columns); } // resolves the target private static CalculationTarget resolveTarget(CalculationTarget target, ReferenceData refData) { if (target instanceof ResolvableCalculationTarget) { ResolvableCalculationTarget resolvable = (ResolvableCalculationTarget) target; try { return resolvable.resolveTarget(refData); } catch (RuntimeException ex) { return new UnresolvableTarget(resolvable, ex.getMessage()); } } return target; } // creates the tasks for a single target private static List createTargetTasks( CalculationTarget resolvedTarget, int rowIndex, CalculationFunction function, List columns) { // create the cells and group them ListMultimap grouped = ArrayListMultimap.create(); for (int colIndex = 0; colIndex < columns.size(); colIndex++) { Column column = columns.get(colIndex); Measure measure = column.getMeasure(); ReportingCurrency reportingCurrency = column.getReportingCurrency().orElse(ReportingCurrency.NATURAL); CalculationTaskCell cell = CalculationTaskCell.of(rowIndex, colIndex, measure, reportingCurrency); // group to find cells that can be shared, with same mappings and params (minus reporting currency) CalculationParameters params = column.getParameters().filter(resolvedTarget, measure); grouped.put(params, cell); } // build tasks ImmutableList.Builder taskBuilder = ImmutableList.builder(); for (CalculationParameters params : grouped.keySet()) { taskBuilder.add(CalculationTask.of(resolvedTarget, function, params, grouped.get(params))); } return taskBuilder.build(); } //------------------------------------------------------------------------- /** * Obtains an instance from a set of tasks and columns. * * @param tasks the tasks that perform the calculations * @param columns the columns that define the calculations * @return the calculation tasks */ public static CalculationTasks of(List tasks, List columns) { return new CalculationTasks(tasks, columns); } //------------------------------------------------------------------------- /** * Creates an instance. * * @param tasks the tasks that perform the calculations * @param columns the columns that define the calculations */ private CalculationTasks(List tasks, List columns) { this.columns = ImmutableList.copyOf(columns); this.tasks = ImmutableList.copyOf(tasks); // validate the number of tasks and number of columns tally long cellCount = tasks.stream() .flatMap(task -> task.getCells().stream()) .count(); int columnCount = columns.size(); if (cellCount != 0) { if (columnCount == 0) { throw new IllegalArgumentException("There must be at least one column"); } if (cellCount % columnCount != 0) { throw new IllegalArgumentException( Messages.format( "Number of cells ({}) must be exactly divisible by the number of columns ({})", cellCount, columnCount)); } } // pull out the targets from the tasks int targetCount = (int) cellCount / columnCount; CalculationTarget[] targets = new CalculationTarget[targetCount]; for (CalculationTask task : tasks) { int rowIdx = task.getRowIndex(); if (targets[rowIdx] == null) { targets[rowIdx] = task.getTarget(); } else if (targets[rowIdx] != task.getTarget()) { throw new IllegalArgumentException(Messages.format( "Tasks define two different targets for row {}: {} and {}", rowIdx, targets[rowIdx], task.getTarget())); } } this.targets = ImmutableList.copyOf(targets); // missing targets will be caught here by null check } //------------------------------------------------------------------------- /** * Gets the market data that is required to perform the calculations. *

* This can be used to pass into the market data system to obtain and calibrate data. * * @param refData the reference data * @return the market data required for all calculations * @throws RuntimeException if unable to obtain the requirements */ public MarketDataRequirements requirements(ReferenceData refData) { // use for loop not streams for shorter stack traces MarketDataRequirementsBuilder builder = MarketDataRequirements.builder(); for (CalculationTask task : tasks) { builder.addRequirements(task.requirements(refData)); } return builder.build(); } //------------------------------------------------------------------------- @Override public String toString() { return Messages.format("CalculationTasks[grid={}x{}]", targets.size(), columns.size()); } //------------------------- AUTOGENERATED START ------------------------- /** * The meta-bean for {@code CalculationTasks}. */ private static final TypedMetaBean META_BEAN = LightMetaBean.of( CalculationTasks.class, MethodHandles.lookup(), new String[] { "targets", "columns", "tasks"}, ImmutableList.of(), ImmutableList.of(), ImmutableList.of()); /** * The meta-bean for {@code CalculationTasks}. * @return the meta-bean, not null */ public static TypedMetaBean meta() { return META_BEAN; } static { MetaBean.register(META_BEAN); } private CalculationTasks( List targets, List columns, List tasks) { JodaBeanUtils.notEmpty(targets, "targets"); JodaBeanUtils.notEmpty(columns, "columns"); JodaBeanUtils.notEmpty(tasks, "tasks"); this.targets = ImmutableList.copyOf(targets); this.columns = ImmutableList.copyOf(columns); this.tasks = ImmutableList.copyOf(tasks); } @Override public TypedMetaBean metaBean() { return META_BEAN; } //----------------------------------------------------------------------- /** * Gets the targets that calculations will be performed on. *

* The result of the calculations will be a grid where each row is taken from this list. * @return the value of the property, not empty */ public List getTargets() { return targets; } //----------------------------------------------------------------------- /** * Gets the columns that will be calculated. *

* The result of the calculations will be a grid where each column is taken from this list. * @return the value of the property, not empty */ public List getColumns() { return columns; } //----------------------------------------------------------------------- /** * Gets the tasks that perform the individual calculations. *

* The results can be visualized as a grid, with a row for each target and a column for each measure. * Each task can calculate the result for one or more cells in the grid. * @return the value of the property, not empty */ public List getTasks() { return tasks; } //----------------------------------------------------------------------- @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj != null && obj.getClass() == this.getClass()) { CalculationTasks other = (CalculationTasks) obj; return JodaBeanUtils.equal(targets, other.targets) && JodaBeanUtils.equal(columns, other.columns) && JodaBeanUtils.equal(tasks, other.tasks); } return false; } @Override public int hashCode() { int hash = getClass().hashCode(); hash = hash * 31 + JodaBeanUtils.hashCode(targets); hash = hash * 31 + JodaBeanUtils.hashCode(columns); hash = hash * 31 + JodaBeanUtils.hashCode(tasks); return hash; } //-------------------------- AUTOGENERATED END -------------------------- }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy