V3FIT
bsc_T.f
1 !*******************************************************************************
2 ! File bsc_mod.f
3 ! Contains module bsc
4 ! Under CVS control at logjam.gat.com
5 
6 !*******************************************************************************
7 ! MODULE bsc
8 ! (Biot-Savart Coils)
9 ! SECTION I. VARIABLE DECLARATIONS
10 ! SECTION II. DERIVED TYPE (STRUCTURE) DECLARATIONS
11 ! SECTION III. INTERFACE BLOCKS
12 ! SECTION IV. CONSTRUCTION SUBROUTINES
13 ! SECTION V. DESTRUCTION SUBROUTINES
14 ! SECTION VI. ASSIGNMENT SUBROUTINES
15 ! SECTION VII. COIL COLLECTION MANIPULATION SUBROUTINES
16 ! SECTION VIII. ROTATE AND SHIFT SUBROUTINES
17 ! SECTION IX. VECTOR POTENTIAL SUBROUTINES
18 ! SECTION X. MAGNETIC FIELD SUBROUTINES
19 ! SECTION XI. MAGNETIC FLUX INTEGRAL SUBROUTINES
20 ! SECTION XII. AUXILIARY SUBROUTINES
21 ! SECTION XIII. DEBUGGING SUBROUTINES
22 ! SECTION XIV. SPECIAL FUNCTIONS
23 ! SECTION XV. DUPLICATE CODING FOR TESTING
24 ! SECTION XVI. COMMENTS FOR DIFFERENT REVISIONS
25 !*******************************************************************************
26  MODULE bsc_t
27 !-------------------------------------------------------------------------------
28 ! Type declarations - lengths of reals, integers, and complexes.
29 !-------------------------------------------------------------------------------
30  USE stel_kinds, ONLY: rprec, iprec, cprec
31 
32  IMPLICIT NONE
33 !*******************************************************************************
34 ! SECTION I. VARIABLE DECLARATIONS
35 !*******************************************************************************
36 
37 !-------------------------------------------------------------------------------
38 ! Frequently used mathematical constants, lots of extra precision.
39 !-------------------------------------------------------------------------------
40  REAL(rprec), PARAMETER :: pi=3.14159265358979323846264338328_rprec
41  REAL(rprec), PARAMETER :: twopi=6.28318530717958647692528677_rprec
42  REAL(rprec), PARAMETER :: one = 1.0_rprec, zero = 0.0_rprec
43 
44 !-------------------------------------------------------------------------------
45 ! Physical Constants
46 !-------------------------------------------------------------------------------
47  REAL(rprec), PARAMETER :: bsc_k2_def = 1.0e-7_rprec
48  REAL(rprec), PARAMETER :: bsc_k2inv_def = 1.0e+7_rprec
49 
50 !-------------------------------------------------------------------------------
51 ! Computational Constants
52 !-------------------------------------------------------------------------------
53  REAL(rprec), PARAMETER :: bsc_mach_eps = epsilon(one)
54 
55 !-------------------------------------------------------------------------------
56 ! Make type declarations and constants Private, so there are no conflicts.
57 !-------------------------------------------------------------------------------
58  PRIVATE rprec, iprec, cprec, pi, twopi, one, zero, bsc_k2_def, &
59  & bsc_k2inv_def, bsc_mach_eps
60 
61 !-------------------------------------------------------------------------------
62 ! Tuning Parameters (Private)
63 !-------------------------------------------------------------------------------
64 ! These are parameters that are pretty well determined, so they
65 ! can be made private. They are not available outside the bsc module.
66 ! For testing purposes, comment out the PRIVATE statement.
67  REAL(rprec) :: bsc_emcut = 0.01_rprec
68 
69 ! bsc_emcut cut off value of m,for A and B for circular coils
70 ! switches between power series and elliptic integrals
71 ! put it here, so that can change in test code
72 
73 ! PRIVATE bsc_emcut
74 
75 !-------------------------------------------------------------------------------
76 ! Tuning Parameters (Not Private)
77 !-------------------------------------------------------------------------------
78 ! These are parameters that are I want to be able to change
79 ! from outside the module, for testing purposes, or for tuning
80 ! the algorithms.
81 
82 ! (Nothing here right now)
83 
84 !*******************************************************************************
85 ! SECTION II. DERIVED TYPE (STRUCTURE) DECLARATIONS
86 ! Type to describe all coils:
87 ! bsc_coil
88 ! Type of coil specified by % c_type.
89 ! Allowable values of c_type:
90 ! fil_loop filamentary loop, consisting of straight line segments
91 ! fil_circ filamentary circular loop, uses complete elliptic integrals
92 ! floop Same as fil_loop. Use is deprecated.
93 ! fcirc Same as fil_circ. Use is deprecated.
94 ! fil_rogo Filamentary (partial) Rogowski coil
95 ! (other c_types not yet implemented)
96 !
97 ! Coil Collection
98 ! bsc_coilcoll collection of bsc_coil's
99 !
100 ! Structure for Rotate and Shift Information
101 ! bsc_rs
102 !*******************************************************************************
103 !-------------------------------------------------------------------------------
104 ! Declare type bsc_coil
105 ! Common to all c_types
106 ! c_type character, type of coil
107 ! s_name character, short name of coil
108 ! l_name character, long name of coil
109 ! current current in the coil
110 ! eps_sq pedestal to avoid numerical singularity if observation point lies on coil
111 ! raux real auxiliary variable. Carried by bsc, but not used within bsc.
112 ! Used for c_type = 'fil_circ'
113 ! rcirc radius of circle
114 ! xcent array(3), Cartesian center of circle
115 ! enhat array(3), unit vector, normal to plane of circle
116 ! Used for c_type = 'fil_loop'
117 ! xnod array(3,-) of cartesian node positions
118 ! dxnod array(3,-) of xnod differences
119 ! ehnod array(3,-) of ehat vectors (normalized dxnod)
120 ! lsqnod array(-) of square lengths of straight line segments (dxnod)
121 ! lnod array(-) of lengths of straight line segments (dxnod)
122 ! sens array(-) of segment sensitivities.
123 ! Used for c_type = 'fil_rogo'
124 ! ave_n_area average value of number of turns per unit length times
125 ! cross-sectional area of turns
126 !-------------------------------------------------------------------------------
127  TYPE bsc_coil
128  CHARACTER (len=10) :: c_type
129  CHARACTER (len=30) :: s_name
130  CHARACTER (len=80) :: l_name
131  REAL(rprec) :: eps_sq
132  REAL(rprec) :: current
133  REAL(rprec) :: raux
134  REAL(rprec) :: rcirc
135  REAL(rprec) :: ave_n_area
136  REAL(rprec), DIMENSION(3) :: xcent, enhat
137  REAL(rprec), DIMENSION(:,:), POINTER :: xnod => null()
138  REAL(rprec), DIMENSION(:,:), POINTER :: dxnod => null()
139  REAL(rprec), DIMENSION(:,:), POINTER :: ehnod => null()
140  REAL(rprec), DIMENSION(:), POINTER :: lsqnod => null()
141  REAL(rprec), DIMENSION(:), POINTER :: lnod => null()
142  REAL(rprec), DIMENSION(:), POINTER :: sens => null()
143  END TYPE bsc_coil
144 !-------------------------------------------------------------------------------
145 ! Declare type bsc_coilcoll
146 ! s_name character, short name of coil collection
147 ! l_name character, long name of coil collection
148 ! ncoil number of coils
149 ! coils array of coils
150 !-------------------------------------------------------------------------------
152  CHARACTER (len=30) :: s_name
153  CHARACTER (len=80) :: l_name
154  INTEGER(iprec) :: ncoil
155  TYPE (bsc_coil), DIMENSION(:), POINTER :: coils => null()
156  END TYPE bsc_coilcoll
157 !-------------------------------------------------------------------------------
158 ! Declare type bsc_rs
159 ! rot_matrix real, array(3,3), rotation matrix for the specific coil
160 ! c_of_rot real, array(3), center of rotation for the specified coil
161 ! shift real, array(3), shift vector for the specified coil
162 !-------------------------------------------------------------------------------
163  TYPE bsc_rs
164  REAL(rprec), DIMENSION(3,3) :: rot_matrix
165  REAL(rprec), DIMENSION(3) :: c_of_rot
166  REAL(rprec), DIMENSION(3) :: shift
167  END TYPE bsc_rs
168 !*******************************************************************************
169 ! SECTION III. INTERFACE BLOCKS
170 !*******************************************************************************
171 !-------------------------------------------------------------------------------
172 ! Assignment for bsc_coil
173 !-------------------------------------------------------------------------------
174  INTERFACE ASSIGNMENT (=)
175  MODULE PROCEDURE bsc_coil_to_coil, bsc_coil_a_to_coil_a
176  END INTERFACE
177 
178 !-------------------------------------------------------------------------------
179 ! Generic construct
180 !-------------------------------------------------------------------------------
181  INTERFACE bsc_construct
182  MODULE PROCEDURE bsc_construct_coil, bsc_construct_coilcoll, &
183  & bsc_construct_rs
184  END INTERFACE
185 
186 !-------------------------------------------------------------------------------
187 ! Generic destroy
188 !-------------------------------------------------------------------------------
189  INTERFACE bsc_destroy
190  MODULE PROCEDURE bsc_destroy_coil, bsc_destroy_coilcoll, &
191  & bsc_destroy_coil_a
192  END INTERFACE
193 
194 !-------------------------------------------------------------------------------
195 ! Generic bsc_rot_shift (Rotation and Shift)
196 !-------------------------------------------------------------------------------
197  INTERFACE bsc_rot_shift
198  MODULE PROCEDURE bsc_rot_shift_pt, bsc_rot_shift_pts, &
199  & bsc_rot_shift_coil, &
200  & bsc_rot_shift_coil_a, bsc_rot_shift_coilcoll
201  END INTERFACE
202 
203 !-------------------------------------------------------------------------------
204 ! Generic bsc_a (Vector Potential)
205 !-------------------------------------------------------------------------------
206  INTERFACE bsc_a
207  MODULE PROCEDURE bsc_a_coil, bsc_a_coil_a, bsc_a_coilcoll
208  END INTERFACE
209 
210 !-------------------------------------------------------------------------------
211 ! Generic bsc_b (Magnetic Field)
212 !-------------------------------------------------------------------------------
213  INTERFACE bsc_b
214  MODULE PROCEDURE bsc_b_coil, bsc_b_coil_a, bsc_b_coilcoll
215  END INTERFACE
216 
217 !-------------------------------------------------------------------------------
218 ! Generic bsc_fluxba (Magnetic Flux of a through coil b)
219 !-------------------------------------------------------------------------------
220  INTERFACE bsc_fluxba
221  MODULE PROCEDURE bsc_fluxba_coil, bsc_fluxba_coil_a, &
222  & bsc_fluxba_coilcoll
223  END INTERFACE
224 
225 !-------------------------------------------------------------------------------
226 ! Interface block for testing goes here. See SECTION XII.
227 !-------------------------------------------------------------------------------
228 
229  CONTAINS
230 !*******************************************************************************
231 ! SECTION IV. CONSTRUCTION SUBROUTINES
232 !*******************************************************************************
233 !-------------------------------------------------------------------------------
234 ! Construct a coil
235 !
236 ! For c_type = 'fil_loop' (filamentary loops)
237 ! Note that not all the structure components are needed as arguments.
238 ! dxnod, ehnod, lsqnod, and lnod are computed during construction.
239 !
240 ! Note that the number of nodes in the coil is determined by the SIZE
241 ! of xnod, as passed into bsc_construct_coil.
242 !
243 ! Note that the coil as input is assumed to be NOT CLOSED.
244 ! JDH To Do: add coding to CHECK this. Want to avoid closing a loop
245 ! that is already closed. Better yet, why not prune out very short
246 ! segments, say < 10^-8 times total length.
247 !
248 ! For c_type = 'fil_circ' (filamentary circular loops)
249 ! Unit length for enhat is enforced on construction
250 !
251 ! For c_type = 'fil_rogo' (filamentary Rogowski coils)
252 ! Much of the coding is the same as for fil_loop coils.
253 !-------------------------------------------------------------------------------
254  SUBROUTINE bsc_construct_coil(this,c_type,s_name,l_name,current, &
255  & xnod,rcirc,xcent,enhat,raux,anturns,xsarea,sen)
256 
257  IMPLICIT NONE
258 
259 ! Declare Arguments
260  TYPE (bsc_coil), INTENT (inout) :: this
261  CHARACTER (len=*), INTENT(in) :: c_type
262  CHARACTER (len=*), INTENT(in) :: s_name
263  CHARACTER (len=*), INTENT(in) :: l_name
264  REAL(rprec), INTENT(in) :: current
265  REAL(rprec), DIMENSION(:,:), INTENT(in), OPTIONAL :: xnod
266  REAL(rprec), INTENT(in), OPTIONAL :: rcirc
267  REAL(rprec), DIMENSION(3), INTENT(in), OPTIONAL :: xcent
268  REAL(rprec), DIMENSION(3), INTENT(in), OPTIONAL :: enhat
269  REAL(rprec), INTENT(in), OPTIONAL :: raux
270 
271 ! Declare Arguments that aren't bsc_coil components
272  REAL(rprec), INTENT(in), OPTIONAL :: anturns
273  REAL(rprec), INTENT(in), OPTIONAL :: xsarea
274 ! anturns Total number of turns in Rogowski coil.
275 ! NB. Declared as REAL, not INTEGER
276 ! xsarea Cross-sectional area of turns in Rogowski coil
277 
278 ! Sensitivity of xnod segments.
279  REAL(rprec), DIMENSION(:), INTENT(in), OPTIONAL :: sen
280 
281 ! Declare local variables
282  INTEGER(iprec) :: n_xnod_1, n_xnod_2, i, n, nm1
283  REAL(rprec) :: enlength
284 
285 ! Local Variables added 2010-07-06 JDH
286  REAL(rprec), ALLOCATABLE, DIMENSION(:,:) :: xnod_temp
287  REAL(rprec), ALLOCATABLE, DIMENSION(:) :: sens_temp
288  REAL(rprec), DIMENSION(3) :: vec_temp
289  INTEGER(iprec) :: itemp
290  INTEGER(iprec) :: itemp2
291  REAL(rprec) :: lsqnod_temp
292 
293 ! Start of executable code
294 
295 ! WRITE(*,*) ' Executing bsc_construct_coil'
296 
297 ! First, destroy the coil
298  CALL bsc_destroy(this)
299 
300 ! Scalar assignments, common to all c_types
301  this % s_name = s_name
302  this % l_name = l_name
303  this % current = current
304  IF (PRESENT(raux)) THEN
305  this % raux = raux
306  ELSE
307  this % raux = zero
308  END IF
309 
310 ! Different coding, depending on c_type
311  SELECT CASE (c_type)
312  CASE ('fil_loop','floop','fil_rogo','fil_rogo_s')
313  this % c_type = c_type
314 
315 ! Check for presence of necessary arguments
316  IF (.not. PRESENT(xnod)) THEN
317  WRITE(*,*) 'FATAL: bsc_construct_coil '
318  WRITE(*,*) 'argument xnod not present for c_type =', c_type
319  stop
320  END IF
321 
322 ! Check lengths of xnod
323  n_xnod_1 = SIZE(xnod,1)
324  n_xnod_2 = SIZE(xnod,2)
325  IF (n_xnod_1 .ne. 3) THEN
326  stop .ne.' FATAL:sub. bsc_construct: n_xnod_1 3'
327  ELSE IF (n_xnod_2 .lt. 2) THEN
328  stop ' FATAL:sub. bsc_construct: n_xnod_2 < 2'
329  ENDIF
330 
331 ! JDH 2010-07-06
332 ! First, Eliminate all zero-length segments.
333  ALLOCATE(xnod_temp(3,n_xnod_2 + 1))
334  IF (PRESENT(sen)) THEN
335  ALLOCATE(sens_temp(n_xnod_2))
336  END IF
337 
338  itemp = 1
339  itemp2 = 1
340  xnod_temp(1:3,1) = xnod(1:3,1)
341  DO i = 2, n_xnod_2
342  vec_temp(1:3) = xnod_temp(1:3,itemp) - xnod(1:3,i)
343  lsqnod_temp = dot_product(vec_temp,vec_temp)
344  IF (lsqnod_temp .eq. zero) THEN
345  cycle
346  ELSE
347  IF (PRESENT(sen)) THEN
348 ! Average the sensitivity of the missing nodes.
349  sens_temp(itemp) = sum(sen(itemp2:i - 1)) &
350  & / SIZE(sen(itemp2:i - 1))
351  itemp2 = i
352  END IF
353 
354  itemp = itemp + 1
355  xnod_temp(1:3,itemp) = xnod(1:3,i)
356  ENDIF
357  END DO
358 
359 ! Check that wrap-around segment is not zero length
360 ! (This effectively unwraps the loop, if it came in wrapped)
361 ! JDH 2012-01-23. Make sure this does NOT apply to Rogowskis
362 ! (because the addition of the wrapping segment only happens for
363 ! fil_loops)
364  IF ((c_type .eq.'fil_loop') .or. (c_type .eq.'floop')) THEN
365  vec_temp(1:3) = xnod_temp(1:3,itemp) - xnod(1:3,1)
366  lsqnod_temp = dot_product(vec_temp,vec_temp)
367  IF (lsqnod_temp .eq. zero) THEN
368  itemp = itemp - 1
369  ENDIF
370  ENDIF
371 
372  IF (itemp .eq. 1) THEN
373  stop .eq.' FATAL:sub. bsc_construct: itemp 1'
374  ENDIF
375 
376 ! Close (wrap) fil_loops
377  IF ((c_type .eq.'fil_loop') .or. (c_type .eq.'floop')) THEN
378  IF (itemp .eq. 2) THEN
379  WRITE (6,*) ' WARNING: bsc_construct: one straight ', &
380  & ' filament for coil: ', trim(s_name)
381  WRITE (6,*) ' (this is a straight coil filament)'
382  ELSE ! Here - need to close (wrap) the coil
383  itemp = itemp + 1
384  xnod_temp(1:3,itemp) = xnod(1:3,1)
385  ENDIF
386  ENDIF
387 
388  n = itemp
389  nm1 = n - 1
390 ! JDH 2010-07-06
391 
392 ! Allocate space for pointers. No need to deallocate space
393 ! as this was done in bsc_destroy (called at
394 ! start of bsc_construct_coil)
395  ALLOCATE(this % xnod(3,n))
396  ALLOCATE(this % dxnod(3,nm1))
397  ALLOCATE(this % ehnod(3,nm1))
398  ALLOCATE(this % lsqnod(nm1))
399  ALLOCATE(this % lnod(nm1))
400  ALLOCATE(this % sens(nm1))
401 
402 ! Copy xnod to this % xnod.
403 ! Modified 2010-07-06 JDH
404 ! this % xnod(1:3,1:nm1) = xnod(1:3,1:nm1)
405  this % xnod(1:3,1:n) = xnod_temp(1:3,1:n)
406  DEALLOCATE(xnod_temp)
407 
408  IF (PRESENT(sen)) THEN
409  this % sens(1:nm1) = sens_temp(1:nm1)
410  ELSE
411  this % sens = 1.0
412  END IF
413 
414 ! Calculations for the other arrays (not included as arguments)
415 ! Compute dxnod
416  this % dxnod(1:3,1:nm1) = this % xnod(1:3,2:n) &
417  & - this % xnod(1:3,1:nm1)
418 
419 ! Compute lsqnod = dxnod*dxnod
420  this % lsqnod(1:nm1) = this % dxnod(1,1:nm1)**2 + &
421  & this % dxnod(2,1:nm1)**2 + this % dxnod(3,1:nm1)**2
422  IF (any(this % lsqnod(1:nm1) .eq. zero)) &
423  & stop 'FATAL: bsc_construct_coil : lsqnod must be nonzero'
424  this % eps_sq = bsc_mach_eps * &
425  & minval(this % lsqnod(1:nm1))
426 ! JDH 11-21-03. Change EPSILON(-) to bsc_mach_eps
427 ! JDH 11-21-03. Not sure just how this % eps_sq will get used.
428 
429 ! Compute lnod
430  this % lnod(1:nm1) = sqrt(this % lsqnod(1:nm1))
431 
432 ! Compute ehnod
433  DO i = 1,3
434  this % ehnod(i,1:nm1) = this % dxnod(i,1:nm1) / &
435  & this % lnod(1:nm1)
436  END DO
437 
438  CASE ('fil_circ','fcirc')
439  this % c_type = c_type
440 
441 ! Check for presence of necessary arguments
442  IF (.not. PRESENT(rcirc)) THEN
443  WRITE(6,*) 'FATAL: bsc_construct_coil '
444  WRITE(6,*) 'arg rcirc not present for c_type =', c_type
445  stop
446  ELSE IF (.not. PRESENT(xcent)) THEN
447  WRITE(6,*) 'FATAL: bsc_construct_coil '
448  WRITE(6,*) 'arg xcent not present for c_type =', c_type
449  stop
450  ELSE IF (.not. PRESENT(enhat)) THEN
451  WRITE(6,*) 'FATAL: bsc_construct_coil '
452  WRITE(6,*) 'arg enhat not present for c_type =', c_type
453  stop
454  END IF
455 
456 ! Copy arguments
457  this % rcirc = rcirc
458  this % xcent(1:3) = xcent(1:3)
459 
460 ! Normalize the enhat unit vector
461 ! ZZZ Think about 1.d-40 number here
462  enlength = sqrt(dot_product(enhat,enhat))
463  IF (enlength .le. 1.e-40_rprec) THEN
464  this % enhat(1) = 0 ! JDH Integers get converted correctly
465  this % enhat(2) = 0
466  this % enhat(3) = 1
467  WRITE(*,*) 'WARN: bsc_contruct: enhat set to (0,0,1)'
468  ELSE
469  this % enhat = enhat / enlength
470  END IF ! normalize the enhat vector
471 
472  CASE DEFAULT
473  WRITE(*,*) 'FATAL: bsc_contruct: unrecognized c_type = ',c_type
474  stop
475  END SELECT ! Different coding depending on c_type
476 
477 ! More stuff, for Rogowskis
478  IF (this % c_type .eq. 'fil_rogo') THEN
479  IF (.not. PRESENT(anturns)) THEN
480  WRITE(6,*) 'FATAL: bsc_construct_coil '
481  WRITE(6,*) 'arg anturns not present for c_type =', c_type
482  stop
483  ELSE IF (.not. PRESENT(xsarea)) THEN
484  WRITE(6,*) 'FATAL: bsc_construct_coil '
485  WRITE(6,*) 'arg xsarea not present for c_type =', c_type
486  stop
487  END IF
488 
489  this % ave_n_area = xsarea * anturns / sum(this % lnod(1:nm1))
490  END IF
491 
492  END SUBROUTINE bsc_construct_coil
493 
494 !-------------------------------------------------------------------------------
495 ! Construct a coil collection: bsc_coilcoll
496 !-------------------------------------------------------------------------------
497  SUBROUTINE bsc_construct_coilcoll(this,s_name,l_name,ncoil_init)
498  IMPLICIT NONE
499 
500 ! Required Arguments
501  TYPE (bsc_coilcoll), INTENT (inout) :: this
502  CHARACTER (len=*), INTENT(in) :: s_name
503  CHARACTER (len=*), INTENT(in) :: l_name
504 
505 ! Optional Arguments
506 ! ncoil_init allows user to override default initial size of this % coils array
507  INTEGER(iprec), INTENT(in), OPTIONAL :: ncoil_init
508 
509 ! Declare local variables
510  INTEGER(iprec), PARAMETER :: ncoil_init_def = 10
511  INTEGER(iprec) :: ncoil_init_use
512 
513 ! Start of executable code
514 ! Check coil pointer. If it is associated, then destroy new_coilcoll
515 ! and start over
516 
517  IF (ASSOCIATED(this % coils)) CALL bsc_destroy(this)
518 
519 ! Initial assignments and allocation
520  this % s_name = s_name
521  this % l_name = l_name
522  this % ncoil = 0
523 
524  IF (PRESENT(ncoil_init)) THEN
525  ncoil_init_use = max(2,ncoil_init)
526  ELSE
527  ncoil_init_use = ncoil_init_def
528  ENDIF
529 
530  ALLOCATE(this % coils(ncoil_init_use))
531 
532  END SUBROUTINE bsc_construct_coilcoll
533 
534 !-------------------------------------------------------------------------------
535 ! Construct a coil rotation and shift type bsc_rs
536 !
537 ! Required Arguments
538 ! this : bsc_rs type to create.
539 ! on exit, contains the rotation matrix, the center of
540 ! rotation, and the shift vector
541 ! theta : real(rprec), theta angle in spherical coordinates to
542 ! indicate the direction of the rotation axis vector
543 ! phi : real(rprec), phi angle in spherical coordinates to
544 ! indicate the direction of the rotation axis vector
545 ! rot_ang : real(rprec), angle specifying rigid-body rotation with
546 ! respect to the axis of rotation (left-hand rule).
547 !
548 ! Optional Arguments
549 ! c_of_rot : real(rprec), array (size 3) center of rigid-body center
550 ! of mass(com) shifts
551 ! shift : real(rprec), array (size 3) shift vector for the
552 ! translation of the coil
553 !-------------------------------------------------------------------------------
554  SUBROUTINE bsc_construct_rs(this,theta,phi,rot_ang, &
555  & c_of_rot,shift)
556  IMPLICIT NONE
557 
558 ! Argument Declaration
559 ! Required Arguments
560  TYPE (bsc_rs), INTENT(inout) :: this
561  REAL(rprec), INTENT(in) :: theta
562  REAL(rprec), INTENT(in) :: phi
563  REAL(rprec), INTENT(in) :: rot_ang
564 
565 ! Optional Arguments
566  REAL(rprec), DIMENSION(3), OPTIONAL, INTENT(in) :: c_of_rot
567  REAL(rprec), DIMENSION(3), OPTIONAL, INTENT(in) :: shift
568 
569 ! Local Variable Declaration
570  REAL(rprec) :: omega(3)
571  REAL(rprec) :: cosrot, sinrot, onemcos
572 
573 ! Start of executable code
574 !*******************************************************************************
575 ! Apply rotation about an axis of rotation formula
576 ! (Ref: "Classical Mechanics", Goldstein, (first ed. P-162)
577 ! (second ed. pp 164-65)
578 !
579 ! x(rot) = [x(in) dot OMEGA]OMEGA
580 ! + cos(rot_ang)[X(in) - (X(in) dot OMEGA)OMEGA]
581 ! + sin(rot_ang) X(in) cross OMEGA
582 !
583 ! == R * X(in)
584 !
585 ! where OMEGA = (sin(theta)cos(phi) xhat + sin(theta)*sin(phi) yhat +
586 ! cos(theta) zhat
587 ! is the unit rotation axis vector. Note that only the component of X(in)
588 ! NORMAL to OMEGA is rotated.
589 !
590 ! NOTE: R(inv) = R(transpose) = R(-rot_ang)
591 ! NOTE: Goldstein's convention is a "left-handed" one. If you point your _left_
592 ! thumb along the OMMEGA vector, the fingers of your left hand indicate
593 ! the direction of rotation.
594 !
595 !*******************************************************************************
596 
597  omega(1) = sin(theta) * cos(phi)
598  omega(2) = sin(theta) * sin(phi)
599  omega(3) = cos(theta)
600 
601  cosrot = cos(rot_ang); sinrot = sin(rot_ang)
602  onemcos = 1 - cosrot
603 
604  this % rot_matrix(1,1) = cosrot + onemcos * omega(1) ** 2
605  this % rot_matrix(1,2) = sinrot * omega(3) + &
606  & onemcos * omega(1) * omega(2)
607  this % rot_matrix(1,3) = -sinrot * omega(2) + &
608  & onemcos * omega(1) * omega(3)
609 
610  this % rot_matrix(2,1) = -sinrot * omega(3) + &
611  & onemcos * omega(1) * omega(2)
612  this % rot_matrix(2,2) = cosrot + onemcos * omega(2) ** 2
613  this % rot_matrix(2,3) = sinrot * omega(1) + &
614  & onemcos * omega(2) * omega(3)
615 
616  this % rot_matrix(3,1) = sinrot * omega(2) + &
617  & onemcos * omega(1) * omega(3)
618  this % rot_matrix(3,2) = -sinrot * omega(1) + &
619  & onemcos * omega(2) * omega(3)
620  this % rot_matrix(3,3) = cosrot + onemcos * omega(3) ** 2
621 
622 
623 ! Assignment of the c_of_rot vector, if present gives the present value of the
624 ! c_of_rot or gives the default value zero
625 
626  IF (PRESENT(c_of_rot)) THEN
627  this % c_of_rot = c_of_rot
628  ELSE
629  this % c_of_rot = zero
630  END IF
631 
632 ! Assignment of the shift vector, if not present gives the default value zero
633  IF (PRESENT(shift)) THEN
634  this % shift = shift
635  ELSE
636  this % shift = zero
637  END IF
638 
639  END SUBROUTINE bsc_construct_rs
640 
641 !*******************************************************************************
642 ! SECTION V. DESTRUCTION SUBROUTINES
643 !*******************************************************************************
644 !-------------------------------------------------------------------------------
645 ! Destroy a coil
646 !-------------------------------------------------------------------------------
647  SUBROUTINE bsc_destroy_coil(this)
648  IMPLICIT NONE
649 
650 ! Declare Arguments
651  TYPE (bsc_coil), INTENT(inout) :: this
652 
653 ! Start of executable code
654 
655 ! Get rid of all components
656  this % c_type = ''
657  this % s_name = ''
658  this % l_name = ''
659  this % current = zero
660  this % eps_sq = zero
661  this % raux = zero
662  this % rcirc = zero
663  this % xcent = zero
664  this % enhat = zero
665  this % ave_n_area = zero
666 
667  IF (ASSOCIATED(this % xnod)) DEALLOCATE(this % xnod)
668  IF (ASSOCIATED(this % dxnod)) DEALLOCATE(this % dxnod)
669  IF (ASSOCIATED(this % ehnod)) DEALLOCATE(this % ehnod)
670  IF (ASSOCIATED(this % lsqnod)) DEALLOCATE(this % lsqnod)
671  IF (ASSOCIATED(this % lnod)) DEALLOCATE(this % lnod)
672  IF (ASSOCIATED(this % sens)) DEALLOCATE(this % sens)
673 
674  END SUBROUTINE bsc_destroy_coil
675 
676 !-------------------------------------------------------------------------------
677 ! Destroy an array of coils
678 !-------------------------------------------------------------------------------
679  SUBROUTINE bsc_destroy_coil_a(this)
680 
681 ! Declare Arguments
682  TYPE (bsc_coil), DIMENSION(:), INTENT(inout) :: this
683  INTEGER :: n, nsize
684 
685  nsize = SIZE(this)
686  DO n = 1, nsize
687  CALL bsc_destroy_coil(this(n))
688  END DO
689 
690  END SUBROUTINE bsc_destroy_coil_a
691 
692 !-------------------------------------------------------------------------------
693 ! Destroy a coilcoll
694 !-------------------------------------------------------------------------------
695  SUBROUTINE bsc_destroy_coilcoll(this)
696 
697 ! Declare Arguments
698  TYPE (bsc_coilcoll), INTENT(inout) :: this
699 
700 ! Declare local variables
701  INTEGER(iprec) :: ncoild
702 
703 ! Start of executable code
704 
705  this % ncoil = 0
706  this % s_name = ''
707  this % l_name = ''
708 
709 ! Get rid of coils. Destroy them one by one, to avoid memory leaks.
710  IF (ASSOCIATED(this % coils)) THEN
711  ncoild = SIZE(this % coils)
712  CALL bsc_destroy(this % coils(1:ncoild))
713  DEALLOCATE(this % coils)
714  END IF
715 
716  END SUBROUTINE bsc_destroy_coilcoll
717 
718 !*******************************************************************************
719 ! SECTION VI. ASSIGNMENT SUBROUTINES
720 !*******************************************************************************
721 !-------------------------------------------------------------------------------
722 ! Assignment for coils
723 !-------------------------------------------------------------------------------
724  SUBROUTINE bsc_coil_to_coil(left,right)
725  IMPLICIT NONE
726 
727 ! Declare Arguments
728  TYPE (bsc_coil), INTENT (out) :: left
729  TYPE (bsc_coil), INTENT (in) :: right
730 
731 ! Declare temporary variables
732  REAL(rprec), DIMENSION(:,:), ALLOCATABLE :: temp2
733  REAL(rprec), DIMENSION(:), ALLOCATABLE:: temp1
734 
735 ! Declare local variables
736  INTEGER(iprec) :: n, nm1
737 
738 ! Start of executable code
739 
740 ! WRITE(*,*) ' Executing bsc_coil_to_coil'
741 
742 ! Non-pointer variables.
743 ! Copy them over, for all types of coils
744  left % c_type = right % c_type
745  left % s_name = right % s_name
746  left % l_name = right % l_name
747  left % current = right % current
748  left % eps_sq = right % eps_sq
749  left % raux = right % raux
750  left % rcirc = right % rcirc
751  left % ave_n_area = right % ave_n_area
752  left % xcent = right % xcent
753  left % enhat = right % enhat
754 
755 ! Pointers components of bsc_coil.
756 ! Only bother with this coding if coil is a fil_loop or fil_rogo
757  IF ((right % c_type .eq. 'fil_loop') .or. &
758  & (right % c_type .eq. 'floop') .or. &
759  & (right % c_type .eq. 'fil_rogo') .or. &
760  & (right % c_type .eq. 'fil_rogo_s')) THEN
761 
762 ! Find the SIZE of the pointer arrays.
763  n = SIZE(right % xnod,2)
764  nm1 = n - 1
765 
766 ! Allocate space for the left components, and copy stuff from the right.
767 
768 ! If left and right are identical, then naive coding could
769 ! accidentally deallocate right before it can get copied.
770 ! To avoid this, I first copy the right components into temporary space
771 ! and then deal with the left component deallocation and allocation.
772 
773 ! Two dimensional pointers
774  ALLOCATE(temp2(3,n))
775 
776  temp2(1:3,1:n) = right % xnod(1:3,1:n)
777  IF (ASSOCIATED(left % xnod)) DEALLOCATE(left % xnod)
778  ALLOCATE(left % xnod(3,n))
779  left % xnod(1:3,1:n) = temp2(1:3,1:n)
780 
781  temp2(1:3,1:nm1) = right % dxnod(1:3,1:nm1)
782  IF (ASSOCIATED(left % dxnod)) DEALLOCATE(left % dxnod)
783  ALLOCATE(left % dxnod(3,nm1))
784  left % dxnod(1:3,1:nm1) = temp2(1:3,1:nm1)
785 
786  temp2(1:3,1:nm1) = right % ehnod(1:3,1:nm1)
787  IF (ASSOCIATED(left % ehnod)) DEALLOCATE(left % ehnod)
788  ALLOCATE(left % ehnod(3,nm1))
789  left % ehnod(1:3,1:nm1) = temp2(1:3,1:nm1)
790 
791  DEALLOCATE(temp2)
792 
793 ! One dimensional pointers
794  ALLOCATE(temp1(n))
795 
796  temp1(1:nm1) = right % lsqnod(1:nm1)
797  IF (ASSOCIATED(left % lsqnod)) DEALLOCATE(left % lsqnod)
798  ALLOCATE(left % lsqnod(nm1))
799  left % lsqnod(1:nm1) = temp1(1:nm1)
800 
801  temp1(1:nm1) = right % lnod(1:nm1)
802  IF (ASSOCIATED(left % lnod)) DEALLOCATE(left % lnod)
803  ALLOCATE(left % lnod(nm1))
804  left % lnod(1:nm1) = temp1(1:nm1)
805 
806  temp1(1:nm1) = right % sens(1:nm1)
807  IF (ASSOCIATED(left % sens)) DEALLOCATE(left % sens)
808  ALLOCATE(left % sens(nm1))
809  left % sens(1:nm1) = temp1(1:nm1)
810 
811  DEALLOCATE(temp1)
812 
813  END IF ! c_type .eq. fil_loop or fil_rogo
814 
815  END SUBROUTINE bsc_coil_to_coil
816 
817 !-------------------------------------------------------------------------------
818 ! Assignment for arrays of type bsc_coil
819 !-------------------------------------------------------------------------------
820  SUBROUTINE bsc_coil_a_to_coil_a(left,right)
821 
822 ! Declare Arguments
823  TYPE (bsc_coil), DIMENSION(:), INTENT (out) :: left
824  TYPE (bsc_coil), DIMENSION(:), INTENT (in) :: right
825 
826 ! Declare temporary variables
827  INTEGER(iprec) :: nleft, nright, i
828 
829 ! Start of executable code
830 
831 ! WRITE(*,*) ' Executing bsc_coil_a_to_coil_a'
832 
833  nleft = SIZE(left)
834  nright = SIZE(right)
835  IF (nleft .ne. nright) THEN
836  WRITE(*,*) .ne.'FATAL in bsc_coil_a_to_coil_a. nleft nright'
837  stop
838  END IF
839 
840 ! Assignment, one by one
841  DO i = 1,nleft
842  left(i) = right(i)
843  END DO
844 
845  END SUBROUTINE bsc_coil_a_to_coil_a
846 
847 
848 ! ZZZ What about scalar = array(1)?
849 ! ZZZ What about broadcast, array(i:j) = scalar?
850 
851 !*******************************************************************************
852 ! SECTION VII. COIL COLLECTION MANIPULATION SUBROUTINES
853 !*******************************************************************************
854 !-------------------------------------------------------------------------------
855 ! Append a coil to a coil collection
856 !
857 ! Note that this has some clunky coding, (within the IF test)
858 ! so that the number of coils in a coil collection can be
859 ! arbitrarily large.
860 ! ZZZ Think about ways to do this better.
861 !-------------------------------------------------------------------------------
862  SUBROUTINE bsc_append(this, newcoil)
863  IMPLICIT NONE
864 
865 ! Declare Arguments
866  TYPE (bsc_coilcoll), INTENT(inout) :: this
867  TYPE (bsc_coil), INTENT(in) :: newcoil
868 
869 ! Declare local variables
870  INTEGER(iprec) :: icoil, ncoild
871  INTEGER(iprec), PARAMETER :: nincr = 10
872 
873  TYPE (bsc_coil), DIMENSION(:), ALLOCATABLE :: coils_temp
874 
875 ! Start of executable code
876 
877 ! Check to see status of coilcoll
878  IF (.NOT. ASSOCIATED(this % coils)) THEN
879  CALL bsc_construct(this,'id from bsc_append', '')
880  END IF
881  ncoild = SIZE(this % coils)
882 
883 ! Check to see if need to increment size of coils array
884  IF (this % ncoil + 1 .gt. ncoild) THEN
885 
886 ! Make some temporary space, and copy coils to it
887  ALLOCATE(coils_temp(ncoild))
888 
889 ! JDH 03.27.03. SPH had coding in here for different compilers
890 ! Problem was that one compiler did not like array syntax for
891 ! coils_temp(1:ncoild) = this % coils(1:ncoild)
892 ! "ON IBM RISC, NEED V7.1.1. OR LATER FOR ASSIGNMENT OF ARRAY TO WORK CORRECTLY"
893 ! I just eliminated array syntax coding. Do loop works, and avoids conditional
894 ! compilation.
895  DO icoil = 1, ncoild
896  coils_temp(icoil) = this % coils(icoil)
897  END DO
898 
899 ! Destroy the existing coils and free up the space
900  CALL bsc_destroy(this % coils(1:ncoild))
901  DEALLOCATE(this % coils)
902 
903 ! Increase the size of the coils array, and copy old stuff there
904  ALLOCATE(this % coils(ncoild + nincr))
905  this % coils(1:ncoild) = coils_temp(1:ncoild)
906 
907 ! Get rid of the temporary coils
908  CALL bsc_destroy(coils_temp(1:ncoild))
909  DEALLOCATE(coils_temp)
910 
911  END IF
912 ! End of Check to see if need to increment SIZE of coils
913 
914 ! Copy newcoil onto end of ncoils
915  this % ncoil = this % ncoil + 1
916  this % coils(this % ncoil) = newcoil
917 
918  END SUBROUTINE bsc_append
919 !*******************************************************************************
920 ! SECTION VIII. ROTATION AND SHIFT SUBROUTINES
921 !*******************************************************************************
922 
923 !-------------------------------------------------------------------------------
924 ! Generic Subroutine: bsc_rot_shift
925 ! First argument is the object to be rotated and shifted
926 ! Second argument is a bsc_rs, which carries the rotation and shift information
927 !
928 ! Different versions depending on first argument:
929 ! bsc_rot_shift_pts First argument is a two dimensional array of points
930 ! bsc_rot_shift_pt First argument is a single point (Dimension(3))
931 ! bsc_rot_shift_coil First argument is a bsc_coil
932 ! bsc_rot_shift_coil_a First argument is an array of bsc_coil
933 ! bsc_rot_shift_coilcoll First argument is a bsc_coilcoll
934 !
935 ! Particular subroutines, called by __coil, depending on c_type.
936 ! bsc_rot_shift_coil_fil_loop
937 ! bsc_rot_shift_coil_fil_circ
938 ! c_type = 'fil_rogo': also calls bsc_rot_shift_coil_fil_loop
939 !-------------------------------------------------------------------------------
940 ! Rotation and Shift for an array of points
941 ! Optional third argument xyz_dim is an integer variable that specifies
942 ! which index of the 2 d array is the coordinate index. Legal values are 1 and 2.
943 !-------------------------------------------------------------------------------
944  SUBROUTINE bsc_rot_shift_pts(this,my_rs,xyz_dim)
945  IMPLICIT NONE
946 
947 ! Argument Declaration
948 ! Required Arguments
949  REAL(rprec), DIMENSION(:,:), INTENT(inout) :: this
950  TYPE (bsc_rs), INTENT(in) :: my_rs
951 
952 ! Optional Arguments
953  INTEGER(iprec), OPTIONAL, INTENT(in) :: xyz_dim
954 
955 ! Local Variable Declaration
956  REAL(rprec), DIMENSION(:,:), ALLOCATABLE :: this_temp
957  REAL(rprec), DIMENSION(3) :: shift_2
958  INTEGER(iprec) :: xyz_dim_use
959  INTEGER(iprec) :: is1, js2, i, j, nm1
960 
961 ! Start of executable code
962 
963  is1 = SIZE(this, 1)
964  js2 = SIZE(this, 2)
965 
966 ! Allocates the temporary array of rotated vectors with the same size as this
967  ALLOCATE(this_temp(is1,js2))
968 
969 ! Logic to determinate the value of xyz_dim_use
970 
971  IF (PRESENT(xyz_dim)) THEN
972  SELECT CASE (xyz_dim)
973  CASE (1)
974  IF (is1 == 3) THEN
975  xyz_dim_use = 1
976  ELSE
977  WRITE(*,*) 'ERROR: bsc_rot_shift_pts: xyz_dim invalid'
978  stop
979  END IF
980 
981  CASE (2)
982  IF (js2 == 3) THEN
983  xyz_dim_use = 2
984  ELSE
985  WRITE(*,*) 'ERROR: bsc_rot_shift_pts: xyz_dim invalid'
986  stop
987  END IF
988 
989  CASE DEFAULT
990  WRITE(*,*) 'WARNING: bsc_rot_shift_pts: xyz_dim has not a', &
991  & 'valid value'
992  END SELECT
993 
994  ELSE
995  IF (is1 == 3) THEN
996  xyz_dim_use = 1
997  ELSE IF (js2 == 3) THEN
998  xyz_dim_use = 2
999  ELSE
1000  WRITE(*,*) 'ERROR: bsc_rot_shift_pts: points have no ', &
1001  & 'dimension of length 3'
1002  stop
1003  END IF
1004 
1005  END IF
1006 
1007 ! Computes the shifts and the rotations
1008  shift_2(1:3) = my_rs % c_of_rot(1:3) + my_rs % shift(1:3)
1009 
1010  SELECT CASE (xyz_dim_use)
1011  CASE (1)
1012  this(1:3,1:js2) = this(1:3,1:js2) - &
1013  & spread(my_rs % c_of_rot,2,js2)
1014  this_temp = matmul(my_rs % rot_matrix, this)
1015  this(1:3,1:js2) = this_temp(1:3,1:js2) + spread(shift_2,2,js2)
1016 
1017  CASE (2)
1018  this(1:is1,1:3) = this(1:is1,1:3) - &
1019  & spread(my_rs % c_of_rot,1,is1)
1020  this_temp = matmul(this,transpose(my_rs % rot_matrix))
1021  this(1:is1,1:3) = this_temp(1:is1,1:3) + spread(shift_2,1,is1)
1022 
1023  CASE DEFAULT
1024  WRITE(*,*) 'FATAL ERROR: bsc_rot_shift_pts: xyz_dim_use is', &
1025  & ' not a valid value (1 or 2)'
1026 
1027  END SELECT
1028 
1029 ! Deallocates the temporary array of rotated vectors
1030  DEALLOCATE(this_temp)
1031 
1032  END SUBROUTINE bsc_rot_shift_pts
1033 
1034 !-------------------------------------------------------------------------------
1035 ! Rotation and Shift for single point
1036 !-------------------------------------------------------------------------------
1037  SUBROUTINE bsc_rot_shift_pt(this,my_rs)
1038  IMPLICIT NONE
1039 
1040 ! Argument Declaration
1041 ! Required Arguments
1042  REAL(rprec), DIMENSION(3), INTENT(inout) :: this
1043  TYPE (bsc_rs), INTENT(in) :: my_rs
1044 
1045 ! Local Variable Declaration
1046  REAL(rprec), DIMENSION(3) :: this_temp
1047 
1048 ! Start of executable code
1049  this = this - my_rs % c_of_rot
1050  this_temp = matmul(my_rs % rot_matrix, this)
1051  this = this_temp + my_rs % c_of_rot + my_rs % shift
1052 
1053  END SUBROUTINE bsc_rot_shift_pt
1054 
1055 !-------------------------------------------------------------------------------
1056 ! Rotation and Shift for single coil
1057 !-------------------------------------------------------------------------------
1058  SUBROUTINE bsc_rot_shift_coil(this,my_rs)
1059  IMPLICIT NONE
1060 
1061 ! Argument Declaration
1062 ! Required Arguments
1063  TYPE (bsc_coil), INTENT(inout) :: this
1064  TYPE (bsc_rs), INTENT(in) :: my_rs
1065 
1066 ! Local Variable Declaration
1067 
1068 ! Start of executable code
1069 
1070  SELECT CASE (this % c_type)
1071  CASE ('fil_loop','floop','fil_rogo')
1072  CALL bsc_rot_shift_coil_fil_loop(this,my_rs)
1073 
1074  CASE ('fil_circ','fcirc')
1075  CALL bsc_rot_shift_coil_fil_circ(this,my_rs)
1076 
1077  CASE DEFAULT
1078  WRITE(*,*) 'FATAL: bsc_rot_shift_coil: c_type unrecognized:', &
1079  & this % c_type
1080  stop
1081  END SELECT
1082 
1083  END SUBROUTINE bsc_rot_shift_coil
1084 
1085 !-------------------------------------------------------------------------------
1086 ! Rotation and Shift for single filamentary loop
1087 !-------------------------------------------------------------------------------
1088  SUBROUTINE bsc_rot_shift_coil_fil_loop(this,my_rs)
1089 ! Rotation and shift for single filamentary loop
1090 ! Should only be called from bsc_rot_shift_coil
1091 
1092 ! Argument Declaration
1093 ! Required Arguments
1094  TYPE (bsc_coil), INTENT(inout) :: this
1095  TYPE (bsc_rs), INTENT(in) :: my_rs
1096 
1097 ! Local Variable Declaration
1098  INTEGER(iprec) :: nwire, nm1, i
1099 
1100 ! Start of executable code
1101 
1102  nwire = SIZE(this % xnod,2)
1103  nm1 = max(1, nwire-1)
1104 
1105 ! Rotates the points that form the coil
1106 
1107  CALL bsc_rot_shift_pts(this % xnod,my_rs,xyz_dim = 1_iprec)
1108 
1109 ! Recompute dxnod, ehat vectors for rotated coils
1110 ! lnod and lsqnod should be invariant (check this?)
1111 
1112  this % dxnod(1:3,1:nm1) = this % xnod(1:3,2:nwire) &
1113  & - this % xnod(1:3,1:nm1)
1114 
1115  DO i = 1,3
1116  this % ehnod(i,1:nm1) = this % dxnod(i,1:nm1) / &
1117  & this % lnod(1:nm1)
1118  END DO
1119 
1120  END SUBROUTINE bsc_rot_shift_coil_fil_loop
1121 
1122 !-------------------------------------------------------------------------------
1123 ! Rotation and shift for single filamentary circle
1124 !-------------------------------------------------------------------------------
1125  SUBROUTINE bsc_rot_shift_coil_fil_circ(this,my_rs)
1126  IMPLICIT NONE
1127 ! Rotation and shift for single filamentary circle
1128 ! Should only be called from bsc_rot_shift_coil
1129 
1130 ! Argument Declaration
1131 ! Required Arguments
1132  TYPE (bsc_coil), INTENT(inout) :: this
1133  TYPE (bsc_rs), INTENT(in) :: my_rs
1134 
1135 ! Local Variable Declaration
1136  REAL(rprec), DIMENSION(3,2) :: rot_vectors
1137 
1138 ! Start of executable code
1139 
1140 ! Rotates the circular coil and its normal vector with respect to the
1141 ! center of rotation
1142 
1143  rot_vectors(1:3,1) = this % xcent(1:3)
1144  rot_vectors(1:3,2) = this % enhat(1:3) + this % xcent(1:3)
1145 
1146  CALL bsc_rot_shift_pts(rot_vectors,my_rs,xyz_dim = 1_iprec)
1147 
1148  this % xcent(1:3) = rot_vectors(1:3,1)
1149  this % enhat(1:3) = rot_vectors(1:3,2) - this % xcent(1:3)
1150 
1151  END SUBROUTINE bsc_rot_shift_coil_fil_circ
1152 
1153 !-------------------------------------------------------------------------------
1154 ! Rotation and Shift for array of coils
1155 !-------------------------------------------------------------------------------
1156  SUBROUTINE bsc_rot_shift_coil_a(this,my_rs)
1157  IMPLICIT NONE
1158 
1159 ! Argument Declaration
1160 ! Required Arguments
1161  TYPE (bsc_coil), DIMENSION(:), INTENT(inout) :: this
1162  TYPE (bsc_rs), INTENT(in) :: my_rs
1163 
1164 ! Local Variable Declaration
1165  INTEGER(iprec) :: n, nsize
1166 
1167 ! Start of executable code
1168  nsize = SIZE(this)
1169 
1170  DO n = 1,nsize
1171  CALL bsc_rot_shift_coil(this(n),my_rs)
1172  END DO
1173 
1174  END SUBROUTINE bsc_rot_shift_coil_a
1175 
1176 !-------------------------------------------------------------------------------
1177 ! Rotation and Shift for a coil collection
1178 !-------------------------------------------------------------------------------
1179  SUBROUTINE bsc_rot_shift_coilcoll(this,my_rs)
1180 
1181 ! Argument Declaration
1182 ! Required Arguments
1183  TYPE (bsc_coilcoll), INTENT(inout) :: this
1184  TYPE (bsc_rs), INTENT(in) :: my_rs
1185 
1186 ! Start of executable code
1187  CALL bsc_rot_shift_coil_a(this % coils(1:this % ncoil),my_rs)
1188 
1189  END SUBROUTINE bsc_rot_shift_coilcoll
1190 
1191 !*******************************************************************************
1192 ! SECTION IX. VECTOR POTENTIAL SUBROUTINES
1193 !*******************************************************************************
1194 ! Generic Subroutine: bsc_a
1195 ! Different versions depending on first argument:
1196 ! bsc_a_coil First argument a bsc_coil. All calls come through here.
1197 ! bsc_a_coil_a First argument an array of bsc_coil
1198 ! bsc_a_coilcoll First argument a bsc_coilcoll
1199 ! Particular to a c_type. Called from bsc_a_coil
1200 ! bsc_a_coil_fil_loop
1201 ! bsc_a_coil_fil_circ
1202 ! NB c_type = 'fil_rogo' calls B field: bsc_b_coil_fil_loop
1203 !-------------------------------------------------------------------------------
1204 ! Vector Potential field for single coil
1205 !-------------------------------------------------------------------------------
1206  SUBROUTINE bsc_a_coil(this,x,a,bsc_k2)
1207  IMPLICIT NONE
1208 
1209 ! Argument Declaration
1210 ! Required Arguments
1211  TYPE (bsc_coil), INTENT(in) :: this
1212  REAL(rprec), DIMENSION(3), INTENT(in) :: x
1213  REAL(rprec), DIMENSION(3), INTENT(out) :: a
1214 
1215 ! Optional Arguments
1216  REAL(rprec), OPTIONAL, INTENT(in) :: bsc_k2
1217 
1218 ! Local Variable Declaration
1219  REAL(rprec) :: bsc_k2_use
1220 
1221 ! Start of executable code
1222  SELECT CASE (this % c_type)
1223  CASE ('fil_loop','floop')
1224  CALL bsc_a_coil_fil_loop(this,x,a)
1225 
1226  CASE ('fil_circ','fcirc')
1227  CALL bsc_a_coil_fil_circ(this,x,a)
1228 
1229  CASE ('fil_rogo')
1230 ! Rogowski. Compute the B field from the nodes.
1231  CALL bsc_b_coil_fil_loop(this,x,a)
1232 ! Scale by the correct factor.
1233  a(1:3) = this % ave_n_area * a(1:3)
1234 
1235  CASE ('fil_rogo_s')
1236 ! Rogowski. Compute the B field from the nodes. The scaling is taken care of
1237 ! externally.
1238  CALL bsc_b_coil_fil_loop(this,x,a)
1239 
1240  CASE DEFAULT
1241  WRITE(*,*) 'FATAL: bsc_a_coil: c_type unrecognized:', &
1242  & this % c_type
1243  stop
1244  END SELECT
1245 
1246 ! Scale with current and k2 constant
1247  IF (PRESENT(bsc_k2)) THEN
1248  bsc_k2_use = bsc_k2
1249  ELSE
1250  bsc_k2_use = bsc_k2_def
1251  ENDIF
1252 
1253  a(1:3) = this % current * bsc_k2_use * a(1:3)
1254 
1255  END SUBROUTINE bsc_a_coil
1256 
1257 !-------------------------------------------------------------------------------
1258 ! Vector Potential field for single filamentary loop
1259 !-------------------------------------------------------------------------------
1260  SUBROUTINE bsc_a_coil_fil_loop(this,x,a)
1261 ! Vector Potential field for single filamentary loop
1262 ! Should only be called from bsc_a_coil
1263 
1264 ! Argument Declaration
1265 ! Required Arguments
1266  TYPE (bsc_coil), INTENT(IN) :: this
1267  REAL(rprec), DIMENSION(3), INTENT(in) :: x
1268  REAL(rprec), DIMENSION(3), INTENT(out) :: a
1269 
1270 ! Local Variable Declaration
1271  INTEGER(iprec) :: n, nm1, i
1272  REAL(rprec), DIMENSION(SIZE(this % xnod,2)) :: capR
1273  REAL(rprec), DIMENSION(SIZE(this % xnod,2)-1) :: lnfactor
1274 
1275 ! Start of executable code
1276  n = SIZE(this % xnod,2)
1277  nm1 = n - 1
1278 
1279 ! Form array of relative vector lengths
1280  capr = sqrt((x(1) - this % xnod(1,1:n))**2 &
1281  & + (x(2) - this % xnod(2,1:n))**2 &
1282  & + (x(3) - this % xnod(3,1:n))**2)
1283 
1284 ! Form lnfactor
1285  lnfactor(1:nm1) = this % lnod(1:nm1)/(capr(1:nm1) + capr(2:n))
1286  CALL log_eps (lnfactor)
1287 
1288 ! lnfactor(1:nm1) = log((capR(1:nm1) + capR(2:n)
1289 ! & + this % lnod(1:nm1)) / (capR(1:nm1) + capR(2:n)
1290 ! & - this % lnod(1:nm1)))
1291 
1292 ! Sum for A field
1293  DO i = 1,3
1294  a(i) = dot_product(this % ehnod(i,1:nm1),lnfactor(1:nm1))
1295  END DO
1296 
1297  END SUBROUTINE bsc_a_coil_fil_loop
1298 
1299 !-------------------------------------------------------------------------------
1300 ! Vector Potential field for single filamentary circle
1301 !-------------------------------------------------------------------------------
1302  SUBROUTINE bsc_a_coil_fil_circ(this,x,a)
1303  IMPLICIT NONE
1304 ! Vector Potential field for single filamentary circle
1305 ! Should only be called from bsc_a_coil
1306 
1307 ! Argument Declaration
1308 ! Required Arguments
1309  TYPE (bsc_coil), INTENT(in) :: this
1310  REAL(rprec), DIMENSION(3), INTENT(in) :: x
1311  REAL(rprec), DIMENSION(3), INTENT(out) :: a
1312 
1313 ! Local Variable Declaration
1314  REAL(rprec), PARAMETER :: two_third = 2._rprec / 3
1315  REAL(rprec), PARAMETER :: pio16 = pi / 16
1316  REAL(rprec), DIMENSION(3) :: rprime, rhoprime, rhophat, phiphat
1317  REAL(rprec) :: zprime, fsq, em, emone
1318  REAL(rprec) :: rhopmsq, rhopmag, f, rf, rd, brackg, aphi, radcc
1319 
1320  REAL(rprec), PARAMETER :: c_gb1 = one
1321  REAL(rprec), PARAMETER :: c_gb2 = 3._rprec / 4
1322  REAL(rprec), PARAMETER :: c_gb3 = 75._rprec / 128
1323  REAL(rprec), PARAMETER :: c_gb4 = 245._rprec / 512
1324  REAL(rprec), PARAMETER :: c_gb5 = 6615._rprec / 16384
1325  REAL(rprec), PARAMETER :: c_gb6 = 22869._rprec / 65536
1326  REAL(rprec), PARAMETER :: c_gb7 = 1288287._rprec / 4194304
1327 
1328 
1329 ! Start of executable code
1330 ! Transform to local (primed) coordinates
1331  rprime = x(1:3) - this % xcent(1:3)
1332  zprime = dot_product(rprime,this % enhat)
1333  rhoprime = rprime(1:3) - zprime * this % enhat(1:3)
1334  rhopmsq = dot_product(rhoprime,rhoprime)
1335 ! ZZZ Think about numbers 1.e-30 and 1.e-15
1336  IF (rhopmsq .lt. 1.e-30_rprec) THEN
1337  rhoprime(1) = 1.e-15_rprec
1338  rhoprime(2) = zero
1339  rhoprime(3) = zero
1340  rhopmsq = dot_product(rhoprime,rhoprime)
1341  END IF
1342  rhopmag = sqrt(rhopmsq)
1343  rhophat(1:3) = rhoprime(1:3) / rhopmag
1344  radcc = this % rcirc
1345 
1346 ! various factors.
1347  fsq = one / ((rhopmag + radcc) ** 2 + zprime ** 2)
1348  f = sqrt(fsq)
1349  em = 4 * rhopmag * radcc * fsq
1350  emone = one - em
1351 
1352  IF (em .gt. bsc_emcut) THEN ! large m, use elliptic integrals
1353 ! All the calculation of the complete elliptic integrals is localized
1354 ! in bsc_cei
1355  CALL bsc_cei(emone,rf,rd)
1356  brackg = two_third * rd - rf
1357  ELSE ! small m, use power series in m
1358  brackg = pio16 * em * (c_gb1 + em * (c_gb2 + em * &
1359  & (c_gb3 + em * (c_gb4 + em * (c_gb5 + em * (c_gb6 + em * &
1360  & c_gb7))))))
1361  END IF
1362  aphi = 4 * radcc * f * brackg
1363 
1364 ! Now convert to global cylindrical coordinates.
1365 ! First, find the phi_prime_hat by taking the cross
1366 ! product of z_prime_hat and rho_prime_hat
1367  phiphat(1) = this % enhat(2) * rhophat(3) - &
1368  & this % enhat(3) * rhophat(2)
1369  phiphat(2) = this % enhat(3) * rhophat(1) - &
1370  & this % enhat(1) * rhophat(3)
1371  phiphat(3) = this % enhat(1) * rhophat(2) - &
1372  & this % enhat(2) * rhophat(1)
1373  a(1:3) = phiphat(1:3) * aphi
1374 
1375  END SUBROUTINE bsc_a_coil_fil_circ
1376 
1377 !-------------------------------------------------------------------------------
1378 ! Vector Potential field for array of coils
1379 !-------------------------------------------------------------------------------
1380  SUBROUTINE bsc_a_coil_a(this,x,a,bsc_k2)
1381  IMPLICIT NONE
1382 
1383 ! Argument Declaration
1384 ! Required Arguments
1385  TYPE (bsc_coil), DIMENSION(:), INTENT(IN) :: this
1386  REAL(rprec), DIMENSION(3), INTENT(IN) :: x
1387  REAL(rprec), DIMENSION(3), INTENT(OUT) :: a
1388 
1389 ! Optional Arguments
1390  REAL(rprec), OPTIONAL, INTENT(in) :: bsc_k2
1391 
1392 ! Local Variable Declaration
1393  INTEGER(iprec) :: i, n
1394  REAL(rprec), DIMENSION(3,SIZE(this)) :: aarray
1395 
1396 ! Start of executable code
1397 
1398 ! WRITE(*,*) 'Executing bsc_a_coil_a'
1399 
1400 ! calls to bsc_a_coil
1401  n = SIZE(this)
1402  DO i = 1,n
1403  CALL bsc_a_coil(this(i),x,aarray(1:3,i))
1404  END DO
1405 
1406 ! Sum for A field
1407  a(1:3) = sum(aarray(1:3,1:n),2)
1408 
1409 ! Rescale if bsc_k2 present
1410  IF (PRESENT(bsc_k2)) THEN
1411  a(1:3) = a(1:3) * bsc_k2 * bsc_k2inv_def
1412  ENDIF
1413 
1414  RETURN
1415  END SUBROUTINE bsc_a_coil_a
1416 
1417 !-------------------------------------------------------------------------------
1418 ! Vector Potential for a coil collection
1419 !-------------------------------------------------------------------------------
1420  SUBROUTINE bsc_a_coilcoll(this,x,a,bsc_k2)
1421 
1422 ! Argument Declaration
1423 ! Required Arguments
1424  TYPE (bsc_coilcoll), INTENT(in) :: this
1425  REAL(rprec), DIMENSION(3), INTENT(in) :: x
1426  REAL(rprec), DIMENSION(3), INTENT(out) :: a
1427 
1428 ! Optional Arguments
1429  REAL(rprec), OPTIONAL, INTENT(in) :: bsc_k2
1430 
1431 ! Local Variable Declaration
1432  INTEGER(iprec) :: n
1433 
1434 ! Start of executable code
1435 ! Calculate a from coils in coilcoll
1436  n = this % ncoil
1437  IF (n .gt. 0) then
1438  CALL bsc_a_coil_a(this % coils(1:n),x,a(1:3))
1439  ELSE
1440  a(1:3) = zero
1441  END IF
1442 
1443 ! Rescale if bsc_k2 present
1444  IF (PRESENT(bsc_k2)) THEN
1445  a(1:3) = a(1:3) * bsc_k2 * bsc_k2inv_def
1446  ENDIF
1447 
1448  END SUBROUTINE bsc_a_coilcoll
1449 
1450 !*******************************************************************************
1451 ! SECTION X. MAGNETIC FIELD SUBROUTINES
1452 !*******************************************************************************
1453 ! Generic Subroutine: bsc_b
1454 ! Different versions depending on first argument:
1455 ! bsc_b_coil First argument a bsc_coil. All calls come through here.
1456 ! bsc_b_coil_a First argument an array of bsc_coil
1457 ! bsc_b_coilcoll First argument a bsc_coilcoll
1458 ! Particular to a c_type. Called from bsc_b_coil
1459 ! bsc_b_coil_fil_loop
1460 ! bsc_b_coil_fil_circ
1461 ! NB: c_type = 'fil_rogo' doesn't compute magnetic field.
1462 !-------------------------------------------------------------------------------
1463 ! Magnetic field for single coil
1464 !-------------------------------------------------------------------------------
1465  SUBROUTINE bsc_b_coil (this,x,b,bsc_k2)
1466  IMPLICIT NONE
1467 
1468 ! Argument Declaration
1469 ! Required Arguments
1470  TYPE (bsc_coil), INTENT(in) :: this
1471  REAL(rprec), DIMENSION(3), INTENT(in) :: x
1472  REAL(rprec), DIMENSION(3), INTENT(out) :: b
1473 
1474 ! Optional Arguments
1475  REAL(rprec), OPTIONAL, INTENT(in) :: bsc_k2
1476 
1477 ! Local Variable Declaration
1478  REAL(rprec) :: bsc_k2_use
1479 
1480 
1481 ! Start of executable code
1482  SELECT CASE (this % c_type)
1483  CASE ('fil_loop','floop')
1484  CALL bsc_b_coil_fil_loop(this,x,b)
1485 
1486  CASE ('fil_circ','fcirc')
1487  CALL bsc_b_coil_fil_circ(this,x,b)
1488 
1489  CASE ('fil_rogo')
1490 ! Rogowski. Not yet implemented
1491  WRITE(*,*) 'WARNING: bsc_b_coil: NOT YET IMPLEMENTED', &
1492  & this % c_type
1493 
1494  CASE ('fil_rogo_s')
1495 ! Rogowski. Not yet implemented
1496  WRITE(*,*) 'WARNING: bsc_b_coil: NOT YET IMPLEMENTED', &
1497  & this % c_type
1498 
1499  CASE DEFAULT
1500  WRITE(*,*) 'FATAL: bsc_b_coil: c_type unrecognized:', &
1501  & this % c_type
1502  stop
1503  END SELECT
1504 
1505 ! Scale with current and k2 constant
1506  IF (PRESENT(bsc_k2)) THEN
1507  bsc_k2_use = bsc_k2
1508  ELSE
1509  bsc_k2_use = bsc_k2_def
1510  ENDIF
1511 
1512  b(1:3) = this % current * bsc_k2_use * b(1:3)
1513 
1514  END SUBROUTINE bsc_b_coil
1515 
1516 !-------------------------------------------------------------------------------
1517 ! Magnetic field for single filamentary loop
1518 !-------------------------------------------------------------------------------
1519 !2 4 6 8(1)2 4 6 8(2)2 4 6 8(3)2 4 6 8(4)2 4 6 8(5)2 4 6 8(6)2 4 6 8(7)2 4 6 8(8
1520  SUBROUTINE bsc_b_coil_fil_loop (this,x,b)
1521  IMPLICIT NONE
1522 ! Should only be called from bsc_b_coil
1523 ! Can also be called from bsc_a_coil with c_type = 'fil_rogo'
1524 
1525 ! Argument Declaration
1526 ! Required Arguments
1527  TYPE (bsc_coil), INTENT(in) :: this
1528  REAL(rprec), DIMENSION(3), INTENT(in) :: x
1529  REAL(rprec), DIMENSION(3), INTENT(out) :: b
1530 
1531 ! Local Variable Declaration
1532  INTEGER(iprec) :: nm1, n, i, j, k
1533  REAL(rprec), DIMENSION(SIZE(this % xnod,2)) :: capR
1534  REAL(rprec), DIMENSION(3,SIZE(this % xnod,2)) :: capRv
1535  REAL(rprec), DIMENSION(SIZE(this % xnod,2)-1) :: Rfactor, R1p2
1536  REAL(rprec), DIMENSION(3,SIZE(this % xnod,2)-1) :: crossv
1537 
1538 ! Start of executable code
1539  n = SIZE(this % xnod,2)
1540  nm1 = n - 1
1541 
1542 ! Form array of vectors relative to observation point x(i)
1543  DO i = 1,3
1544  caprv(i,1:n) = x(i) - this % xnod(i,1:n)
1545  END DO
1546 
1547 ! Form array of relative vector lengths
1548 !JDH Quick Fix 2007-05-24
1549  capr(1:n) = sqrt(max(this % eps_sq,caprv(1,1:n) * caprv(1,1:n) + &
1550  & caprv(2,1:n) * caprv(2,1:n) + &
1551  & caprv(3,1:n) * caprv(3,1:n)))
1552 ! capR(1:n) = SQRT(capRv(1,1:n) * capRv(1,1:n) + &
1553 ! & capRv(2,1:n) * capRv(2,1:n) + &
1554 ! & capRv(3,1:n) * capRv(3,1:n))
1555 
1556 ! Form Cross Product
1557  DO i = 1, 3
1558  j = mod(i,3_iprec) + 1
1559  k = mod(j,3_iprec) + 1
1560  crossv(i,1:nm1) = this % dxnod(j,1:nm1) * caprv(k,1:nm1) &
1561  & - this % dxnod(k,1:nm1) * caprv(j,1:nm1)
1562  END DO
1563 
1564  r1p2(1:nm1) = capr(1:nm1) + capr(2:n)
1565  rfactor(1:nm1) = 2 * r1p2(1:nm1) / (capr(1:nm1) * capr(2:n) * &
1566  & max(r1p2(1:nm1)*r1p2(1:nm1) - this % lsqnod(1:nm1), &
1567  & this % eps_sq))
1568 
1569 ! Sum for B field
1570  DO i = 1,3
1571  b(i) = dot_product(this%sens*crossv(i,1:nm1),rfactor(1:nm1))
1572  END DO
1573 
1574  END SUBROUTINE bsc_b_coil_fil_loop
1575 
1576 !-------------------------------------------------------------------------------
1577 ! Magnetic Field for single filamentary circle
1578 !-------------------------------------------------------------------------------
1579  SUBROUTINE bsc_b_coil_fil_circ(this,x,b)
1580  IMPLICIT NONE
1581 ! Magnetic field for single filamentary circle
1582 ! Should only be CALLed from bsc_b_coil
1583 
1584 ! Argument Declaration
1585 ! Required Arguments
1586  TYPE (bsc_coil), INTENT(in) :: this
1587  REAL(rprec), DIMENSION(3), INTENT(in) :: x
1588  REAL(rprec), DIMENSION(3), INTENT(out) :: b
1589 
1590 ! Local Variable Declaration
1591  REAL(rprec), PARAMETER :: third = one / 3
1592  REAL(rprec), PARAMETER :: sixth = one / 6
1593  REAL(rprec), PARAMETER :: two_third = 2._rprec / 3
1594 
1595  REAL(rprec), DIMENSION(3) :: rprime, rhoprime, rhophat, phiphat
1596  REAL(rprec) :: zprime, fsq, fcube, em, emone, cfcube, geofac1
1597  REAL(rprec) :: rhopmsq, rhopmag, f, rf, rd, brackg, brackh, &
1598  & brfac1, brho, bz, aphi, radcc, add_on, fac1, fac2
1599 
1600 ! Coefficients for power series in m
1601  REAL(rprec) :: c_bz0, c_bz1, c_bz2, c_bz3, c_bz4, c_bz5, c_bz6
1602  REAL(rprec) :: cb_bz0, cb_bz1, cb_bz2, cb_bz3, cb_bz4, cb_bz5, &
1603  & cb_bz6
1604  REAL(rprec), PARAMETER :: c_brho1 = one
1605  REAL(rprec), PARAMETER :: c_brho2 = 5._rprec / 4
1606  REAL(rprec), PARAMETER :: c_brho3 = 175._rprec / 128
1607  REAL(rprec), PARAMETER :: c_brho4 = 735._rprec / 512
1608  REAL(rprec), PARAMETER :: c_brho5 = 24255._rprec / 16384
1609  REAL(rprec), PARAMETER :: c_brho6 = 99099._rprec / 65536
1610  REAL(rprec), PARAMETER :: c_brho7 = 6441435._rprec / 4194304
1611  REAL(rprec), PARAMETER :: ca_bz1 = 3._rprec / 4
1612  REAL(rprec), PARAMETER :: ca_bz2 = 75._rprec / 128
1613  REAL(rprec), PARAMETER :: ca_bz3 = 245._rprec / 512
1614  REAL(rprec), PARAMETER :: ca_bz4 = 6615._rprec / 16384
1615  REAL(rprec), PARAMETER :: ca_bz5 = 22869._rprec / 65536
1616  REAL(rprec), PARAMETER :: ca_bz6 = 1288287._rprec / 4194304
1617  REAL(rprec), PARAMETER :: pio4 = pi / 4
1618  REAL(rprec), PARAMETER :: pi3o16 = 3._rprec * pi / 16
1619 
1620 ! Start of executable code
1621 ! Transform to local (primed) coordinates
1622  rprime = x(1:3) - this % xcent(1:3)
1623  zprime = dot_product(rprime,this % enhat)
1624  rhoprime = rprime(1:3) - zprime * this % enhat(1:3)
1625  rhopmsq = dot_product(rhoprime,rhoprime)
1626 ! ZZZ Think about numbers 1.e-30 and 1.e-15
1627  IF (rhopmsq .lt. 1.e-30_rprec) THEN
1628  rhoprime(1) = 1.e-15_rprec
1629  rhoprime(2) = zero
1630  rhoprime(3) = zero
1631  rhopmsq = dot_product(rhoprime,rhoprime)
1632  END IF
1633  rhopmag = sqrt(rhopmsq)
1634  rhophat(1:3) = rhoprime(1:3) / rhopmag
1635  radcc = this % rcirc
1636 
1637 ! various factors.
1638  fsq = one / ((rhopmag + radcc) ** 2 + zprime ** 2)
1639  f = sqrt(fsq)
1640  em = 4 * rhopmag * radcc * fsq
1641  emone = one - em
1642  cfcube = 4 * radcc * f * fsq
1643 ! Current gets multiplied in bsc_b_coil
1644  geofac1 = (radcc ** 2 + zprime ** 2) / rhopmag
1645 
1646  IF (em .gt. bsc_emcut) THEN ! large m, use elliptic integrals
1647 ! All the calculation of the complete elliptic integrals is localized
1648 ! in bsc_cei
1649  CALL bsc_cei(emone,rf,rd)
1650  brackg = two_third * rd - rf
1651  brackh = sixth * (-(1 + 3 * emone) * rd + &
1652  & 3 * (1 + emone) * rf) / emone
1653  brfac1 = brackg + 2 * brackh
1654  brho = cfcube * zprime * brfac1
1655  bz = cfcube * (brackg * (geofac1 + radcc) &
1656  & + brackh * (geofac1 - rhopmag))
1657  ELSE ! small m, use power series
1658  fac2 = pi3o16 * zprime * cfcube
1659  brho = fac2 * em * (c_brho1 + em * (c_brho2 + &
1660  & em * (c_brho3 + em * (c_brho4 + em * (c_brho5 + em * &
1661  & (c_brho6 + em * c_brho7))))))
1662  fac1 = cfcube * radcc * fsq * pio4
1663  add_on = zprime ** 2 + (radcc + rhopmag) * (radcc - rhopmag)
1664  cb_bz0 = (radcc + rhopmag) * rhopmag + 2 * add_on
1665  cb_bz1 = cb_bz0 + add_on
1666  cb_bz2 = cb_bz1 + add_on
1667  cb_bz3 = cb_bz2 + add_on
1668  cb_bz4 = cb_bz3 + add_on
1669  cb_bz5 = cb_bz4 + add_on
1670  cb_bz6 = cb_bz5 + add_on
1671  c_bz0 = cb_bz0
1672  c_bz1 = ca_bz1 * cb_bz1
1673  c_bz2 = ca_bz2 * cb_bz2
1674  c_bz3 = ca_bz3 * cb_bz3
1675  c_bz4 = ca_bz4 * cb_bz4
1676  c_bz5 = ca_bz5 * cb_bz5
1677  c_bz6 = ca_bz6 * cb_bz6
1678  bz = fac1 * (c_bz0 + em * (c_bz1 + em * (c_bz2 + &
1679  & em * (c_bz3 + em * (c_bz4 + em * (c_bz5 + em * c_bz6))))))
1680  END IF
1681 
1682 ! Now convert to global cylindrical coordinates.
1683  b(1:3) = brho * rhophat(1:3) + bz * this % enhat(1:3)
1684 
1685  END SUBROUTINE bsc_b_coil_fil_circ
1686 
1687 !-------------------------------------------------------------------------------
1688 ! Magnetic field for array of coils
1689 !-------------------------------------------------------------------------------
1690  SUBROUTINE bsc_b_coil_a(this,x,b,bsc_k2)
1691  IMPLICIT NONE
1692 
1693 ! Argument Declaration
1694 ! Required Arguments
1695  TYPE (bsc_coil), DIMENSION(:), INTENT(IN) :: this
1696  REAL(rprec), DIMENSION(3), INTENT(IN) :: x
1697  REAL(rprec), DIMENSION(3), INTENT(OUT) :: b
1698 
1699 ! Optional Arguments
1700  REAL(rprec), OPTIONAL, INTENT(in) :: bsc_k2
1701 
1702 ! Local Variable Declaration
1703  INTEGER(iprec) :: i, n
1704  REAL(rprec), DIMENSION(3,SIZE(this)) :: barray
1705 
1706 ! Start of executable code
1707 ! Calls to bsc_b_coil
1708  n = SIZE(this)
1709  DO i = 1,n
1710  CALL bsc_b_coil(this(i),x,barray(1:3,i))
1711  END DO
1712 
1713 ! Sum for B field
1714  b = sum(barray(1:3,1:n),2)
1715 
1716 ! Rescale if bsc_k2 present
1717  IF (PRESENT(bsc_k2)) THEN
1718  b(1:3) = b(1:3) * bsc_k2 * bsc_k2inv_def
1719  ENDIF
1720 
1721  END SUBROUTINE bsc_b_coil_a
1722 
1723 !-------------------------------------------------------------------------------
1724 ! Magnetic field for a coil collection
1725 !-------------------------------------------------------------------------------
1726  SUBROUTINE bsc_b_coilcoll(this,x,b,bsc_k2)
1727  IMPLICIT NONE
1728 
1729 ! Argument Declaration
1730 ! Required Arguments
1731  TYPE (bsc_coilcoll), INTENT(in) :: this
1732  REAL(rprec), DIMENSION(3), INTENT(in) :: x
1733  REAL(rprec), DIMENSION(3), INTENT(out) :: b
1734 
1735 ! Optional Arguments
1736  REAL(rprec), OPTIONAL, INTENT(in) :: bsc_k2
1737 
1738 ! Local Variable Declaration
1739  INTEGER(iprec) :: n
1740 
1741 ! Start of executable code
1742 ! Calculate b from coils
1743  n = this % ncoil
1744  IF (n .gt. 0) then
1745  CALL bsc_b_coil_a(this % coils(1:n),x,b(1:3))
1746  ELSE
1747  b(1:3) = zero
1748  END IF
1749 
1750 ! Rescale if bsc_k2 present
1751  IF (PRESENT(bsc_k2)) THEN
1752  b(1:3) = b(1:3) * bsc_k2 * bsc_k2inv_def
1753  ENDIF
1754 
1755  END SUBROUTINE bsc_b_coilcoll
1756 
1757 !*******************************************************************************
1758 ! SECTION XI. MAGNETIC FLUX INTEGRAL SUBROUTINES
1759 !*******************************************************************************
1760 ! No mutual induction subroutine yet - use magnetic flux instead
1761 ! Mutual inductance can be computed from the flux, by dividing by the current
1762 ! in coil_a, and multiplying by the appropriate number of turns for coil_a and
1763 ! coil_b
1764 ! Note: bsc_fluxba is the generic subroutine. There are implementations for
1765 ! the first argument as a bsc_coil, as an array of bsc_coils, and as a bsc_coilcoll
1766 ! The three subroutine should look very similar, since the difference is only
1767 ! in the vector potential.
1768 ! All of the work related to coil_b is put into subroutine bsc_flux_pos, so that
1769 ! it does not have to be duplicated in each of the three subroutines.
1770 ! 2012-01-17 JDH. Add len_integrate argument
1771 
1772 !-------------------------------------------------------------------------------
1773 ! Magnetic Flux for a single coil
1774 !-------------------------------------------------------------------------------
1775  SUBROUTINE bsc_fluxba_coil(coil_a,coil_b,len_integerate,flux, &
1776  & bsc_k2)
1777  IMPLICIT NONE
1778 
1779 ! This subroutine calculates the magnetic flux due to coil_a through coil_b.
1780 ! The flux is computed using the vector potential due to coil_a, with a line
1781 ! integral around coil_b.
1782 
1783 ! Argument Declaration
1784 
1785 ! Required Arguments
1786  TYPE (bsc_coil), INTENT(in) :: coil_a
1787  TYPE (bsc_coil), INTENT(in) :: coil_b
1788  REAL(rprec), INTENT(IN) :: len_integerate
1789  REAL(rprec), INTENT(out) :: flux
1790 
1791 ! Optional Arguments
1792  REAL(rprec), OPTIONAL, INTENT(in) :: bsc_k2
1793 
1794 ! Local Variable Declaration
1795  REAL(rprec), DIMENSION(:,:), POINTER :: positions => null(), &
1796  & tangents => null(), avecs => null()
1797  REAL(rprec), DIMENSION(:), POINTER :: sens => null()
1798  INTEGER(iprec) :: i, npoints
1799 
1800 ! Start of executable code
1801 
1802 ! Get array of positions at which to evaluate the vector potential
1803 ! Subroutine also allocates space to the pointers: positions, tangents, and
1804 ! avecs.
1805  CALL bsc_flux_pos(coil_b,len_integerate,positions,tangents, &
1806  & avecs,sens,npoints)
1807 
1808 ! Calculate vector potentials
1809  SELECT CASE (coil_b % c_type)
1810  CASE DEFAULT
1811  DO i = 1,npoints
1812  CALL bsc_a(coil_a,positions(1:3,i),avecs(1:3,i))
1813  END DO
1814  CASE ('fil_rogo','fil_rogo_s')
1815  DO i = 1,npoints
1816  CALL bsc_b(coil_a,positions(1:3,i),avecs(1:3,i))
1817  END DO
1818  END SELECT
1819 
1820 ! Do summations
1821  CALL bsc_flux_sum(coil_b,positions,tangents,avecs,sens,npoints, &
1822  & flux)
1823 
1824 ! Rescale if bsc_k2 present
1825  IF (PRESENT(bsc_k2)) THEN
1826  flux = flux * bsc_k2 * bsc_k2inv_def
1827  ENDIF
1828 
1829 ! Deallocate space.
1830  DEALLOCATE(avecs,positions,tangents,sens)
1831 
1832 ! That's all
1833  END SUBROUTINE bsc_fluxba_coil
1834 
1835 !-------------------------------------------------------------------------------
1836 ! Magnetic Flux for an array of coils
1837 !-------------------------------------------------------------------------------
1838  SUBROUTINE bsc_fluxba_coil_a(coil_a,coil_b,len_integerate,flux, &
1839  & bsc_k2)
1840  IMPLICIT NONE
1841 
1842 ! This subroutine calculates the magnetic flux due to coil_a through coil_b.
1843 ! The flux is computed using the vector potential due to coil_a, with a line
1844 ! integral around coil_b.
1845 
1846 ! Argument Declaration
1847 
1848 ! Required Arguments
1849  TYPE (bsc_coil), DIMENSION(:), INTENT(IN) :: coil_a
1850  TYPE (bsc_coil), INTENT(in) :: coil_b
1851  REAL(rprec), INTENT(IN) :: len_integerate
1852  REAL(rprec), INTENT(out) :: flux
1853 
1854 ! Optional Arguments
1855  REAL(rprec), OPTIONAL, INTENT(in) :: bsc_k2
1856 
1857 ! Local Variable Declaration
1858  REAL(rprec), DIMENSION(:,:), POINTER :: positions => null(), &
1859  & tangents => null(), avecs => null()
1860  REAL(rprec), DIMENSION(:),POINTER :: sens => null()
1861  INTEGER(iprec) :: i, npoints
1862 
1863 ! Start of executable code
1864 
1865 ! Get array of positions at which to evaluate the vector potential
1866 ! Subroutine also allocates space to the pointers: positions, tangents, and
1867 ! avecs.
1868  CALL bsc_flux_pos(coil_b,len_integerate,positions,tangents, &
1869  & avecs,sens,npoints)
1870 
1871 ! Calculate vector potentials
1872  SELECT CASE (coil_b % c_type)
1873  CASE DEFAULT
1874  DO i = 1,npoints
1875  CALL bsc_a(coil_a,positions(1:3,i),avecs(1:3,i))
1876  END DO
1877  CASE ('fil_rogo','fil_rogo_s')
1878  DO i = 1,npoints
1879  CALL bsc_b(coil_a,positions(1:3,i),avecs(1:3,i))
1880  END DO
1881  END SELECT
1882 
1883 ! Do summations
1884  CALL bsc_flux_sum(coil_b,positions,tangents,avecs,sens,npoints, &
1885  & flux)
1886 
1887 ! Rescale if bsc_k2 present
1888  IF (PRESENT(bsc_k2)) THEN
1889  flux = flux * bsc_k2 * bsc_k2inv_def
1890  ENDIF
1891 
1892 ! Deallocate space.
1893  DEALLOCATE(avecs,positions,tangents,sens)
1894 
1895 ! That's all
1896  END SUBROUTINE bsc_fluxba_coil_a
1897 
1898 !-------------------------------------------------------------------------------
1899 ! Magnetic Flux for a coil collection
1900 !-------------------------------------------------------------------------------
1901  SUBROUTINE bsc_fluxba_coilcoll(coil_a,coil_b,len_integerate,flux, &
1902  & bsc_k2)
1903  IMPLICIT NONE
1904 
1905 ! This subroutine calculates the magnetic flux due to coil_a through coil_b.
1906 ! The flux is computed using the vector potential due to coil_a, with a line
1907 ! integral around coil_b.
1908 
1909 ! Argument Declaration
1910 
1911 ! Required Arguments
1912  TYPE (bsc_coilcoll), INTENT(IN) :: coil_a
1913  TYPE (bsc_coil), INTENT(in) :: coil_b
1914  REAL(rprec), INTENT(IN) :: len_integerate
1915  REAL(rprec), INTENT(out) :: flux
1916 
1917 ! Optional Arguments
1918  REAL(rprec), OPTIONAL, INTENT(in) :: bsc_k2
1919 
1920 ! Local Variable Declaration
1921  REAL(rprec), DIMENSION(:,:), POINTER :: positions => null(), &
1922  & tangents => null(), avecs => null()
1923  REAl(rprec), DIMENSION(:), POINTER :: sens => null()
1924  INTEGER(iprec) :: i, npoints
1925 
1926 ! Start of executable code
1927 
1928 ! Get array of positions at which to evaluate the vector potential
1929 ! Subroutine also allocates space to the pointers: positions, tangents, avecs
1930 ! and sens.
1931  CALL bsc_flux_pos(coil_b,len_integerate,positions,tangents, &
1932  & avecs,sens,npoints)
1933 
1934 ! Calculate vector potentials
1935  SELECT CASE (coil_b % c_type)
1936  CASE DEFAULT
1937  DO i = 1,npoints
1938  CALL bsc_a(coil_a,positions(1:3,i),avecs(1:3,i))
1939  END DO
1940  CASE ('fil_rogo','fil_rogo_s')
1941  DO i = 1,npoints
1942  CALL bsc_b(coil_a,positions(1:3,i),avecs(1:3,i))
1943  END DO
1944  END SELECT
1945 
1946 ! Do summations
1947  CALL bsc_flux_sum(coil_b,positions,tangents,avecs,sens,npoints, &
1948  & flux)
1949 
1950 ! Rescale if bsc_k2 present
1951  IF (PRESENT(bsc_k2)) THEN
1952  flux = flux * bsc_k2 * bsc_k2inv_def
1953  ENDIF
1954 
1955 ! Deallocate space.
1956  DEALLOCATE(avecs,positions,tangents,sens)
1957 
1958 ! That's all
1959  END SUBROUTINE bsc_fluxba_coilcoll
1960 
1961 
1962 !-------------------------------------------------------------------------------
1963 ! Subroutine to find positions and tangents for second coil
1964 !-------------------------------------------------------------------------------
1965  SUBROUTINE bsc_flux_pos(coil_b,len_integrate,positions, &
1966  & tangents,avecs,sens,npoints)
1967  IMPLICIT NONE
1968 ! This subroutine will return positions and tangents to the coil coil_b.
1969 ! It is called by the bsc_flux_ subroutines.
1970 ! For now, the positions chosen lie ON the coil. In future, this should be
1971 ! changed, so that the evaluations points are nearby (about a wire radius away)
1972 ! 2012-01-17 JDH. Add len_integrate argument.
1973 
1974 ! Argument Declaration
1975 ! coil_b Coil to determine integration positions for
1976 ! len_integrate Integration length. If zero or negative, use one point
1977 ! per segment.
1978 ! positions Array of positions for integration
1979 ! tangents Array of tangent vectors
1980 
1981 ! Required Arguments
1982  TYPE (bsc_coil), INTENT(in) :: coil_b
1983  REAL(rprec), INTENT(in) :: len_integrate
1984  REAL(rprec), DIMENSION(:,:), POINTER :: positions, tangents, &
1985  & avecs
1986  REAL(rprec), DIMENSION(:), POINTER :: sens
1987  INTEGER(iprec), INTENT(out) :: npoints
1988 
1989 ! Local Variable Declaration
1990  INTEGER(iprec) :: i, j, iseg, npoints_this_segment, n_denom
1991  INTEGER(iprec) :: nseg
1992  REAL(rprec), DIMENSION(3) :: xhatlocal, yhatlocal, zhatlocal, &
1993  & rhohat, phihat
1994  REAL(rprec) :: dphi, phi, cphi, sphi, frac_denom
1995  INTEGER(iprec), PARAMETER :: npcirc = 60 ! zzz - Picked out of a hat
1996 
1997 ! Start of executable code
1998 
1999 ! Define length of arrays
2000  SELECT CASE (coil_b % c_type)
2001  CASE ('fil_loop','floop','fil_rogo','fil_rogo_s')
2002  IF (len_integrate .le. zero) THEN
2003  npoints = SIZE(coil_b % lnod)
2004  ELSE
2005  npoints = 0
2006  DO iseg = 1,SIZE(coil_b % lnod)
2007  npoints_this_segment = coil_b % lnod(iseg) / &
2008  & len_integrate + 1
2009  npoints = npoints + npoints_this_segment
2010  END DO
2011  ENDIF
2012  CASE ('fil_circ','fcirc')
2013  IF (len_integrate .le. zero) THEN
2014  npoints = npcirc
2015  ELSE
2016  npoints = twopi * coil_b % rcirc / len_integrate + 1
2017  npoints = max(npcirc,npoints)
2018  ENDIF
2019  END SELECT
2020 
2021 ! Allocate space
2022  IF (ASSOCIATED(positions)) DEALLOCATE(positions)
2023  IF (ASSOCIATED(tangents)) DEALLOCATE(tangents)
2024  IF (ASSOCIATED(avecs)) DEALLOCATE(avecs)
2025  ALLOCATE(positions(3,npoints),tangents(3,npoints), &
2026  & avecs(3,npoints),sens(npoints))
2027 
2028 ! For fil_loops, points spaced throughout the segment
2029 ! First and last points in a segment weighted at half the weight of all other
2030 ! segments.
2031 ! points per segment position fraction weights
2032 ! 1 1/2 1
2033 ! 2 1/4, 3/4 1/2, 1/2
2034 ! 3 1/8, 1/2, 7/8 1/4, 1/2, 1/4
2035 ! 4 1/12, 4/12, 8/12, 11/12 1/6, 1/3, 1/3, 1/6
2036  SELECT CASE (coil_b % c_type)
2037  CASE ('fil_loop','floop','fil_rogo','fil_rogo_s')
2038  i = 1
2039  nseg = SIZE(coil_b % lnod)
2040  DO iseg = 1,nseg
2041  IF (len_integrate .le. zero) THEN
2042  npoints_this_segment = 1
2043  ELSE
2044  npoints_this_segment = coil_b % lnod(iseg) / &
2045  & len_integrate + 1
2046  ENDIF
2047  IF (npoints_this_segment .eq. 1) THEN
2048  positions(1:3,i) = coil_b % xnod(1:3,iseg) + &
2049  & 0.5 * coil_b % dxnod(1:3,iseg)
2050  tangents(1:3,i) = coil_b % dxnod(1:3,iseg)
2051  sens(i) = coil_b % sens(iseg)
2052  i = i + 1
2053  ELSEIF (npoints_this_segment .eq. 2) THEN
2054  positions(1:3,i) = coil_b % xnod(1:3,iseg) + &
2055  & 0.25 * coil_b % dxnod(1:3,iseg)
2056  tangents(1:3,i) = 0.5 * coil_b % dxnod(1:3,iseg)
2057  sens(i) = coil_b % sens(iseg)
2058  i = i + 1
2059  positions(1:3,i) = coil_b % xnod(1:3,iseg) + &
2060  & 0.75 * coil_b % dxnod(1:3,iseg)
2061  tangents(1:3,i) = 0.5 * coil_b % dxnod(1:3,iseg)
2062  sens(i) = coil_b % sens(iseg)
2063  i = i + 1
2064  ELSE ! Here, 3 or more points per segment
2065  n_denom = npoints_this_segment - 1
2066  frac_denom = one / n_denom
2067  positions(1:3,i) = coil_b % xnod(1:3,iseg) + &
2068  & 0.25 * frac_denom * coil_b % dxnod(1:3,iseg)
2069  tangents(1:3,i) = 0.5 * frac_denom * &
2070  & coil_b % dxnod(1:3,iseg)
2071  sens(i) = coil_b % sens(iseg)
2072  i = i + 1
2073  DO j = 2,npoints_this_segment - 1
2074  positions(1:3,i) = coil_b % xnod(1:3,iseg) + &
2075  & frac_denom * (j-1) * coil_b % dxnod(1:3,iseg)
2076  tangents(1:3,i) = frac_denom * &
2077  & coil_b % dxnod(1:3,iseg)
2078  sens(i) = coil_b % sens(iseg)
2079  i = i + 1
2080  END DO
2081  positions(1:3,i) = coil_b % xnod(1:3,iseg) + &
2082  & (1 - 0.25 * frac_denom) * coil_b % dxnod(1:3,iseg)
2083  tangents(1:3,i) = 0.5 * frac_denom * &
2084  & coil_b % dxnod(1:3,iseg)
2085  sens(i) = coil_b % sens(iseg)
2086  i = i + 1
2087  ENDIF
2088  END DO
2089  IF (i - 1 .ne. npoints) THEN
2090  stop 'ERROR 1 in bsc_flux_pos'
2091  ENDIF
2092  CASE ('fil_circ','fcirc')
2093 ! For circles, npcirc points on the circle
2094  CALL bsc_triplet(coil_b % enhat,xhatlocal,yhatlocal,zhatlocal)
2095  dphi = twopi / npoints
2096  DO i = 1,npoints
2097  phi = i * dphi
2098  cphi = cos(phi)
2099  sphi = sin(phi)
2100  rhohat = cphi * xhatlocal + sphi * yhatlocal
2101  phihat = - sphi * xhatlocal + cphi * yhatlocal
2102  positions(1:3,i) = coil_b % xcent(1:3) + coil_b % rcirc * &
2103  & rhohat
2104  tangents(1:3,i) = coil_b % rcirc * dphi * phihat
2105  END DO
2106  sens = 1.0
2107  END SELECT
2108 
2109  END SUBROUTINE bsc_flux_pos
2110 
2111 !-------------------------------------------------------------------------------
2112 ! Subroutine to find do summations for flux
2113 !-------------------------------------------------------------------------------
2114  SUBROUTINE bsc_flux_sum(coil_b,positions,tangents,avecs,sens, &
2115  & npoints,flux)
2116  IMPLICIT NONE
2117 ! This subroutine will compute some sums
2118 ! It is called by the bsc_flux_ subroutines
2119 
2120 ! Argument Declaration
2121 
2122 ! Required Arguments
2123  TYPE (bsc_coil), INTENT(in) :: coil_b
2124  REAL(rprec), DIMENSION(:,:), POINTER :: positions, tangents, &
2125  & avecs
2126  REAL(rprec), DIMENSION(:), POINTER :: sens
2127  INTEGER(iprec), INTENT(in) :: npoints
2128  REAL(rprec), INTENT(out) :: flux
2129 
2130 ! Local Variable Declaration
2131  INTEGER(iprec) :: i
2132 
2133 ! Start of executable code
2134 
2135 ! Sum dot products
2136  flux = zero
2137  DO i = 1,npoints
2138  flux = flux + sens(i)*dot_product(avecs(1:3,i),tangents(1:3,i))
2139  END DO
2140 
2141 ! Extra Factor for coil_b a Rogowski coil
2142  IF (coil_b % c_type .eq. 'fil_rogo') THEN
2143  flux = flux * coil_b % ave_n_area
2144  END IF
2145 
2146  END SUBROUTINE bsc_flux_sum
2147 
2148 !*******************************************************************************
2149 ! SECTION XII. AUXILIARY SUBROUTINES
2150 !*******************************************************************************
2151 
2152 !-------------------------------------------------------------------------------
2153 ! Subroutine to compute complete elliptic integrals needed for circular loops
2154 !-------------------------------------------------------------------------------
2155  SUBROUTINE bsc_cei(xarg, rf, rd)
2156  IMPLICIT NONE
2157 !
2158 ! Should only be called from bsc_a_coil_fil_circ subroutine
2159 ! or from the bsc_b_coil_fil_circ subroutine
2160 
2161 ! This subroutine calculates Rf(0,xarg,1) and Rd(0,xarg,1)
2162 ! where Rf(x,y,z) and Rd(x,y,z) are the Carlson forms of the
2163 ! elliptic integral functions. The algorithm is based on those in section
2164 ! 6.11 of Numerical Recipes, 2nd edition. The iteration loops have been
2165 ! combined. The first two iterations have been done explicitly, since
2166 ! the Rf and Rd arguments x and z are 0 and 1, respectively.
2167 
2168 ! Argument Declaration
2169 ! Required Arguments
2170  REAL(rprec), INTENT(IN) :: xarg
2171  REAL(rprec), INTENT(out) :: rf, rd
2172 
2173 ! Local Variable Declaration
2174  REAL(rprec) :: xt, yt, zt, sum, x
2175  REAL(rprec) :: alamb, fac, sqrtx, sqrty, sqrtz, avef, recavef, &
2176  & delxf, delyf, delzf, e2f, e3f, aved, recaved, delxd, &
2177  & delyd, delzd, ead, ebd, ecd, edd, eed
2178  INTEGER(iprec) :: iter
2179  INTEGER(iprec), PARAMETER :: niter = 5
2180 
2181 ! parameters for the algorithm
2182  REAL(rprec), PARAMETER :: third = one / 3._rprec
2183  REAL(rprec), PARAMETER :: c1f = one / 24._rprec
2184  REAL(rprec), PARAMETER :: c2f = 0.1_rprec
2185  REAL(rprec), PARAMETER :: c3f = 3._rprec / 44._rprec
2186  REAL(rprec), PARAMETER :: c4f = one / 14._rprec
2187  REAL(rprec), PARAMETER :: sixth = one / 6._rprec
2188  REAL(rprec), PARAMETER :: twelfth = one / 12._rprec
2189  REAL(rprec), PARAMETER :: c1d = 3._rprec / 14._rprec
2190  REAL(rprec), PARAMETER :: c2d = one / 6._rprec
2191  REAL(rprec), PARAMETER :: c3d = 9._rprec / 22._rprec
2192  REAL(rprec), PARAMETER :: c4d = 3._rprec / 26._rprec
2193  REAL(rprec), PARAMETER :: c5d = .25_rprec * c3d
2194  REAL(rprec), PARAMETER :: c6d = 1.5_rprec * c4d
2195 
2196 ! Start of executable code
2197 ! First, make sure that 0 < x <= 1
2198  x = min(max(xarg,1.e-12_rprec),one)
2199 
2200 ! Do first iteration explicitly, since xt, yt, and zt are known
2201 ! (Saves two square roots)
2202  alamb = sqrt(x)
2203  fac = .25_rprec
2204  xt = fac * alamb
2205  yt = fac * (x + alamb)
2206  zt = fac * (one + alamb)
2207  sum = one / (one + alamb)
2208 
2209 ! Do other iterations
2210  do iter = 2,niter
2211  sqrtx = sqrt(xt)
2212  sqrty = sqrt(yt)
2213  sqrtz = sqrt(zt)
2214  alamb = sqrtx * (sqrty + sqrtz) + sqrty * sqrtz
2215  sum = sum + fac / (sqrtz * (zt + alamb))
2216  xt = .25_rprec * (xt + alamb)
2217  yt = .25_rprec * (yt + alamb)
2218  zt = .25_rprec * (zt + alamb)
2219  fac = .25_rprec * fac
2220  end do
2221 
2222 ! Done with iterations. Now get stuff for power series evaluation
2223 ! of Rf and Rd.
2224 
2225  aved = .2_rprec * (xt + yt + 3._rprec * zt)
2226  recaved = one / aved
2227  delxd = one - xt * recaved
2228  delyd = one - yt * recaved
2229  delzd = one - zt * recaved
2230  ead = delxd * delyd
2231  ebd = delzd * delzd
2232  ecd = ead - ebd
2233  edd = ead - 6._rprec * ebd
2234  eed = edd + ecd + ecd
2235  rd = 3._rprec * sum + fac * (one + edd * (- c1d + c5d * edd - &
2236  & c6d * delzd * eed) + delzd * (c2d * eed + delzd * &
2237  & (- c3d * ecd + delzd * c4d * ead))) * recaved * &
2238  & sqrt(recaved)
2239 
2240  avef = third * (xt + yt + zt)
2241  recavef = one / avef
2242  delxf = one - xt * recavef
2243  delyf = one - yt * recavef
2244  delzf = one - zt * recavef
2245  e2f = delxf * delyf - delzf ** 2
2246  e3f = delxf * delyf * delzf
2247  rf = (one + (c1f * e2f - c2f - c3f * e3f) * &
2248  & e2f + c4f * e3f) * sqrt(recavef)
2249 
2250  END SUBROUTINE bsc_cei
2251 
2252 !-------------------------------------------------------------------------------
2253 ! Subroutine to compute local unit vectors, given an initial z direction
2254 !-------------------------------------------------------------------------------
2255  SUBROUTINE bsc_triplet(zlocal,xhatlocal,yhatlocal,zhatlocal)
2256  IMPLICIT NONE
2257 ! Subroutine to compute a right-handed set of orthogonal unit vectors (x,y,z)hatlocal
2258 ! where zhatlocal is parallel to the input argument zlocal.
2259 
2260 ! Argument Declaration
2261 
2262 ! Required Arguments
2263  REAL(rprec), DIMENSION(3), INTENT(in) :: zlocal
2264  REAL(rprec), DIMENSION(3), INTENT(out) :: xhatlocal, yhatlocal, &
2265  & zhatlocal
2266 
2267 ! Local Variable Declaration
2268  REAL(rprec), DIMENSION(3) :: zloc, xloc
2269  REAL(rprec) :: fac, lsq
2270 
2271 ! Start of executable code
2272 ! Normalize zlocal. Copy first, so zlocal can be INTENT(in).
2273  zloc = zlocal
2274  lsq = dot_product(zloc,zloc)
2275  IF (lsq .le. 0.) THEN
2276  lsq = 1._rprec
2277  zloc(3) = 1._rprec
2278  END IF
2279  fac = 1._rprec / sqrt(lsq)
2280  zhatlocal = fac * zloc
2281 
2282 ! Find a direction that is not parallel to zhatlocal
2283  IF (abs(zhatlocal(1)) .le. 0.8_rprec) THEN
2284  xloc = (/ 1._rprec, 0._rprec, 0._rprec /)
2285  ELSE
2286  xloc = (/ 0._rprec, 1._rprec, 0._rprec /)
2287  END IF
2288 
2289 ! Subtract off piece of xloc that is parallel to zhatlocal
2290  fac = dot_product(xloc,zhatlocal)
2291  xloc = xloc - fac * zhatlocal
2292 
2293 ! Normalize xloc, call it xhatlocal
2294  lsq = dot_product(xloc,xloc)
2295  fac = 1._rprec / sqrt(lsq)
2296  xhatlocal = fac * xloc
2297 
2298 ! Cross product to determine yhatlocal
2299  yhatlocal(1) = zhatlocal(2) * xhatlocal(3) - &
2300  & zhatlocal(3) * xhatlocal(2)
2301  yhatlocal(2) = zhatlocal(3) * xhatlocal(1) - &
2302  & zhatlocal(1) * xhatlocal(3)
2303  yhatlocal(3) = zhatlocal(1) * xhatlocal(2) - &
2304  & zhatlocal(2) * xhatlocal(1)
2305 
2306  END SUBROUTINE bsc_triplet
2307 
2308 !-------------------------------------------------------------------------------
2309 ! Subroutine to compute the mean position of a coil
2310 ! this : bsc_coil to compute its mean position
2311 ! mean_r : real(rprec), array (size 3) output specifying the
2312 ! mean position of the coil
2313 !
2314 ! Difference between mean_xnod and mean_r is in the weighting.
2315 ! mean_xnod is just a simple average of the node positions
2316 ! mean_r is length weighted.
2317 !-------------------------------------------------------------------------------
2318  SUBROUTINE bsc_mean_r(this,mean_r)
2319  IMPLICIT NONE
2320 
2321 ! Argument Declaration
2322 ! Required Arguments
2323  TYPE (bsc_coil), INTENT(in) :: this
2324  REAL(rprec), DIMENSION(3), INTENT(out) :: mean_r
2325 
2326 ! Local Variable Declaration
2327  INTEGER :: nwire, nm1, iwire, i
2328  REAL(rprec) :: coil_length
2329 
2330 ! Start of executable code
2331 
2332 ! Computes the mean position depending on the type
2333 
2334  SELECT CASE (this % c_type)
2335  CASE ('fil_circ','fcirc')
2336  mean_r(1:3) = this % xcent(1:3)
2337  CASE ('fil_loop','floop','fil_rogo','fil_rogo_s')
2338  nwire = SIZE(this % xnod,2)
2339  nm1 = max(1, nwire-1)
2340  coil_length = sum(this % lnod(1:nm1))
2341  DO i = 1,3
2342  mean_r(i) = dot_product(this % lnod(1:nm1), &
2343  & this % xnod(i,1:nm1) + 0.5 * this % dxnod(i,1:nm1)) / &
2344  & coil_length
2345  END DO
2346  CASE DEFAULT
2347  WRITE(*,*) 'FATAL: bsc_mean_r: &
2348  & c_type unrecognized:', this % c_type
2349  stop
2350  END SELECT
2351 
2352  END SUBROUTINE bsc_mean_r
2353 
2354 !-------------------------------------------------------------------------------
2355 ! Subroutine to compute the mean xnod of a coil
2356 ! this : bsc_coil to compute its mean xnod
2357 ! mean_xnod : real(rprec), array (size 3) output specifying the
2358 ! mean position of the coil. Average of Node positions.
2359 !
2360 ! Difference between mean_xnod and mean_r is in the weighting.
2361 ! mean_xnod is just a simple average of the node positions
2362 ! mean_r is length weighted.
2363 !-------------------------------------------------------------------------------
2364  SUBROUTINE bsc_mean_xnod(this,mean_xnod)
2365  IMPLICIT NONE
2366 
2367 ! Argument Declaration
2368 ! Required Arguments
2369  TYPE (bsc_coil), INTENT(in) :: this
2370  REAL(rprec), DIMENSION(3), INTENT(out) :: mean_xnod
2371 
2372 ! Local Variable Declaration
2373  INTEGER :: nwire, nm1, iwire, i
2374 
2375 ! Start of executable code
2376 
2377 ! Computes the mean position depending on the type
2378 
2379  SELECT CASE (this % c_type)
2380  CASE ('fil_circ','fcirc')
2381  mean_xnod(1:3) = this % xcent(1:3)
2382  CASE ('fil_loop','floop','fil_rogo','fil_rogo_s')
2383  nwire = SIZE(this % xnod,2)
2384  nm1 = max(1, nwire-1)
2385  DO i = 1,3
2386  mean_xnod(i) = sum(this % xnod(i,1:nm1)) / nm1
2387  END DO
2388  CASE DEFAULT
2389  WRITE(*,*) 'FATAL: bsc_mean_r: &
2390  & c_type unrecognized:', this % c_type
2391  stop
2392  END SELECT
2393 
2394  END SUBROUTINE bsc_mean_xnod
2395 
2396 
2397 !*******************************************************************************
2398 ! SECTION XIII. DEBUGGING SUBROUTINES
2399 !*******************************************************************************
2400 !-------------------------------------------------------------------------------
2401 ! Print out the contents of a coil
2402 !-------------------------------------------------------------------------------
2403 
2404  SUBROUTINE bsc_spill_coil(this,identifier)
2405  IMPLICIT NONE
2406 ! Subroutine to print out the contents of a coil structure
2407 
2408  TYPE (bsc_coil), INTENT (in) :: this
2409  CHARACTER (len=*) :: identifier
2410  INTEGER(iprec) :: i, n
2411 
2412 ! start of executable code
2413  WRITE(*,*)
2414  WRITE(*,*) 'sub spill_coil CALL with -- ',identifier,' --'
2415 
2416 ! Components common to all c_types
2417  WRITE(*,*) ' c_type = ', this % c_type
2418  WRITE(*,*) ' s_name = ', this % s_name
2419  WRITE(*,*) ' l_name = ', this % l_name
2420  WRITE(*,*) ' eps_sq = ', this % eps_sq
2421  WRITE(*,*) ' current = ', this % current
2422  WRITE(*,*) ' raux = ', this % raux
2423  IF (this % c_type .eq. 'fil_rogo') THEN
2424  WRITE(*,*) ' ave_n_area = ', this % ave_n_area
2425  END IF
2426 
2427  SELECT CASE (this % c_type)
2428  CASE ('fil_loop','floop','fil_rogo')
2429  IF (ASSOCIATED(this % xnod)) THEN
2430  n = SIZE(this % xnod,2)
2431  WRITE(*,*) ' i xnod(1,i), xnod(2,i), xnod(3,i)'
2432  DO i = 1,n
2433  WRITE(*,*) i, this % xnod(1:3,i)
2434  END DO
2435 ! Comment out Printout of dxnod, lsqnod, lnod and ehnod - redundant info
2436 ! WRITE(*,*) ' i dxnod(1-3,i), lsqnod(i)'
2437 ! DO i = 1,n-1
2438 ! WRITE(*,*) i, this % dxnod(1:3,i), this % lsqnod(i)
2439 ! END DO
2440 ! WRITE(*,*) ' i ehnod(1-3,i), lnod(i)'
2441 ! DO i = 1,n-1
2442 ! WRITE(*,*) i, this % ehnod(1:3,i), this % lnod(i)
2443 ! END DO
2444  ELSE
2445  WRITE(*,*) ' xnod is NOT ASSOCIATED'
2446  END IF ! this % xnod ASSOCIATED
2447  CASE ('fil_circ','fcirc')
2448  WRITE(*,*) ' rcirc = ', this % rcirc
2449  WRITE(*,*) ' xcent = ', this % xcent(1:3)
2450  WRITE(*,*) ' enhat = ', this % enhat(1:3)
2451  END SELECT
2452 
2453  END SUBROUTINE bsc_spill_coil
2454 
2455 !-------------------------------------------------------------------------------
2456 ! Print out lots of stuff about a coil collection
2457 !-------------------------------------------------------------------------------
2458  SUBROUTINE bsc_spill_coilcoll(this,identifier)
2459  IMPLICIT NONE
2460 ! Subroutine to print out the contents of a coil structure
2461 
2462  TYPE (bsc_coilcoll), INTENT (in) :: this
2463  CHARACTER (len=*) :: identifier
2464  INTEGER(iprec) :: i, n, ncoild
2465 
2466 
2467 ! start of executable code
2468  WRITE(*,*)
2469  WRITE(*,*) 'sub spill_coilcoll CALL with -- ',identifier,' --'
2470  WRITE(*,*) ' s_name = ', this % s_name
2471  WRITE(*,*) ' l_name = ', this % l_name
2472  WRITE(*,*) ' ncoil = ', this % ncoil
2473  ncoild = SIZE(this % coils)
2474  WRITE(*,*) ' ncoild = ', ncoild
2475 
2476 ! Note that loop below ru ns up through dimension of this % coils array
2477 ! So that expect blank s_names for ncoil < i <= ncoild
2478  DO i = 1,ncoild
2479  WRITE(*,*) i,' this coil, s_name = ',this % coils(i) % s_name
2480  IF (ASSOCIATED(this % coils(i) % xnod)) THEN
2481  n = SIZE(this % coils(i) % xnod,2)
2482  WRITE(*,*) ' xnod associated. SIZE(2) = ',n
2483  ELSE
2484  WRITE(*,*) ' xnod is NOT ASSOCIATED'
2485  END IF
2486  END DO
2487 
2488 ! JDH 12.03.02
2489 ! Here's an alternate loop over the coils in the coilcoll:
2490 ! DO i = 1,this % ncoil
2491 ! CALL bsc_spill_coil(this % coils(i),'In bsc_spill_coilcoll')
2492 ! END DO
2493 
2494  WRITE(*,*) 'End of spill_coilcoll'
2495 
2496  END SUBROUTINE bsc_spill_coilcoll
2497 
2498 
2499 !*******************************************************************************
2500 ! SECTION XIV. SPECIAL FUNCTION(S)
2501 !*******************************************************************************
2502  SUBROUTINE log_eps (x1)
2503  IMPLICIT NONE
2504 !-----------------------------------------------
2505 ! D u m m y A r g u m e n t s
2506 !-----------------------------------------------
2507  REAL(RPREC), INTENT(INOUT) :: x1(:)
2508 !-----------------------------------------------
2509 ! L o c a l P a r a m e t e r s
2510 !-----------------------------------------------
2511  REAL(rprec), PARAMETER :: c3 = one/3, &
2512  & c5 = one/5, c7 = one/7, c9 = one/9, c11 = one/11
2513  REAL(rprec), PARAMETER :: threshold = 0.1_rprec
2514  !(MAX ALLOWED: 1/3, LOG(1+x), x < 1)
2515 !-----------------------------------------------
2516 ! L o c a l V a r i a b l e s
2517 !-----------------------------------------------
2518  INTEGER :: i
2519  REAL(rprec) :: x2
2520 !-----------------------------------------------
2521 !
2522 ! FAST COMPUTATION OF LOG[(1+x)/(1-x)] USING TAYLOR OR PADE APPROXIMATION
2523 ! FOR X < THRESHOLD
2524 !
2525 ! ON ENTRY, x1 = E < 1 [ = LNOD/(RI + RF) ]
2526 ! ON RETURN, x1 = LOG((1+E)/(1-E))
2527 !
2528 ! JDH Notes, 11-21-2003:
2529 ! 1) Simplified coding, 11/2003. Previously, used for testing.
2530 ! 2) threshold value set from testing. Could vary with compiler, etc.
2531 ! 3) Other options tested (and coding eliminated)
2532 ! - Pade approximation instead of Taylor Series
2533 ! - Where loop instead of do loop
2534 !
2535 !-----------------------------------------------
2536 
2537  DO i = 1, SIZE(x1)
2538  IF (x1(i) <= threshold) THEN
2539  x2 = x1(i)*x1(i)
2540 
2541 ! TAYLOR SERIES
2542 ! (TEST CASE: 11.2 s ON PC, MAX ERR = 1.305E-10 FOR THRESHOLD = 0.2,
2543 ! 1.6E-14 FOR THRESHOLD = 0.1)
2544 
2545  x1(i) = 2 * x1(i) * (one + x2 * (c3 + x2 * (c5 + x2 * (c7 &
2546  & + x2 * (c9 + x2 * c11)))))
2547  ELSE
2548 
2549 ! THE MAX BELOW IS NECESSARY TO AVOID REAL SINGULARITY WHEN
2550 ! OBSERVATION POINT IS ON A COIL SEGMENT
2551 ! bsc_mach_eps is machine epsilon parameter
2552 
2553  x1(i) = log((1 + x1(i))/max(1 - x1(i) ,bsc_mach_eps))
2554 
2555  END IF
2556  END DO
2557 
2558  RETURN
2559 
2560  END SUBROUTINE log_eps
2561 
2562 !*******************************************************************************
2563 ! SECTION XV. DUPLICATE CODING FOR TESTING
2564 !*******************************************************************************
2565 ! File 6.3: Duplicate magnetic field subroutine, and alter coding
2566 ! so that can do speed tests.
2567 ! The Interface block is above, in SECTION III
2568 ! File 6.4 - eliminated.
2569 !*******************************************************************************
2570 ! SECTION XVI. COMMENTS FOR DIFFERENT REVISIONS
2571 !*******************************************************************************
2572 !
2573 ! JDH 10.03.02
2574 ! Adding power series in m to magnetic field and vector potential
2575 ! subroutines, for circular coils.
2576 ! Subroutines bsc_a_coil_fil_circ and bsc_b_coil_fil_circ
2577 ! JDH 10.11.02
2578 ! Fixed some bugs, extended power series in m to higher order. Adjusted
2579 ! bsc_emcut appropriately.
2580 ! JDH 10.23.02
2581 ! A minor bug with fcirc fixed (in flux calculation), and a few comments changed.
2582 ! JDH 11.19.2002
2583 ! Added % raux component to bsc_coil definition. Used to carry auxiliary information
2584 ! Not used within bsc.
2585 ! JDH 11.20.2002
2586 ! Changed file name from bsc_mod.f to bsc.f
2587 ! JDH 12.03.02
2588 ! 1) Steve Hirshman made some minor changes, eliminating unused variables, and adding
2589 ! lots of IMPLICIT NONE statements.
2590 ! 2) Updated bsc_spill_coil and bsc_spill_coilcoll
2591 ! JDH 03.27.03
2592 ! 1) Added c_type='fil_rogo'
2593 ! 2) Changed many IF - ELSEIF structures to SELECT CASE structures.
2594 ! JDH 05.15.03
2595 ! 1) Fixed bug with assignment of fil_rogo. (Forgot to copy '% ave_n_area')
2596 ! 2) In bsc_spill_coil, now print out ave_n_area.
2597 ! JDH 05.16.03
2598 ! Cleaned up intial variable declaration a bit
2599 ! Revised the flux subroutines, so that they are shorter. More gets done in
2600 ! bsc_flux_pos and the new subroutine bsc_flux_sum
2601 ! JDH 10.06.03
2602 ! Fixed a bug in subroutine bsc_triplet. Problem was in the choice of a direction
2603 ! for the initial xhatlocal.
2604 ! JDH 11.22.03
2605 ! Simplified coding in log_eps. Little changes throughout to make both free and fixed
2606 ! format compatable. Added bsc_mach_eps parameter, and replaced EPSILON calls.
2607 ! JDH 07-14-03
2608 ! Added Coil Rotations.
2609 ! Original Coding by Steve Hirshman and Dennis Strickler.
2610 ! Function calls and structure declarations changed from their original.
2611 ! Parameterization of rotation is unchanged.
2612 ! Also note the subroutines bsc_mean_r and bsc_mean_xnod, used to compute the mean
2613 ! postion of a coil. These are in the Auxiliary Subroutines section.
2614 ! Jorge Munoz did most of coding.
2615 ! I made some further changes.
2616 !
2617 ! JDH 2007-06-13
2618 ! Lines 1481-1487, in subroutine bsc_b_coil_fil_loop. Did a quick fix to
2619 ! eliminate a division by zero. (Change made 2007-05-04).
2620 
2621 ! >>> TO DO NEXT:
2622 ! 1) Fix up flux_ba, more points, with tuning parameters
2623 
2624 ! JDH 2010-07-06
2625 ! Changed coding for wrapping of coils. Need to eliminate zero length segments
2626 ! without crashing, for W7X diagnostics.
2627 ! 2010-07-07. Passed test code from J. Hebert.
2628 
2629  END MODULE bsc_t
bsc_t::bsc_destroy
Definition: bsc_T.f:189
bsc_t::bsc_fluxba
Definition: bsc_T.f:220
bsc_t::bsc_rs
Definition: bsc_T.f:163
bsc_t::bsc_a
Definition: bsc_T.f:206
bsc_t::bsc_coilcoll
Definition: bsc_T.f:151
bsc_t::bsc_b
Definition: bsc_T.f:213
bsc_t::bsc_construct
Definition: bsc_T.f:181
bsc_t::bsc_coil
Definition: bsc_T.f:127
bsc_t::bsc_rot_shift
Definition: bsc_T.f:197