I am trying to apply cycling load to the top wall in a 2D biaxial test using the sinusoidal function (q = q0sinwt). From the literature, different values for omega (w) have been suggested, among which I selected 10*pi as an initial guess. The value of ‘qo’ has been obtained from the cyclic stress ratio (CSR) and confining stress (CSR = qo/2*confining stress). I defined a fish function that applies a force on the top wall based on the value of q and the width of the samples, and to maintain the undrained condition, I found the velocity of the top wall, and, accordingly, the lateral wall velocities were adjusted. However, once the simlation starts ‘q’ does not follow the sinusoidal variation. I have a attached the code block for your reference.
[csr = 0.1]
[q_amp = 2*p0*csr]
[omg = 10*math.pi]
fish define cyclic_loading
whilestepping
local t = mech.time.total
global q_target = q_amp * math.sin(omg*t)
global Fy = -q_target * wlx
command
wall servo activate on force-y [Fy] velocity-max 1.0 range set name ‘vesselTop’
endcommand
local vy = wall.vel.y(wp_top)
local vx = -(wlx/wly)0.5vy
command
wall attribute velocity-x [vx] range set name ‘vesselRight’
wall attribute velocity-x [-vx] range set name ‘vesselLeft’
endcommand
Please consider providing a Minimum Working Example (MWE) that can be run and replicated when requesting help; that greatly simplifies troubleshooting and helps getting you to a resolution faster. From this FISH snippet alone, it is difficult to guide you.
You might be able to draw inspiration from the Probing a Granular Specimen example which perform similar loading to what you are trying to achieve.
Please let me know if that helps. If not, please share a complete MWE and we will help you troubleshoot it.
The data file Step1_sample.dat calls for program call 'StrainUtilities.p2fis' suppress line 5. I had to change the extension of the file you shared from StrainUtilities.p2fis to StrainUtilities.fis.
The data file Step1_sample.dat calls for call 'm3_sphere.fis' on line 95. This file was not shared and the script cannot run past this point.
Please make sure to provide all information and files necessary to run the program. If the issue cannot be replicated, it cannot be resolved.
Which exact version of PFC9 are you using? e.g., 9.00.184, 9.6.45?
I ran the simulation and I think some of your issues may be coming from the callbacks.
In the Stress_cyclic.dat file, running the fish list callbacks command just before solving for the model line 143 prints the following:
Position Function
-------- --------
-1.000000000000000 cyclic_loading
1.000000000000000 wsxx
1.000000000000000 wsyy
1.000000000000000 poro_sample
1.000000000000000 average_ratio
1.000000000000000 cyclic_loading
9.000000000000000 servo_walls
the cycling_loading function appears twice, at position -1.0 and 1.0. This is due to the whilestepping FISH function, which automatically inserts a callback to the function that call whilestepping at position -1.0. This command is deprecated and only conserved for backward compatibility; I recommand you remove it from this script and replace it with a regular fish callback in your future workflows.
the servo_walls callback defined line 64-69 of Step2_Contact.dat is still active and overwrites the values of [Fy] in the wall servo command line 120 of Stress_cyclic.dat. I suggest this callback be removed fish callback remove servo_walls. Just like you did the first time during compaction, the command wall servo line 120 can be called once directly in the input file, and a FISH function is only used to modify the target force of the servo, as opposed to calling the servo command each step in the callback. Same thing with the left / right wall velocities.
please note that global t = mech.time.total gives the current global time, which includes prior time spent compacting the sample, so that the sinusoid global q_target = q_amp * math.cos(omg*t) will start with a value that is not the current force at the end of compaction and might be different from what you want. This sinusoid will also change sign, so that the servo wall will try to impose a tensile force, which is not feasible with cohesionless particles; you may want to revisit this loading.
An updated script would look similar to the snippet below (to be modified according to your precise needs):
wall servo activate off range set name 'vesselTop' ...
set name 'vesselBottom' union
wall servo activate off range set name 'vesselRight' ...
set name 'vesselLeft' union
; remove servo_walls callback from compaction phase
fish callback remove servo_walls
[csr = 0.02]
[q_amp = 2*p0*csr]
[omg = 100*math.pi]
; Activate new servo wall on top wall. force [0.0] will be overwritten in [cyclic_loading] fish callback
wall servo activate on force-y [0.0] velocity-max 1.0 range set name 'vesselTop'
fish define cyclic_loading
; No whilestepping !
; TO BE MODIFIED ACCORDING TO YOUR NEEDS
global t = mech.time.total
; sinusoidal deviatoric stress
; TO BE MODIFIED ACCORDING TO YOUR NEEDS
global q_target = q_amp * math.cos(omg*t)
; convert stress to force
global Fy = -q_target * wlx
wall.servo.force.y(wp_top) = Fy
; constant volume
local vy = wall.vel.y(wp_top)
local vx = -(wlx/wly)*0.5*vy
wall.vel.x(wp_right) = vx
wall.vel.x(wp_left) = -vx
end
fish callback add cyclic_loading 9.0 ; MODIFIED FROM 1.0 TO 9.0