Class: NumRu::AssocCoords

Inherits:
Object
  • Object
show all
Defined in:
lib/numru/gphys/assoccoords.rb,
ext/numru/gphys/ext_coord.c

Overview

Associated coordinates

To use in a Grid in order to support non-rectangular coordnate systems

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(assoc_crds, axnames) ⇒ AssocCoords

  • assoc_crds : Array of GPhys

  • axnames : Array of axis names of the original Grid



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
# File 'lib/numru/gphys/assoccoords.rb', line 16

def initialize(assoc_crds, axnames)

  # < argument check >
  if assoc_crds.uniq.length != assoc_crds.length
	raise ArgumentError, "Names are not uniq: #{assoc_crds.inspect}."
  end
  @axnames = axnames.dup
  assoc_crds.each do |gp|
	raise(ArgumentError,"Non-GPhys included") if !gp.is_a?(GPhys)
	if axnames.include?(gp.name)
	  raise ArgumentError, 
   "'#{gp.name}' overwraps an axis name #{axnames.inspect}."
	end
    if (gp.axnames - @axnames).length > 0
      raise ArgumentError, "Provided assoc coord '#{gp.name}' has an axis (axes) #{gp.axnames - @axnames} not in the present object #{@axnames}"
    end
  end

  # < some internal variables >

  @assoc_crds = Hash.new
  assoc_crds.each{|gp| @assoc_crds[gp.name] = gp}
  @lost_assoc_crds = nil

  # < lengths of original axes >

  @axlens = Hash.new
  @axnames.each do |nm|
    len = nil
    lens = nil
    assoc_crds.each do |gp|
      if gp.axnames.include?(nm)
        len = gp.axis(nm).length
        if lens && len!=lens
          raise("Inconsistency in assoc coord length for ax #{nm}: #{len} (#{gp.name}) vs #{lens}") 
        end
        lens = len
      end
    end
    @axlens[nm] = len      # can be nil
  end

  # < grouping in terms of original-dimension sharing >
  @groups = Hash.new    # axnames => assoc coord names
  assoc_crds.each do |gp|
    pushed = false
    axnames_sv = acnames_sv = nil
    @groups.each do | axnames, acnames |
      a = gp.axnames
      if (axnames - a).length < axnames.length   # included?
        unless pushed
          # first time in this loop
          axnames.concat(a).uniq!
          acnames.push(gp.name)
          axnames_sv = axnames
          acnames_sv = acnames
        else
          # second or greater time in this loop --> need merger to the first
          @groups.delete(axnames)
          axnames_sv.concat(axnames).uniq!
          acnames_sv.concat(acnames).uniq!
        end
        pushed = true
        #break  # <-- old code; this doesn't work
      end
    end
    @groups[ gp.axnames ] = [gp.name] if !pushed  # new group
  end

  # < sort keys in @groups in the order of original axes >
  # -- though its necesity was not originally supposed, but...
  @groups.each_key do |axnames|
    axnames.replace( @axnames - (@axnames - axnames) )
  end
end

Instance Attribute Details

#axlensObject (readonly)

Returns the value of attribute axlens.



92
93
94
# File 'lib/numru/gphys/assoccoords.rb', line 92

def axlens
  @axlens
end

Instance Method Details

#[](*args) ⇒ Object

slicing in terms of the original axes



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
# File 'lib/numru/gphys/assoccoords.rb', line 219

def [](*args)
  return self.dup if args.length == 0

  args = __rubber_expansion( args )
  slicer = Hash.new
  @axnames.each_with_index{|nm,i| slicer[nm] = args[i]}

  new_assoc_crds = Array.new
  lost_assoc_crds = Array.new
  @assoc_crds.each do |dummy, gp|
    sub = gp[ *( gp.axnames.collect{|nm| slicer[nm] || true} ) ]
    if sub.rank > 0
      new_assoc_crds.push( sub )
    else
      lost_assoc_crds.push( "#{sub.name}=#{sub.val}" )
    end
  end

  axnames = Array.new
  args.each_with_index do |a, i|
    axnames.push @axnames[i] unless Numeric === a
  end

  ret = self.class.new( new_assoc_crds, axnames )
  ret.set_lost_coords( lost_assoc_crds ) if !lost_assoc_crds.empty?
  ret
end

#coord(name) ⇒ Object



113
114
115
# File 'lib/numru/gphys/assoccoords.rb', line 113

def coord(name)
  @assoc_crds[name].data   # return a VArray
end

#coord_gphys(name) ⇒ Object



126
127
128
# File 'lib/numru/gphys/assoccoords.rb', line 126

def coord_gphys(name)
  @assoc_crds[name]   # return a GPhys
end

#coordnamesObject



134
135
136
# File 'lib/numru/gphys/assoccoords.rb', line 134

def coordnames
  @assoc_crds.keys
end

#copyObject



109
110
111
# File 'lib/numru/gphys/assoccoords.rb', line 109

def copy
  self.class.new( @assoc_crds.values.collect{|gp| gp.copy}, @axnames )
end

#cut(hash) ⇒ Object

assoc_crds に関する座標値ベースの切り出し : 引数は Hash のみ



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
# File 'lib/numru/gphys/assoccoords.rb', line 139

def cut(hash)
  cutaxnms = hash.keys
  newcrds = Array.new
  slicer_hash = Hash.new
  @groups.each do |orgaxnms, group|
    ca2 = cutaxnms - group
    if ca2.length < cutaxnms.length
      # Some of cutaxnms are included in group
      # --> Do cutting regarding this group
      crds = Array.new
      crdnms = Array.new
      crdaxexist = Array.new
      masks = Array.new   # for NArrayMiss
      cuts = Array.new
      group.each do |nm|
        cutter = hash[nm]
        if !cutter.nil? && cutter!=true && cutter!=(0..-1)
          crdnms.push( nm )
          cuts.push( hash[nm] )
   anms = @assoc_crds[nm].axnames
          crdaxexist.push( NArray.to_na(
  orgaxnms.collect{|a| anms.include?(a) ? 1 : 0} ) )
          v = @assoc_crds[nm].val   # 座標値 (NArray or NArrayMiss)
          if v.is_a?(NArrayMiss)
            crds.push(v.to_na)
            masks.push(v.get_mask)
          else
            crds.push(v)
            masks.push(nil)
          end
        end
      end
      cuttype = cuts.collect{|x| x.class}.uniq
      if cuttype.length == 1
        orgaxlens = @axlens.values_at(*orgaxnms)
        if cuttype[0] == Range
   vmins = Array.new
   vmaxs = Array.new
   cuts.each do |range|
		a = range.first
		b = range.last
		if (b<a)
vmins.push(b)
vmaxs.push(a)
		else
vmins.push(a)
vmaxs.push(b)
		end
   end
          idxs = cut_range(vmins,vmaxs,crds,masks,crdaxexist,orgaxlens)
        elsif cuttype[0] == Numeric
          raise "SORRY!  cut_nearest is yet to be implemented."
          idxs = cut_nearest()  # YET TO BE IMPLEMENT
        else
          raise ArgumentError, "Not allowed cutting type (#{cuttype[0]})"
        end
        ncrds = group.collect{ |nm| 
          gp = @assoc_crds[nm]
          sl = gp.axnames.collect{|anm| idxs[orgaxnms.index(anm)]}
          gp[ *sl ]
        }
        newcrds.concat( ncrds )
        orgaxnms.each_with_index{|nm,i| slicer_hash[nm] = idxs[i]}
      else
        raise "Cutting specification for a group of assoc coords (here, #{group.inspect}) must be uniformly set to either by range or by point -- Cannot mix."
      end
    else
      # None of cutaxnms are included in group --> just copy
      ncrds = group.collect{ |nm| @assoc_crds[nm] }
      newcrds.concat( ncrds )
    end
    cutaxnms = ca2
    break if cutaxnms.length == 0     # cutting finished
  end
  new_assocoords = self.class.new( newcrds, @axnames )
  [ new_assocoords, slicer_hash ] 
end

#has_coord?(name) ⇒ Boolean

Returns:

  • (Boolean)


130
131
132
# File 'lib/numru/gphys/assoccoords.rb', line 130

def has_coord?(name)
  @assoc_crds.has_key?(name)
end

#inspectObject



105
106
107
# File 'lib/numru/gphys/assoccoords.rb', line 105

def inspect
  "<AssocCoords  #{@assoc_crds.collect{|nm,gp| gp.data.inspect}.join("\n\t")}\n\t#{@groups.inspect}>"
end

#lost_coordsObject



262
263
264
# File 'lib/numru/gphys/assoccoords.rb', line 262

def lost_coords
	@lost_assoc_crds.dup
end

#merge(other) ⇒ Object



95
96
97
98
99
100
101
102
103
# File 'lib/numru/gphys/assoccoords.rb', line 95

def merge(other)
  if other.nil?
    self
  else
    ac = self.assoc_crds.merge(other.assoc_crds)
    an = (self.axnames + other.axnames).uniq
    self.class.new(ac,an)
  end
end

#replace(gphys) ⇒ Object

Raises:

  • (ArgumentError)


117
118
119
120
121
122
123
124
# File 'lib/numru/gphys/assoccoords.rb', line 117

def replace(gphys)
  raise(ArgumentError,"not a GPhys") unless gphys.is_a?(GPhys)
  nm = gphys.name
  raise("assoc coord '#{nm}' is not found") unless (old=@assoc_crds[nm])
  raise("shapes of the current and new '#{nm}' are different") unless old.shape==gphys.shape
  @assoc_crds[nm] = gphys
  self
end

#set_lost_coords(lost_assoc_crds) ⇒ Object



257
258
259
260
# File 'lib/numru/gphys/assoccoords.rb', line 257

def set_lost_coords( lost_assoc_crds )
  @lost_assoc_crds = lost_assoc_crds   # Array of String
  self
end

#subset_having_axnames(axnames) ⇒ Object

make a subset with assoc coords related only to axnames



248
249
250
251
252
253
254
255
# File 'lib/numru/gphys/assoccoords.rb', line 248

def subset_having_axnames( axnames )
  acnms = Array.new
  @groups.each do |ks,vs|
    acnms.concat(vs) if ( (ks-axnames).length == 0 )  # all of ks present
  end
  assoc_crds = acnms.collect{|nm| @assoc_crds[nm]}
  self.class.new(assoc_crds, axnames)
end