#!/bin/shset-eu
select_wget(){ifcommand-vwget1>/dev/null2>&1;thenechowget1
elifcommand-vwget>/dev/null2>&1&&!wget--version2>&1|grep-q'Wget2';thenechowget
elseecho'Error: GNU Wget 1.x (wget or wget1) is required.'>&2exit1fi}["$#"-eq5]||{echo"Usage: $0 YYYY MM DD HH MN">&2;exit1;}YYYY=$1;MM=$2;DD=$3;HH=$4;MN=$5case"$YYYY"in[0-9][0-9][0-9][0-9]);;*)echo'YYYY must be four digits.'>&2;exit1;;esaccase"$MM"in0[1-9]|1[0-2]);;*)echo'MM must be 01-12.'>&2;exit1;;esaccase"$DD"in0[1-9]|[12][0-9]|3[01]);;*)echo'DD must be 01-31.'>&2;exit1;;esaccase"$HH"in[01][0-9]|2[0-3]);;*)echo'HH must be 00-23.'>&2;exit1;;esaccase"$MN"in00|10|20|30|40|50);;*)echo'MN must be one of 00,10,20,30,40,50.'>&2;exit1;;esacDAY="${YYYY}${MM}${DD}";TIME="${DAY}${HH}${MN}";YYYYMM="${YYYY}${MM}"EXPECTED=30262084WGET=$(select_wget)BASE=${AMATERASS_JP_BASE:-ftp://amaterass.cr.chiba-u.ac.jp/quasi-realtime/himawari829/archived/JP}DEST=data/sample;DIR="$BASE/$YYYYMM/$DAY";mkdir-p"$DEST"
file_is_complete(){FILE=$1;[-f"$FILE"]||return1;SIZE=$(wc-c<"$FILE"|tr-d' ');["$SIZE"-eq"$EXPECTED"];}DECOMP_PID=;DECOMP_NAME=;DECOMP_BZ2=
cleanup_pending(){[-n"$DECOMP_PID"]||return0;kill"$DECOMP_PID"2>/dev/null||true;wait"$DECOMP_PID"2>/dev/null||true;rm-f"$DEST/$DECOMP_NAME""$DEST/$DECOMP_BZ2";DECOMP_PID=;DECOMP_NAME=;DECOMP_BZ2=;}trap'cleanup_pending'0trap'cleanup_pending; exit 1'1215
finish_decompress(){[-n"$DECOMP_PID"]||return0if!wait"$DECOMP_PID";thenrm-f"$DEST/$DECOMP_NAME""$DEST/$DECOMP_BZ2";echo"Decompression failed: $DECOMP_BZ2">&2;DECOMP_PID=;return1;fiif!file_is_complete"$DEST/$DECOMP_NAME";thenSIZE=$(wc-c<"$DEST/$DECOMP_NAME"2>/dev/null|tr-d' '||echo0);rm-f"$DEST/$DECOMP_NAME""$DEST/$DECOMP_BZ2";echo"Unexpected file size: $DEST/$DECOMP_NAME ($SIZE bytes)">&2;DECOMP_PID=;return1;firm-f"$DEST/$DECOMP_BZ2";DECOMP_PID=;DECOMP_NAME=;DECOMP_BZ2=}forTYPEindwn.sw.flx.sfc.msm.1km.bingrd.time.mjd.hms.msm.1km.bin
doNAME="$TIME.$TYPE";BZ2="$NAME.bz2"iffile_is_complete"$DEST/$NAME";thenrm-f"$DEST/$BZ2";echo"Already exists: $DEST/$NAME";continue;fiif[-e"$DEST/$NAME"];thenSIZE=$(wc-c<"$DEST/$NAME"|tr-d' ');echo"Removing incomplete file: $NAME ($SIZE bytes)";rm-f"$DEST/$NAME";fi(cd"$DEST"&&"$WGET"-c"$DIR/$BZ2")finish_decompress||exit1rm-f"$DEST/$NAME"(cd"$DEST"&&bzip2-d"$BZ2")&DECOMP_PID=$!;DECOMP_NAME=$NAME;DECOMP_BZ2=$BZ2done
finish_decompress||exit1trap-01215echo"Sample solar/TIME ready: $TIME"
#!/bin/shset-eu
["$#"-eq5]||{echo"Usage: $0 file max min color_div unit">&2;exit1;}FILE=$1MAX=$2MIN=$3DIV=$4UNIT=$5[-f"$FILE"]||{echo"Missing: $FILE">&2;exit1;}[-ftmap/tmap.class]||{echo'Tmap is not compiled. Run: cd tmap && javac *.java'>&2;exit1;}GRID="$FILE.grid.txt"if[-f"$GRID"];thengetv(){sed-n"s/^$1=//p""$GRID"|head-n1;}WIDTH=$(getvwidth)HEIGHT=$(getvheight)NORTH=$(getvnorth)LAT_SPAN=$(getvlat_span)WEST=$(getvwest)LON_SPAN=$(getvlon_span)LAT_DIV=$(getvlat_div)LON_DIV=$(getvlon_div):"${LAT_DIV:=6}""${LON_DIV:=6}"elseSIZE=$(wc-c<"$FILE"|tr-d' ')if["$SIZE"-ne30262084];thenecho"No grid metadata for non-standard file: $FILE">&2exit1fiWIDTH=3001HEIGHT=2521NORTH=47.6
LAT_SPAN=25.2
LAT_DIV=5WEST=120LON_SPAN=30LON_DIV=6fi(cdtmap
javatmap"../$FILE""$MAX""$MIN""$DIV""$UNIT"autopng\"$NORTH""$LAT_SPAN""$LAT_DIV""$WEST""$LON_SPAN""$LON_DIV"\"$WIDTH""$HEIGHT")
#!/bin/shset-eu
select_wget(){ifcommand-vwget1>/dev/null2>&1;thenechowget1;elifcommand-vwget>/dev/null2>&1&&!wget--version2>&1|grep-q'Wget2';thenechowget;elseecho'Error: GNU Wget 1.x (wget or wget1) is required.'>&2;exit1;fi;}["$#"-eq7]||["$#"-eq8]||{echo"Usage: $0 YYYY MM DD START_HH START_MN END_HH END_MN [DECOMP_JOBS]">&2;exit1;}YYYY=$1;MM=$2;DD=$3;START_HH=$4;START_MN=$5;END_HH=$6;END_MN=$7;JOBS=${8:-4};DAY="${YYYY}${MM}${DD}"case"$JOBS"in''|*[!0-9]*)echo'DECOMP_JOBS must be a positive integer.'>&2;exit1;;esacCHECK=$(date-u-d"${YYYY}-${MM}-${DD}"+%Y%m%d2>/dev/null||true);["$CHECK"="$DAY"]||{echo'Invalid calendar date.'>&2;exit1;}START=$(date-u-d"${YYYY}-${MM}-${DD}${START_HH}:${START_MN} +0900"+%s);END=$(date-u-d"${YYYY}-${MM}-${DD}${END_HH}:${END_MN} +0900"+%s);["$END"-ge"$START"]||{echo'End time must not be earlier than start time.'>&2;exit1;}EXPECTED=30262084;WGET=$(select_wget);BASE=${AMATERASS_JP_BASE:-ftp://amaterass.cr.chiba-u.ac.jp/quasi-realtime/himawari829/archived/JP};DEST="data/animation/$DAY";LIST="$DEST/timestamps.txt";mkdir-p"$DEST";:>"$LIST"
file_is_complete(){FILE=$1;[-f"$FILE"]||return1;SIZE=$(wc-c<"$FILE"|tr-d' ');["$SIZE"-eq"$EXPECTED"];}QUEUE=;RUNNING=0
cleanup_queue(){forJOBin$QUEUE;doPID=${JOB%%|*};REST=${JOB#*|};NAME=${REST%%|*};BZ2=${REST#*|};kill"$PID"2>/dev/null||true;wait"$PID"2>/dev/null||true;rm-f"$DEST/$NAME""$DEST/$BZ2";done;QUEUE=;RUNNING=0;}trap'cleanup_queue'0;trap'cleanup_queue; exit 1'1215
finish_oldest(){["$RUNNING"-gt0]||return0;set--$QUEUE;JOB=$1;shift;QUEUE="$*";PID=${JOB%%|*};REST=${JOB#*|};NAME=${REST%%|*};BZ2=${REST#*|};if!wait"$PID";thenrm-f"$DEST/$NAME""$DEST/$BZ2";echo"Decompression failed: $BZ2">&2;exit1;fi;if!file_is_complete"$DEST/$NAME";thenSIZE=$(wc-c<"$DEST/$NAME"2>/dev/null|tr-d' '||echo0);rm-f"$DEST/$NAME""$DEST/$BZ2";echo"Unexpected file size: $DEST/$NAME ($SIZE bytes)">&2;exit1;fi;rm-f"$DEST/$BZ2";echo"Ready: $NAME";RUNNING=$((RUNNING-1));}
start_decompress(){NAME=$1;BZ2=$2;rm-f"$DEST/$NAME";(cd"$DEST"&&bzip2-d"$BZ2")&PID=$!;QUEUE="${QUEUE}${QUEUE:+ }${PID}|${NAME}|${BZ2}";RUNNING=$((RUNNING+1));["$RUNNING"-lt"$JOBS"]||finish_oldest;}T=$START;TOTAL=0while["$T"-le"$END"];doTIME=$(date-u-d"@$T"+%Y%m%d%H%M);printf'%s\n'"$TIME">>"$LIST";TOTAL=$((TOTAL+1));YYYYMM=$(printf'%s'"$TIME"|cut-c1-6);YYYYMMDD=$(printf'%s'"$TIME"|cut-c1-8);NAME="$TIME.dwn.sw.flx.sfc.msm.1km.bin";BZ2="$NAME.bz2"iffile_is_complete"$DEST/$NAME";thenrm-f"$DEST/$BZ2";elseif[-e"$DEST/$NAME"];thenSIZE=$(wc-c<"$DEST/$NAME"|tr-d' ');echo"Removing incomplete file: $NAME ($SIZE bytes)";rm-f"$DEST/$NAME";fi;URL="$BASE/$YYYYMM/$YYYYMMDD/$BZ2";if(cd"$DEST"&&"$WGET"-q-c"$URL");thenstart_decompress"$NAME""$BZ2";elserm-f"$DEST/$BZ2";fi;fiT=$((T+600))donewhile["$RUNNING"-gt0];dofinish_oldest;donetrap-01215READY=$(whileIFS=read-rTIME;dofile_is_complete"$DEST/$TIME.dwn.sw.flx.sfc.msm.1km.bin"&&echo1;done<"$LIST"|wc-l|tr-d' ')["$READY"-gt1]||{echo'Not enough frames were downloaded.'>&2;exit1;}echo"Available frames: $READY / $TOTAL (max $JOBS decompression jobs)";echo"Timestamp list: $LIST"
render_animation.sh Shell
何をしている? 取得した各時刻のbinをTmapで1枚ずつPNGへ変換します。
#!/bin/shset-eu
["$#"-eq7]||{echo"Usage: $0 YYYY MM DD MAX MIN COLOR_DIV UNIT">&2;exit1;}YYYY=$1;MM=$2;DD=$3;MAX=$4;MIN=$5;DIV=$6;UNIT=$7DAY="${YYYY}${MM}${DD}"DEST="data/animation/$DAY"LIST="$DEST/timestamps.txt"[-f"$LIST"]||{echo"Missing: $LIST">&2;exit1;}COUNT=0whileIFS=read-rTIME;do[-n"$TIME"]||continueFILE="$DEST/$TIME.dwn.sw.flx.sfc.msm.1km.bin"[-f"$FILE"]||continue./draw_map.sh"$FILE""$MAX""$MIN""$DIV""$UNIT"COUNT=$((COUNT+1))done<"$LIST"["$COUNT"-gt1]||{echo'Not enough frames to render.'>&2;exit1;}echo"PNG frames ready: $COUNT"
#!/bin/shset-eu
["$#"-eq5]||{echo"Usage: $0 YYYY MM DD WIDTH DELAY">&2;exit1;}YYYY=$1;MM=$2;DD=$3;WIDTH=$4;DELAY=$5DAY="${YYYY}${MM}${DD}"DEST="data/animation/$DAY"LIST="$DEST/timestamps.txt"OUT="amaterass_${DAY}.gif"[-f"$LIST"]||{echo"Missing: $LIST">&2;exit1;}case"$WIDTH"in''|*[!0-9]*)echo'WIDTH must be a positive integer.'>&2;exit1;;esaccase"$DELAY"in''|*[!0-9]*)echo'DELAY must be a non-negative integer.'>&2;exit1;;esac["$WIDTH"-gt0]||{echo'WIDTH must be greater than zero.'>&2;exit1;}set--
whileIFS=read-rTIME;do[-n"$TIME"]||continuePNG="$DEST/$TIME.dwn.sw.flx.sfc.msm.1km.bin.png"[-f"$PNG"]||continueset--"$@""$PNG"done<"$LIST"["$#"-gt1]||{echo'Not enough PNG files for an animation.'>&2;exit1;}ifcommand-vmagick>/dev/null2>&1;thenmagick-delay"$DELAY"-loop0"$@"-resize"${WIDTH}x""$OUT"elifcommand-vconvert>/dev/null2>&1;thenconvert-delay"$DELAY"-loop0"$@"-resize"${WIDTH}x""$OUT"elseecho'ImageMagick is required.'>&2exit1fiecho"Created: $OUT ($# frames, ${WIDTH} px wide)"
importjava.io.*;importjava.nio.*;importjava.nio.channels.*;importjava.nio.file.*;importjava.util.*;finalclassFloatGrid{staticlongfloatCount(Pathp)throwsIOException{longsize=Files.size(p);if((size&3L)!=0)thrownewIOException("File size is not a multiple of 4: "+p);returnsize/4L;}staticvoidrequireSameSize(Path...ps)throwsIOException{longs=Files.size(ps[0]);for(Pathp:ps)if(Files.size(p)!=s)thrownewIOException("Grid size mismatch: "+p);}staticMappedByteBuffermap(Pathp)throwsIOException{try(FileChannelch=FileChannel.open(p,StandardOpenOption.READ)){MappedByteBufferb=ch.map(FileChannel.MapMode.READ_ONLY,0,ch.size());b.order(ByteOrder.BIG_ENDIAN);returnb;}}staticfloatreadAt(Pathp,longindex)throwsIOException{try(RandomAccessFileraf=newRandomAccessFile(p.toFile(),"r")){raf.seek(index*4L);returnraf.readFloat();}}staticvoidwriteFloats(Pathout,float[]data)throwsIOException{Files.createDirectories(out.toAbsolutePath().getParent());try(DataOutputStreamdos=newDataOutputStream(newBufferedOutputStream(Files.newOutputStream(out)))){for(floatv:data)dos.writeFloat(v);}}staticPathgridMetaPath(Pathbin){returnPaths.get(bin.toString()+".grid.txt");}staticbooleanhasGridMeta(Pathbin){returnFiles.isRegularFile(gridMetaPath(bin));}staticPropertiesreadGridMeta(Pathbin)throwsIOException{Pathp=gridMetaPath(bin);Propertiesprops=newProperties();try(Readerr=Files.newBufferedReader(p)){props.load(r);}returnprops;}staticvoidcopyGridMeta(PathfromBin,PathtoBin)throwsIOException{Pathfrom=gridMetaPath(fromBin);Pathto=gridMetaPath(toBin);if(Files.isRegularFile(from)){Files.copy(from,to,StandardCopyOption.REPLACE_EXISTING);}else{Files.deleteIfExists(to);}}staticbooleansameGridMeta(Patha,Pathb)throwsIOException{booleanah=hasGridMeta(a);booleanbh=hasGridMeta(b);if(!ah&&!bh)returntrue;if(ah!=bh)returnfalse;returnreadGridMeta(a).equals(readGridMeta(b));}}
importjava.nio.*;importjava.nio.file.*;importjava.time.*;importjava.time.format.*;publicclasspixelinfo{publicstaticvoidmain(String[]args)throwsException{if(args.length!=6){System.err.println("Usage: pixelinfo solar lat lng time target_lat target_lon");System.exit(1);}Pathsolar=Paths.get(args[0]),latf=Paths.get(args[1]),lngf=Paths.get(args[2]),timef=Paths.get(args[3]);doubletargetLat=Double.parseDouble(args[4]);doubletargetLon=Double.parseDouble(args[5]);FloatGrid.requireSameSize(solar,latf,lngf,timef);longn=FloatGrid.floatCount(solar);if(n>Integer.MAX_VALUE)thrownewIllegalArgumentException("Grid too large");MappedByteBufferlat=FloatGrid.map(latf);MappedByteBufferlng=FloatGrid.map(lngf);doublebest=Double.POSITIVE_INFINITY;intbestIndex=-1;floatbestLat=Float.NaN,bestLon=Float.NaN;for(inti=0;i<(int)n;i++){floatla=lat.getFloat(i*4);floatlo=lng.getFloat(i*4);if(!Float.isFinite(la)||!Float.isFinite(lo))continue;doubledlat=la-targetLat;doubledlon=(lo-targetLon)*Math.cos(Math.toRadians(targetLat));doubled2=dlat*dlat+dlon*dlon;if(d2<best){best=d2;bestIndex=i;bestLat=la;bestLon=lo;}}if(bestIndex<0)thrownewIllegalStateException("No valid coordinate found");floatflux=FloatGrid.readAt(solar,bestIndex);floatdays=FloatGrid.readAt(timef,bestIndex);Stringname=solar.getFileName().toString();if(name.length()<8)thrownewIllegalArgumentException("Filename must begin with YYYYMMDD");LocalDatedate=LocalDate.parse(name.substring(0,8),DateTimeFormatter.BASIC_ISO_DATE);longmillis=Math.round(days*86400.0*1000.0);Instantinstant=date.atStartOfDay(ZoneOffset.UTC).toInstant().plusMillis(millis);DateTimeFormatterfmt=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS 'UTC'").withZone(ZoneOffset.UTC);intnx=3001;introw=bestIndex/nx;intcol=bestIndex%nx;System.out.printf("pixel : row=%d column=%d (0-based)%n",row,col);System.out.printf("latitude : %.6f deg%n",bestLat);System.out.printf("longitude : %.6f deg%n",bestLon);System.out.printf("solar flux : %.3f W/m^2%n",flux);System.out.printf("actual UTC : %s%n",fmt.format(instant));}}
#!/bin/shset-eu
select_wget(){ifcommand-vwget1>/dev/null2>&1;thenechowget1
elifcommand-vwget>/dev/null2>&1&&!wget--version2>&1|grep-q'Wget2';thenechowget
elseecho'Error: GNU Wget 1.x (wget or wget1) is required.'>&2;exit1fi}["$#"-eq3]||["$#"-eq4]||{echo"Usage: $0 YYYY MM DD [DECOMP_JOBS]">&2;exit1;}YYYY=$1;MM=$2;DD=$3;JOBS=${4:-4}case"$JOBS"in''|*[!0-9]*)echo'DECOMP_JOBS must be a positive integer.'>&2;exit1;;esac["$JOBS"-ge1]||{echo'DECOMP_JOBS must be at least 1.'>&2;exit1;}DAY="${YYYY}${MM}${DD}";YYYYMM="${YYYY}${MM}";EXPECTED=30262084WGET=$(select_wget);BASE=${AMATERASS_JP_BASE:-ftp://amaterass.cr.chiba-u.ac.jp/quasi-realtime/himawari829/archived/JP};DEST="data/daily_raw/$DAY"
mkdir-p"$DEST"
file_is_complete(){FILE=$1;[-f"$FILE"]||return1;SIZE=$(wc-c<"$FILE"|tr-d' ');["$SIZE"-eq"$EXPECTED"];}QUEUE=;RUNNING=0
cleanup_queue(){forJOBin$QUEUE;doPID=${JOB%%|*};REST=${JOB#*|};NAME=${REST%%|*};BZ2=${REST#*|};kill"$PID"2>/dev/null||true;wait"$PID"2>/dev/null||true;rm-f"$DEST/$NAME""$DEST/$BZ2";done;QUEUE=;RUNNING=0;}trap'cleanup_queue'0trap'cleanup_queue; exit 1'1215
finish_oldest(){["$RUNNING"-gt0]||return0set--$QUEUE;JOB=$1;shift;QUEUE="$*"PID=${JOB%%|*};REST=${JOB#*|};NAME=${REST%%|*};BZ2=${REST#*|}if!wait"$PID";thenrm-f"$DEST/$NAME""$DEST/$BZ2";echo"Decompression failed: $BZ2">&2;exit1;fiif!file_is_complete"$DEST/$NAME";thenSIZE=$(wc-c<"$DEST/$NAME"2>/dev/null|tr-d' '||echo0);rm-f"$DEST/$NAME""$DEST/$BZ2";echo"Unexpected file size: $DEST/$NAME ($SIZE bytes)">&2;exit1;firm-f"$DEST/$BZ2";echo"Ready: $NAME";RUNNING=$((RUNNING-1))}
start_decompress(){NAME=$1;BZ2=$2;rm-f"$DEST/$NAME";(cd"$DEST"&&bzip2-d"$BZ2")&PID=$!;QUEUE="${QUEUE}${QUEUE:+ }${PID}|${NAME}|${BZ2}";RUNNING=$((RUNNING+1));["$RUNNING"-lt"$JOBS"]||finish_oldest;}forHHin000102030405060708091011121314151617181920212223;doforMNin001020304050;doTIME="$DAY$HH$MN";NAME="$TIME.dwn.sw.flx.sfc.msm.1km.bin";BZ2="$NAME.bz2"iffile_is_complete"$DEST/$NAME";thenrm-f"$DEST/$BZ2";continue;fiif[-e"$DEST/$NAME"];thenSIZE=$(wc-c<"$DEST/$NAME"|tr-d' ');echo"Removing incomplete file: $NAME ($SIZE bytes)";rm-f"$DEST/$NAME";fiURL="$BASE/$YYYYMM/$DAY/$BZ2"if(cd"$DEST"&&"$WGET"-q-c"$URL");thenstart_decompress"$NAME""$BZ2";elserm-f"$DEST/$BZ2";fidonedonewhile["$RUNNING"-gt0];dofinish_oldest;donetrap-01215COUNT=$(find"$DEST"-maxdepth1-typef-name"$DAY*.dwn.sw.flx.sfc.msm.1km.bin"-size30262084c|wc-l|tr-d' ')["$COUNT"-gt0]||{echo"No solar-radiation files were downloaded for $DAY. Check the date or network connection.">&2;exit1;}echo"Ready: $DAY ($COUNT files, max $JOBS decompression jobs)"
importjava.io.*;importjava.nio.*;importjava.nio.file.*;importjava.util.*;importjava.util.stream.*;publicclassdailymean{publicstaticvoidmain(String[]args)throwsException{if(args.length!=2){System.err.println("Usage: dailymean input_day_directory output.bin");System.exit(1);}Pathdir=Paths.get(args[0]);Pathout=Paths.get(args[1]);if(!Files.isDirectory(dir))thrownewIOException("Missing directory: "+dir);List<Path>all;try(Stream<Path>s=Files.list(dir)){all=s.filter(p->p.getFileName().toString().matches("\\d{12}\\.dwn\\.sw\\.flx\\.sfc\\.msm\\.1km\\.bin")).sorted().collect(Collectors.toList());}if(all.isEmpty())thrownewIOException("No 10-minute files in "+dir);longnLong=FloatGrid.floatCount(all.get(0));if(nLong>Integer.MAX_VALUE)thrownewIOException("Grid too large");intn=(int)nLong;for(Pathp:all)if(FloatGrid.floatCount(p)!=nLong)thrownewIOException("Size mismatch: "+p);float[]daily=newfloat[n];float[]hour=newfloat[n];for(inthh=0;hh<24;hh++){finalStringhourKey=String.format("%02d",hh);List<Path>files=all.stream().filter(p->{Stringx=p.getFileName().toString();returnx.substring(8,10).equals(hourKey);}).collect(Collectors.toList());if(files.isEmpty()){// AMATERASS solar-radiation files are not produced during fully dark hours.// For a 24-hour daily mean, those hours contribute 0 W/m^2.System.out.printf("hour %02d: 0 files -> 0 W/m^2%n",hh);continue;}Arrays.fill(hour,0f);for(Pathp:files){MappedByteBufferb=FloatGrid.map(p);for(inti=0;i<n;i++)hour[i]+=b.getFloat(i*4);}floatinv=1.0f/files.size();for(inti=0;i<n;i++)daily[i]+=hour[i]*inv;System.out.printf("hour %02d: %d files%n",hh,files.size());}for(inti=0;i<n;i++)daily[i]/=24.0f;FloatGrid.writeFloats(out,daily);System.out.println("Created: "+out);}}
#!/bin/shset-eu
select_wget(){ifcommand-vwget1>/dev/null2>&1;thenechowget1
elifcommand-vwget>/dev/null2>&1&&!wget--version2>&1|grep-q'Wget2';thenechowget
elseecho'Error: GNU Wget 1.x (wget or wget1) is required.'>&2exit1fi}["$#"-eq5]||{echo"Usage: $0 YYYY MM DD HH MN">&2;exit1;}YYYY=$1;MM=$2;DD=$3;HH=$4;MN=$5case"$YYYY"in[0-9][0-9][0-9][0-9]);;*)echo'YYYY must be four digits.'>&2;exit1;;esaccase"$MM"in0[1-9]|1[0-2]);;*)echo'MM must be 01-12.'>&2;exit1;;esaccase"$DD"in0[1-9]|[12][0-9]|3[01]);;*)echo'DD must be 01-31.'>&2;exit1;;esaccase"$HH"in[01][0-9]|2[0-3]);;*)echo'HH must be 00-23.'>&2;exit1;;esaccase"$MN"in00|10|20|30|40|50);;*)echo'MN must be one of 00,10,20,30,40,50.'>&2;exit1;;esacDAY="${YYYY}${MM}${DD}";TIME="${DAY}${HH}${MN}";YYYYMM="${YYYY}${MM}"EXPECTED=30262084WGET=$(select_wget)BASE=${AMATERASS_JP_BASE:-ftp://amaterass.cr.chiba-u.ac.jp/quasi-realtime/himawari829/archived/JP}DEST=data/crop_source;NAME="$TIME.dwn.sw.flx.sfc.msm.1km.bin";BZ2="$NAME.bz2";URL="$BASE/$YYYYMM/$DAY/$BZ2"
mkdir-p"$DEST"
file_is_complete(){FILE=$1;[-f"$FILE"]||return1;SIZE=$(wc-c<"$FILE"|tr-d' ');["$SIZE"-eq"$EXPECTED"];}iffile_is_complete"$DEST/$NAME";thenrm-f"$DEST/$BZ2"elseif[-e"$DEST/$NAME"];thenSIZE=$(wc-c<"$DEST/$NAME"|tr-d' ');echo"Removing incomplete file: $NAME ($SIZE bytes)";firm-f"$DEST/$NAME"(cd"$DEST"&&"$WGET"-c"$URL")(cd"$DEST"&&bzip2-d"$BZ2")fiif!file_is_complete"$DEST/$NAME";thenSIZE=$(wc-c<"$DEST/$NAME"2>/dev/null|tr-d' '||echo0);rm-f"$DEST/$NAME""$DEST/$BZ2";echo"Unexpected file size: $DEST/$NAME ($SIZE bytes)">&2;exit1;fi
rm-f"$DEST/$BZ2"echo"Ready: $DEST/$NAME"
#!/bin/shset-eu
["$#"-eq9]||{echo"Usage: $0 YYYY MM DD HH MN WEST EAST SOUTH NORTH">&2;exit1;}YYYY=$1;MM=$2;DD=$3;HH=$4;MN=$5;WEST=$6;EAST=$7;SOUTH=$8;NORTH=$9TIME="${YYYY}${MM}${DD}${HH}${MN}"SRC=analysis.msm1km/crop.java;CLS=analysis.msm1km/crop.class
[-f"$SRC"]||{echo'Missing crop.java. Extract analysis_msm1km.tar.gz first.'>&2;exit1;}if[!-f"$CLS"]||["$SRC"-nt"$CLS"]||[analysis.msm1km/FloatGrid.java-nt"$CLS"];thenjavacanalysis.msm1km/*.java;fiLAT=data/reference/standard_2521x3001.lat.msm.1km.bin
LNG=data/reference/standard_2521x3001.lng.msm.1km.bin
[-f"$LAT"]&&[-f"$LNG"]||{echo'LAT/LNG files are required.'>&2;exit1;}IN="data/crop_source/$TIME.dwn.sw.flx.sfc.msm.1km.bin"OUT="data/crop/$TIME.dwn.sw.flx.sfc.msm.1km.crop.bin"[-f"$IN"]||{echo"Missing: $IN">&2;exit1;}
mkdir-pdata/crop
java-cpanalysis.msm1kmcrop"$IN""$LAT""$LNG""$WEST""$EAST""$SOUTH""$NORTH""$OUT"
importjava.io.*;importjava.nio.*;importjava.nio.channels.*;importjava.nio.file.*;importjava.util.*;publicclasscrop{staticfinalintNX=3001;staticfinalintNY=2521;staticfinaldoubleRANGE_EPS=1.0e-5;publicstaticvoidmain(String[]args)throwsException{if(args.length!=8){System.err.println("Usage: crop input lat lng west east south north output");System.exit(1);}Pathin=Paths.get(args[0]),latf=Paths.get(args[1]),lngf=Paths.get(args[2]),out=Paths.get(args[7]);doublewest=Double.parseDouble(args[3]),east=Double.parseDouble(args[4]);doublesouth=Double.parseDouble(args[5]),north=Double.parseDouble(args[6]);// Never leave an old crop behind when the current request fails.Files.deleteIfExists(out);Files.deleteIfExists(Paths.get(out.toString()+".grid.txt"));FloatGrid.requireSameSize(in,latf,lngf);if(FloatGrid.floatCount(in)!=(long)NX*NY)thrownewIOException("Expected 2521x3001 msm.1km grid");if(!Double.isFinite(west)||!Double.isFinite(east)||!Double.isFinite(south)||!Double.isFinite(north)){failInvalidBounds(west,east,south,north,"All crop bounds must be finite numbers.");}if(west>=east||south>=north){failInvalidBounds(west,east,south,north,"WEST must be smaller than EAST, and SOUTH must be smaller than NORTH.");}MappedByteBufferlat=FloatGrid.map(latf);MappedByteBufferlng=FloatGrid.map(lngf);// Derive the available geographic domain from the coordinate grids.floatfirstLat=lat.getFloat(0);floatlastLat=lat.getFloat(((NY-1)*NX+(NX-1))*4);floatfirstLon=lng.getFloat(0);floatlastLon=lng.getFloat(((NY-1)*NX+(NX-1))*4);doublelatStep=Math.abs(lat.getFloat(NX*4)-firstLat);doublelonStep=Math.abs(lng.getFloat(4)-firstLon);doublegridNorth=Math.max(firstLat,lastLat)+latStep/2.0;doublegridSouth=Math.min(firstLat,lastLat)-latStep/2.0;doublegridWest=Math.min(firstLon,lastLon)-lonStep/2.0;doublegridEast=Math.max(firstLon,lastLon)+lonStep/2.0;// The requested rectangle must be completely inside the data domain.// Do not silently clip a partly out-of-range request.if(west<gridWest-RANGE_EPS||east>gridEast+RANGE_EPS||south<gridSouth-RANGE_EPS||north>gridNorth+RANGE_EPS){failOutsideGrid(west,east,south,north,gridWest,gridEast,gridSouth,gridNorth);}intc0=-1,c1=-1,r0=-1,r1=-1;for(intc=0;c<NX;c++){floatlo=lng.getFloat(c*4);if(lo>=west&&lo<east){if(c0<0)c0=c;c1=c;}}for(intr=0;r<NY;r++){floatla=lat.getFloat((r*NX)*4);if(la<north&&la>=south){if(r0<0)r0=r;r1=r;}}if(c0<0||r0<0){System.err.println("ERROR: Requested crop contains no grid-cell centers.");System.err.printf(Locale.ROOT,"Requested longitude: %.3f .. %.3f E%n",west,east);System.err.printf(Locale.ROOT,"Requested latitude : %.3f .. %.3f N%n",south,north);System.err.printf(Locale.ROOT,"Grid spacing : %.3f deg (lon), %.3f deg (lat)%n",lonStep,latStep);System.exit(2);}intwidth=c1-c0+1,height=r1-r0+1;Files.createDirectories(out.toAbsolutePath().getParent());try(FileChannelsrc=FileChannel.open(in,StandardOpenOption.READ);FileChanneldst=FileChannel.open(out,StandardOpenOption.CREATE,StandardOpenOption.TRUNCATE_EXISTING,StandardOpenOption.WRITE)){ByteBufferrow=ByteBuffer.allocate(width*4);for(intr=r0;r<=r1;r++){row.clear();longpos=((long)r*NX+c0)*4L;intneed=width*4;while(row.position()<need){intx=src.read(row,pos+row.position());if(x<0)thrownewEOFException(in.toString());}row.flip();while(row.hasRemaining())dst.write(row);}}firstLat=lat.getFloat((r0*NX+c0)*4);lastLat=lat.getFloat((r1*NX+c0)*4);firstLon=lng.getFloat((r0*NX+c0)*4);lastLon=lng.getFloat((r0*NX+c1)*4);latStep=height>1?Math.abs(lat.getFloat(((r0+1)*NX+c0)*4)-firstLat):latStep;lonStep=width>1?Math.abs(lng.getFloat((r0*NX+c0+1)*4)-firstLon):lonStep;doublenorthBound=cleanBound(Math.max(firstLat,lastLat)+latStep/2.0);doublesouthBound=cleanBound(Math.min(firstLat,lastLat)-latStep/2.0);doublewestBound=cleanBound(Math.min(firstLon,lastLon)-lonStep/2.0);doubleeastBound=cleanBound(Math.max(firstLon,lastLon)+lonStep/2.0);Propertiesp=newProperties();p.setProperty("width",Integer.toString(width));p.setProperty("height",Integer.toString(height));p.setProperty("north",String.format(Locale.ROOT,"%.6f",northBound));p.setProperty("lat_span",String.format(Locale.ROOT,"%.6f",northBound-southBound));p.setProperty("lat_div","6");p.setProperty("west",String.format(Locale.ROOT,"%.6f",westBound));p.setProperty("lon_span",String.format(Locale.ROOT,"%.6f",eastBound-westBound));p.setProperty("lon_div","6");Pathmeta=Paths.get(out.toString()+".grid.txt");try(Writerw=Files.newBufferedWriter(meta)){for(Stringk:newString[]{"width","height","north","lat_span","lat_div","west","lon_span","lon_div"})w.write(k+"="+p.getProperty(k)+System.lineSeparator());}System.out.printf("source index : column=%d..%d row=%d..%d (0-based)%n",c0,c1,r0,r1);System.out.printf("grid : %d x %d%n",width,height);System.out.printf(Locale.ROOT,"grid centers : %.3fE..%.3fE / %.3fN..%.3fN%n",firstLon,lastLon,firstLat,lastLat);System.out.printf(Locale.ROOT,"grid bounds : %.3fE..%.3fE / %.3fN..%.3fN%n",westBound,eastBound,southBound,northBound);System.out.println("Created : "+out);}staticdoublecleanBound(doublevalue){returnMath.rint(value*10000.0)/10000.0;}staticvoidfailInvalidBounds(doublewest,doubleeast,doublesouth,doublenorth,Stringreason){System.err.println("ERROR: Invalid crop bounds.");System.err.println(reason);System.err.printf(Locale.ROOT,"Requested longitude: %.3f .. %.3f E%n",west,east);System.err.printf(Locale.ROOT,"Requested latitude : %.3f .. %.3f N%n",south,north);System.exit(2);}staticvoidfailOutsideGrid(doublewest,doubleeast,doublesouth,doublenorth,doublegridWest,doublegridEast,doublegridSouth,doublegridNorth){System.err.println("ERROR: Requested crop is outside the available grid.");System.err.printf(Locale.ROOT,"Requested longitude: %.3f .. %.3f E%n",west,east);System.err.printf(Locale.ROOT,"Requested latitude : %.3f .. %.3f N%n",south,north);System.err.printf(Locale.ROOT,"Available longitude: %.3f .. %.3f E%n",gridWest,gridEast);System.err.printf(Locale.ROOT,"Available latitude : %.3f .. %.3f N%n",gridSouth,gridNorth);System.exit(2);}}
importjava.io.*;importjava.nio.*;importjava.nio.file.*;importjava.time.*;importjava.time.format.*;importjava.util.*;importjava.util.stream.*;publicclassmonthlymean{publicstaticvoidmain(String[]args)throwsException{if(args.length!=3){System.err.println("Usage: monthlymean input_dir YYYYMM output.bin");System.exit(1);}Pathdir=Paths.get(args[0]);Stringmonth=args[1];Pathout=Paths.get(args[2]);YearMonthym;try{ym=YearMonth.parse(month,DateTimeFormatter.ofPattern("yyyyMM"));}catch(DateTimeExceptione){thrownewIOException("YYYYMM must be a valid month: "+month,e);}Stringsuffix=".dailymean.dwn.sw.flx.sfc.msm.1km.bin";List<Path>files;try(Stream<Path>s=Files.list(dir)){files=s.filter(p->p.getFileName().toString().startsWith(month)).filter(p->p.getFileName().toString().endsWith(suffix)).sorted().collect(Collectors.toList());}intexpected=ym.lengthOfMonth();if(files.size()!=expected)thrownewIOException("Expected "+expected+" daily files, found "+files.size());longnLong=FloatGrid.floatCount(files.get(0));if(nLong>Integer.MAX_VALUE)thrownewIOException("Grid too large");intn=(int)nLong;float[]sum=newfloat[n];for(Pathp:files){if(FloatGrid.floatCount(p)!=nLong)thrownewIOException("Size mismatch: "+p);if(!FloatGrid.sameGridMeta(files.get(0),p))thrownewIOException("Grid metadata mismatch: "+p);MappedByteBufferb=FloatGrid.map(p);for(inti=0;i<n;i++)sum[i]+=b.getFloat(i*4);System.out.println("read: "+p.getFileName());}for(inti=0;i<n;i++)sum[i]/=files.size();FloatGrid.writeFloats(out,sum);FloatGrid.copyGridMeta(files.get(0),out);System.out.println("Days used : "+files.size());System.out.println("Created : "+out);}}
#!/bin/shset-eu
select_wget(){ifcommand-vwget1>/dev/null2>&1;thenechowget1
elifcommand-vwget>/dev/null2>&1&&!wget--version2>&1|grep-q'Wget2';thenechowget
elseecho'Error: GNU Wget 1.x (wget or wget1) is required.'>&2exit1fi}["$#"-eq3]||["$#"-eq4]||{echo"Usage: $0 YYYY MM DD [DECOMP_JOBS]">&2;exit1;}YYYY=$1;MM=$2;DD=$3;JOBS=${4:-4}case"$JOBS"in''|*[!0-9]*)echo'DECOMP_JOBS must be a positive integer.'>&2;exit1;;esac["$JOBS"-ge1]||{echo'DECOMP_JOBS must be at least 1.'>&2;exit1;}DAY="${YYYY}${MM}${DD}"CHECK=$(date-u-d"${YYYY}-${MM}-${DD}"+%Y%m%d2>/dev/null||true)["$CHECK"="$DAY"]||{echo'Invalid calendar date.'>&2;exit1;}EXPECTED=30262084WGET=$(select_wget)BASE=${AMATERASS_JP_BASE:-ftp://amaterass.cr.chiba-u.ac.jp/quasi-realtime/himawari829/archived/JP}DEST="data/timeseries/$DAY"
mkdir-p"$DEST"
file_is_complete(){FILE=$1[-f"$FILE"]||return1SIZE=$(wc-c<"$FILE"|tr-d' ')["$SIZE"-eq"$EXPECTED"]}QUEUE=RUNNING=0
cleanup_queue(){forJOBin$QUEUE;doPID=${JOB%%|*};REST=${JOB#*|};NAME=${REST%%|*};BZ2=${REST#*|}kill"$PID"2>/dev/null||truewait"$PID"2>/dev/null||truerm-f"$DEST/$NAME""$DEST/$BZ2"doneQUEUE=;RUNNING=0}trap'cleanup_queue'0trap'cleanup_queue; exit 1'1215
finish_oldest(){["$RUNNING"-gt0]||return0set--$QUEUEJOB=$1;shift;QUEUE="$*"PID=${JOB%%|*};REST=${JOB#*|};NAME=${REST%%|*};BZ2=${REST#*|}if!wait"$PID";thenrm-f"$DEST/$NAME""$DEST/$BZ2"echo"Decompression failed: $BZ2">&2exit1fiif!file_is_complete"$DEST/$NAME";thenSIZE=$(wc-c<"$DEST/$NAME"2>/dev/null|tr-d' '||echo0)rm-f"$DEST/$NAME""$DEST/$BZ2"echo"Unexpected file size: $DEST/$NAME ($SIZE bytes)">&2exit1firm-f"$DEST/$BZ2"echo"Ready: $NAME"RUNNING=$((RUNNING-1))}
start_decompress(){NAME=$1;BZ2=$2rm-f"$DEST/$NAME"(cd"$DEST"&&bzip2-d"$BZ2")&PID=$!QUEUE="${QUEUE}${QUEUE:+ }${PID}|${NAME}|${BZ2}"RUNNING=$((RUNNING+1))if["$RUNNING"-ge"$JOBS"];thenfinish_oldest;fi}
fetch_file(){NAME=$1;URL=$2BZ2="$NAME.bz2"iffile_is_complete"$DEST/$NAME";thenrm-f"$DEST/$BZ2"return0fiif[-e"$DEST/$NAME"];thenSIZE=$(wc-c<"$DEST/$NAME"|tr-d' ')echo"Removing incomplete file: $NAME ($SIZE bytes)"rm-f"$DEST/$NAME"fiif(cd"$DEST"&&"$WGET"-q-c"$URL");thenstart_decompress"$NAME""$BZ2"return0firm-f"$DEST/$BZ2"return1}START=$(date-u-d"${YYYY}-${MM}-${DD} 00:00 +0900"+%s)END=$(date-u-d"${YYYY}-${MM}-${DD} 23:50 +0900"+%s)T=$STARTFOUND=0while["$T"-le"$END"];doSTAMP=$(date-u-d"@$T"+%Y%m%d%H%M)YYYYMM=$(printf'%s'"$STAMP"|cut-c1-6)YYYYMMDD=$(printf'%s'"$STAMP"|cut-c1-8)DIR="$BASE/$YYYYMM/$YYYYMMDD"SOLAR="$STAMP.dwn.sw.flx.sfc.msm.1km.bin"TIME="$STAMP.grd.time.mjd.hms.msm.1km.bin"iffile_is_complete"$DEST/$SOLAR"||fetch_file"$SOLAR""$DIR/$SOLAR.bz2";thenFOUND=$((FOUND+1))file_is_complete"$DEST/$TIME"||fetch_file"$TIME""$DIR/$TIME.bz2"||{echo"Missing TIME file for $STAMP">&2;exit1;}fiT=$((T+600))donewhile["$RUNNING"-gt0];dofinish_oldest;donetrap-01215COUNT=$(find"$DEST"-maxdepth1-typef-name'*.dwn.sw.flx.sfc.msm.1km.bin'-size30262084c|wc-l|tr-d' ')["$COUNT"-gt1]||{echo"Not enough solar-radiation files for $DAY.">&2;exit1;}echo"Time-series source files ready: $DAY ($COUNT solar files, max $JOBS decompression jobs)"