rb-daspk 0.0.5-x86-mswin32-60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. data/examples/springmass.rb +130 -0
  2. data/lib/daspk.dll +0 -0
  3. data/lib/rb-daspk.rb +317 -0
  4. metadata +66 -0
@@ -0,0 +1,130 @@
1
+ # Copyright (c) 2009 Eric Todd Meyers
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person
4
+ # obtaining a copy of this software and associated documentation
5
+ # files (the "Software"), to deal in the Software without
6
+ # restriction, including without limitation the rights to use,
7
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the
9
+ # Software is furnished to do so, subject to the following
10
+ # conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ # OTHER DEALINGS IN THE SOFTWARE.
23
+ #
24
+ #
25
+ # More information, source code and gems @ http://rubyforge.org/projects/rb-daspk/
26
+ #
27
+
28
+ require 'rubygems'
29
+ require 'rb-daspk'
30
+ include DASPK
31
+
32
+ #
33
+ # classic spring mass problem
34
+ #
35
+ # d2x/dt + 2*l*w0*dxdt + w0*w0*x = 0
36
+ #
37
+ # let v = dx/dt, then
38
+ #
39
+ # 1. dxdt - v = 0
40
+ # 2. dvdt + 2*l*w0*v + w0*w0*x = 0
41
+ #
42
+ #
43
+ # let's start with x at 1, dxdt at 0 (v=0)
44
+ # we'll ask DASPK for the state derivatives
45
+ #
46
+ y = [1.0,0.0]
47
+ yprime= [0.0,-1.0] # these are gusses in this case. we will call solveForInitialValues to get them
48
+
49
+
50
+ w0 = 1.0
51
+ l = 0.0 # undamped
52
+
53
+ #
54
+ # in case we want to see details during the integration. in this case were just dumping values
55
+ # not required (can pass nil to Solver.new if you want)
56
+ #
57
+ inter = Proc.new do |time,y,yprime|
58
+ print " time = #{time} x = #{y[0]}\n"
59
+ end
60
+
61
+ jac = Proc.new do |time,y,yprime,jacm,cj|
62
+
63
+ jacm[0][0] = cj
64
+ jacm[0][1] = -1.0
65
+ jacm[1][0] = w0**2.0
66
+ jacm[1][1] = (2*l*w0 + cj)
67
+
68
+ end
69
+
70
+ s=Solver.new(2,y,yprime,inter,jac) do |time,y,yprime,delta|
71
+ #s=Solver.new(2,y,yprime,inter) do |time,y,yprime,delta|
72
+ delta[0] = yprime[0] - y[1]
73
+ delta[1] = yprime[1] + 2.0*l*w0*y[1] + w0*w0*y[0]
74
+ end
75
+
76
+
77
+ #
78
+ # solve the initial value problem
79
+ # note, this isnt required if the y and yprimes are already consistent
80
+ #
81
+ # return code from solveFoeInitialValues
82
+ # 4 success (see DDASPK for all possible values)
83
+ #
84
+ idid = s.solveForInitialValues(0,y,yprime,[0,0])
85
+ print " ----------------------------------------\n"
86
+ print " initial conditions\n"
87
+ print " x = #{y[0]}\n"
88
+ print " vel = #{y[1]}\n"
89
+ print " accelaration = #{yprime[1]}\n"
90
+ print " ----------------------------------------\n"
91
+
92
+ #
93
+ # integrate to PI seconds
94
+ #
95
+ #
96
+ ans = s.solve(0.0,Math::PI)
97
+ #
98
+ # answer is an array of arrays
99
+ # ans[0] = end time
100
+ # ans[1] = end y array
101
+ # ans[2] = end yprime array
102
+ # ans[3] = DASPK return code (see DDASPK.F for meaning)
103
+ #
104
+ print " ----------------------------------------\n"
105
+ print " final conditions\n"
106
+ print " time = #{ans[0]}\n"
107
+ print " x = #{ans[1][0]}\n"
108
+ print " vel = #{ans[1][1]}\n"
109
+ print " accelaration = #{ans[2][1]}\n"
110
+ print " ----------------------------------------\n"
111
+
112
+ #
113
+ # continue to integrate to 2PI seconds
114
+ #
115
+ #
116
+ ans = s.solve(0.0,2*Math::PI)
117
+ #
118
+ # answer is an array of arrays
119
+ # ans[0] = end time
120
+ # ans[1] = end y array
121
+ # ans[2] = end yprime array
122
+ # ans[3] = DASPK return code (see DDASPK.F for meaning)
123
+ #
124
+ print " ----------------------------------------\n"
125
+ print " final conditions\n"
126
+ print " time = #{ans[0]}\n"
127
+ print " x = #{ans[1][0]}\n"
128
+ print " vel = #{ans[1][1]}\n"
129
+ print " accelaration = #{ans[2][1]}\n"
130
+ print " ----------------------------------------\n"
data/lib/daspk.dll ADDED
Binary file
data/lib/rb-daspk.rb ADDED
@@ -0,0 +1,317 @@
1
+ # Copyright (c) 2009 Eric Todd Meyers
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person
4
+ # obtaining a copy of this software and associated documentation
5
+ # files (the "Software"), to deal in the Software without
6
+ # restriction, including without limitation the rights to use,
7
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the
9
+ # Software is furnished to do so, subject to the following
10
+ # conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ # OTHER DEALINGS IN THE SOFTWARE.
23
+ #
24
+ #
25
+ # More information, source code and gems @ http://rubyforge.org/projects/rb-daspk/
26
+ #
27
+ #:main:DASPK::Solver
28
+ #
29
+
30
+
31
+ require 'rubygems'
32
+ require 'ffi'
33
+
34
+ module FFI
35
+ class Pointer
36
+ def read_double
37
+ get_float64(0)
38
+ end
39
+
40
+ def write_double(obj)
41
+ put_float64(0, obj)
42
+ end
43
+
44
+ def read_array_of_double(length)
45
+ get_array_of_double(0, length)
46
+ end
47
+
48
+ def write_array_of_double(ary)
49
+ put_array_of_double(0, ary)
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+ module DASPKLIB
56
+ extend FFI::Library
57
+ ffi_lib File.dirname(__FILE__) + '/daspk.dll'
58
+ callback :jac, [:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer], :void
59
+ callback :res, [:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer], :void
60
+ attach_function 'DDASPK', [:res, :pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:pointer,
61
+ :pointer,:pointer,:pointer,:pointer,:pointer,:pointer,:jac, :pointer], :void
62
+ attach_function 'D1MACH', [:pointer],:double
63
+ end
64
+
65
+ module DASPK
66
+ #
67
+ # interface to DASPK
68
+ #
69
+ # typical usage
70
+ #
71
+ # 1. create an instance of the Solver class. pass in the initial states/derivatives and the residual function as a block
72
+ # 2. if the initial conditions are not consistent call solveForInitialValues
73
+ # 3. call solve with the start and end times desired
74
+ # 4. repeated calls to solve will solve to each end time. the start time is ingored. this allows
75
+ # for continued integration
76
+ #
77
+ class Solver
78
+
79
+ include DASPKLIB
80
+ attr_accessor :rtol,:atol,:inter,:jac,:maxstep
81
+ #
82
+ #
83
+ # * neq = the number of equations. this is always the sum of the number of states and algebraics
84
+ # * y = array containing the initial states and algebraics
85
+ # * yprime = array containing the initial state derivatives
86
+ # * inter = Proc instance. defaults to nil. if non-nil used as a callback to report the integration results at every time step
87
+ # * jac = Proc instance. defauls to nil. if non-nil used to get the modified Jacbian matrix. otherwise DASPK will determine by iteration
88
+ # * res = residual (delta) Proc. must be present. this is responsible for filling of the delta (residual) array.
89
+ #
90
+ def initialize (neq, y, yprime, inter=nil, jac=nil, &res)
91
+ @lwr = 500
92
+ @lwi = 500
93
+ @plwr = FFI::MemoryPointer.new(:int)
94
+ @plwr.write_int(@lwr)
95
+ @plwi = FFI::MemoryPointer.new(:int)
96
+ @plwi.write_int(@lwi)
97
+ @iwork = [0]*@lwi
98
+ @work = [0]*@lwr
99
+ @pwork = FFI::MemoryPointer.new(:double,@lwr)
100
+ @piwork = FFI::MemoryPointer.new(:int,@lwi)
101
+ @info = [0]*30
102
+ @pinfo = FFI::MemoryPointer.new(:int,30)
103
+ @ialgs = [0]*neq
104
+ @res = res
105
+ @inter = inter
106
+ @rtol = 0.000001
107
+ @atol = 0.000001
108
+ @jac = jac
109
+ @maxstep = 0
110
+
111
+
112
+ if (inter) then
113
+ @info[2]=1
114
+ end
115
+
116
+ @neq = neq
117
+ @pneq = FFI::MemoryPointer.new(:int)
118
+ @pneq.write_int(neq)
119
+ @y = y
120
+ @yprime = yprime
121
+
122
+ @py = FFI::MemoryPointer.new(:double,neq)
123
+ @py.write_array_of_double(y)
124
+ @pyprime = FFI::MemoryPointer.new(:double,neq)
125
+ @pyprime.write_array_of_double(yprime)
126
+
127
+ @prtol = FFI::MemoryPointer.new(:double)
128
+ @patol = FFI::MemoryPointer.new(:double)
129
+
130
+ #
131
+ # residual proc called from the Fortran. Let's pass it onto the user's residual procedure
132
+ # in a easier to use form
133
+ #
134
+ @resproc = Proc.new do |p1,p2,p3,p4,p5,p6,p7,p8|
135
+ delta = p5.read_array_of_double(@neq)
136
+ @res.call(p1.read_double,p2.read_array_of_double(@neq),p3.read_array_of_double(@neq),delta)
137
+ p5.write_array_of_double(delta)
138
+ end
139
+
140
+ #
141
+ # jacobian proc called from the Fortran. Let's pass it onto the user's jacboian procedure
142
+ # in a easier to use form
143
+ #
144
+ @jacproc = Proc.new do |p1,p2,p3,p4,p5,p6,p7|
145
+ all = p4.read_array_of_double(@neq*@neq)
146
+ jacm = Array.new
147
+ for i in 0..(@neq-1) do
148
+ arow = Array.new
149
+ for j in 0..(@neq-1) do
150
+ arow << all[j*@neq+i] # Fortran stores in column major, though references in row major
151
+ end
152
+ jacm << arow
153
+ end
154
+
155
+ @jac.call(p1.read_double,p2.read_array_of_double(@neq),p3.read_array_of_double(@neq),jacm,p5.read_double)
156
+
157
+ p4.write_array_of_double(jacm.transpose.flatten) # Fortran stores in column major, though references in row major
158
+ end
159
+
160
+
161
+
162
+
163
+ end
164
+ #
165
+ # solve the initial value problem
166
+ # this is only required if the Y's and Y'primes are not
167
+ # already consistent
168
+ #
169
+ # the contents of y or yprime will be modified
170
+ #
171
+ # init=
172
+ # * 1 compute derivatives and algebraics from states
173
+ # * 2 compute algebraics and states from derivatives
174
+ #
175
+ # ialgs = an array indicating which Y's are algebraics
176
+ # 0 means it is a state (aka has derivative in the equations)
177
+ # 1 means it is an algebraic
178
+ #
179
+ def solveForInitialValues(time,y,yprime,ialgs,init=1,mxnit=5,mxnj=6,mxnh=5,lsoff=0,stptol=0,epinit=0.01)
180
+
181
+ @mxnit = mxnit
182
+ @mxnj = mxnj
183
+ @mxnh = mxnh
184
+ @lsoff = lsoff
185
+ pidum = FFI::MemoryPointer.new(:int)
186
+ @stptol = (stptol==0 ? D1MACH(pidum)**(2.0/3.0) : stptol)
187
+ @epinit = epinit
188
+ @info[16] = 1
189
+ @iwork[31] = @mxnit
190
+ @iwork[32] = @mxnj
191
+ @iwork[33] = @mxnh
192
+ @iwork[34] = @lsoff
193
+ @work[13] = @stptol
194
+ @work[14] = @epinit
195
+
196
+ ptime = FFI::MemoryPointer.new(:double)
197
+ ptout = FFI::MemoryPointer.new(:double)
198
+ pidid = FFI::MemoryPointer.new(:int)
199
+ @y = y
200
+ @yprime = yprime
201
+
202
+ ptime.write_double(time)
203
+ ptout.write_double(time+1)
204
+ @py.write_array_of_double(@y)
205
+ @pyprime.write_array_of_double(@yprime)
206
+ @prtol.write_double(@rtol)
207
+ @patol.write_double(@atol)
208
+
209
+ if (init==1) then
210
+ @info[10]=1
211
+ for i in 0..(@neq-1) do
212
+ @iwork[40+i] = (ialgs[i]==1 ? -1 : 1)
213
+ end
214
+ @info[13]=1
215
+ @piwork.write_array_of_int(@iwork)
216
+ @pwork.write_array_of_double(@work)
217
+ @pinfo.write_array_of_int(@info)
218
+ DDASPK(@resproc,@pneq,ptime,@py,@pyprime,ptout,@pinfo,@prtol,@patol,pidid,@pwork,@plwr,@piwork,@plwi,nil,nil,@jacproc,nil)
219
+ @y.replace @py.read_array_of_double(@neq)
220
+ @yprime.replace @pyprime.read_array_of_double(@neq)
221
+ idid = pidid.read_int
222
+ elsif (init==2) then
223
+ @info[10]=2
224
+ for i in 0..(@neq-1) do
225
+ @iwork[40+i] = (ialgs[i]==1 ? -1 : 1)
226
+ end
227
+ @info[13]=1
228
+ @piwork.write_array_of_int(@iwork)
229
+ @pwork.write_array_of_double(@work)
230
+ @pinfo.write_array_of_int(@info)
231
+ DDASPK(@resproc,@pneq,ptime,@py,@pyprime,ptout,@pinfo,@prtol,@patol,pidid,@pwork,@plwr,@piwork,@plwi,nil,nil,@jacproc,nil)
232
+ @y.replace @py.read_array_of_double(@neq)
233
+ @yprime.replace @pyprime.read_array_of_double(@neq)
234
+ idid = pidid.read_int
235
+ end
236
+ @info[13] = 0
237
+ @info[10] = 0
238
+ @info[0] = 0
239
+ @info[16] = 0
240
+ idid
241
+
242
+ end
243
+
244
+ def solve (time, tout)
245
+ #
246
+ # solver options
247
+ #
248
+
249
+ @prtol.write_double(@rtol)
250
+ @patol.write_double(@atol)
251
+
252
+ #
253
+ # user supply an explicit Jacobian?
254
+ #
255
+ if (@jac) then
256
+ @info[4]=1
257
+ else
258
+ @info[4]=0
259
+ end
260
+ #
261
+ # maximum time step option
262
+ #
263
+ if (@maxstep!=0) then
264
+ @info[6]=1
265
+ @work[1]=@maxstep
266
+ else
267
+ @info[6]=0
268
+ @work[1]=@maxstep
269
+ end
270
+
271
+ #
272
+ # starting time
273
+ #
274
+ ptime = FFI::MemoryPointer.new(:double)
275
+ ptime.write_double(time)
276
+
277
+ #
278
+ # ending time
279
+ #
280
+ ptout = FFI::MemoryPointer.new(:double)
281
+ ptout.write_double(tout)
282
+
283
+ idid=1
284
+ pidid = FFI::MemoryPointer.new(:int)
285
+ pidid.write_int(idid)
286
+ @pwork.write_array_of_double(@work)
287
+ @piwork.write_array_of_int(@iwork)
288
+ @pinfo.write_array_of_int(@info)
289
+
290
+ while (idid==1) do
291
+ DDASPK(@resproc,@pneq,ptime,@py,@pyprime,ptout,@pinfo,@prtol,@patol,pidid,@pwork,@plwr,@piwork,@plwi,nil,nil,@jacproc,nil)
292
+ idid = pidid.read_int
293
+ #
294
+ # report intermediate values ?
295
+ #
296
+ if ((idid==1)&&(@inter)) then
297
+ @inter.call(ptime.read_double,@py.read_array_of_double(@neq),@pyprime.read_array_of_double(@neq))
298
+ end
299
+
300
+ end
301
+
302
+ @work = @pwork.read_array_of_double(@lwr) # save the working ram
303
+ @iwork = @piwork.read_array_of_int(@lwi)
304
+ @info[0] = 1
305
+ [ptime.read_double,@py.read_array_of_double(@neq),@pyprime.read_array_of_double(@neq),idid]
306
+
307
+ end
308
+
309
+ def reset
310
+ @info[0]=0
311
+ @py.write_array_of_double(@y)
312
+ @pyprime.write_array_of_double(@yprime)
313
+ end
314
+
315
+ end
316
+
317
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rb-daspk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ platform: x86-mswin32-60
6
+ authors:
7
+ - Eric Meyers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-05 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ffi
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.5.3
24
+ version:
25
+ description: Allows users to solve differential algebraic equations in Ruby, using Ruby constructs. Interfaces with the DASPK Fortran library. DASPK solves DAE's of the form G(t,y,y',p) = 0
26
+ email: etm@ericmeyers.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/daspk.dll
35
+ - lib/rb-daspk.rb
36
+ - examples/springmass.rb
37
+ has_rdoc: true
38
+ homepage: http://rb-daspk.rubyforge.org
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options:
43
+ - -S
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project: rb-daspk
61
+ rubygems_version: 1.3.5
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: DASPK Ruby Interface. Allows users to solve differential algebraic equations in Ruby, using Ruby constructs. Interfaces with the DASPK Fortran library. DASPK solves DAE's of the form G(t,y,y',p) = 0
65
+ test_files: []
66
+