import java.util.logging.Logger; import java.util.logging.Level; import java.util.List; import java.util.ArrayList; import java.util.Arrays; import java.time.Instant; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileNotFoundException; import java.nio.file.StandardOpenOption; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.*;// Timestamp in cut-filename import java.io.ByteArrayOutputStream; // for SODA direct streaming doSubimgStream import vo.parameter.*; class SodaImpl implements Soda { static final Logger LOGGER = Logger.getLogger("SodaImpl"); private Settings settings = null; private Subsurvey[] subsurveys = null; public SodaImpl() { LOGGER.info("trace SodaImpl()"); this.settings = Settings.getInstance(); this.subsurveys = null; } public SodaImpl(Settings settings) { LOGGER.info("trace SodaImpl(settings)"); this.settings = settings; this.subsurveys = null; } public SodaImpl(Settings settings, Subsurvey[] subsurveys) { LOGGER.info("trace SodaImpl(settings)"); this.settings = settings; this.subsurveys = subsurveys; } public void doStream(String relPathname, int hdunum, Pos pos, Band band, Time time, Pol pol, String pixels, OutputStream outputStream) throws IOException, InterruptedException { Instant start = Instant.now(); boolean has_overlap = false; boolean pixels_valid = (pixels != null); String boundsString = ""; String absPathname = settings.fitsPaths.surveys() + "/" + relPathname; if( !pixels_valid ) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); if(bos == null) throw new AssertionError("byte output stream for bounds was not created, is null"); JsonEncoder jReq = new JsonEncoder(); jReq.add(pos); jReq.add(band); jReq.add(time); jReq.add(pol); String coordString = jReq.toString(); LOGGER.info("coordString: " + coordString); /* calc bounds */ String[] cmdBounds = new String[4]; cmdBounds[0] = "/usr/local/bin/vlkb"; cmdBounds[1] = "overlap"; cmdBounds[2] = absPathname; cmdBounds[3] = coordString; ExecCmd execBounds = new ExecCmd(); execBounds.doRun(bos, cmdBounds); LOGGER.info("execBounds exitValue: " + execBounds.exitValue); boolean has_result = (execBounds.exitValue == 0); if(has_result) { boundsString = new String(bos.toByteArray()); boundsString = replaceWithGrid(boundsString, pos, band, time, pol); LOGGER.info("boundsString(with GRID): " + boundsString); has_overlap = !((boundsString != null) && boundsString.trim().isEmpty()); if( !has_overlap ) { throw new IllegalArgumentException( "region in file does not overlap with region defined by SODA parameters"); } } bos.close(); Instant boundsDone = Instant.now(); LOGGER.info("EXECTIME boundsDone: " + Duration.between(start, boundsDone)); } if(has_overlap || pixels_valid) { /* cutout -> outputStream */ String pixFilterString = pixels_valid ? pixels : boundsString; String[] cmdCut = new String[6]; cmdCut[0] = "/usr/local/bin/vlkb"; cmdCut[1] = "imcopy"; cmdCut[2] = absPathname; cmdCut[3] = String.valueOf(hdunum-1); cmdCut[4] = pixFilterString; cmdCut[5] = settings.fitsPaths.cutouts(); if(outputStream == null) LOGGER.info("supplied outputStream for cut-file is null"); ExecCmd execCut = new ExecCmd(); execCut.doRun(outputStream, cmdCut); LOGGER.info("execCut exitValue: " + execCut.exitValue); boolean cut_successful = (execCut.exitValue == 0); if(!cut_successful) { throw new IllegalArgumentException("cut by pixels not completed for pixels : " + pixFilterString); } Instant cutDone = Instant.now(); LOGGER.info("EXECTIME cutDone: " + Duration.between(start, cutDone)); } else { throw new IllegalArgumentException( "overlap computation could not be completed with the given arguments"); } } private String genRegionForVlkbOverlapCmd(Pos pos, Band band) { String region = ""; if(pos != null) { String skySystem = pos.system.name(); if(pos.shape.equals("CIRCLE")) { double l = pos.circle.lon; double b = pos.circle.lat; double r = pos.circle.radius; region = region + "skysystem=" + skySystem + "&l=" + String.valueOf(l) + "&b=" + String.valueOf(b) + "&r=" + String.valueOf(r); } else if(pos.shape.equals("RANGE")) { double l = (pos.range.lon1 + pos.range.lon2)/2.0; double b = (pos.range.lat1 + pos.range.lat2)/2.0; double dl = (pos.range.lon2 - pos.range.lon1); double db = (pos.range.lat2 - pos.range.lat1); region = region + "skysystem=" + skySystem + "&l=" + String.valueOf(l) + "&b=" + String.valueOf(b) + "&dl=" + String.valueOf(dl) + "&db=" + String.valueOf(db); } else { LOGGER.info("FIXME here Exception: POLYGON not supported or pos.shape invalid: " + pos.shape); } } if(band != null) { String specSystem = band.system.name(); double vl = band.getMin(); double vu = band.getMax(); region =region + "specsystem=" + specSystem + "&vl=" + String.valueOf(vl) + "&vu=" + String.valueOf(vu); } return region; } private String replaceWithGrid(String wcsBounds, Pos pos, Band band, Time time, Pol pol) { // remove end-of-line (was added by vlkb_ast.cpp: cout << ... << endl) String lineSeparator = System.lineSeparator(); wcsBounds = wcsBounds.replace(lineSeparator, ""); LOGGER.info("BOUNDS: " + wcsBounds); // replace in wcsBounds those bounds where pos,band,time or pol has system=GRID String[] substr = wcsBounds.split("(?=AXES)", 2); for(String ss : substr) LOGGER.info("boundsResult: " + ss); String boundsString = substr[0]; boolean noOverlap = ((boundsString != null) && boundsString.trim().isEmpty()); if(noOverlap) { boundsString = ""; // no overlap } else { String axesTypes = ""; if(substr.length > 1) { axesTypes = substr[1].replace("AXES"," ").trim(); LOGGER.info("AXES TYPES: " + axesTypes); String[] bnds = normalize(boundsString); String[] types = normalize(axesTypes); // assert: bnds.length == types.length LOGGER.info("boundsCount: " + bnds.length + " typesCount: " + types.length); if(bnds.length == types.length) boundsString = replaceBounds(bnds, types, pos, band); } } return boundsString; } private String replaceBounds(String[] bnds, String[] types, Pos pos, Band band) { int ix; for(ix=0; ix<bnds.length; ix++) { if( types[ix].equals("LON") && ((pos != null) && (pos.system == Pos.System.GRID)) ) { bnds[ix] = pos.lonBoundsString(); } else if(types[ix].equals("LAT") && ((pos != null) && (pos.system == Pos.System.GRID))) { bnds[ix] = pos.latBoundsString(); } else if(types[ix].equals("BAND") && ((band != null) && (band.system == Band.System.GRID))) { bnds[ix] = band.boundsString(); } } LOGGER.info("replaced: " + String.join(" ", bnds)) ; return "[" + String.join(" ", bnds) + "]"; } // MAKE SURE vlkb overlap returns space delimited bounds: [ a:b c:d ] // normalize: strip [,] if any, and split into array by space private String[] normalize(String spaceStr) { String other = spaceStr.replace("[","").replace("]",""); LOGGER.info("normalize: " + other); return other.split("\\s+"); } }