Class: Ignis::FFT::FFTPlan

Inherits:
Object
  • Object
show all
Defined in:
lib/nvruby/fft/fft_plan.rb

Overview

Reusable FFT plan for repeated operations with same dimensions

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(shape:, dtype: :complex64, direction: :forward, transform_type: :c2c, batch: 1) ⇒ FFTPlan

Returns a new instance of FFTPlan.

Parameters:

  • shape (Array<Integer>)

    Input shape

  • dtype (Symbol) (defaults to: :complex64)

    Input data type

  • direction (Symbol) (defaults to: :forward)

    :forward or :inverse

  • transform_type (Symbol) (defaults to: :c2c)

    :c2c, :r2c, or :c2r

  • batch (Integer) (defaults to: 1)

    Batch size for multiple FFTs



27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/nvruby/fft/fft_plan.rb', line 27

def initialize(shape:, dtype: :complex64, direction: :forward, transform_type: :c2c, batch: 1)
  @shape = Array(shape)
  @dtype = DType.validate!(dtype)
  @direction = direction
  @transform_type = transform_type
  @batch = batch

  @plan_handle = nil
  @destroyed = false

  create_plan!
end

Instance Attribute Details

#directionSymbol (readonly)

Returns Transform direction (:forward, :inverse).

Returns:

  • (Symbol)

    Transform direction (:forward, :inverse)



14
15
16
# File 'lib/nvruby/fft/fft_plan.rb', line 14

def direction
  @direction
end

#dtypeSymbol (readonly)

Returns Input data type.

Returns:

  • (Symbol)

    Input data type



11
12
13
# File 'lib/nvruby/fft/fft_plan.rb', line 11

def dtype
  @dtype
end

#plan_handleFFI::Pointer (readonly)

Returns cuFFT plan handle.

Returns:

  • (FFI::Pointer)

    cuFFT plan handle



20
21
22
# File 'lib/nvruby/fft/fft_plan.rb', line 20

def plan_handle
  @plan_handle
end

#shapeArray<Integer> (readonly)

Returns Input shape.

Returns:

  • (Array<Integer>)

    Input shape



8
9
10
# File 'lib/nvruby/fft/fft_plan.rb', line 8

def shape
  @shape
end

#transform_typeSymbol (readonly)

Returns Transform type (:c2c, :r2c, :c2r).

Returns:

  • (Symbol)

    Transform type (:c2c, :r2c, :c2r)



17
18
19
# File 'lib/nvruby/fft/fft_plan.rb', line 17

def transform_type
  @transform_type
end

Class Method Details

.release_finalizer(handle) ⇒ Proc

Create finalizer for plan cleanup

Parameters:

  • handle (FFI::Pointer)

    Plan handle

Returns:

  • (Proc)


279
280
281
282
283
284
# File 'lib/nvruby/fft/fft_plan.rb', line 279

def release_finalizer(handle)
  proc do
    CuFFTBindings.ensure_loaded!
    CuFFTBindings.cufftDestroy(handle)
  end
end

Instance Method Details

#destroy!void

This method returns an undefined value.

Destroy the plan and free resources



126
127
128
129
130
131
132
# File 'lib/nvruby/fft/fft_plan.rb', line 126

def destroy!
  return if @destroyed || @plan_handle.nil?

  CuFFTBindings.cufftDestroy(@plan_handle)
  @plan_handle = nil
  @destroyed = true
end

#destroyed?Boolean

Check if plan has been destroyed

Returns:

  • (Boolean)


136
137
138
# File 'lib/nvruby/fft/fft_plan.rb', line 136

def destroyed?
  @destroyed
end

#execute(input, output: nil, stream: nil) ⇒ NvArray

Execute the FFT plan

Parameters:

  • input (NvArray)

    Input array

  • output (NvArray, nil) (defaults to: nil)

    Output array (created if nil)

  • stream (CUDA::Stream, nil) (defaults to: nil)

    CUDA stream

Returns:

Raises:

  • (InvalidOperationError)


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
# File 'lib/nvruby/fft/fft_plan.rb', line 79

def execute(input, output: nil, stream: nil)
  raise InvalidOperationError, "FFTPlan has been destroyed" if @destroyed

  validate_input!(input)

  input = input.to_device unless input.on_device?

  output ||= NvArray.new(shape: output_shape, dtype: output_dtype, device: input.device_index)
  output = output.to_device unless output.on_device?

  if stream
    status = CuFFTBindings.cufftSetStream(@plan_handle, stream.handle)
    CuFFTBindings.check_status!(status, "Set FFT stream")
  end

  direction_flag = @direction == :forward ? CuFFTBindings::CUFFT_FORWARD : CuFFTBindings::CUFFT_INVERSE

  status = case @transform_type
           when :c2c
             execute_c2c(input, output, direction_flag)
           when :r2c
             execute_r2c(input, output)
           when :c2r
             execute_c2r(input, output)
           else
             raise InvalidOperationError, "Unknown transform type: #{@transform_type}"
           end

  CuFFTBindings.check_status!(status, "Execute FFT")

  output
end

#ndimInteger

Returns Number of dimensions.

Returns:

  • (Integer)

    Number of dimensions



41
42
43
# File 'lib/nvruby/fft/fft_plan.rb', line 41

def ndim
  @shape.size
end

#output_dtypeSymbol

Returns Output data type.

Returns:

  • (Symbol)

    Output data type



63
64
65
66
67
68
69
70
71
72
# File 'lib/nvruby/fft/fft_plan.rb', line 63

def output_dtype
  case @transform_type
  when :r2c
    DType.complex_dtype(@dtype)
  when :c2r
    DType.real_dtype(@dtype)
  else
    @dtype
  end
end

#output_shapeArray<Integer>

Returns Output shape.

Returns:

  • (Array<Integer>)

    Output shape



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/nvruby/fft/fft_plan.rb', line 46

def output_shape
  case @transform_type
  when :r2c
    out = @shape.dup
    out[-1] = out[-1] / 2 + 1
    out
  when :c2r
    out = @shape.dup
    # Output size should be provided, default to (n-1)*2
    out[-1] = (@shape[-1] - 1) * 2
    out
  else
    @shape.dup
  end
end

#to_sString

Returns:

  • (String)


141
142
143
144
# File 'lib/nvruby/fft/fft_plan.rb', line 141

def to_s
  status = @destroyed ? "destroyed" : "active"
  "FFTPlan(shape=#{@shape}, dtype=#{@dtype}, #{@transform_type}, #{@direction}, #{status})"
end

#workspace_sizeInteger

Get estimated workspace size

Returns:

  • (Integer)

    Workspace size in bytes

Raises:

  • (InvalidOperationError)


114
115
116
117
118
119
120
121
122
# File 'lib/nvruby/fft/fft_plan.rb', line 114

def workspace_size
  raise InvalidOperationError, "FFTPlan has been destroyed" if @destroyed

  size_ptr = FFI::MemoryPointer.new(:size_t)
  status = CuFFTBindings.cufftGetSize(@plan_handle, size_ptr)
  CuFFTBindings.check_status!(status, "Get FFT workspace size")

  size_ptr.read(:size_t)
end