Code Comments
Programming Forum and web based access to our favorite programming groups.I have a derived type, e.g. type circle_datatype real :: radius real :: x real :: y real :: z character(len=*) :: circle_label endtype circle_datatype type(circle_datatype) :: circle and want to refer to the individual elements via some indexing scheme, say in this example I want to change the value of circle%radius I would use index #1, or the z-coordinate I would use #4. Is there some method by which this is possible? I think IDL has a system for this, such that circle.radius can be referenced by circle.(0), but I really need Fortran's horsepower for this code!
Post Follow-up to this messageRob Crain wrote: > I have a derived type, e.g. > > type circle_datatype > real :: radius > real :: x > real :: y > real :: z > character(len=*) :: circle_label > endtype circle_datatype > type(circle_datatype) :: circle > > > and want to refer to the individual elements via some indexing scheme, > say in this example I want to change the value of circle%radius I would > use index #1, or the z-coordinate I would use #4. Is there some method > by which this is possible? > > I think IDL has a system for this, such that circle.radius can be > referenced by circle.(0), but I really need Fortran's horsepower for > this code! type circle_datatype real :: radius(100) real :: x(100) real :: y(100) real :: z(100) character(len=256) :: circle_label(100) endtype circle_datatype type(circle_datatype) :: circle circle%radius(1) = <something> -- Gary Scott mailto:garylscott@sbcglobal dot net Fortran Library: http://www.fortranlib.com Support the Original G95 Project: http://www.g95.org -OR- Support the GNU GFortran Project: http://gcc.gnu.org/fortran/index.html If you want to do the impossible, don't hire an expert because he knows it can't be done. -- Henry Ford
Post Follow-up to this messageGary Scott wrote: > Rob Crain wrote: > > > type circle_datatype > real :: radius(100) > real :: x(100) > real :: y(100) > real :: z(100) > character(len=256) :: circle_label(100) > endtype circle_datatype > type(circle_datatype) :: circle > > circle%radius(1) = <something> > > Oops or using your original type declaration, another possibility: type(circle_datatype) :: circle(100) circle(1)%radius = something -- Gary Scott mailto:garylscott@sbcglobal dot net Fortran Library: http://www.fortranlib.com Support the Original G95 Project: http://www.g95.org -OR- Support the GNU GFortran Project: http://gcc.gnu.org/fortran/index.html If you want to do the impossible, don't hire an expert because he knows it can't be done. -- Henry Ford
Post Follow-up to this messageHi Gary - thanks for your reply. I think my initial explanation may have been unclear, as this is not the solution to my problem. The problem reduces to the following: I don't know explicitly which variable (I incorrectly referred to this variable as an element previously, hence the confusion) I want to update, so I can't say circle%radius = <something> All I have is an index that tells me I need to update the i^th variable within the derived type. So say I need to update circle%z, the index would have value 4. But I know that I can't do circle%(4) = <something> but hoped there was some syntax that might allow this procedure? Any help appreciated --Rob Gary Scott wrote: > Rob Crain wrote: > > type circle_datatype > real :: radius(100) > real :: x(100) > real :: y(100) > real :: z(100) > character(len=256) :: circle_label(100) > endtype circle_datatype > type(circle_datatype) :: circle > > circle%radius(1) = <something> > >
Post Follow-up to this messageRob Crain wrote: > Hi Gary - thanks for your reply. I think my initial explanation may have > been unclear, as this is not the solution to my problem. The problem > reduces to the following: I don't know explicitly which variable (I > incorrectly referred to this variable as an element previously, hence > the confusion) I want to update, so I can't say > > circle%radius = <something> > > All I have is an index that tells me I need to update the i^th variable > within the derived type. So say I need to update circle%z, the index > would have value 4. But I know that I can't do By i'th variable, are you saying the i'th component? No you can't alias an index with the formally defined components and have value 1 refer to radius and value 2 refer to x. You could use select case to make that choice based upon the index. Still not sure I understand fully tho. > <snip> -- Gary Scott mailto:garylscott@sbcglobal dot net Fortran Library: http://www.fortranlib.com Support the Original G95 Project: http://www.g95.org -OR- Support the GNU GFortran Project: http://gcc.gnu.org/fortran/index.html If you want to do the impossible, don't hire an expert because he knows it can't be done. -- Henry Ford
Post Follow-up to this messageRob Crain <r.a.crain@durham.ac.uk> wrote: > I have a derived type, e.g. > > type circle_datatype > real :: radius > real :: x > real :: y > real :: z > character(len=*) :: circle_label > endtype circle_datatype > type(circle_datatype) :: circle You have a compiler that let you get by with that? It shouldn't. Unrelated to your question, but the len=* is invalid Fortran. > and want to refer to the individual elements via some indexing scheme, > say in this example I want to change the value of circle%radius I would > use index #1, or the z-coordinate I would use #4. Is there some method > by which this is possible? Not directly, no. You can sometimes play games with equivalence, but that has a lot of "issues" and is very limitting. For example, the simplest games aren't standard conforming or portable unless the derived type meets the stringent conditions for being a numeric sequence type (the conditions are considerably more stringent than you'd guess from the term). In some cases you might be able to get by with an accessor function, with a select case construct buried in the function. Thus you could have a notation like component(circle,3) where component is the function. That will only work well when al the components you want to access have the same type. -- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
Post Follow-up to this messageHi - yes, that's what I want to do. If, as you say, this can't be done then a case statement might be the way to go - it's not as elegant as I'd hoped, but this is just a simple routine to parse a parameter file, so it's not mission-critical. Thanks for your help! Gary Scott wrote: > Rob Crain wrote: > > > By i'th variable, are you saying the i'th component? No you can't alias > an index with the formally defined components and have value 1 refer to > radius and value 2 refer to x. You could use select case to make that > choice based upon the index. Still not sure I understand fully tho. >
Post Follow-up to this messageOn Mar 29, 6:11=A0pm, Rob Crain <r.a.cr...@durham.ac.uk> wrote: > I have a derived type, e.g. > > type circle_datatype > =A0 =A0 real =A0 =A0 =A0 =A0 =A0 =A0 :: radius > =A0 =A0 real =A0 =A0 =A0 =A0 =A0 =A0 :: x > =A0 =A0 real =A0 =A0 =A0 =A0 =A0 =A0 :: y > =A0 =A0 real =A0 =A0 =A0 =A0 =A0 =A0 :: z > =A0 =A0 character(len=3D*) :: circle_label > endtype circle_datatype > type(circle_datatype) :: circle > > and want to refer to the individual elements via some indexing scheme, > say in this example I want to change the value of circle%radius I would > use index #1, or the z-coordinate I would use #4. Is there some method > by which this is possible? > > I think IDL has a system for this, such that circle.radius can be > referenced by circle.(0), but I really need Fortran's horsepower for > this code! The following might help: !--------------------------------------------------------------------------- = --- module circle_mod implicit none integer, parameter :: MAX_CIRCLE_LABEL =3D 64 type circle_datatype real, pointer :: radius =3D> null() real, pointer :: x =3D> null() real, pointer :: y =3D> null() real, pointer :: z =3D> null() real :: set(4) =3D 0. character(MAX_CIRCLE_LABEL) :: label end type circle_datatype contains subroutine create_circle(this, label) type(circle_datatype), target, intent(INOUT) :: this character(*), intent(IN) :: label this%radius =3D> this%set(1) this%x =3D> this%set(2) this%y =3D> this%set(3) this%z =3D> this%set(4) this%label =3D ADJUSTL(label) end subroutine subroutine destroy_circle(this) type(circle_datatype), intent(INOUT) :: this nullify(this%radius, this%x, this%y, this%z) this%set =3D 0. this%label =3D '' end subroutine end module circle_mod program circle_test use circle_mod implicit none type(circle_datatype), target :: circle call create_circle(circle, 'unit_xy1') circle%set =3D REAL([1, 1, 1, 0]) write (*, '((A,G13.6))') "circle's label =3D ", circle%label, & "radius =3D ", circle%radius, 'x =3D ', circle%x, 'y =3D ', & circle%y, 'z =3D ', circle%z call destroy_circle(circle) stop end program circle_test !--------------------------------------------------------------------------- = ---
Post Follow-up to this messageRob Crain wrote: > I have a derived type, e.g. > > type circle_datatype > real :: radius > real :: x > real :: y > real :: z > character(len=*) :: circle_label > endtype circle_datatype > type(circle_datatype) :: circle > > > and want to refer to the individual elements via some indexing scheme, > say in this example I want to change the value of circle%radius I would > use index #1, or the z-coordinate I would use #4. Is there some method > by which this is possible? > > I think IDL has a system for this, such that circle.radius can be > referenced by circle.(0), but I really need Fortran's horsepower for > this code! If you don't mind making the code clumsy, error-prone, and difficult to read, it's trivial ;). Create a hidden helper type, something like type helper integer :: index real :: x character(len=whatever) :: c ! any other types that are in circle_datatype endtype helper Next create some generic operators or functions that return type helper results. i .func. value or maybe func(i,value) returns a type helper result with the index set to i, and the appropriate x or c set to value. You'll, obviously, need one function for each type of element in circle_datatype. The character one is trivial, the real one needs a select case. You can then also provide overloads to do arithmetic between type helper and the intrinsic types, helper types, and circle_datatype and return type helper. (i .func. circle) * 3.14 * (j .func. other_circle)**2 Then create an assignment operator that assigns type helper to type circle by using an internal select case to assign to the INDEXth element. The result is that circle = i .func. value is ultimately equivalent to call assigner(circle, i, value) I'm not real happy with putting the circle subscript on the right, it's ugly and error-prone. But I think it'll work. After thinking about this, why not just create a few generic subroutines that implement the above call if you only want to do assignments that update (but not use) elements? If you're not in a big hurry and can wait until 2008, the new Fortran allows pointer functions on the left hand side. You could probably make circle.element.i = whatever do what you want. But that won't be standard until later this year. It might take even longer to get a F2008 compiler :(. Dick Hendrickson
Post Follow-up to this messageSince it's not mission critical and I'm pushed for time I opted for an inelegant select case statement; it does the job. Thanks to all for your responses though - when I get time to tune the code I'll revisit Dick's suggestion, it looks like it might be the answer.
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.