File: SMoc.java

package info (click to toggle)
libcds-moc-java 6.31-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 388 kB
  • sloc: java: 4,935; makefile: 18
file content (284 lines) | stat: -rw-r--r-- 12,276 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
// Copyright 2021 - Unistra/CNRS
// The MOC API project is distributed under the terms
// of the GNU General Public License version 3.
//
//This file is part of MOC API java project.
//
//    MOC API java project is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, version 3 of the License.
//
//    MOC API java project is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    The GNU General Public License is available in COPYING file
//    along with MOC API java project.
//

package cds.moc;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;

/**
 * The SMoc class implements the methods specific to spatial MOCs.
 * It is based on the HEALpix tesselation of the sphere.
 * See:  IVOA MOC 2.0 standard => https://www.ivoa.net/documents/MOC/
 * @author Pierre Fernique [CDS]
 * @version 1.0 - April 2021 - creation
 *
 */
public class SMoc extends Moc1D {
   
   static final public int  MAXORD_S = 29;       // Max order (<=> deepest HEALPix level)
   static final public int  FACT_S   = 4;        // Factor between two consecutive order
   static final public char DIM_S    = 's';      // Char signature for SMoc
   static final public long NBVAL_S  = pow2( MAXORD_S ) * pow2( MAXORD_S ) * 12L;   // nb of cells at the deepest order
   static final public String SYS_S = "C";    // Celestial coordinate system
   
   private int minOrder;                         // Min order, 0 by default
   
   /** Return the deepest possible order (ex: 29 for SMoc, 61 for TMoc) */
   public final int  maxOrder() { return MAXORD_S;  }
   
   /** Return the number of bit shifting between two consecutive orders (ex: 2 for SMoc, 1 for TMoc) */
   public final int  shiftOrder() { return FACT_S/2;   }
   
   /** Return the Moc signature character (ex: 's' for SMoc, 't' for TMOC) */
   public final char cDim() { return DIM_S; }
   
   /** Return the number of values at the deepest order (ex: 2x2^29x2^29 for SMoc, 2^61 for TMoc) */
   public final long maxVal() { return NBVAL_S; }
   
   /** Return the default reference system */
   public final String sys() { return SYS_S; }
   
   public SMoc() { super(); }
   public SMoc( int mocOrder ) { super( mocOrder ); }
   public SMoc( String s ) throws Exception { super(s); }
   public SMoc( SMoc moc ) throws Exception { super( moc ); }
   public SMoc( InputStream in ) throws Exception { super(in); }
   
   /** Reinitialisation of the MOC - data only (not the properties) */
   public void clear() {
      super.clear();
      minOrder=0;
   }
   
   /** Clone Moc (deep copy) */
   public SMoc clone() throws CloneNotSupportedException {
      SMoc moc = dup();
      clone1( moc );
      return moc;
   }
   
   /** Deep copy. The source is this, the target is the Moc in parameter */
   protected void clone1( Moc moc ) throws CloneNotSupportedException {
      if( !(moc instanceof SMoc) ) throw new CloneNotSupportedException("Uncompatible type of MOC for clone. Must be SMoc");
      super.clone1( moc );
      ((SMoc)moc).minOrder = minOrder;
      
   }
      
   /** Create and instance of same class, same sys, but no data nor mocorder */
   public SMoc dup() {
      SMoc moc = new SMoc();
      moc.sys=sys;
      return moc;
   }
   
   /** Return the number of bytes used for coding each FITS value (4 for integer, 8 for long) */
   public int sizeOfCoding() { return getDeepestOrder()<14 ? 4 : 8; }
   
   /** Return the number of values to write in FITS serialization */
   public int getNbCoding() { return getNbCells(); }
   
   /** Add directly a SMoc */
   public void add(Moc moc) throws Exception { 
      if( !(moc instanceof SMoc) ) throw new Exception("Uncompatible Moc for adding");
      super.add(moc);
   }
   
   /************************************ SMoc specifical methods => HEALPix *****************************************/
   
   /** Add a Moc pixel (at max order) corresponding to the alpha,delta position
    * @param alpha, delta position
    * @return true if the cell (or its father) has been effectively inserted
    */
   public void add(HealpixImpl healpix,double alpha, double delta) throws Exception {
      int order = getMocOrder();
      if( order==-1 ) throw new Exception("Undefined Moc order");
      long npix = healpix.ang2pix(order, alpha, delta);
      add(order,npix,npix);
   }
   
   /** Check if the spherical coord is inside the MOC. The coordinate system must be compatible
    * with the MOC coordinate system.
    * @param alpha in degrees
    * @param delta in degrees
    * @return true if the coordinates is in one MOC pixel
    * @throws Exception
    */
   public boolean contains(HealpixImpl healpix,double alpha, double delta) throws Exception {
      int order = getDeepestOrder();
      if( order==-1 ) return false;
      long npix = healpix.ang2pix(order, alpha, delta);
      return isIncluding(order,npix);
   }

   /**
    * Provide Moc pixels totally or partially inside a circle
    * @param alpha circle center (in degrees)
    * @param delta circle center (in degrees)
    * @param radius circle radius (in degrees)
    * @return an HealpixMox containing the list of pixels
    * @throws Exception
    */
   public SMoc queryDisc(HealpixImpl healpix,double alpha, double delta,double radius) throws Exception {
      int order = getDeepestOrder();
      if( order==-1 ) return null;
      SMoc mocA = dup();
      long [] list = healpix.queryDisc(order, alpha, delta, radius);
      for( long npix : list ) mocA.add(order,npix,npix);
      return intersection(mocA);
   }   
   
   /** Set alternative Coosys. All celestial SMoc must be expressed in ICRS (see IVOA MOC 2.0)
    * but alternative is possible for other sphere coverage notably the planets
    * @param coosys alternative coosys keyword (not standardized in IVOA document)
    */
   public void setSpaceSys( String coosys ) { setSys(coosys); }
   
   /** Get the Coosys. See setSpaceSys() */
   public String getSpaceSys() { return getSys(); }
   
   /** Set min Moc min Order. The hierarchical view will be start at this order. 0 by default */
   public void setMinOrder( int minOrder ) throws Exception {
      if( minOrder==this.minOrder ) return;
      if( minOrder<0 || minOrder>maxOrder() ) throw new Exception("MinOrder error ("+minOrder+" not in [0.."+maxOrder()+"])");
      if( mocOrder!=-1 && minOrder>mocOrder ) throw new Exception("MinOrder cannot be bigger that Moc order");
      this.minOrder = minOrder;
      resetCache();
   }
   
   /** get min Moc min Order. The hierarchical view will be start at this order. 0 by default */
   public int getMinOrder() { return minOrder; }
      
   /** Provide the angular resolution (in degrees) of the SMoc (sqrt of the smallest pixel area) */
   public double getAngularRes() {
      return Math.sqrt( Healpix.getPixelArea( getMocOrder() ) );
   }

   /** True if the npix at the deepest order is in the MOC */
   public boolean contains(long npix) { return range.contains(npix); }

   
   /***************************************************** Operations ******************************************/
   
   
   public boolean isIncluding(Moc moc) throws Exception { 
      if( moc instanceof STMoc ) moc = ((STMoc)moc).getSpaceMoc();
      else if( !(moc instanceof SMoc ) ) throw new Exception("Uncompatible Moc type for SMoc isIncluding test");
      if( !((SMoc)moc).isCompatible( this ) ) throw new Exception("Uncompatible sys");
      flush(); 
      return range.contains( ((SMoc)moc).range ); 
   }   
   
   public boolean isIntersecting(Moc moc) throws Exception { 
      if( moc instanceof STMoc ) moc = ((STMoc)moc).getSpaceMoc();
      else if( !(moc instanceof SMoc ) ) throw new Exception("Uncompatible Moc type for SMoc isIncluding test");
      flush(); 
      return range.overlaps( ((SMoc)moc).range ); 
   }
   
   /** Return the Union with another Moc */
   public SMoc union(Moc moc) throws Exception {
      if( moc instanceof STMoc ) moc = ((STMoc)moc).getSpaceMoc();
      else if( !(moc instanceof SMoc ) ) throw new Exception("Uncompatible Moc type for SMoc union");
      return (SMoc) super.union(moc);
   }

   /** Return the Intersection with another Moc */
   public SMoc intersection(Moc moc) throws Exception {
      if( moc instanceof STMoc ) moc = ((STMoc)moc).getSpaceMoc();
      else if( !(moc instanceof SMoc ) ) throw new Exception("Uncompatible Moc type for SMoc subtraction");
      return (SMoc) super.intersection(moc);
   }

   /** Return the subtraction with another Moc */
   public SMoc subtraction(Moc moc) throws Exception {
      if( moc instanceof STMoc ) moc = ((STMoc)moc).getSpaceMoc();
      else if( !(moc instanceof SMoc ) ) throw new Exception("Uncompatible Moc type for SMoc subtraction");
      return (SMoc) super.subtraction(moc);
   }
   
   /** Return the complement */
   public SMoc complement() throws Exception { return (SMoc) super.complement(); }

   
   /*************************************************************** I/O *****************************************************/
   
   /** Internal method: read FITS data according to the type of MOC.
    * @param in The input stream
    * @param naxis1 size of FITS row (in bytes) (generally ==nbyte, but may be 1024 for buffering)
    * @param naxis2 number of values
    * @param nbyte size of each value (in bytes)
    * @param header HDU1 header
    * @throws Exception
    */
   protected  void readSpecificData(InputStream in, int naxis1, int naxis2, int nbyte, HeaderFits header) throws Exception {
      
      // Moc order detection
      int mocOrder=-1;
      String val = header.getStringFromHeader("MOCORD_S");
      if( val==null ) val = header.getStringFromHeader("MOCORDER");   // Compatibility with MOC 1.0 and 1.1
      try { mocOrder = Integer.parseInt(val); }
//      catch( Exception e ) { throw new Exception("Missing MOC order in FITS header (MOCORD_S)"); }
      catch( Exception e ) { }
      setMocOrder( mocOrder );
      
      String type = header.getStringFromHeader("ORDERING");
      String sys = header.getStringFromHeader("COORDSYS");
      if( sys!=null && !sys.equals("C") ) setSpaceSys(sys);

      // We anticipate the SMOC coded in RANGE (not possible in IVOA M0C 2.0) => Range coding
      if( type!=null && type.equals("RANGE") ) readSpecificDataRange(in, naxis1, naxis2, nbyte);

      // Regular SMOC coding => NUNIQ
      else readSpecificDataUniq(in, naxis1, naxis2, nbyte);
      

   }

   /** Write specifical SMOC properties */
   protected int writeSpecificFitsProp( OutputStream out ) throws Exception {
      int n=0;
      out.write( getFitsLine("TTYPE1","UNIQ","UNIQ pixel number") );        n+=80;
      out.write( getFitsLine("ORDERING","NUNIQ","NUNIQ coding method") );   n+=80;      
      out.write( getFitsLine("COORDSYS",getSpaceSys(),"Space reference frame") );  n+=80;
      out.write( getFitsLine("MOCDIM","SPACE","Physical dimension") );      n+=80;      
      out.write( getFitsLine("MOCORD_S",""+getMocOrder(),"MOC resolution (best order)") );        n+=80;      
      out.write( getFitsLine("MOCORDER",""+getMocOrder(),"=MOCORD_S (backward compatibility)") );    n+=80;      
      return n;
   }

   /** Write SMOC data -> hierarchy mode */
   protected int writeSpecificData(OutputStream out) throws Exception {
      int size = 0;
      byte [] buf = new byte[ sizeOfCoding() ];
      Iterator<MocCell> it = cellIterator( true );
      while( it.hasNext() ) {
         MocCell cell = it.next();
         for( long val=cell.start; val<cell.end; val++ ) {
            long nuniq = hpix2uniq(cell.order, val );
            size+=writeVal(out,nuniq,buf);
         }
      }
      return size;
   }
   

}