Фортран: список имен + партнер не работает
Я храню параметры в производном типе и хочу загрузить их из файла через список имен во время выполнения. Это набросок кода:
module options_definitions
implicit none
type :: opts
integer :: option1
integer :: option2
contains
procedure :: load => load_options
end type opts
contains
subroutine load_options(this,path_to_profiles_folder,profile_name)
class(opts), intent(inout) :: this
character(len=*), intent(in) :: path_to_profiles_folder
character(len=*), intent(in) :: profile_name
integer :: err, ios
logical :: file_exists
character(len=255) :: err_message
character(len=255) :: path_to_profile_folder
ASSOCIATE( option1 => this%option1, &
option2 => this%option2)
namelist /options_nml/ option1, option2
! the following is INESSENTIAL added for completeness
!-----------------------------------------------------
path_to_profile_folder=trim(path_to_profiles_folder)//trim(profile_name)
! load options from the configuration file (namelist set above)
INQUIRE(FILE=trim(path_to_profile_folder)//'/'//trim(opt_file_name), EXIST=file_exists) ! 'file_exists' will be TRUE if the file exists and FALSE otherwise
if (file_exists) then
call my_open(111,trim(path_to_profile_folder)//'/'//trim(opt_file_name),&
'Options module could not open the options configuration file')
read(111,NML=options_nml,iostat=ios,iomsg=err_message)
call check_read_success_and_close(111,trim(path_to_profile_folder)//'/'//trim(opt_file_name),ios,err_message,&
'Options module could not read from the options configuration file')
else
print*,'Warning: The required configuration file containing options &
(options.nml) does not exist. The inbuilt options will be &
used instead.'
endif
!---------------------------------------
end associate
end subroutine load_options
Компилятор жалуется, что option1
, option2
... не были объявлены ((iFort) error #6404: This name does not have a type, and must have an explicit type. [OPTION1]
).
Из описания конструкции списка имен ( https://software.intel.com/sites/products/documentation/doclib/stdxe/2013/composerxe/compiler/fortran-mac/GUID-EAC90ABA-859A-4745-B9FC-B8D66B5B6FF0.htm) читаю
каждая переменная в var-list должна быть доступна USE или ассоциацией хоста
который я бы сказал, дело здесь как this
это фиктивный аргумент с intent(inout)
, Разве это не ассоциация использования?
Что случилось? Есть ли обходной путь, чтобы мне не приходилось объявлять одни и те же вещи много раз в разных местах?
(например, объявление option1
как частный модуль и копировать его в this
в конце load_options
рутина, а не с помощью associate
Конструкция будет работать, но я бы предпочел что-то менее склонное к упущениям при добавлении опций позже)
Заранее спасибо за любые комментарии.
PS: незадолго до публикации я нашел этот вопрос. Код выглядит так, как будто он может делать то, что я хочу, но не видя определения unit
типа я не могу понять что он делает.
EDIT1: следить за комментариями Владимира Теперь я вполне понимаю, что происходит. В вопросе, на который я ссылался, автор использует указатель на this
не для отдельных полей, и это было бы моим предпочтительным вариантом, если бы я мог заставить его работать. Когда я попробовал это, компилятор был в порядке с объявлением списка имен, но отказался читать из входного файла, говоря
ошибка #5498: для выделенных полей или полей производного типа указателя требуется определенная пользователем процедура ввода-вывода. чтения (111,NML=options_nml, IOSTAT = ИОС, iomsg = err_message)
Любые предложения, как такая процедура ввода / вывода может выглядеть? Я запутался, если возможно добавить производный тип (или указатель на него) в объявлении списка имен, то я бы предположил, что переменные во входном файле должны называться как this%option1
и это было бы это. Я нашел другое обсуждение здесь, где Стив Лайонел из Intel поддерживает эту точку зрения, говоря
Стандарт Fortran допускает только "имя-переменной" в списке объектов списка имен. Однако вы можете поместить T в список имен и ссылаться на T%I на входе списка имен (и это будет показано на выходе).
Но компилятор жалуется, даже не видя файл.
EDIT2: то, что я изменил в коде выше (что привело к ошибке компилятора при первом редактировании), было так:
class(opts), intent(inout), target :: THIS
TYPE(opts), POINTER :: THIS_NML
namelist /options_nml/ THIS_NML
THIS_NML => THIS
Связанная конструкция удалена, оригинальное объявление списка имен удалено. Ошибка произошла в read
заявление в if (file_exists)
блок. Поэтому я использовал указатель на структуру в объявлении списка имен. Это все.
1 ответ
Для ifort вы можете использовать решение из моего ответа вы связали. Точное определение unit
там не важно
select type(t => this)
type is (opts)
associate( option1 => t%option1, &
option2 => t%option2)
namelist /options_nml/ option1, option2
read...
end associate
end select
Это потому что this
полиморфен в вашем примере.
Я исследовал, является ли это использование стандартным соответствием, и это не так. Ifort четко предупреждает, когда его просят следовать стандарту
ifort -stand f08 namelist.f90
namelist.f90(8): warning #7775: Placement of NAMELIST statement is non-standard.
Есть много других обходных путей, которые вы можете сделать. Вы можете создавать локальные указатели и читать их в прочитанном списке имен, это именно то, что делает ответ, связанный с вами. Это будет компилировать также с gfortran
, Я бы пошел по этому пути.
integer, pointer :: option1, option2
namelist /options_nml/ option1, option2
option1 => this%option1
option2 => this%option2
read...
Или используйте обычные локальные переменные и скопируйте значения в this
,