1

this is my first post here and I hope I will be clear describing the issues I'm having with Abaqus subroutine. I'm quite a newbie using Fortran. Basically, my goal is to define a non-uniform surface heat flux over an open cross-section tube and I'm using the DFLUX subroutine. Being open cross-section, the flux is influenced by the self-shadowing of the structure and has to be defined accordingly. Apparently the subroutine is called at each integration point, so that the coordinates of these points are not stored and I have each time just X,Y,Z values for a single point. What I'd like to do is to store all the coordinates in one array so that I can compare the different points to apply the conditions for the heat flux. I've read around about COMMON blocks or SAVE command, but I can't find how to use such options in my subroutine. I hope I've been clear enough. This is the subroutine I'm using:

     SUBROUTINE DFLUX(FLUX,SOL,JSTEP,JINC,TIME,NOEL,NPT,COORDS,JLTYP,
 1 TEMP,PRESS,SNAME)

  INCLUDE 'ABA_PARAM.INC'

   REAL X,Y,Z,t,pi,theta
   parameter(pi=3.1415)
   DIMENSION COORDS(3),FLUX(2),TIME(2)

   CHARACTER*80 SNAME

  X=COORDS(1)-0.1 ! X coordinate of the center in global ref
  Y=COORDS(2)+0.1732 ! Y coord of the center in global ref
  Z=COORDS(3)
  t=TIME(2)
  theta=atan2(X,Y)
  if (JSTEP.eq.1) then !Step with heat flux impinging on structure
  !flux dependant on the angle of incidence
      if (theta.ge.0 .and.theta.le.pi/2 .or. theta.le.-pi/2) then
       flux(1)=1400*abs(cos(theta))
       flux(2)=0
    else !shadowed portion of the structure
       flux(1)=0
       flux(2)=0
    endif
  else
     STOP
  endif
  RETURN

  END
Gianluca
  • 23
  • 6
  • First of all, welcome to StackOverflow. Following the advices of the community, it is recommended to include source code formatted to help people to understand your problem. Please check the documentation [on how to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) – Carlos Cavero Mar 06 '19 at 11:51
  • Ok, I've added the subroutine now, thank you for the advice! – Gianluca Mar 06 '19 at 12:11
  • No need to thank, it is my pleasure to help newbies to better describe the problem and find the solution. Hope you find a good answer. – Carlos Cavero Mar 06 '19 at 12:14
  • I think we also need the code where you sue the subroutine. Not just the call itself, but the context, to see how you want to compare the other points. – Vladimir F Героям слава Mar 06 '19 at 13:25
  • The input file for Abaqus is quite long as it contains all the nodes of the FEM model! Should I attach it somehow? – Gianluca Mar 06 '19 at 15:34
  • @Gianluca If I understand, @VladimirF is asking for the program that calls the `dflux` subroutine (not the analysis input file). Unfortunately, in this case, providing code from the calling program is not possible - the commercial/closed-source abaqus solver handles when each user subroutine is called, what info is passed in/out, etc. Users do not have access to it. – Matt P Mar 06 '19 at 15:42
  • The call for the subroutine is in the input file for Abaqus, but I don't think it could be useful in some way. – Gianluca Mar 06 '19 at 15:50
  • The input file merely states that `dflux` is going to be used, and defines certain parameters like the region where it is needed. That's different than the actual call to the subroutine during the analysis. – Matt P Mar 06 '19 at 16:17

1 Answers1

2

background: Abaqus provides a number of Fortran subroutine "templates" (in fixed-format/F77 style) that allow users to get specific info or influence certain aspects of the solution during an analysis, aka user-subroutines. Abaqus controls when the user-subroutines are called, what info is passed in/out, etc. Users cannot change any of that, and have no access to the main program or its proprietary source code. However, within a user-subroutine, the user is free to write any valid code they feel is necessary.

In this question, the OP wants to store information from each call to the dflux user-subroutine so that it is available to other subroutines or to other calls to the dflux subroutine. Note: this capability is not provided by dflux, so the OP needs a work-around.

possible work-arounds: Luckily, the dflux user-subroutine provides the element number, the integration point number, and the spatial coords for the current call. This info can probably be used to store (and access) any data you need. The data storage/transfer method might be accomplished through a COMMON block, a Fortran module, or even a text file or some other external "database".

> I recommend the module-based approach. However, see this answer for a good explanation of how to use both COMMON blocks and modules.

(EDIT) For completeness, a very simple example with a module and an abaqus subroutine could be structured something like:

module data_mod
  ! Any routine may access this module with the statement: "USE data_mod".
  ! Any variable within the module is then shared by those routines.

  implicit none

  ! You can use an allocatable array, but for this example I will assume
  ! there are 1000 or fewer points, and up to 10 values for each.
  real, dimension(1000,10) :: point_data

end module data_mod


subroutine dflux(....all the args...)
  ! Note: you must "USE" modules before any other statements in the routine.

  use data_mod

  ! Now you may carry on with the rest of your code. 
  ! Be sure to have the required "INCLUDE 'ABA_PARAM.INC" statement,
  ! which defines how abaqus implements "IMPLICIT REAL" for your machine,
  ! and all of the boilerplate variable declarations included with the 
  ! DFLUX subroutine template.

  include 'aba_param.inc'
  (...etc...)

  ! For simplicity, I am assuming you have a unique ID for each point, and
  ! each ID is numerically equal to one of the row indices in 'point_data'.
  ! When ready to read/write data in the 'point_data' array:

  ! Read data:
  neighbor_vals(:) = point_data(NEIGHBOR_ID, 2:)
  old_data_at_current_point(:) = point_data(ID, 2:)

  (...etc...)

  ! Write data:
  point_data(ID,2:4) = coords(:)
  point_data(ID,5) = result1
  point_data(ID,6) = result2

end subroutine dflux

> You will need to choose a type of data container and some clever organizational concept - perhaps using the element number, integration point number, or the (x,y,z) coordinates to uniquely identify the data you want to store. For instance, a simple 2-dimensional (MxN) array might be sufficient: each row represents the Mth integration point, the first column contains the unique point identifier(s), and the remaining columns contain any values you want to store from each point. Note: Determining which points are "neighbors" is another topic you will need a clever solution for. Once you've done this, perhaps neighboring points can be stored in the array as well, for faster access.

> You are safe reading data from other integration points stored in the data container, but do not write/change the values stored in the data container (whether it is within a COMMON block or a module) unless it is for the current integration point where dflux is currently being called.


side notes:

  1. New users often think they are stuck writing FORTRAN 77 in their Abaqus user-subroutines. They aren't.
  2. The easiest way to use modules along with abaqus user-subroutines is to place them at the top of your file. Abaqus will then compile and link them automatically when you run the analysis.
Matt P
  • 2,287
  • 1
  • 11
  • 26
  • Thank you Matt, I still have some questions about the module-based approach. In the module at the top of my subroutine should I declare a 2-dimensional array (allocatable maybe?), define the location of dflux variables inside that array and store that array in a COMMON block? And how could I access to the stored data from the subroutine? I'm still quite confused. – Gianluca Mar 07 '19 at 11:54
  • @Gianluca I added some example code you could use to get started. Also, notice that the 2D array (allocatable or not) was suggested as a really simple data container that could work. You might certainly find others that suit your needs better (such as user-defined types, etc). In any case, using a module will allow you to store/transfer/share data between subroutines (without a COMMON block). – Matt P Mar 07 '19 at 16:01
  • Your answer was extremely useful, I finally managed to save the coordinates I need in a matrix. Now I'm trying to find a convenient way to use the data I stored for the heat flux. I noticed that for each increment the subroutine is called a number of times greater than the number of integration points. I was expecting an equal number. Basically I want to fill the matrix first and apply the condition for the flux when there are no more zeros in the matrix. I'm trying to implement this at the moment! – Gianluca Mar 12 '19 at 16:31
  • @Gianluca That's great. BTW, most subroutines are called multiple times during each increment ;) For example: call #1 to initialize data, call #2 to calculate values, etc...When and how often a subroutine is called isn't always well-documented, but you can put print statements into your subroutine to test. – Matt P Mar 12 '19 at 16:54
  • I'm printing almost everything to try how the subroutine is called ;) Now I have some silly basic questions: the first is about the continuation lines, as I can't manage to avoid errors from the compiler. The second is about "MINVAL": how could I put a MASK to find the minimum value inside an interval? For example, if I want to find the minimum angle in my array considering the interval from 0 to pi. So far I only manage to write a condition like this: MASK=array.gt.0 – Gianluca Mar 14 '19 at 10:10
  • @Gianluca Those sound like new questions you could ask on SO ;) – Matt P Mar 14 '19 at 13:31
  • Ok Matt, I will follow again your advice ;D – Gianluca Mar 14 '19 at 15:34