Octopus
interactions_factory_abst.F90
Go to the documentation of this file.
1!! Copyright (C) 2020 M. Oliveira
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
24 use debug_oct_m
26 use global_oct_m
33 use parser_oct_m
34 use system_oct_m
36 implicit none
37
38 private
39 public :: &
41
42 integer, parameter, public :: &
43 NO_PARTNERS = -1, &
44 all_partners = -2, &
45 only_partners = -3, &
46 all_except = -4
47
48
56 !
57 type, abstract :: interactions_factory_abst_t
58 contains
59 procedure :: create_interactions => interactions_factory_abst_create_interactions
60
61 procedure(interactions_factory_abst_create), deferred :: create
62
63 procedure(interactions_factory_abst_default_mode), deferred :: default_mode
64
65 procedure(interactions_factory_abst_block_name), deferred :: block_name
66
68
69 abstract interface
70
74 !
75 function interactions_factory_abst_create(this, type, partner) result(interaction)
78 import interaction_t
79 class(interactions_factory_abst_t), intent(in) :: this
80 integer, intent(in) :: type
81 class(interaction_partner_t), target, intent(inout) :: partner
82 class(interaction_t), pointer :: interaction
84
89 !
90 integer function interactions_factory_abst_default_mode(this, namespace, type)
93 class(interactions_factory_abst_t), intent(in) :: this
94 type(namespace_t), intent(in) :: namespace
95 integer, intent(in) :: type
97
102 !
103 character(len=80) function interactions_factory_abst_block_name(this)
105 class(interactions_factory_abst_t), intent(in) :: this
107 end interface
108
109contains
110
111 ! ---------------------------------------------------------------------------------------
121 !
122 recursive subroutine interactions_factory_abst_create_interactions(this, system, available_partners)
123 class(interactions_factory_abst_t), intent(in) :: this
124 class(system_t), intent(inout) :: system
125 class(partner_list_t), target, intent(in) :: available_partners
127 type(integer_list_t) :: interactions_to_create
128 type(integer_iterator_t) :: interaction_iter
129 integer :: interaction_type
130 type(partner_list_t) :: partners, partners_flat_list
131 type(partner_iterator_t) :: partner_iter
132 class(interaction_partner_t), pointer :: partner
133 type(system_iterator_t) :: iter
134 class(system_t), pointer :: subsystem
135
136 integer :: il, ic, mode
137 type(block_t) :: blk
138 character(len=MAX_NAMESPACE_LEN) :: input_name
139
142 ! Make a copy of the interactions list so that we can modify it
143 interactions_to_create = system%supported_interactions
144
145 ! Get the list of partners as a flat list
146 call flatten_partner_list(available_partners, partners_flat_list)
148 ! Parse input. The variable name and description should be given by the
149 ! factory, as different factories might have different options.
150 if (parse_block(system%namespace, this%block_name(), blk) == 0) then
151
152 ! Loop over all interactions specified in the input file
153 do il = 0, parse_block_n(blk) - 1
154 ! Read the interaction type (first column)
155 call parse_block_integer(blk, il, 0, interaction_type)
156
157 ! Sanity check: the interaction type must be known and must not be mistaken for an interaction mode
158 if (.not. varinfo_valid_option(this%block_name(), interaction_type) .or. &
159 any(interaction_type == (/all_partners, only_partners, no_partners, all_except/))) then
160 call messages_input_error(system%namespace, this%block_name(), details="Unknown interaction type", row=il, column=0)
161 end if
162
163 ! Ignore interactions that are not supported by this system
164 if (.not. interactions_to_create%has(interaction_type)) cycle
165
166 ! Read how this interaction should be treated (second column)
167 call parse_block_integer(blk, il, 1, mode)
168
169 ! Create list of partners for this interaction taking into account the selected mode
170 select case (mode)
171 case (all_partners)
172 ! Use all available partners
173 partners = partners_flat_list
174 case (no_partners)
175 ! No partners for this interaction
176 call partners%empty()
177 case (only_partners)
178 ! Start with an empty list. We will add only the select partners bellow
179 call partners%empty()
180 case (all_except)
181 ! Start with full list. We will remove the select partners bellow
182 partners = partners_flat_list
183 case default
184 call messages_input_error(system%namespace, this%block_name(), "Unknown interaction mode", row=il, column=1)
185 end select
186
187 if (mode == only_partners .or. mode == all_except) then
188 ! In these two cases we need to read the names of the selected
189 ! partners (remaining columns) and handled them appropriately
190 do ic = 2, parse_block_cols(blk, il) - 1
191 call parse_block_string(blk, il, ic, input_name)
192
193 ! Loop over available partners and either add them or remove them
194 ! from the list depending on the selected mode
195 call partner_iter%start(partners_flat_list)
196 do while (partner_iter%has_next())
197 partner => partner_iter%get_next()
198 if (partner%namespace%is_contained_in(input_name)) then
199 select case (mode)
200 case (only_partners)
201 call partners%add(partner)
202 case (all_except)
203 call partners%delete(partner)
204 end select
205 end if
206 end do
207 end do
208
209 end if
210
211 ! Now actually create the interactions for the selected partners
212 call create_interactions(this, system, partners, interaction_type)
213
214 ! Remove this interaction type from the list, as it has just been handled
215 call interactions_to_create%delete(interaction_type)
216 end do
217 call parse_block_end(blk)
218 end if
219
220 ! Loop over all the remaining interactions supported by the system
221 call interaction_iter%start(interactions_to_create)
222 do while (interaction_iter%has_next())
223 interaction_type = interaction_iter%get_next()
224
225 ! Check what is the default mode for this interaction type (all or none)
226 select case (this%default_mode(system%namespace, interaction_type))
227 case (all_partners)
228 partners = partners_flat_list
229 case (no_partners)
230 call partners%empty()
231 case default
232 message(1) = "Default interaction mode can only be all_partners or no_partners."
233 call messages_fatal(1, namespace=system%namespace)
234 end select
235
236 call create_interactions(this, system, partners, interaction_type)
237 end do
238
239 ! All systems need to be connected to make sure they remain synchronized.
240 ! We enforce that be adding a ghost interaction between all systems
241 call create_interactions(this, system, partners_flat_list)
242
243 ! If the system is a multisystem, then we also need to create the interactions for the subsystems
244 select type (system)
245 class is (multisystem_t)
246 call iter%start(system%list)
247 do while (iter%has_next())
248 subsystem => iter%get_next()
249 call this%create_interactions(subsystem, available_partners)
250 end do
251 end select
252
254 contains
255
256 recursive subroutine flatten_partner_list(partners, flat_list)
257 class(partner_list_t), intent(in) :: partners
258 class(partner_list_t), intent(inout) :: flat_list
259
260 class(interaction_partner_t), pointer :: partner
261 type(partner_iterator_t) :: iterator
262
264
265 call iterator%start(partners)
266 do while (iterator%has_next())
267 partner => iterator%get_next()
268
269 call flat_list%add(partner)
270
271 select type (partner)
272 class is (multisystem_t)
273 ! Also include the subsystems of a multisystem
274 call flatten_partner_list(partner%list, flat_list)
275 end select
276
277 end do
278
280 end subroutine flatten_partner_list
281
283
284 ! ---------------------------------------------------------------------------------------
288 !
289 subroutine create_interactions(this, system, partners, interaction_type)
290 class(interactions_factory_abst_t), intent(in) :: this
291 class(system_t), intent(inout) :: system
292 class(partner_list_t), target, intent(in) :: partners
293 integer, optional, intent(in) :: interaction_type
294
295 type(partner_iterator_t) :: iter
296 class(interaction_partner_t), pointer :: partner
297 class(interaction_t), pointer :: interaction
298
299 push_sub(create_interactions)
300
301 ! Loop over all available partners
302 call iter%start(partners)
303 do while (iter%has_next())
304 partner => iter%get_next()
305
306 ! No self-interaction
307 if (partner%namespace%get() /= system%namespace%get()) then
308
309 if (present(interaction_type)) then
310 ! If the partner also supports this type of interaction, then create the interaction
311 if (partner%supported_interactions_as_partner%has(interaction_type)) then
312 interaction => this%create(interaction_type, partner)
313
314 !Mark all the quantities needed by the interaction from the system and the partner as required
315 if (allocated(interaction%system_quantities)) then
316 system%quantities(interaction%system_quantities)%required = .true.
317 end if
318 if (allocated(interaction%couplings_from_partner)) then
319 partner%quantities(interaction%couplings_from_partner)%required = .true.
320 end if
321
322 ! Add interaction to list
323 call system%interactions%add(interaction)
324 end if
325 else
326 ! Create a ghost interaction if no interaction type was given
327 interaction => ghost_interaction_t(partner)
328 call system%interactions%add(interaction)
329 end if
330 end if
331
332 end do
333
334 pop_sub(create_interactions)
335 end subroutine create_interactions
336
338
339!! Local Variables:
340!! mode: f90
341!! coding: utf-8
342!! End:
if write to the Free Software Franklin Fifth USA !If the compiler accepts long Fortran it is better to use that and build all the preprocessor definitions in one line In !this the debuggers will provide the right line numbers !If the compiler accepts line number then CARDINAL and ACARDINAL !will put them just a new line or a ampersand plus a new line !These macros should be used in macros that span several lines They should by !put immedialty before a line where a compilation error might occur and at the !end of the macro !Note that the cardinal and newline words are substituted by the program !preprocess pl by the ampersand and by a real new line just before compilation !The assertions are ignored if the code is compiled in not debug mode(NDEBUG ! is defined). Otherwise it is merely a logical assertion that
recursive subroutine flatten_partner_list(partners, flat_list)
Interface for the function to get the name of the input file block for interactions.
Interface for the function to create a specific interaction.
Interface for the function to get the default mode for a given interaction.
This module defines the abstract interaction_t class, and some auxiliary classes for interactions.
This module defines classes and functions for interaction partners.
This module defines the abstract class for the interaction factory.
recursive subroutine interactions_factory_abst_create_interactions(this, system, available_partners)
create all interactions for a system and the partners.
subroutine create_interactions(this, system, partners, interaction_type)
Create all interacions of a given type for a system to its interaction partners.
This module implements fully polymorphic linked lists, and some specializations thereof.
Definition: linked_list.F90:96
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:151
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:400
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:702
This module implements the abstract multisystem class.
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:568
This module implements the abstract system type.
Definition: system.F90:109
The ghost ineraction is a dummy interaction, which needs to be setup between otherwise non-interactin...
abstract interaction class
abstract class for general interaction partners
This class implements a linked list of integer values.
the abstract multisystem class
Abstract class for systems.
Definition: system.F90:161
int true(void)