/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.components.optimizer.execution;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.map.ObjectMapper;
import de.rcenvironment.components.optimizer.common.MethodDescription;
import de.rcenvironment.components.optimizer.common.OptimizerComponentConstants;
import de.rcenvironment.components.optimizer.common.OptimizerComponentHistoryDataItem;
import de.rcenvironment.components.optimizer.common.OptimizerFileLoader;
import de.rcenvironment.components.optimizer.common.OptimizerPublisher;
import de.rcenvironment.components.optimizer.common.OptimizerResultService;
import de.rcenvironment.components.optimizer.common.OptimizerResultSet;
import de.rcenvironment.components.optimizer.common.ResultStructure;
import de.rcenvironment.components.optimizer.common.execution.OptimizerAlgorithmExecutor;
import de.rcenvironment.components.optimizer.execution.algorithms.registry.OptimizerAlgorithmExecutorFactoryRegistry;
import de.rcenvironment.core.component.api.ComponentConstants;
import de.rcenvironment.core.component.api.ComponentException;
import de.rcenvironment.core.component.api.LoopComponentConstants;
import de.rcenvironment.core.component.datamanagement.api.ComponentDataManagementService;
import de.rcenvironment.core.component.execution.api.Component;
import de.rcenvironment.core.component.model.api.LazyDisposal;
import de.rcenvironment.core.component.model.spi.AbstractNestedLoopComponent;
import de.rcenvironment.core.datamodel.api.DataType;
import de.rcenvironment.core.datamodel.api.TypedDatum;
import de.rcenvironment.core.datamodel.api.TypedDatumFactory;
import de.rcenvironment.core.datamodel.api.TypedDatumService;
import de.rcenvironment.core.datamodel.types.api.FileReferenceTD;
import de.rcenvironment.core.datamodel.types.api.FloatTD;
import de.rcenvironment.core.datamodel.types.api.VectorTD;
import de.rcenvironment.core.toolkitbridge.transitional.ConcurrencyUtils;
import de.rcenvironment.core.utils.common.JsonUtils;
import de.rcenvironment.core.utils.common.LogUtils;
import de.rcenvironment.core.utils.common.StringUtils;
import de.rcenvironment.core.utils.common.TempFileServiceAccess;
/**
* Optimizer implementation of {@link Component}.
*
* @author Sascha Zur
*/
@LazyDisposal
public class OptimizerComponent extends AbstractNestedLoopComponent {
private static final String INPUT_PREFIX_CONSTANT = "f81ec917-2221-4bcd-ac17-1c1cef6e08a5_input:";
private static final String ITERATION = "Iteration";
private static final double CONST_1E99 = 1E99;
private static final String COMMA = ",";
private static OptimizerResultService optimizerResultService;
private static OptimizerAlgorithmExecutorFactoryRegistry optimizerAlgorithmExecutorFactoryRegistry;
private static final Log LOGGER = LogFactory.getLog(OptimizerComponent.class);
private static TypedDatumFactory typedDatumFactory;
/** Flag. */
public boolean programThreadInterrupted;
private OptimizerPublisher resultPublisher;
private Collection<String> output;
private Collection<String> input;
private Map<String, TypedDatum> outputValues;
private OptimizerResultSet dataset = null;
private String algorithm;
private OptimizerAlgorithmExecutor optimizer;
private final ObjectMapper mapper = JsonUtils.getDefaultObjectMapper();
private Map<String, MethodDescription> methodConfigurations;
private Map<String, Double> startValues;
private Integer iterationCount = 0;
private Map<String, Double> lowerBoundsStartValues;
private Map<String, Double> upperBoundsStartValues;
private boolean initFailed = false;
private boolean optimizerStarted;
private OptimizerComponentHistoryDataItem historyDataItem;
private Map<String, TypedDatum> runtimeViewValues = new HashMap<>();
private Map<Integer, Map<String, Double>> iterationData;
private Map<Integer, Map<String, TypedDatum>> dataForwarded = new HashMap<>();
private Map<String, Double> stepValues;
private void prepareExternalProgram() throws ComponentException {
Map<String, Map<String, Double>> boundMaps = new HashMap<>();
boundMaps.put("lower", lowerBoundsStartValues);
boundMaps.put("upper", upperBoundsStartValues);
optimizer = optimizerAlgorithmExecutorFactoryRegistry.createAlgorithmProviderInstance(
methodConfigurations.get(algorithm.split(COMMA)[0]).getOptimizerPackage(),
methodConfigurations, outputValues, input, componentContext, boundMaps, stepValues);
programThreadInterrupted = false;
ConcurrencyUtils.getAsyncTaskService().execute(optimizer);
if (optimizer.isInitFailed()) {
throw new ComponentException("Failed to prepare optimizer", optimizer.getStartFailedException());
}
}
private void manageNewInput(Map<String, Double> inputVariables, Map<String, Double> inputVariablesGradients,
Map<String, Double> constraintVariables, Map<String, Double> constraintVariablesGradients) {
Set<String> inputValues = componentContext.getInputsWithDatum();
Map<String, Double> iteration = iterationData.get(iterationCount);
boolean gotRealInput = false;
for (String e : input) {
if (inputValues.contains(e)) {
gotRealInput = true;
if (componentContext.getInputDataType(e) == DataType.Vector) {
if (componentContext.readInput(e).getDataType() == DataType.NotAValue) {
for (int i = 0; i < Integer.parseInt(componentContext.getOutputMetaDataValue(
e.substring(e.lastIndexOf(OptimizerComponentConstants.GRADIENT_DELTA) + 1),
OptimizerComponentConstants.METADATA_VECTOR_SIZE)); i++) {
convertValue(inputVariables, inputVariablesGradients, constraintVariables, e
+ OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
componentContext.readInput(e), iteration);
}
} else {
VectorTD vector = (VectorTD) componentContext.readInput(e);
for (int i = 0; i < vector.getRowDimension(); i++) {
convertValue(inputVariables, inputVariablesGradients, constraintVariables, e
+ OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
vector.getFloatTDOfElement(i), iteration);
}
}
} else {
convertValue(inputVariables, inputVariablesGradients, constraintVariables, e,
componentContext.readInput(e), iteration);
}
}
}
if (gotRealInput) {
createNewResultfile(iteration);
fillRuntimeView(inputVariables, inputVariablesGradients, constraintVariables);
}
}
private void createNewResultfile(Map<String, Double> iteration) {
iterationData.put(iterationCount, iteration);
if (!componentContext.getInputsWithDatum().isEmpty() && historyDataItem != null) {
File resultFile;
try {
List<String> outputs = (new LinkedList<>(componentContext.getOutputs()));
Collections.sort(outputs);
resultFile = TempFileServiceAccess.getInstance().createTempFileFromPattern("OptimizerResultFile*.csv");
writeResultToCSVFile(resultFile.getAbsolutePath());
FileReferenceTD resultFileReference =
componentContext.getService(ComponentDataManagementService.class).createFileReferenceTDFromLocalFile(componentContext,
resultFile, "Result.csv");
historyDataItem.setResultFileReference(resultFileReference.getFileReference());
} catch (IOException e) {
String errorMessage = "Failed to store result file into the data management"
+ "; it is not available in the workflow data browser";
String errorId = LogUtils.logExceptionWithStacktraceAndAssignUniqueMarker(LOGGER, errorMessage, e);
componentLog.componentError(errorMessage, e, errorId);
}
}
}
private void writeResultToCSVFile(String path) throws IOException {
if (path != null && !iterationData.isEmpty()) {
List<String> orderedOutputs = new LinkedList<>(output);
List<String> orderedInputs = new LinkedList<>(input);
List<String> insert = new LinkedList<>();
List<String> remove = new LinkedList<>();
for (String outputName : orderedOutputs) {
if (componentContext.getOutputDataType(outputName) == DataType.Vector) {
remove.add(outputName);
for (int i = 0; i < Integer.parseInt(
componentContext.getOutputMetaDataValue(outputName, OptimizerComponentConstants.METADATA_VECTOR_SIZE)); i++) {
insert.add(outputName + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i);
}
}
}
for (String toRemove : remove) {
orderedOutputs.remove(toRemove);
}
for (String toInsert : insert) {
orderedOutputs.add(toInsert);
}
insert = new LinkedList<>();
remove = new LinkedList<>();
for (String inputName : orderedInputs) {
if (componentContext.getInputDataType(inputName) == DataType.Vector) {
int vectorSize = 0;
if (inputName.contains(OptimizerComponentConstants.GRADIENT_DELTA)) {
String outputName =
inputName.substring(inputName.lastIndexOf(OptimizerComponentConstants.GRADIENT_DELTA) + 1);
vectorSize = Integer.parseInt(
componentContext.getOutputMetaDataValue(outputName, OptimizerComponentConstants.METADATA_VECTOR_SIZE));
} else {
vectorSize = Integer.parseInt(
componentContext.getInputMetaDataValue(inputName, OptimizerComponentConstants.METADATA_VECTOR_SIZE));
}
remove.add(inputName);
for (int i = 0; i < vectorSize; i++) {
insert.add(inputName + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i);
}
}
}
for (String toRemove : remove) {
orderedInputs.remove(toRemove);
}
for (String toInsert : insert) {
orderedInputs.add(toInsert);
}
Collections.sort(orderedOutputs);
Collections.sort(orderedInputs);
try (FileWriter fw = new FileWriter(new File(path));
CSVPrinter printer = CSVFormat.newFormat(';').withIgnoreSurroundingSpaces()
.withAllowMissingColumnNames().withRecordSeparator("\n").print(fw)) {
printer.print(ITERATION);
for (String outputName : orderedOutputs) {
printer.print(outputName);
}
for (String inputName : orderedInputs) {
printer.print(inputName);
}
printer.println();
// Iteration start at 1.
for (Integer i = 1; i < iterationData.keySet().size() + 1; i++) {
Map<String, Double> iteration = iterationData.get(i);
printer.print(i);
for (String out : orderedOutputs) {
printer.print(iteration.get(out));
}
for (String in : orderedInputs) {
printer.print(iteration.get(INPUT_PREFIX_CONSTANT + in));
}
printer.println();
printer.flush();
}
}
}
}
private void fillRuntimeView(Map<String, Double> inputVariables, Map<String, Double> inputVariablesGradients,
Map<String, Double> constraintVariables) {
for (String key : inputVariables.keySet()) {
if (inputVariables.get(key).isNaN()) {
runtimeViewValues.put(key, typedDatumFactory.createFloat(CONST_1E99));
} else {
runtimeViewValues.put(key, typedDatumFactory.createFloat(inputVariables.get(key)));
}
}
for (String key : inputVariablesGradients.keySet()) {
if (inputVariablesGradients.get(key).isNaN()) {
runtimeViewValues.put(key, typedDatumFactory.createFloat(CONST_1E99));
} else {
runtimeViewValues.put(key, typedDatumFactory.createFloat(inputVariablesGradients.get(key)));
}
}
for (String key : constraintVariables.keySet()) {
if (constraintVariables.get(key).isNaN()) {
runtimeViewValues.put(key, typedDatumFactory.createFloat(CONST_1E99));
} else {
runtimeViewValues.put(key, typedDatumFactory.createFloat(constraintVariables.get(key)));
}
}
runtimeViewValues.put(ITERATION, typedDatumFactory.createInteger(iterationCount));
dataset = new OptimizerResultSet(runtimeViewValues, componentContext.getExecutionIdentifier());
resultPublisher.add(dataset);
runtimeViewValues = new HashMap<>();
}
private void convertValue(Map<String, Double> inputVariables, Map<String, Double> inputVariablesGradients,
Map<String, Double> constraintVariables, String variableName, TypedDatum value, Map<String, Double> iteration) {
double inputField;
if (value.getDataType() != DataType.NotAValue) {
inputField = ((FloatTD) value).getFloatValue();
} else {
inputField = Double.NaN;
}
if (variableName.contains(OptimizerComponentConstants.GRADIENT_DELTA)) {
inputVariablesGradients.put(variableName, inputField);
} else {
String identifier;
if (variableName.contains(OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL)
&& componentContext.getDynamicInputIdentifier(
variableName.substring(0, variableName.indexOf(OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL))) != null) {
identifier = componentContext.getDynamicInputIdentifier(
variableName.substring(0, variableName.indexOf(OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL)));
} else {
identifier = componentContext.getDynamicInputIdentifier(variableName);
}
if (identifier.equals(OptimizerComponentConstants.ID_OBJECTIVE)) {
inputVariables.put(variableName, inputField);
} else {
constraintVariables.put(variableName, inputField);
}
}
iteration.put(INPUT_PREFIX_CONSTANT + variableName, inputField);
}
private void terminateExecutor() {
if (optimizer != null) {
optimizer.closeConnection();
programThreadInterrupted = true;
optimizer.stop();
File workDir = optimizer.getWorkingDir();
optimizer.dispose();
optimizer = null;
try {
TempFileServiceAccess.getInstance().disposeManagedTempDirOrFile(workDir);
} catch (IOException e) {
LOGGER.error("Failed to delete temporary directory", e);
}
}
}
private ResultStructure createStructure() {
final ResultStructure structure = new ResultStructure();
// outputs are dimensions
for (String e : output) {
if (componentContext.getOutputDataType(e) == DataType.Vector) {
for (int i = 0; i < Integer.parseInt(
componentContext.getOutputMetaDataValue(e, OptimizerComponentConstants.METADATA_VECTOR_SIZE)); i++) {
final de.rcenvironment.components.optimizer.common.Dimension dimension =
new de.rcenvironment.components.optimizer.common.Dimension(
e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i, //
DataType.Float.getDisplayName(), //
true);
structure.addDimension(dimension);
}
} else {
final de.rcenvironment.components.optimizer.common.Dimension dimension =
new de.rcenvironment.components.optimizer.common.Dimension(
e, //
componentContext.getOutputDataType(e).getDisplayName(), //
true);
structure.addDimension(dimension);
}
}
final de.rcenvironment.components.optimizer.common.Dimension dimension =
new de.rcenvironment.components.optimizer.common.Dimension(
ITERATION, //
DataType.Integer.getDisplayName(), //
true);
structure.addDimension(dimension);
// inputs are measures
for (String e : input) {
if (componentContext.getInputDataType(e) == DataType.Vector) {
int vecSize =
Integer.parseInt(componentContext
.getOutputMetaDataValue(e.substring(e.lastIndexOf(OptimizerComponentConstants.GRADIENT_DELTA) + 1),
OptimizerComponentConstants.METADATA_VECTOR_SIZE));
for (int i = 0; i < vecSize; i++) {
final de.rcenvironment.components.optimizer.common.Measure measure =
new de.rcenvironment.components.optimizer.common.Measure(
e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i, //
DataType.Float.getDisplayName());
structure.addMeasure(measure);
}
} else {
final de.rcenvironment.components.optimizer.common.Measure measure =
new de.rcenvironment.components.optimizer.common.Measure(
e, //
DataType.Float.getDisplayName());
structure.addMeasure(measure);
}
}
return structure;
}
@Override
public boolean treatStartAsComponentRun() {
boolean runInitial = true;
for (String e : componentContext.getInputs()) {
if (e.endsWith(OptimizerComponentConstants.STARTVALUE_SIGNATURE)
|| e.endsWith(OptimizerComponentConstants.STEP_VALUE_SIGNATURE)
|| e.endsWith(LoopComponentConstants.ENDPOINT_STARTVALUE_SUFFIX)) {
runInitial = false;
}
}
return runInitial;
}
@SuppressWarnings("unchecked")
@Override
protected void startNestedComponentSpecific() throws ComponentException {
optimizerResultService = componentContext.getService(OptimizerResultService.class);
optimizerAlgorithmExecutorFactoryRegistry = componentContext.getService(OptimizerAlgorithmExecutorFactoryRegistry.class);
typedDatumFactory = componentContext.getService(TypedDatumService.class).getFactory();
iterationData = new TreeMap<>();
output = new HashSet<>();
output.addAll(componentContext.getOutputs());
List<String> toRemove = new LinkedList<>();
for (String e : output) {
if (e.endsWith(OptimizerComponentConstants.OPTIMUM_VARIABLE_SUFFIX)) {
toRemove.add(e);
}
if (e.endsWith(LoopComponentConstants.ENDPOINT_NAME_LOOP_DONE)) {
toRemove.add(e);
}
if (e.endsWith(OptimizerComponentConstants.ITERATION_COUNT_ENDPOINT_NAME)) {
toRemove.add(e);
}
if (e.endsWith(OptimizerComponentConstants.DERIVATIVES_NEEDED)) {
toRemove.add(e);
}
if (componentContext.isDynamicInput(e)
&& componentContext.getDynamicInputIdentifier(e).equals(LoopComponentConstants.ENDPOINT_ID_TO_FORWARD)) {
toRemove.add(e);
}
}
for (String e : toRemove) {
output.remove(e);
}
input = new HashSet<>();
for (String inputName : componentContext.getInputs()) {
if (componentContext.getDynamicInputIdentifier(inputName).equals(OptimizerComponentConstants.ID_OBJECTIVE)
|| componentContext.getDynamicInputIdentifier(inputName).equals(OptimizerComponentConstants.ID_CONSTRAINT)
|| componentContext.getDynamicInputIdentifier(inputName).equals(OptimizerComponentConstants.ID_GRADIENTS)) {
input.add(inputName);
}
}
algorithm = componentContext.getConfigurationValue(OptimizerComponentConstants.ALGORITHMS);
String configurations = componentContext.getConfigurationValue(
OptimizerComponentConstants.METHODCONFIGURATIONS);
if (output.isEmpty() || input.isEmpty()) {
throw new ComponentException("Design variables or target functions not configured");
}
try {
if (configurations != null && !configurations.equals("")) {
methodConfigurations = mapper.readValue(configurations, new HashMap<String, MethodDescription>().getClass());
for (String key : methodConfigurations.keySet()) {
methodConfigurations.put(key, mapper.convertValue(methodConfigurations.get(key), MethodDescription.class));
}
} else {
methodConfigurations = OptimizerFileLoader.getAllMethodDescriptions("optimizer");
}
} catch (IOException e) {
throw new ComponentException("Failed to load or parse method file", e);
}
String[] splittedAlgorithms = algorithm.split(",");
for (String alg : splittedAlgorithms) {
if (!methodConfigurations.containsKey(alg)) {
throw new ComponentException("Failed to load algorithm '" + alg + "'; not found");
}
}
resultPublisher = optimizerResultService.createPublisher(
componentContext.getExecutionIdentifier(),
componentContext.getInstanceName(),
createStructure());
optimizerStarted = false;
boolean runInitial = treatStartAsComponentRun();
if (runInitial) {
super.processInputs();
}
}
@Override
protected void processInputsNestedComponentSpecific() throws ComponentException {
initializeNewHistoryDataItem();
if (!optimizerStarted) {
firstRun();
} else {
if (!initFailed) {
storeDataForwarded();
Map<String, Double> inputVariables = new HashMap<>();
Map<String, Double> constraintVariables = new HashMap<>();
Map<String, Double> inputVariablesGradients = new HashMap<>();
Map<String, Double> constraintVariablesGradients = new HashMap<>();
// isolate variables and save result
manageNewInput(inputVariables, inputVariablesGradients,
constraintVariables, constraintVariablesGradients);
// start new algorithm run
if (optimizer != null && !optimizer.isStopped()) {
optimizer.runStep(inputVariables, inputVariablesGradients,
constraintVariables, constraintVariablesGradients, outputValues);
}
} else {
if (optimizer != null) {
terminateExecutor();
}
throw new ComponentException("Failed to initialize optimizer");
}
if (Boolean.valueOf(componentContext.getConfigurationValue(ComponentConstants.CONFIG_KEY_STORE_DATA_ITEM))
&& optimizer != null) {
optimizer.writeHistoryDataItem(historyDataItem);
writeFinalHistoryDataItem();
}
}
iterationCount++;
}
private void storeDataForwarded() {
Integer iteration = iterationCount;
for (String inputName : componentContext.getInputsWithDatum()) {
if (componentContext.isDynamicInput(inputName)
&& componentContext.getDynamicInputIdentifier(inputName).equals(LoopComponentConstants.ENDPOINT_ID_TO_FORWARD)) {
if (!dataForwarded.containsKey(iteration)) {
dataForwarded.put(iterationCount, new HashMap<String, TypedDatum>());
}
dataForwarded.get(iteration).put(inputName, componentContext.readInput(inputName));
}
}
}
private void firstRun() throws ComponentException {
final String errorMessage = "Failed to start optimizer";
outputValues = new HashMap<>();
startValues = new HashMap<>();
stepValues = new HashMap<>();
lowerBoundsStartValues = new HashMap<>();
upperBoundsStartValues = new HashMap<>();
for (String e : output) {
String hasStartValue =
componentContext.getOutputMetaDataValue(e, OptimizerComponentConstants.META_HAS_STARTVALUE);
String hasStep =
componentContext.getOutputMetaDataValue(e, OptimizerComponentConstants.META_USE_STEP);
String hasUseUnifiedStep =
componentContext.getOutputMetaDataValue(e, OptimizerComponentConstants.META_USE_UNIFIED_STEP);
String hasBoundValues =
componentContext.getOutputMetaDataValue(e, OptimizerComponentConstants.META_KEY_HAS_BOUNDS);
String startValue = componentContext.getOutputMetaDataValue(e, OptimizerComponentConstants.META_STARTVALUE);
if (startValue.equals("-")) {
startValue = "";
}
getStartAndStepValues(e, hasStartValue, hasStep, hasUseUnifiedStep, startValue);
if (hasBoundValues != null && Boolean.parseBoolean(hasBoundValues)) {
if (componentContext.getOutputDataType(e) == DataType.Vector) {
for (int i = 0; i < Integer.parseInt(componentContext
.getOutputMetaDataValue(e, OptimizerComponentConstants.METADATA_VECTOR_SIZE)); i++) {
lowerBoundsStartValues.put(e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
Double.parseDouble(componentContext
.getOutputMetaDataValue(e, OptimizerComponentConstants.META_LOWERBOUND)));
upperBoundsStartValues.put(e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
Double.parseDouble(componentContext
.getOutputMetaDataValue(e, OptimizerComponentConstants.META_UPPERBOUND)));
}
} else {
lowerBoundsStartValues.put(e,
Double.parseDouble(componentContext.getOutputMetaDataValue(e, OptimizerComponentConstants.META_LOWERBOUND)));
upperBoundsStartValues.put(e,
Double.parseDouble(componentContext.getOutputMetaDataValue(e, OptimizerComponentConstants.META_UPPERBOUND)));
}
}
}
for (String e : input) {
String hasBoundValues =
componentContext.getInputMetaDataValue(e, OptimizerComponentConstants.META_KEY_HAS_BOUNDS);
if (hasBoundValues != null && Boolean.parseBoolean(hasBoundValues)) {
if (componentContext.getInputDataType(e) == DataType.Vector) {
for (int i = 0; i < Integer.parseInt(componentContext
.getInputMetaDataValue(e, OptimizerComponentConstants.METADATA_VECTOR_SIZE)); i++) {
lowerBoundsStartValues.put(e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
Double.parseDouble(componentContext.getInputMetaDataValue(e, OptimizerComponentConstants.META_LOWERBOUND)));
upperBoundsStartValues.put(e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
Double.parseDouble(componentContext.getInputMetaDataValue(e, OptimizerComponentConstants.META_UPPERBOUND)));
}
} else {
lowerBoundsStartValues.put(e,
Double.parseDouble(componentContext.getInputMetaDataValue(e, OptimizerComponentConstants.META_LOWERBOUND)));
upperBoundsStartValues.put(e,
Double.parseDouble(componentContext.getInputMetaDataValue(e, OptimizerComponentConstants.META_UPPERBOUND)));
}
}
}
for (String e : componentContext.getInputsWithDatum()) {
if (e.contains(OptimizerComponentConstants.BOUNDS_STARTVALUE_LOWER_SIGNITURE)) {
if (componentContext.getInputDataType(e) == DataType.Vector) {
for (int i = 0; i < ((VectorTD) componentContext.readInput(e)).getRowDimension(); i++) {
lowerBoundsStartValues.put(e.substring(0, e.indexOf(OptimizerComponentConstants.BOUNDS_STARTVALUE_LOWER_SIGNITURE))
+ OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
((VectorTD) componentContext.readInput(e)).getFloatTDOfElement(0).getFloatValue());
}
} else {
lowerBoundsStartValues.put(e.substring(0, e.indexOf(OptimizerComponentConstants.BOUNDS_STARTVALUE_LOWER_SIGNITURE)),
((FloatTD) componentContext.readInput(e)).getFloatValue());
}
}
if (e.contains(OptimizerComponentConstants.BOUNDS_STARTVALUE_UPPER_SIGNITURE)) {
if (componentContext.getInputDataType(e) == DataType.Vector) {
for (int i = 0; i < ((VectorTD) componentContext.readInput(e)).getRowDimension(); i++) {
upperBoundsStartValues.put(e.substring(0, e.indexOf(OptimizerComponentConstants.BOUNDS_STARTVALUE_UPPER_SIGNITURE))
+ OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
((VectorTD) componentContext.readInput(e)).getFloatTDOfElement(0).getFloatValue());
}
} else {
upperBoundsStartValues.put(e.substring(0, e.indexOf(OptimizerComponentConstants.BOUNDS_STARTVALUE_UPPER_SIGNITURE)),
((FloatTD) componentContext.readInput(e)).getFloatValue());
}
}
}
for (String e : startValues.keySet()) {
outputValues.put(e, typedDatumFactory.createFloat(startValues.get(e)));
}
prepareExternalProgram();
if (optimizer != null && !optimizer.isInitFailed() && !(optimizer.getStartFailed().get())) {
try {
if (optimizer.initializationLoop()) {
optimizer.readOutputFileFromExternalProgram(outputValues);
sendValuesNestedComponentSpecific();
} else {
if (!optimizer.getStartFailed().get()) {
sendFinalValues();
componentContext.closeAllOutputs();
} else {
throw new ComponentException("Could not start optimizer. Maybe binaries are missing or not compatible with system.",
optimizer.getStartFailedException());
}
}
optimizerStarted = true;
} catch (IOException e) {
componentContext.getLog().componentError("Failed to initialize optimizer: " + e.getMessage());
LOGGER.error("Failed to initialize optimizer", e);
initFailed = true;
}
} else {
throw new ComponentException(errorMessage);
}
}
private void getStartAndStepValues(String e, String hasStartValue, String hasStep, String hasUseUnifiedStep, String startValue) {
if ((hasStartValue != null && Boolean.parseBoolean(hasStartValue) && !startValue.isEmpty())
|| (hasStartValue == null && !startValue.isEmpty())) {
if (componentContext.getOutputDataType(e) == DataType.Vector) {
for (int i = 0; i < Integer.parseInt(componentContext
.getOutputMetaDataValue(e, OptimizerComponentConstants.METADATA_VECTOR_SIZE)); i++) {
startValues.put(e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
Double.parseDouble(componentContext
.getOutputMetaDataValue(e, OptimizerComponentConstants.META_STARTVALUE)));
}
} else {
startValues.put(e, Double.parseDouble(startValue));
}
} else if (!Boolean.parseBoolean(hasStartValue)) {
outputValues.put(e, componentContext.readInput(e + OptimizerComponentConstants.STARTVALUE_SIGNATURE));
}
if (Boolean.parseBoolean(hasStep) && Boolean.parseBoolean(hasUseUnifiedStep)) {
if (componentContext.getOutputDataType(e) == DataType.Vector) {
for (int i = 0; i < Integer.parseInt(componentContext
.getOutputMetaDataValue(e, OptimizerComponentConstants.METADATA_VECTOR_SIZE)); i++) {
stepValues.put(e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
Double.parseDouble(componentContext
.getOutputMetaDataValue(e, OptimizerComponentConstants.META_STEP)));
}
} else {
stepValues.put(e, Double.parseDouble(componentContext
.getOutputMetaDataValue(e, OptimizerComponentConstants.META_STEP)));
}
} else if (Boolean.parseBoolean(hasStep) && !Boolean.parseBoolean(hasUseUnifiedStep)) {
if (componentContext.getOutputDataType(e) == DataType.Vector) {
VectorTD stepVector = ((VectorTD) componentContext.readInput(e + OptimizerComponentConstants.STEP_VALUE_SIGNATURE));
for (int i = 0; i < Integer.parseInt(componentContext
.getOutputMetaDataValue(e, OptimizerComponentConstants.METADATA_VECTOR_SIZE)); i++) {
stepValues.put(e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
stepVector.getFloatTDOfElement(i).getFloatValue());
}
} else {
stepValues.put(e,
((FloatTD) componentContext.readInput(e + OptimizerComponentConstants.STEP_VALUE_SIGNATURE)).getFloatValue());
}
}
}
@Override
protected void sendValuesNestedComponentSpecific() {
if (optimizerStarted && optimizer != null && !optimizer.isStopped()) {
Map<String, Double> iteration = new HashMap<>();
for (String e : output) {
if (outputValues.get(e) != null) {
writeOutput(e, outputValues.get(e));
if (componentContext.getOutputDataType(e) == DataType.Vector) {
for (int i = 0; i < Integer.parseInt(componentContext.getOutputMetaDataValue(e,
OptimizerComponentConstants.METADATA_VECTOR_SIZE)); i++) {
runtimeViewValues.put("Output: " + e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
((VectorTD) outputValues.get(e)).getFloatTDOfElement(i));
iteration.put(e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i,
((VectorTD) outputValues.get(e)).getFloatTDOfElement(i).getFloatValue());
}
} else {
runtimeViewValues.put("Output: " + e, outputValues.get(e));
iteration.put(e, ((FloatTD) outputValues.get(e)).getFloatValue());
}
} else {
LOGGER.info(StringUtils.format("Could not send out output %s because the value was null", e));
}
}
writeOutput(OptimizerComponentConstants.ITERATION_COUNT_ENDPOINT_NAME,
typedDatumFactory.createInteger(iterationCount));
if (optimizer != null) {
writeOutput(OptimizerComponentConstants.DERIVATIVES_NEEDED,
typedDatumFactory.createBoolean(optimizer.getDerivativedNeeded()));
}
iterationData.put(iterationCount, iteration);
}
}
@Override
protected void resetNestedComponentSpecific() {
programThreadInterrupted = false;
outputValues.clear();
runtimeViewValues.clear();
startValues = new HashMap<>();
lowerBoundsStartValues = new HashMap<>();
upperBoundsStartValues = new HashMap<>();
stepValues = new HashMap<>();
iterationCount = 0;
optimizerStarted = false;
}
@Override
protected void finishLoopNestedComponentSpecific() {
writeFinalHistoryDataItem();
}
@Override
protected boolean isDoneNestedComponentSpecific() {
return optimizerStarted && (programThreadInterrupted || optimizer == null || optimizer.isStopped());
}
@Override
protected void sendFinalValues() throws ComponentException {
if (optimizer != null) {
optimizer.setIterationData(iterationData);
int optimalRunNumber = optimizer.getOptimalRunNumber();
Map<String, Double> optimum = iterationData.get(optimalRunNumber);
if (optimalRunNumber != Integer.MIN_VALUE && optimum != null) {
for (String e : output) {
if (componentContext.getOutputDataType(e) == DataType.Vector) {
int vectorSize = Integer.parseInt(componentContext.getOutputMetaDataValue(e,
OptimizerComponentConstants.METADATA_VECTOR_SIZE));
VectorTD optimumVector =
typedDatumFactory.createVector(vectorSize);
for (int i = 0; i < vectorSize; i++) {
String vectorOutputName = e + OptimizerComponentConstants.OPTIMIZER_VECTOR_INDEX_SYMBOL + i;
runtimeViewValues.put(vectorOutputName, typedDatumFactory.createFloat(optimum.get(vectorOutputName)));
optimumVector.setFloatTDForElement(typedDatumFactory.createFloat(optimum.get(vectorOutputName)), i);
}
writeOutput(e + OptimizerComponentConstants.OPTIMUM_VARIABLE_SUFFIX, optimumVector);
} else {
writeOutput(e + OptimizerComponentConstants.OPTIMUM_VARIABLE_SUFFIX,
typedDatumFactory.createFloat(optimum.get(e)));
}
}
sendFinalValuesForwarded(optimalRunNumber);
} else {
throw new ComponentException("Failed to read optimal design variables");
}
}
terminateExecutor();
}
private void sendFinalValuesForwarded(Integer optimalRunNumber) {
if (optimalRunNumber == null || optimalRunNumber == Integer.MIN_VALUE) {
componentContext.getLog().componentError("Internal error: iteration of optimal design variable cannot be determined");
// should not happen
return;
}
if (!dataForwarded.isEmpty()) {
for (String inputName : dataForwarded.get(optimalRunNumber).keySet()) {
writeOutput(inputName + OptimizerComponentConstants.OPTIMUM_VARIABLE_SUFFIX,
dataForwarded.get(optimalRunNumber).get(inputName));
}
}
}
private void initializeNewHistoryDataItem() {
if (Boolean.valueOf(componentContext.getConfigurationValue(ComponentConstants.CONFIG_KEY_STORE_DATA_ITEM))) {
historyDataItem = new OptimizerComponentHistoryDataItem();
}
}
private void writeFinalHistoryDataItem() {
if (Boolean.valueOf(componentContext.getConfigurationValue(ComponentConstants.CONFIG_KEY_STORE_DATA_ITEM))) {
componentContext.writeFinalHistoryDataItem(historyDataItem);
}
}
@Override
public void tearDown(FinalComponentState state) {
super.tearDown(state);
terminateExecutor();
}
}