ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/src/UseTheForce/DarkSide/simulation.F90
Revision: 2432
Committed: Tue Nov 15 16:01:06 2005 UTC (18 years, 8 months ago) by chuckv
File size: 21673 byte(s)
Log Message:
Added Sutton-Chen to force loop...

File Contents

# Content
1 !!
2 !! Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3 !!
4 !! The University of Notre Dame grants you ("Licensee") a
5 !! non-exclusive, royalty free, license to use, modify and
6 !! redistribute this software in source and binary code form, provided
7 !! that the following conditions are met:
8 !!
9 !! 1. Acknowledgement of the program authors must be made in any
10 !! publication of scientific results based in part on use of the
11 !! program. An acceptable form of acknowledgement is citation of
12 !! the article in which the program was described (Matthew
13 !! A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher
14 !! J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented
15 !! Parallel Simulation Engine for Molecular Dynamics,"
16 !! J. Comput. Chem. 26, pp. 252-271 (2005))
17 !!
18 !! 2. Redistributions of source code must retain the above copyright
19 !! notice, this list of conditions and the following disclaimer.
20 !!
21 !! 3. Redistributions in binary form must reproduce the above copyright
22 !! notice, this list of conditions and the following disclaimer in the
23 !! documentation and/or other materials provided with the
24 !! distribution.
25 !!
26 !! This software is provided "AS IS," without a warranty of any
27 !! kind. All express or implied conditions, representations and
28 !! warranties, including any implied warranty of merchantability,
29 !! fitness for a particular purpose or non-infringement, are hereby
30 !! excluded. The University of Notre Dame and its licensors shall not
31 !! be liable for any damages suffered by licensee as a result of
32 !! using, modifying or distributing the software or its
33 !! derivatives. In no event will the University of Notre Dame or its
34 !! licensors be liable for any lost revenue, profit or data, or for
35 !! direct, indirect, special, consequential, incidental or punitive
36 !! damages, however caused and regardless of the theory of liability,
37 !! arising out of the use of or inability to use software, even if the
38 !! University of Notre Dame has been advised of the possibility of
39 !! such damages.
40 !!
41
42 !! Fortran interface to C entry plug.
43
44 module simulation
45 use definitions
46 use neighborLists
47 use force_globals
48 use vector_class
49 use atype_module
50 use switcheroo
51 #ifdef IS_MPI
52 use mpiSimulation
53 #endif
54
55 implicit none
56 PRIVATE
57
58 #define __FORTRAN90
59 #include "brains/fSimulation.h"
60 #include "UseTheForce/fSwitchingFunction.h"
61 #include "UseTheForce/DarkSide/fElectrostaticSummationMethod.h"
62
63 type (simtype), public, save :: thisSim
64
65 logical, save :: simulation_setup_complete = .false.
66
67 integer, public, save :: nLocal, nGlobal
68 integer, public, save :: nGroups, nGroupGlobal
69 integer, public, save :: nExcludes_Global = 0
70 integer, public, save :: nExcludes_Local = 0
71 integer, allocatable, dimension(:,:), public :: excludesLocal
72 integer, allocatable, dimension(:), public :: excludesGlobal
73 integer, allocatable, dimension(:), public :: molMembershipList
74 integer, allocatable, dimension(:), public :: groupListRow
75 integer, allocatable, dimension(:), public :: groupStartRow
76 integer, allocatable, dimension(:), public :: groupListCol
77 integer, allocatable, dimension(:), public :: groupStartCol
78 integer, allocatable, dimension(:), public :: groupListLocal
79 integer, allocatable, dimension(:), public :: groupStartLocal
80 integer, allocatable, dimension(:), public :: nSkipsForAtom
81 integer, allocatable, dimension(:,:), public :: skipsForAtom
82 real(kind=dp), allocatable, dimension(:), public :: mfactRow
83 real(kind=dp), allocatable, dimension(:), public :: mfactCol
84 real(kind=dp), allocatable, dimension(:), public :: mfactLocal
85
86 logical, allocatable, dimension(:) :: simHasAtypeMap
87 #ifdef IS_MPI
88 logical, allocatable, dimension(:) :: simHasAtypeMapTemp
89 #endif
90
91 real(kind=dp), public, dimension(3,3), save :: Hmat, HmatInv
92 logical, public, save :: boxIsOrthorhombic
93
94 public :: SimulationSetup
95 public :: getNlocal
96 public :: setBox
97 public :: getDielect
98 public :: SimUsesPBC
99
100 public :: SimUsesDirectionalAtoms
101 public :: SimUsesLennardJones
102 public :: SimUsesElectrostatics
103 public :: SimUsesCharges
104 public :: SimUsesDipoles
105 public :: SimUsesSticky
106 public :: SimUsesStickyPower
107 public :: SimUsesGayBerne
108 public :: SimUsesEAM
109 public :: SimUsesShapes
110 public :: SimUsesFLARB
111 public :: SimUsesRF
112 public :: SimUsesSF
113 public :: SimRequiresPrepairCalc
114 public :: SimRequiresPostpairCalc
115 public :: SimHasAtype
116 public :: SimUsesSC
117 public :: SimUsesMEAM
118
119 contains
120
121 subroutine SimulationSetup(setThisSim, CnGlobal, CnLocal, c_idents, &
122 CnLocalExcludes, CexcludesLocal, CnGlobalExcludes, CexcludesGlobal, &
123 CmolMembership, Cmfact, CnGroups, CglobalGroupMembership, &
124 status)
125
126 type (simtype) :: setThisSim
127 integer, intent(inout) :: CnGlobal, CnLocal
128 integer, dimension(CnLocal),intent(inout) :: c_idents
129
130 integer :: CnLocalExcludes
131 integer, dimension(2,CnLocalExcludes), intent(in) :: CexcludesLocal
132 integer :: CnGlobalExcludes
133 integer, dimension(CnGlobalExcludes), intent(in) :: CexcludesGlobal
134 integer, dimension(CnGlobal),intent(in) :: CmolMembership
135 !! Result status, success = 0, status = -1
136 integer, intent(out) :: status
137 integer :: i, j, me, thisStat, alloc_stat, myNode, id1, id2
138 integer :: ia
139
140 !! mass factors used for molecular cutoffs
141 real ( kind = dp ), dimension(CnLocal) :: Cmfact
142 integer, intent(in):: CnGroups
143 integer, dimension(CnGlobal), intent(in):: CglobalGroupMembership
144 integer :: maxSkipsForAtom, glPointer
145
146 #ifdef IS_MPI
147 integer, allocatable, dimension(:) :: c_idents_Row
148 integer, allocatable, dimension(:) :: c_idents_Col
149 integer :: nAtomsInRow, nGroupsInRow, aid
150 integer :: nAtomsInCol, nGroupsInCol, gid
151 #endif
152
153 simulation_setup_complete = .false.
154 status = 0
155
156 ! copy C struct into fortran type
157
158 nLocal = CnLocal
159 nGlobal = CnGlobal
160 nGroups = CnGroups
161
162 thisSim = setThisSim
163
164 nExcludes_Global = CnGlobalExcludes
165 nExcludes_Local = CnLocalExcludes
166
167 call InitializeForceGlobals(nLocal, thisStat)
168 if (thisStat /= 0) then
169 write(default_error,*) "SimSetup: InitializeForceGlobals error"
170 status = -1
171 return
172 endif
173
174 call InitializeSimGlobals(thisStat)
175 if (thisStat /= 0) then
176 write(default_error,*) "SimSetup: InitializeSimGlobals error"
177 status = -1
178 return
179 endif
180
181 #ifdef IS_MPI
182 ! We can only set up forces if mpiSimulation has been setup.
183 if (.not. isMPISimSet()) then
184 write(default_error,*) "MPI is not set"
185 status = -1
186 return
187 endif
188 nAtomsInRow = getNatomsInRow(plan_atom_row)
189 nAtomsInCol = getNatomsInCol(plan_atom_col)
190 nGroupsInRow = getNgroupsInRow(plan_group_row)
191 nGroupsInCol = getNgroupsInCol(plan_group_col)
192 mynode = getMyNode()
193
194 allocate(c_idents_Row(nAtomsInRow),stat=alloc_stat)
195 if (alloc_stat /= 0 ) then
196 status = -1
197 return
198 endif
199
200 allocate(c_idents_Col(nAtomsInCol),stat=alloc_stat)
201 if (alloc_stat /= 0 ) then
202 status = -1
203 return
204 endif
205
206 call gather(c_idents, c_idents_Row, plan_atom_row)
207 call gather(c_idents, c_idents_Col, plan_atom_col)
208
209 do i = 1, nAtomsInRow
210 me = getFirstMatchingElement(atypes, "c_ident", c_idents_Row(i))
211 atid_Row(i) = me
212 enddo
213
214 do i = 1, nAtomsInCol
215 me = getFirstMatchingElement(atypes, "c_ident", c_idents_Col(i))
216 atid_Col(i) = me
217 enddo
218
219 !! free temporary ident arrays
220 if (allocated(c_idents_Col)) then
221 deallocate(c_idents_Col)
222 end if
223 if (allocated(c_idents_Row)) then
224 deallocate(c_idents_Row)
225 endif
226
227 #endif
228
229 #ifdef IS_MPI
230 allocate(groupStartRow(nGroupsInRow+1),stat=alloc_stat)
231 if (alloc_stat /= 0 ) then
232 status = -1
233 return
234 endif
235 allocate(groupStartCol(nGroupsInCol+1),stat=alloc_stat)
236 if (alloc_stat /= 0 ) then
237 status = -1
238 return
239 endif
240 allocate(groupListRow(nAtomsInRow),stat=alloc_stat)
241 if (alloc_stat /= 0 ) then
242 status = -1
243 return
244 endif
245 allocate(groupListCol(nAtomsInCol),stat=alloc_stat)
246 if (alloc_stat /= 0 ) then
247 status = -1
248 return
249 endif
250 allocate(mfactRow(nAtomsInRow),stat=alloc_stat)
251 if (alloc_stat /= 0 ) then
252 status = -1
253 return
254 endif
255 allocate(mfactCol(nAtomsInCol),stat=alloc_stat)
256 if (alloc_stat /= 0 ) then
257 status = -1
258 return
259 endif
260 allocate(mfactLocal(nLocal),stat=alloc_stat)
261 if (alloc_stat /= 0 ) then
262 status = -1
263 return
264 endif
265
266 glPointer = 1
267
268 do i = 1, nGroupsInRow
269
270 gid = GroupRowToGlobal(i)
271 groupStartRow(i) = glPointer
272
273 do j = 1, nAtomsInRow
274 aid = AtomRowToGlobal(j)
275 if (CglobalGroupMembership(aid) .eq. gid) then
276 groupListRow(glPointer) = j
277 glPointer = glPointer + 1
278 endif
279 enddo
280 enddo
281 groupStartRow(nGroupsInRow+1) = nAtomsInRow + 1
282
283 glPointer = 1
284
285 do i = 1, nGroupsInCol
286
287 gid = GroupColToGlobal(i)
288 groupStartCol(i) = glPointer
289
290 do j = 1, nAtomsInCol
291 aid = AtomColToGlobal(j)
292 if (CglobalGroupMembership(aid) .eq. gid) then
293 groupListCol(glPointer) = j
294 glPointer = glPointer + 1
295 endif
296 enddo
297 enddo
298 groupStartCol(nGroupsInCol+1) = nAtomsInCol + 1
299
300 mfactLocal = Cmfact
301
302 call gather(mfactLocal, mfactRow, plan_atom_row)
303 call gather(mfactLocal, mfactCol, plan_atom_col)
304
305 if (allocated(mfactLocal)) then
306 deallocate(mfactLocal)
307 end if
308 #else
309 allocate(groupStartRow(nGroups+1),stat=alloc_stat)
310 if (alloc_stat /= 0 ) then
311 status = -1
312 return
313 endif
314 allocate(groupStartCol(nGroups+1),stat=alloc_stat)
315 if (alloc_stat /= 0 ) then
316 status = -1
317 return
318 endif
319 allocate(groupListRow(nLocal),stat=alloc_stat)
320 if (alloc_stat /= 0 ) then
321 status = -1
322 return
323 endif
324 allocate(groupListCol(nLocal),stat=alloc_stat)
325 if (alloc_stat /= 0 ) then
326 status = -1
327 return
328 endif
329 allocate(mfactRow(nLocal),stat=alloc_stat)
330 if (alloc_stat /= 0 ) then
331 status = -1
332 return
333 endif
334 allocate(mfactCol(nLocal),stat=alloc_stat)
335 if (alloc_stat /= 0 ) then
336 status = -1
337 return
338 endif
339 allocate(mfactLocal(nLocal),stat=alloc_stat)
340 if (alloc_stat /= 0 ) then
341 status = -1
342 return
343 endif
344
345 glPointer = 1
346 do i = 1, nGroups
347 groupStartRow(i) = glPointer
348 groupStartCol(i) = glPointer
349 do j = 1, nLocal
350 if (CglobalGroupMembership(j) .eq. i) then
351 groupListRow(glPointer) = j
352 groupListCol(glPointer) = j
353 glPointer = glPointer + 1
354 endif
355 enddo
356 enddo
357 groupStartRow(nGroups+1) = nLocal + 1
358 groupStartCol(nGroups+1) = nLocal + 1
359
360 do i = 1, nLocal
361 mfactRow(i) = Cmfact(i)
362 mfactCol(i) = Cmfact(i)
363 end do
364
365 #endif
366
367
368 ! We build the local atid's for both mpi and nonmpi
369 do i = 1, nLocal
370
371 me = getFirstMatchingElement(atypes, "c_ident", c_idents(i))
372 atid(i) = me
373
374 enddo
375
376 do i = 1, nExcludes_Local
377 excludesLocal(1,i) = CexcludesLocal(1,i)
378 excludesLocal(2,i) = CexcludesLocal(2,i)
379 enddo
380
381 #ifdef IS_MPI
382 allocate(nSkipsForAtom(nAtomsInRow), stat=alloc_stat)
383 #else
384 allocate(nSkipsForAtom(nLocal), stat=alloc_stat)
385 #endif
386 if (alloc_stat /= 0 ) then
387 thisStat = -1
388 write(*,*) 'Could not allocate nSkipsForAtom array'
389 return
390 endif
391
392 maxSkipsForAtom = 0
393 #ifdef IS_MPI
394 do j = 1, nAtomsInRow
395 #else
396 do j = 1, nLocal
397 #endif
398 nSkipsForAtom(j) = 0
399 #ifdef IS_MPI
400 id1 = AtomRowToGlobal(j)
401 #else
402 id1 = j
403 #endif
404 do i = 1, nExcludes_Local
405 if (excludesLocal(1,i) .eq. id1 ) then
406 nSkipsForAtom(j) = nSkipsForAtom(j) + 1
407
408 if (nSkipsForAtom(j) .gt. maxSkipsForAtom) then
409 maxSkipsForAtom = nSkipsForAtom(j)
410 endif
411 endif
412 if (excludesLocal(2,i) .eq. id1 ) then
413 nSkipsForAtom(j) = nSkipsForAtom(j) + 1
414
415 if (nSkipsForAtom(j) .gt. maxSkipsForAtom) then
416 maxSkipsForAtom = nSkipsForAtom(j)
417 endif
418 endif
419 end do
420 enddo
421
422 #ifdef IS_MPI
423 allocate(skipsForAtom(nAtomsInRow, maxSkipsForAtom), stat=alloc_stat)
424 #else
425 allocate(skipsForAtom(nLocal, maxSkipsForAtom), stat=alloc_stat)
426 #endif
427 if (alloc_stat /= 0 ) then
428 write(*,*) 'Could not allocate skipsForAtom array'
429 return
430 endif
431
432 #ifdef IS_MPI
433 do j = 1, nAtomsInRow
434 #else
435 do j = 1, nLocal
436 #endif
437 nSkipsForAtom(j) = 0
438 #ifdef IS_MPI
439 id1 = AtomRowToGlobal(j)
440 #else
441 id1 = j
442 #endif
443 do i = 1, nExcludes_Local
444 if (excludesLocal(1,i) .eq. id1 ) then
445 nSkipsForAtom(j) = nSkipsForAtom(j) + 1
446 ! exclude lists have global ID's so this line is
447 ! the same in MPI and non-MPI
448 id2 = excludesLocal(2,i)
449 skipsForAtom(j, nSkipsForAtom(j)) = id2
450 endif
451 if (excludesLocal(2, i) .eq. id1 ) then
452 nSkipsForAtom(j) = nSkipsForAtom(j) + 1
453 ! exclude lists have global ID's so this line is
454 ! the same in MPI and non-MPI
455 id2 = excludesLocal(1,i)
456 skipsForAtom(j, nSkipsForAtom(j)) = id2
457 endif
458 end do
459 enddo
460
461 do i = 1, nExcludes_Global
462 excludesGlobal(i) = CexcludesGlobal(i)
463 enddo
464
465 do i = 1, nGlobal
466 molMemberShipList(i) = CmolMembership(i)
467 enddo
468
469 call createSimHasAtype(alloc_stat)
470 if (alloc_stat /= 0) then
471 status = -1
472 end if
473
474 if (status == 0) simulation_setup_complete = .true.
475
476 end subroutine SimulationSetup
477
478 subroutine setBox(cHmat, cHmatInv, cBoxIsOrthorhombic)
479 real(kind=dp), dimension(3,3) :: cHmat, cHmatInv
480 integer :: cBoxIsOrthorhombic
481 integer :: smallest, status, i
482
483 Hmat = cHmat
484 HmatInv = cHmatInv
485 if (cBoxIsOrthorhombic .eq. 0 ) then
486 boxIsOrthorhombic = .false.
487 else
488 boxIsOrthorhombic = .true.
489 endif
490
491 return
492 end subroutine setBox
493
494 function getDielect() result(dielect)
495 real( kind = dp ) :: dielect
496 dielect = thisSim%dielect
497 end function getDielect
498
499 function SimUsesPBC() result(doesit)
500 logical :: doesit
501 doesit = thisSim%SIM_uses_PBC
502 end function SimUsesPBC
503
504 function SimUsesDirectionalAtoms() result(doesit)
505 logical :: doesit
506 doesit = thisSim%SIM_uses_dipoles .or. thisSim%SIM_uses_Sticky .or. &
507 thisSim%SIM_uses_StickyPower .or. &
508 thisSim%SIM_uses_GayBerne .or. thisSim%SIM_uses_Shapes
509 end function SimUsesDirectionalAtoms
510
511 function SimUsesLennardJones() result(doesit)
512 logical :: doesit
513 doesit = thisSim%SIM_uses_LennardJones
514 end function SimUsesLennardJones
515
516 function SimUsesElectrostatics() result(doesit)
517 logical :: doesit
518 doesit = thisSim%SIM_uses_Electrostatics
519 end function SimUsesElectrostatics
520
521 function SimUsesCharges() result(doesit)
522 logical :: doesit
523 doesit = thisSim%SIM_uses_Charges
524 end function SimUsesCharges
525
526 function SimUsesDipoles() result(doesit)
527 logical :: doesit
528 doesit = thisSim%SIM_uses_Dipoles
529 end function SimUsesDipoles
530
531 function SimUsesSticky() result(doesit)
532 logical :: doesit
533 doesit = thisSim%SIM_uses_Sticky
534 end function SimUsesSticky
535
536 function SimUsesStickyPower() result(doesit)
537 logical :: doesit
538 doesit = thisSim%SIM_uses_StickyPower
539 end function SimUsesStickyPower
540
541 function SimUsesGayBerne() result(doesit)
542 logical :: doesit
543 doesit = thisSim%SIM_uses_GayBerne
544 end function SimUsesGayBerne
545
546 function SimUsesEAM() result(doesit)
547 logical :: doesit
548 doesit = thisSim%SIM_uses_EAM
549 end function SimUsesEAM
550
551
552 function SimUsesSC() result(doesit)
553 logical :: doesit
554 doesit = thisSim%SIM_uses_SC
555 end function SimUsesSC
556
557 function SimUsesMEAM() result(doesit)
558 logical :: doesit
559 doesit = thisSim%SIM_uses_MEAM
560 end function SimUsesMEAM
561
562
563 function SimUsesShapes() result(doesit)
564 logical :: doesit
565 doesit = thisSim%SIM_uses_Shapes
566 end function SimUsesShapes
567
568 function SimUsesFLARB() result(doesit)
569 logical :: doesit
570 doesit = thisSim%SIM_uses_FLARB
571 end function SimUsesFLARB
572
573 function SimUsesRF() result(doesit)
574 logical :: doesit
575 doesit = thisSim%SIM_uses_RF
576 end function SimUsesRF
577
578 function SimUsesSF() result(doesit)
579 logical :: doesit
580 doesit = thisSim%SIM_uses_SF
581 end function SimUsesSF
582
583 function SimRequiresPrepairCalc() result(doesit)
584 logical :: doesit
585 doesit = thisSim%SIM_uses_EAM .or. thisSim%SIM_uses_SC &
586 .or. thisSim%SIM_uses_MEAM
587 end function SimRequiresPrepairCalc
588
589 function SimRequiresPostpairCalc() result(doesit)
590 logical :: doesit
591 doesit = thisSim%SIM_uses_RF .or. thisSim%SIM_uses_SF
592 end function SimRequiresPostpairCalc
593
594 ! Function returns true if the simulation has this atype
595 function SimHasAtype(thisAtype) result(doesit)
596 logical :: doesit
597 integer :: thisAtype
598 doesit = .false.
599 if(.not.allocated(SimHasAtypeMap)) return
600
601 doesit = SimHasAtypeMap(thisAtype)
602
603 end function SimHasAtype
604
605 subroutine createSimHasAtype(status)
606 integer, intent(out) :: status
607 integer :: alloc_stat
608 integer :: me_i
609 integer :: mpiErrors
610 integer :: nAtypes
611 status = 0
612
613 nAtypes = getSize(atypes)
614 ! Setup logical map for atypes in simulation
615 if (.not.allocated(SimHasAtypeMap)) then
616 allocate(SimHasAtypeMap(nAtypes),stat=alloc_stat)
617 if (alloc_stat /= 0 ) then
618 status = -1
619 return
620 end if
621 SimHasAtypeMap = .false.
622 end if
623
624 ! Loop through the local atoms and grab the atypes present
625 do me_i = 1,nLocal
626 SimHasAtypeMap(atid(me_i)) = .true.
627 end do
628 ! For MPI, we need to know all possible atypes present in
629 ! simulation on all processors. Use LOR operation to set map.
630 #ifdef IS_MPI
631 if (.not.allocated(SimHasAtypeMapTemp)) then
632 allocate(SimHasAtypeMapTemp(nAtypes),stat=alloc_stat)
633 if (alloc_stat /= 0 ) then
634 status = -1
635 return
636 end if
637 end if
638 call mpi_allreduce(SimHasAtypeMap, SimHasAtypeMaptemp, nAtypes, &
639 mpi_logical, MPI_LOR, mpi_comm_world, mpiErrors)
640 simHasAtypeMap = simHasAtypeMapTemp
641 deallocate(simHasAtypeMapTemp)
642 #endif
643 end subroutine createSimHasAtype
644
645 subroutine InitializeSimGlobals(thisStat)
646 integer, intent(out) :: thisStat
647 integer :: alloc_stat
648
649 thisStat = 0
650
651 call FreeSimGlobals()
652
653 allocate(excludesLocal(2,nExcludes_Local), stat=alloc_stat)
654 if (alloc_stat /= 0 ) then
655 thisStat = -1
656 return
657 endif
658
659 allocate(excludesGlobal(nExcludes_Global), stat=alloc_stat)
660 if (alloc_stat /= 0 ) then
661 thisStat = -1
662 return
663 endif
664
665 allocate(molMembershipList(nGlobal), stat=alloc_stat)
666 if (alloc_stat /= 0 ) then
667 thisStat = -1
668 return
669 endif
670
671 end subroutine InitializeSimGlobals
672
673 subroutine FreeSimGlobals()
674
675 !We free in the opposite order in which we allocate in.
676
677 if (allocated(skipsForAtom)) deallocate(skipsForAtom)
678 if (allocated(nSkipsForAtom)) deallocate(nSkipsForAtom)
679 if (allocated(mfactLocal)) deallocate(mfactLocal)
680 if (allocated(mfactCol)) deallocate(mfactCol)
681 if (allocated(mfactRow)) deallocate(mfactRow)
682 if (allocated(groupListCol)) deallocate(groupListCol)
683 if (allocated(groupListRow)) deallocate(groupListRow)
684 if (allocated(groupStartCol)) deallocate(groupStartCol)
685 if (allocated(groupStartRow)) deallocate(groupStartRow)
686 if (allocated(molMembershipList)) deallocate(molMembershipList)
687 if (allocated(excludesGlobal)) deallocate(excludesGlobal)
688 if (allocated(excludesLocal)) deallocate(excludesLocal)
689
690 end subroutine FreeSimGlobals
691
692 pure function getNlocal() result(n)
693 integer :: n
694 n = nLocal
695 end function getNlocal
696
697
698
699
700
701 end module simulation