V1_0.java [src/java/m/sensitivity/model] Revision: default  Date:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package m.sensitivity.model;

import csip.ModelDataService;
import csip.annotations.Description;
import csip.annotations.Name;
import csip.annotations.Polling;
import csip.annotations.VersionInfo;
import csip.api.server.ServiceException;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.Path;
import m.sensitivity.model.methods.RegionalSensitivityAnalyzer;
import m.sensitivity.model.methods.SensitivityAnalyzer;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

/**
 * Sensitivity service.
 *
 * @author nathan
 */
@Name("Model Parameter Sensitivity")
@Description("Service to compute model parameter sensitivity")
@VersionInfo("1.0")
@Path("m/sensitivity/1.0.0")
@Polling(first = 5000, next = 4500)
public class V1_0 extends ModelDataService {

    @Override
    public void doProcess() throws Exception {
        LOG.info("===>  Running Sensitivity Analysis");

        String traceFileName = parameter().getString("traceFileName", "trace.csv");
        File trace = workspace().getFile(traceFileName);
        if (!trace.exists()) {
            throw new ServiceException("Trace file was not found: " + traceFileName);
        }
        LOG.info("Trace File: " + trace.getAbsolutePath());

        String[] params = parameter().getStringArray("parameters", new String[0]);
        if (params.length == 0) {
            throw new ServiceException("No parameters specified");
        }
        LOG.info("Parameters: " + Arrays.toString(params));

        String[] positiveBestMetrics = parameter().getStringArray("positiveBestMetrics", new String[0]);
        String[] zeroBestMetrics = parameter().getStringArray("zeroBestMetrics", new String[0]);
        if (positiveBestMetrics.length == 0 && zeroBestMetrics.length == 0) {
            throw new ServiceException("No metrics specified");
        }
        LOG.info("Positive Best Metrics: " + Arrays.toString(positiveBestMetrics));
        LOG.info("Zero Best Metrics: " + Arrays.toString(zeroBestMetrics));

        List<Map<String, Object>> customMetrics = getCustomMetrics();

        Executor ex = new Executor(trace, params, positiveBestMetrics, zeroBestMetrics, customMetrics);
        SensitivityAnalyzer sa = new RegionalSensitivityAnalyzer();

        File outputDirectory = workspace().getFile( "output");
        outputDirectory.mkdir();
        ex.execute(sa, outputDirectory.toPath());

        File[] outputFiles = outputDirectory.listFiles();
        LOG.info("Output Files: " + Arrays.toString(outputFiles));
        if (outputFiles != null && outputFiles.length > 0) {
            results().put(outputFiles);
        }
    }

    private List<Map<String, Object>> getCustomMetrics() throws Exception {
        Object obj = parameter().get("customMetrics", null);
        if (obj instanceof JSONArray arr) {
            int length = arr.length();
            List<Map<String, Object>> customMetrics = new ArrayList<>(length);
            Set<String> customMetricNames = new HashSet<>();
            for (int i = 0; i < length; ++i) {
                Map<String, Object> map = convertToMap(arr.getJSONObject(i));
                if (verifyCustomMetricMap(map) && customMetricNames.add((String) map.get("name"))) {
                    customMetrics.add(map);
                }
            }
            return customMetrics;
        } else {
            return new ArrayList<>();
        }
    }
    
    private Map<String, Object> convertToMap(JSONObject obj) throws JSONException {
        Iterator<String> iter = obj.keys();
        Map<String, Object> map = new HashMap<>();
        while(iter.hasNext()) {
            String key = iter.next();
            Object value = obj.get(key);
            map.put(key, value);
        }
        
        return map;
    }

    private boolean verifyCustomMetricMap(Map map) {
        if (!map.containsKey("name")
                || !map.containsKey("value")
                || !map.containsKey("positiveBest")) {
            return false;
        }

        if (!(map.get("name") instanceof String)
                || !(map.get("value") instanceof String)
                || !(map.get("positiveBest") instanceof Boolean)) {
            return false;
        }

        return true;
    }
}