001package com.astrolabsoftware.FinkBrowser.Januser;
002
003import com.Lomikel.HBaser.HBaseClient;
004import com.Lomikel.Utils.LomikelException;
005import com.astrolabsoftware.FinkBrowser.FinkPortalClient.FPC;
006import com.astrolabsoftware.FinkBrowser.HBaser.Clusteriser.ClusterFinder;
007
008// org.json
009import org.json.JSONArray;
010import org.json.JSONObject;
011
012// Java
013import java.util.Arrays;
014import java.util.Set;
015import java.util.TreeSet;
016import java.util.Map;
017import java.util.TreeMap;
018import java.io.IOException;
019
020// Log4J
021import org.apache.logging.log4j.Logger;
022import org.apache.logging.log4j.LogManager;
023
024/** <code>FeaturesClassifier</code> classifies sources according to
025  * HBase <tt>lc_features_*</tt> field.
026  * @opt attributes
027  * @opt operations
028  * @opt types
029  * @opt visibility
030  * @author <a href="mailto:Julius.Hrivnac@cern.ch">J.Hrivnac</a> */
031// BUG: jd should be String or long
032public class LightCurvesClassifier implements Classifier {
033  
034  @Override
035  public void classify(FinkGremlinRecipies recipies,
036                       String              oid,
037                       boolean             enhance,
038                       String              columns) throws LomikelException {
039    double jd;
040    String cl;
041    Map<String, String> value;
042    String[] featuresS;
043    double[] featuresD;
044    String fg;
045    String fr;
046    Map<String, Set<Double>> classes; // cl -> [jd]
047    Set<Double> jds;
048    String key;
049    Set<Double> val;
050    double weight;
051    double totalWeight;
052    Map<String, Map<String, String>> alerts = recipies.fhclient().scan(null,
053                                                                       "key:key:" + oid + ":prefix",
054                                                                       "i:jd,d:lc_features_g,d:lc_features_r",
055                                                                       0,
056                                                                       0,
057                                                                       false,
058                                                                       false);
059    classes = new TreeMap<>();
060    // get all alerts (jd) and their classses
061    for (Map.Entry<String, Map<String, String>> entry : alerts.entrySet()) {
062      value = entry.getValue();
063      jd = Double.parseDouble(value.get("i:jd"));
064      if (value.containsKey("d:lc_features_g") &&
065          value.containsKey("d:lc_features_r")) {
066        fg = value.get("d:lc_features_g").replaceFirst("\\[", "").replaceAll("]$", "");
067        fr = value.get("d:lc_features_r").replaceFirst("\\[", "").replaceAll("]$", "");
068        featuresS = (fg + "," + fr).replaceAll("null", "0.0").
069                                    replaceAll("NaN", "0.0").
070                                    split(",");
071        featuresD = Arrays.stream(featuresS).
072                           mapToDouble(Double::parseDouble).
073                           toArray();
074        cl = String.valueOf(finder().transformAndPredict(featuresD));                  
075        if (!cl.equals("-1")) {
076          if (classes.containsKey(cl)) {
077            jds = classes.get(cl);
078            jds.add(jd);
079            }
080          else {
081            jds = new TreeSet<Double>();
082            jds.add(jd);
083            classes.put(cl, jds);
084            }
085          }
086        }
087      }
088    totalWeight = 0;
089    for (Map.Entry<String, Set<Double>> cls : classes.entrySet()) {
090      totalWeight += cls.getValue().size();
091      }
092    for (Map.Entry<String, Set<Double>> cls : classes.entrySet()) {
093      key = "FC-" + cls.getKey();
094      val = cls.getValue();
095      weight = val.size() / totalWeight;
096      recipies.registerSourcesOfInterest(Classifiers.FEATURES, key, oid, weight, val, enhance, columns);
097      }
098    }
099    
100  /** Give {@link ClusterFinder} to current database. Singleton.
101    * @return The corresponding {@link ClusterFinder}. 
102    * @throws LomikelExceltion If {@link ClusterFinder} cannot be created. */
103  private ClusterFinder finder() throws LomikelException {
104    if (_finder == null) {
105      if (_dirName == null) {
106        _dirName = "/tmp";
107        }
108      try {
109        _finder = new ClusterFinder(_dirName + "/scaler_params.json",
110                                    _dirName + "/pca_params.json",
111                                    _dirName + "/cluster_centers.json");
112        }
113      catch (IOException e) {
114        throw new LomikelException("Cannot create Cluster Finder", e);
115        }
116      }
117    return _finder;
118    }
119    
120  /** Set the directory for model json files
121    * <tt>scaler_params.json, pca_params.json, cluster_centers.json</tt>.
122    * If not set, <tt>/tmp</tt> will be used.
123    * @param dirName The directory for model json files. */
124  public void setModelDirectory(String dirName) {
125    _dirName = dirName;
126    }
127  
128  private static ClusterFinder _finder;
129  
130  private static String _dirName;
131
132  /** Logging . */
133  private static Logger log = LogManager.getLogger(LightCurvesClassifier.class);
134  
135  }
136           
137