(git:374b731)
Loading...
Searching...
No Matches
atoms_input.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \par History
10!> cjm, Feb-20-2001 : added all the extended variables to
11!> system_type
12!> gt 23-09-2002 : major changes. Pointer part is allocated/deallocated
13!> and initialized here. Atomic coordinates can now be
14!> read also from &COORD section in the input file.
15!> If &COORD is not found, .dat file is read.
16!> If & coord is found and .NOT. 'INIT', parsing of the .dat
17!> is performed to get the proper coords/vel/eta variables
18!> CJM 31-7-03 : Major rewrite. No more atype
19! **************************************************************************************************
23 USE cell_types, ONLY: cell_type,&
24 pbc,&
31 USE cp_units, ONLY: cp_unit_to_cp2k
38 USE input_val_types, ONLY: val_get,&
40 USE kinds, ONLY: default_string_length,&
41 dp
45 USE string_table, ONLY: id2str,&
46 s2s,&
47 str2id
51#include "./base/base_uses.f90"
52
53 IMPLICIT NONE
54
55 PRIVATE
57 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'atoms_input'
58
59CONTAINS
60
61! **************************************************************************************************
62!> \brief ...
63!> \param topology ...
64!> \param overwrite ...
65!> \param subsys_section ...
66!> \param save_mem ...
67!> \author CJM
68! **************************************************************************************************
69 SUBROUTINE read_atoms_input(topology, overwrite, subsys_section, save_mem)
70
72 LOGICAL, INTENT(IN), OPTIONAL :: overwrite
73 TYPE(section_vals_type), POINTER :: subsys_section
74 LOGICAL, INTENT(IN), OPTIONAL :: save_mem
75
76 CHARACTER(len=*), PARAMETER :: routinen = 'read_atoms_input'
77
78 CHARACTER(len=2*default_string_length) :: line_att
79 CHARACTER(len=default_string_length) :: error_message, my_default_index, strtmp, &
80 unit_str
81 INTEGER :: default_id, end_c, handle, iatom, j, &
82 natom, output_unit, start_c, wrd
83 LOGICAL :: explicit, is_ok, my_overwrite, &
84 my_save_mem, scaled_coordinates
85 REAL(kind=dp) :: r0(3), unit_conv
86 TYPE(atom_info_type), POINTER :: atom_info
87 TYPE(cell_type), POINTER :: cell
88 TYPE(cp_sll_val_type), POINTER :: list
89 TYPE(section_vals_type), POINTER :: coord_section
90 TYPE(val_type), POINTER :: val
91
92 my_overwrite = .false.
93 my_save_mem = .false.
94 error_message = ""
95 output_unit = cp_logger_get_default_io_unit()
96 IF (PRESENT(overwrite)) my_overwrite = overwrite
97 IF (PRESENT(save_mem)) my_save_mem = save_mem
98 NULLIFY (coord_section)
99 coord_section => section_vals_get_subs_vals(subsys_section, "COORD")
100 CALL section_vals_get(coord_section, explicit=explicit)
101 IF (.NOT. explicit) RETURN
102
103 CALL timeset(routinen, handle)
104 !-----------------------------------------------------------------------------
105 !-----------------------------------------------------------------------------
106 ! 1. get cell and topology%atom_info
107 !-----------------------------------------------------------------------------
108 atom_info => topology%atom_info
109 cell => topology%cell_muc
110 CALL section_vals_val_get(coord_section, "UNIT", c_val=unit_str)
111 CALL section_vals_val_get(coord_section, "SCALED", l_val=scaled_coordinates)
112 unit_conv = cp_unit_to_cp2k(1.0_dp, trim(unit_str))
113
114 !-----------------------------------------------------------------------------
115 !-----------------------------------------------------------------------------
116 ! 2. Read in the coordinates from &COORD section in the input file
117 !-----------------------------------------------------------------------------
118 CALL section_vals_val_get(coord_section, "_DEFAULT_KEYWORD_", &
119 n_rep_val=natom)
120 topology%natoms = natom
121 IF (my_overwrite) THEN
122 cpassert(SIZE(atom_info%r, 2) == natom)
123 CALL cp_warn(__location__, &
124 "Overwriting coordinates. Active coordinates read from &COORD section."// &
125 " Active coordinates READ from &COORD section ")
126 CALL section_vals_list_get(coord_section, "_DEFAULT_KEYWORD_", list=list)
127 DO iatom = 1, natom
128 is_ok = cp_sll_val_next(list, val)
129 CALL val_get(val, c_val=line_att)
130 ! Read name and atomic coordinates
131 start_c = 1
132 DO wrd = 1, 4
133 DO j = start_c, len(line_att)
134 IF (line_att(j:j) /= ' ') THEN
135 start_c = j
136 EXIT
137 END IF
138 END DO
139 end_c = len(line_att) + 1
140 DO j = start_c, len(line_att)
141 IF (line_att(j:j) == ' ') THEN
142 end_c = j
143 EXIT
144 END IF
145 END DO
146 IF (len_trim(line_att(start_c:end_c - 1)) == 0) &
147 cpabort("incorrectly formatted line in coord section'"//line_att//"'")
148 IF (wrd == 1) THEN
149 atom_info%id_atmname(iatom) = str2id(s2s(line_att(start_c:end_c - 1)))
150 ELSE
151 READ (line_att(start_c:end_c - 1), *) atom_info%r(wrd - 1, iatom)
152 END IF
153 start_c = end_c
154 END DO
155 END DO
156 ELSE
157 ! Element is assigned on the basis of the atm_name
158 topology%aa_element = .true.
159
160 CALL reallocate(atom_info%id_molname, 1, natom)
161 CALL reallocate(atom_info%id_resname, 1, natom)
162 CALL reallocate(atom_info%resid, 1, natom)
163 CALL reallocate(atom_info%id_atmname, 1, natom)
164 CALL reallocate(atom_info%id_element, 1, natom)
165 CALL reallocate(atom_info%r, 1, 3, 1, natom)
166 CALL reallocate(atom_info%atm_mass, 1, natom)
167 CALL reallocate(atom_info%atm_charge, 1, natom)
168
169 CALL section_vals_list_get(coord_section, "_DEFAULT_KEYWORD_", list=list)
170 DO iatom = 1, natom
171 ! we use only the first default_string_length characters of each line
172 is_ok = cp_sll_val_next(list, val)
173 CALL val_get(val, c_val=line_att)
174 default_id = str2id(s2s(""))
175 atom_info%id_molname(iatom) = default_id
176 atom_info%id_resname(iatom) = default_id
177 atom_info%resid(iatom) = 1
178 atom_info%id_atmname(iatom) = default_id
179 atom_info%id_element(iatom) = default_id
180 topology%molname_generated = .true.
181 ! Read name and atomic coordinates
182 start_c = 1
183 DO wrd = 1, 6
184 DO j = start_c, len(line_att)
185 IF (line_att(j:j) /= ' ') THEN
186 start_c = j
187 EXIT
188 END IF
189 END DO
190 end_c = len(line_att) + 1
191 DO j = start_c, len(line_att)
192 IF (line_att(j:j) == ' ') THEN
193 end_c = j
194 EXIT
195 END IF
196 END DO
197 IF (len_trim(line_att(start_c:end_c - 1)) == 0) &
198 CALL cp_abort(__location__, &
199 "Incorrectly formatted input line for atom "// &
200 trim(adjustl(cp_to_string(iatom)))// &
201 " found in COORD section. Input line: <"// &
202 trim(line_att)//"> ")
203 SELECT CASE (wrd)
204 CASE (1)
205 atom_info%id_atmname(iatom) = str2id(s2s(line_att(start_c:end_c - 1)))
206 CASE (2:4)
207 CALL read_float_object(line_att(start_c:end_c - 1), &
208 atom_info%r(wrd - 1, iatom), error_message)
209 IF (len_trim(error_message) /= 0) &
210 CALL cp_abort(__location__, &
211 "Incorrectly formatted input line for atom "// &
212 trim(adjustl(cp_to_string(iatom)))// &
213 " found in COORD section. "//trim(error_message)// &
214 " Input line: <"//trim(line_att)//"> ")
215 CASE (5)
216 READ (line_att(start_c:end_c - 1), *) strtmp
217 atom_info%id_molname(iatom) = str2id(strtmp)
218 atom_info%id_resname(iatom) = atom_info%id_molname(iatom)
219 topology%molname_generated = .false.
220 CASE (6)
221 READ (line_att(start_c:end_c - 1), *) strtmp
222 atom_info%id_resname(iatom) = str2id(strtmp)
223 END SELECT
224 start_c = end_c
225 IF (start_c > len_trim(line_att)) EXIT
226 END DO
227 IF (topology%molname_generated) THEN
228 ! Use defaults, if no molname was specified
229 WRITE (my_default_index, '(I0)') iatom
230 atom_info%id_molname(iatom) = str2id(s2s(trim(id2str(atom_info%id_atmname(iatom)))//trim(my_default_index)))
231 atom_info%id_resname(iatom) = atom_info%id_molname(iatom)
232 END IF
233 atom_info%id_element(iatom) = atom_info%id_atmname(iatom)
234 atom_info%atm_mass(iatom) = 0.0_dp
235 atom_info%atm_charge(iatom) = -huge(0.0_dp)
236 END DO
237 END IF
238 !-----------------------------------------------------------------------------
239 !-----------------------------------------------------------------------------
240 ! 3. Convert coordinates into internal cp2k coordinates
241 !-----------------------------------------------------------------------------
242 DO iatom = 1, natom
243 IF (scaled_coordinates) THEN
244 r0 = atom_info%r(:, iatom)
245 CALL scaled_to_real(atom_info%r(:, iatom), r0, cell)
246 ELSE
247 atom_info%r(:, iatom) = atom_info%r(:, iatom)*unit_conv
248 END IF
249 END DO
250 IF (my_save_mem) CALL section_vals_remove_values(coord_section)
251
252 CALL timestop(handle)
253 END SUBROUTINE read_atoms_input
254
255! **************************************************************************************************
256!> \brief ...
257!> \param particle_set ...
258!> \param shell_particle_set ...
259!> \param cell ...
260!> \param subsys_section ...
261!> \param core_particle_set ...
262!> \param save_mem ...
263!> \author MI
264! **************************************************************************************************
265 SUBROUTINE read_shell_coord_input(particle_set, shell_particle_set, cell, &
266 subsys_section, core_particle_set, save_mem)
267
268 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set, shell_particle_set
269 TYPE(cell_type), POINTER :: cell
270 TYPE(section_vals_type), POINTER :: subsys_section
271 TYPE(particle_type), DIMENSION(:), OPTIONAL, &
272 POINTER :: core_particle_set
273 LOGICAL, INTENT(IN), OPTIONAL :: save_mem
274
275 CHARACTER(len=*), PARAMETER :: routinen = 'read_shell_coord_input'
276
277 CHARACTER(len=2*default_string_length) :: line_att
278 CHARACTER(len=default_string_length) :: name_kind, unit_str
279 CHARACTER(len=default_string_length), &
280 ALLOCATABLE, DIMENSION(:) :: at_name, at_name_c
281 INTEGER :: end_c, handle, ishell, j, nshell, &
282 output_unit, sh_index, start_c, wrd
283 INTEGER, ALLOCATABLE, DIMENSION(:) :: at_index, at_index_c
284 LOGICAL :: core_scaled_coordinates, explicit, &
285 is_ok, is_shell, my_save_mem, &
286 shell_scaled_coordinates
287 REAL(kind=dp) :: dab, mass_com, rab(3), unit_conv_core, &
288 unit_conv_shell
289 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: r, rc
290 TYPE(atomic_kind_type), POINTER :: atomic_kind
291 TYPE(cp_sll_val_type), POINTER :: list
292 TYPE(section_vals_type), POINTER :: core_coord_section, shell_coord_section
293 TYPE(shell_kind_type), POINTER :: shell
294 TYPE(val_type), POINTER :: val
295
296 my_save_mem = .false.
297 NULLIFY (atomic_kind, list, shell_coord_section, shell, val)
298 output_unit = cp_logger_get_default_io_unit()
299
300 IF (PRESENT(save_mem)) my_save_mem = save_mem
301 NULLIFY (shell_coord_section, core_coord_section)
302 shell_coord_section => section_vals_get_subs_vals(subsys_section, "SHELL_COORD")
303 CALL section_vals_get(shell_coord_section, explicit=explicit)
304 IF (.NOT. explicit) RETURN
305
306 CALL timeset(routinen, handle)
307 cpassert(ASSOCIATED(particle_set))
308 !-----------------------------------------------------------------------------
309 !-----------------------------------------------------------------------------
310 ! 2. Read in the coordinates from &SHELL_COORD section in the input file
311 !-----------------------------------------------------------------------------
312 CALL section_vals_val_get(shell_coord_section, "UNIT", c_val=unit_str)
313 CALL section_vals_val_get(shell_coord_section, "SCALED", l_val=shell_scaled_coordinates)
314 unit_conv_shell = cp_unit_to_cp2k(1.0_dp, trim(unit_str))
315 CALL section_vals_val_get(shell_coord_section, "_DEFAULT_KEYWORD_", &
316 n_rep_val=nshell)
317
318 IF (ASSOCIATED(shell_particle_set)) THEN
319 cpassert((SIZE(shell_particle_set, 1) == nshell))
320 ALLOCATE (r(3, nshell), at_name(nshell), at_index(nshell))
321 CALL cp_warn(__location__, &
322 "Overwriting shell coordinates. "// &
323 "Active coordinates READ from &SHELL_COORD section. ")
324 CALL section_vals_list_get(shell_coord_section, "_DEFAULT_KEYWORD_", list=list)
325 DO ishell = 1, nshell
326 ! we use only the first default_string_length characters of each line
327 is_ok = cp_sll_val_next(list, val)
328 CALL val_get(val, c_val=line_att)
329 start_c = 1
330 DO wrd = 1, 5
331 DO j = start_c, len(line_att)
332 IF (line_att(j:j) /= ' ') THEN
333 start_c = j
334 EXIT
335 END IF
336 END DO
337 end_c = len(line_att) + 1
338 DO j = start_c, len(line_att)
339 IF (line_att(j:j) == ' ') THEN
340 end_c = j
341 EXIT
342 END IF
343 END DO
344 IF (wrd /= 5 .AND. end_c >= len(line_att) + 1) &
345 cpabort("incorrectly formatted line in coord section'"//line_att//"'")
346 IF (wrd == 1) THEN
347 at_name(ishell) = line_att(start_c:end_c - 1)
348 CALL uppercase(at_name(ishell))
349 ELSE IF (wrd == 5) THEN
350 READ (line_att(start_c:end_c - 1), *) at_index(ishell)
351 ELSE
352 READ (line_att(start_c:end_c - 1), *) r(wrd - 1, ishell)
353 END IF
354 start_c = end_c
355 END DO
356 END DO
357
358 IF (PRESENT(core_particle_set)) THEN
359 cpassert(ASSOCIATED(core_particle_set))
360 core_coord_section => section_vals_get_subs_vals(subsys_section, "CORE_COORD")
361 CALL section_vals_get(core_coord_section, explicit=explicit)
362 IF (explicit) THEN
363 CALL section_vals_val_get(core_coord_section, "UNIT", c_val=unit_str)
364 CALL section_vals_val_get(core_coord_section, "SCALED", l_val=core_scaled_coordinates)
365 unit_conv_core = cp_unit_to_cp2k(1.0_dp, trim(unit_str))
366 CALL section_vals_val_get(core_coord_section, "_DEFAULT_KEYWORD_", &
367 n_rep_val=nshell)
368
369 cpassert((SIZE(core_particle_set, 1) == nshell))
370 ALLOCATE (rc(3, nshell), at_name_c(nshell), at_index_c(nshell))
371 CALL cp_warn(__location__, &
372 "Overwriting cores coordinates. "// &
373 "Active coordinates READ from &CORE_COORD section. ")
374 CALL section_vals_list_get(core_coord_section, "_DEFAULT_KEYWORD_", list=list)
375 DO ishell = 1, nshell
376 ! we use only the first default_string_length characters of each line
377 is_ok = cp_sll_val_next(list, val)
378 CALL val_get(val, c_val=line_att)
379 start_c = 1
380 DO wrd = 1, 5
381 DO j = start_c, len(line_att)
382 IF (line_att(j:j) /= ' ') THEN
383 start_c = j
384 EXIT
385 END IF
386 END DO
387 end_c = len(line_att) + 1
388 DO j = start_c, len(line_att)
389 IF (line_att(j:j) == ' ') THEN
390 end_c = j
391 EXIT
392 END IF
393 END DO
394 IF (wrd /= 5 .AND. end_c >= len(line_att) + 1) &
395 cpabort("incorrectly formatted line in coord section'"//line_att//"'")
396 IF (wrd == 1) THEN
397 at_name_c(ishell) = line_att(start_c:end_c - 1)
398 CALL uppercase(at_name_c(ishell))
399 ELSE IF (wrd == 5) THEN
400 READ (line_att(start_c:end_c - 1), *) at_index_c(ishell)
401 ELSE
402 READ (line_att(start_c:end_c - 1), *) rc(wrd - 1, ishell)
403 END IF
404 start_c = end_c
405 END DO
406 END DO
407 IF (my_save_mem) CALL section_vals_remove_values(core_coord_section)
408 END IF ! explicit
409 END IF ! core_particle_set
410
411 !-----------------------------------------------------------------------------
412 ! 3. Check corrispondence and convert coordinates into internal cp2k coordinates
413 !-----------------------------------------------------------------------------
414 DO ishell = 1, nshell
415 atomic_kind => particle_set(at_index(ishell))%atomic_kind
416 CALL get_atomic_kind(atomic_kind=atomic_kind, &
417 name=name_kind, shell_active=is_shell, mass=mass_com, shell=shell)
418 CALL uppercase(name_kind)
419 IF ((trim(at_name(ishell)) == trim(name_kind)) .AND. is_shell) THEN
420 sh_index = particle_set(at_index(ishell))%shell_index
421 IF (shell_scaled_coordinates) THEN
422 CALL scaled_to_real(r(:, ishell), shell_particle_set(sh_index)%r(:), cell)
423 ELSE
424 shell_particle_set(sh_index)%r(:) = r(:, ishell)*unit_conv_shell
425 END IF
426 shell_particle_set(sh_index)%atom_index = at_index(ishell)
427
428 IF (PRESENT(core_particle_set) .AND. .NOT. explicit) THEN
429 core_particle_set(sh_index)%r(1) = (mass_com*particle_set(at_index(ishell))%r(1) - &
430 shell%mass_shell*shell_particle_set(sh_index)%r(1))/shell%mass_core
431 core_particle_set(sh_index)%r(2) = (mass_com*particle_set(at_index(ishell))%r(2) - &
432 shell%mass_shell*shell_particle_set(sh_index)%r(2))/shell%mass_core
433 core_particle_set(sh_index)%r(3) = (mass_com*particle_set(at_index(ishell))%r(3) - &
434 shell%mass_shell*shell_particle_set(sh_index)%r(3))/shell%mass_core
435 core_particle_set(sh_index)%atom_index = at_index(ishell)
436 rab = pbc(shell_particle_set(sh_index)%r, core_particle_set(sh_index)%r, cell)
437 ELSE IF (explicit) THEN
438 IF (core_scaled_coordinates) THEN
439 CALL scaled_to_real(rc(:, ishell), core_particle_set(sh_index)%r(:), cell)
440 ELSE
441 core_particle_set(sh_index)%r(:) = rc(:, ishell)*unit_conv_core
442 END IF
443 core_particle_set(sh_index)%atom_index = at_index_c(ishell)
444 rab = pbc(shell_particle_set(sh_index)%r, core_particle_set(sh_index)%r, cell)
445 cpassert(trim(at_name(ishell)) == trim(at_name_c(ishell)))
446 cpassert(at_index(ishell) == at_index_c(ishell))
447 ELSE
448 rab = pbc(shell_particle_set(sh_index)%r, particle_set(at_index(ishell))%r, cell)
449 END IF
450
451 dab = sqrt(rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3))
452 IF (shell%max_dist > 0.0_dp .AND. shell%max_dist < dab) THEN
453 IF (output_unit > 0) THEN
454 WRITE (output_unit, *) "WARNING : shell and core for atom ", at_index(ishell), " seem to be too distant. "
455 END IF
456 END IF
457
458 ELSE
459 cpabort("shell coordinate assigned to the wrong atom. check the shell indexes in the input")
460 END IF
461 END DO
462 DEALLOCATE (r, at_index, at_name)
463 DEALLOCATE (rc, at_index_c, at_name_c)
464
465 END IF
466
467 IF (my_save_mem) CALL section_vals_remove_values(shell_coord_section)
468
469 CALL timestop(handle)
470
471 END SUBROUTINE read_shell_coord_input
472
473END MODULE atoms_input
Define the atomic kind types and their sub types.
subroutine, public get_atomic_kind(atomic_kind, fist_potential, element_symbol, name, mass, kind_number, natom, atom_list, rcov, rvdw, z, qeff, apol, cpol, mm_radius, shell, shell_active, damping)
Get attributes of an atomic kind.
subroutine, public read_atoms_input(topology, overwrite, subsys_section, save_mem)
...
Definition atoms_input.F:70
subroutine, public read_shell_coord_input(particle_set, shell_particle_set, cell, subsys_section, core_particle_set, save_mem)
...
Handles all functions related to the CELL.
Definition cell_types.F:15
subroutine, public scaled_to_real(r, s, cell)
Transform scaled cell coordinates real coordinates. r=h*s.
Definition cell_types.F:516
logical function, public cp_sll_val_next(iterator, el_att)
returns true if the actual element is valid (i.e. iterator ont at end) moves the iterator to the next...
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
Utility routines to read data from files. Kept as close as possible to the old parser because.
elemental subroutine, public read_float_object(string, object, error_message)
Returns a floating point number read from a string including fraction like z1/z2.
unit conversion facility
Definition cp_units.F:30
real(kind=dp) function, public cp_unit_to_cp2k(value, unit_str, defaults, power)
converts to the internal cp2k units to the given unit
Definition cp_units.F:1150
objects that represent the structure of input sections and the data contained in an input section
subroutine, public section_vals_remove_values(section_vals)
removes the values of a repetition of the section
subroutine, public section_vals_list_get(section_vals, keyword_name, i_rep_section, list)
returns the requested list
recursive type(section_vals_type) function, pointer, public section_vals_get_subs_vals(section_vals, subsection_name, i_rep_section, can_return_null)
returns the values of the requested subsection
subroutine, public section_vals_get(section_vals, ref_count, n_repetition, n_subs_vals_rep, section, explicit)
returns various attributes about the section_vals
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
a wrapper for basic fortran types.
subroutine, public val_get(val, has_l, has_i, has_r, has_lc, has_c, l_val, l_vals, i_val, i_vals, r_val, r_vals, c_val, c_vals, len_c, type_of_var, enum)
returns the stored values
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public default_string_length
Definition kinds.F:57
An array-based list which grows on demand. When the internal array is full, a new array of twice the ...
Definition list.F:24
Utility routines for the memory handling.
Define the data structure for the particle information.
generates a unique id number for a string (str2id) that can be used two compare two strings....
character(len=default_string_length) function, public s2s(str)
converts a string in a string of default_string_length
integer function, public str2id(str)
returns a unique id for a given string, and stores the string for later retrieval using the id.
character(len=default_string_length) function, public id2str(id)
returns the string associated with a given id
Utilities for string manipulations.
elemental subroutine, public uppercase(string)
Convert all lower case characters in a string to upper case.
Control for reading in different topologies and coordinates.
Definition topology.F:13
Provides all information about an atomic kind.
Type defining parameters related to the simulation cell.
Definition cell_types.F:55
represent a single linked list that stores pointers to the elements
a type to have a wrapper that stores any basic fortran type