From 570c0421000461cb193f3032c31f86a01d78a7f5 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 07:18:37 +0200 Subject: [PATCH 001/186] update of dependent state always in conjunction with state integration --- src/crystallite.f90 | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index fb12c439b..d657b5b55 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -849,6 +849,9 @@ logical function integrateStress(ipc,ip,el,timeFraction) F = crystallite_subF(1:3,1:3,ipc,ip,el) endif + call constitutive_dependentState(crystallite_partionedF(1:3,1:3,ipc,ip,el), & + crystallite_Fp(1:3,1:3,ipc,ip,el),ipc,ip,el) + Lpguess = crystallite_Lp(1:3,1:3,ipc,ip,el) ! take as first guess Liguess = crystallite_Li(1:3,1:3,ipc,ip,el) ! take as first guess @@ -1060,10 +1063,6 @@ subroutine integrateStateFPI source_dotState(1:sizeDotState,1,s) = sourceState(p)%p(s)%dotState(:,c) enddo - call constitutive_dependentState(crystallite_partionedF(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) - crystallite_todo(g,i,e) = integrateStress(g,i,e) if(.not. crystallite_todo(g,i,e)) exit iteration @@ -1202,10 +1201,6 @@ subroutine integrateStateEuler nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle - call constitutive_dependentState(crystallite_partionedF(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) - crystallite_todo(g,i,e) = integrateStress(g,i,e) if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. @@ -1281,10 +1276,6 @@ subroutine integrateStateAdaptiveEuler nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle - call constitutive_dependentState(crystallite_partionedF(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) - crystallite_todo(g,i,e) = integrateStress(g,i,e) if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. @@ -1415,10 +1406,6 @@ subroutine integrateStateRK4 * crystallite_subdt(g,i,e) enddo - call constitutive_dependentState(crystallite_partionedF(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) - crystallite_todo(g,i,e) = integrateStress(g,i,e,CC(stage)) if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. @@ -1466,14 +1453,6 @@ subroutine integrateStateRK4 nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle - call constitutive_dependentState(crystallite_partionedF(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) - - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & - nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle - crystallite_todo(g,i,e) = integrateStress(g,i,e) if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. @@ -1583,10 +1562,6 @@ subroutine integrateStateRKCK45 * crystallite_subdt(g,i,e) enddo - call constitutive_dependentState(crystallite_partionedF(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) - crystallite_todo(g,i,e) = integrateStress(g,i,e,CC(stage)) if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. @@ -1644,10 +1619,6 @@ subroutine integrateStateRKCK45 nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle - call constitutive_dependentState(crystallite_partionedF(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) - crystallite_todo(g,i,e) = integrateStress(g,i,e) if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. From 9e926f1545d2f7218d63b5a0472e5d2221141fbe Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 07:41:55 +0200 Subject: [PATCH 002/186] centralize test for error --- src/constitutive.f90 | 20 +++++++++----- src/crystallite.f90 | 62 ++++++++++++-------------------------------- 2 files changed, 30 insertions(+), 52 deletions(-) diff --git a/src/constitutive.f90 b/src/constitutive.f90 index 94e590ab3..4402820e8 100644 --- a/src/constitutive.f90 +++ b/src/constitutive.f90 @@ -709,7 +709,7 @@ end subroutine constitutive_hooke_SandItsTangents !-------------------------------------------------------------------------------------------------- !> @brief contains the constitutive equation for calculating the rate of change of microstructure !-------------------------------------------------------------------------------------------------- -subroutine constitutive_collectDotState(S, FArray, Fi, FpArray, subdt, ipc, ip, el) +function constitutive_collectDotState(S, FArray, Fi, FpArray, subdt, ipc, ip, el) result(broken) integer, intent(in) :: & ipc, & !< component-ID of integration point @@ -727,19 +727,22 @@ subroutine constitutive_collectDotState(S, FArray, Fi, FpArray, subdt, ipc, ip, real(pReal), dimension(3,3) :: & Mp integer :: & + phase, & ho, & !< homogenization tme, & !< thermal member position i, & !< counter in source loop instance, of + logical :: broken ho = material_homogenizationAt(el) tme = thermalMapping(ho)%p(ip,el) of = material_phasememberAt(ipc,ip,el) - instance = phase_plasticityInstance(material_phaseAt(ipc,el)) + phase = material_phaseAt(ipc,el) + instance = phase_plasticityInstance(phase) Mp = matmul(matmul(transpose(Fi),Fi),S) - plasticityType: select case (phase_plasticity(material_phaseAt(ipc,el))) + plasticityType: select case (phase_plasticity(phase)) case (PLASTICITY_ISOTROPIC_ID) plasticityType call plastic_isotropic_dotState (Mp,instance,of) @@ -760,10 +763,11 @@ subroutine constitutive_collectDotState(S, FArray, Fi, FpArray, subdt, ipc, ip, call plastic_nonlocal_dotState (Mp,FArray,FpArray,temperature(ho)%p(tme),subdt, & instance,of,ip,el) end select plasticityType + broken = any(IEEE_is_NaN(plasticState(phase)%dotState(:,of))) - SourceLoop: do i = 1, phase_Nsources(material_phaseAt(ipc,el)) + SourceLoop: do i = 1, phase_Nsources(phase) - sourceType: select case (phase_source(i,material_phaseAt(ipc,el))) + sourceType: select case (phase_source(i,phase)) case (SOURCE_damage_anisoBrittle_ID) sourceType call source_damage_anisoBrittle_dotState (S, ipc, ip, el) !< correct stress? @@ -775,13 +779,15 @@ subroutine constitutive_collectDotState(S, FArray, Fi, FpArray, subdt, ipc, ip, call source_damage_anisoDuctile_dotState ( ipc, ip, el) case (SOURCE_thermal_externalheat_ID) sourceType - call source_thermal_externalheat_dotState(material_phaseAt(ipc,el),of) + call source_thermal_externalheat_dotState(phase,of) end select sourceType + broken = broken .or. any(IEEE_is_NaN(sourceState(phase)%p(i)%dotState(:,of))) + enddo SourceLoop -end subroutine constitutive_collectDotState +end function constitutive_collectDotState !-------------------------------------------------------------------------------------------------- diff --git a/src/crystallite.f90 b/src/crystallite.f90 index d657b5b55..03de4dea3 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1027,15 +1027,12 @@ subroutine integrateStateFPI p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) - call constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - crystallite_todo(g,i,e) = all(.not. IEEE_is_NaN(plasticState(p)%dotState(:,c))) - do s = 1, phase_Nsources(p) - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. all(.not. IEEE_is_NaN(sourceState(p)%p(s)%dotState(:,c))) - enddo + if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle @@ -1066,15 +1063,12 @@ subroutine integrateStateFPI crystallite_todo(g,i,e) = integrateStress(g,i,e) if(.not. crystallite_todo(g,i,e)) exit iteration - call constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - crystallite_todo(g,i,e) = all(.not. IEEE_is_NaN(plasticState(p)%dotState(:,c))) - do s = 1, phase_Nsources(p) - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. all(.not. IEEE_is_NaN(sourceState(p)%p(s)%dotState(:,c))) - enddo + if(.not. crystallite_todo(g,i,e)) exit iteration sizeDotState = plasticState(p)%sizeDotState @@ -1172,15 +1166,12 @@ subroutine integrateStateEuler p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) - call constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - crystallite_todo(g,i,e) = all(.not. IEEE_is_NaN(plasticState(p)%dotState(:,c))) - do s = 1, phase_Nsources(p) - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. all(.not. IEEE_is_NaN(sourceState(p)%p(s)%dotState(:,c))) - enddo + if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle @@ -1244,15 +1235,12 @@ subroutine integrateStateAdaptiveEuler p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) - call constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - crystallite_todo(g,i,e) = all(.not. IEEE_is_NaN(plasticState(p)%dotState(:,c))) - do s = 1, phase_Nsources(p) - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. all(.not. IEEE_is_NaN(sourceState(p)%p(s)%dotState(:,c))) - enddo + if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle @@ -1281,15 +1269,12 @@ subroutine integrateStateAdaptiveEuler nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle - call constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - crystallite_todo(g,i,e) = all(.not. IEEE_is_NaN(plasticState(p)%dotState(:,c))) - do s = 1, phase_Nsources(p) - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. all(.not. IEEE_is_NaN(sourceState(p)%p(s)%dotState(:,c))) - enddo + if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle @@ -1361,15 +1346,12 @@ subroutine integrateStateRK4 p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) - call constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - crystallite_todo(g,i,e) = all(.not. IEEE_is_NaN(plasticState(p)%dotState(:,c))) - do s = 1, phase_Nsources(p) - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. all(.not. IEEE_is_NaN(sourceState(p)%p(s)%dotState(:,c))) - enddo + if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle @@ -1411,15 +1393,12 @@ subroutine integrateStateRK4 nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) exit - call constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e)*CC(stage), g,i,e) - crystallite_todo(g,i,e) = all(.not. IEEE_is_NaN(plasticState(p)%dotState(:,c))) - do s = 1, phase_Nsources(p) - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. all(.not. IEEE_is_NaN(sourceState(p)%p(s)%dotState(:,c))) - enddo + if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) exit @@ -1517,15 +1496,12 @@ subroutine integrateStateRKCK45 p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) - call constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - crystallite_todo(g,i,e) = all(.not. IEEE_is_NaN(plasticState(p)%dotState(:,c))) - do s = 1, phase_Nsources(p) - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. all(.not. IEEE_is_NaN(sourceState(p)%p(s)%dotState(:,c))) - enddo + if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) cycle @@ -1567,15 +1543,11 @@ subroutine integrateStateRKCK45 nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) exit - call constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e)*CC(stage), g,i,e) - crystallite_todo(g,i,e) = all(.not. IEEE_is_NaN(plasticState(p)%dotState(:,c))) - do s = 1, phase_Nsources(p) - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. all(.not. IEEE_is_NaN(sourceState(p)%p(s)%dotState(:,c))) - enddo if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & nonlocalBroken = .true. if(.not. crystallite_todo(g,i,e)) exit From 6b11d438424ccc74241719434de678d1d156758d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 08:02:08 +0200 Subject: [PATCH 003/186] handle error checking centrally --- src/constitutive.f90 | 22 +++++++++++++++------- src/crystallite.f90 | 13 ++----------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/constitutive.f90 b/src/constitutive.f90 index 4402820e8..582222dae 100644 --- a/src/constitutive.f90 +++ b/src/constitutive.f90 @@ -327,7 +327,7 @@ module constitutive constitutive_initialFi, & constitutive_SandItsTangents, & constitutive_collectDotState, & - constitutive_collectDeltaState, & + constitutive_deltaState, & constitutive_results contains @@ -794,7 +794,7 @@ end function constitutive_collectDotState !> @brief for constitutive models having an instantaneous change of state !> will return false if delta state is not needed/supported by the constitutive model !-------------------------------------------------------------------------------------------------- -subroutine constitutive_collectDeltaState(S, Fe, Fi, ipc, ip, el) +function constitutive_deltaState(S, Fe, Fi, ipc, ip, el) result(broken) integer, intent(in) :: & ipc, & !< component-ID of integration point @@ -808,13 +808,18 @@ subroutine constitutive_collectDeltaState(S, Fe, Fi, ipc, ip, el) Mp integer :: & i, & - instance, of + instance, of, & + phase + logical :: & + broken + Mp = matmul(matmul(transpose(Fi),Fi),S) of = material_phasememberAt(ipc,ip,el) + phase = material_phaseAt(ipc,el) instance = phase_plasticityInstance(material_phaseAt(ipc,el)) - plasticityType: select case (phase_plasticity(material_phaseAt(ipc,el))) + plasticityType: select case (phase_plasticity(phase)) case (PLASTICITY_KINEHARDENING_ID) plasticityType call plastic_kinehardening_deltaState(Mp,instance,of) @@ -823,10 +828,11 @@ subroutine constitutive_collectDeltaState(S, Fe, Fi, ipc, ip, el) call plastic_nonlocal_deltaState(Mp,instance,of,ip,el) end select plasticityType + broken = any(IEEE_is_NaN(plasticState(phase)%deltaState(:,of))) - sourceLoop: do i = 1, phase_Nsources(material_phaseAt(ipc,el)) + sourceLoop: do i = 1, phase_Nsources(phase) - sourceType: select case (phase_source(i,material_phaseAt(ipc,el))) + sourceType: select case (phase_source(i,phase)) case (SOURCE_damage_isoBrittle_ID) sourceType call source_damage_isoBrittle_deltaState (constitutive_homogenizedC(ipc,ip,el), Fe, & @@ -834,9 +840,11 @@ subroutine constitutive_collectDeltaState(S, Fe, Fi, ipc, ip, el) end select sourceType + broken = broken .or. any(IEEE_is_NaN(sourceState(phase)%p(i)%deltaState(:,of))) + enddo SourceLoop -end subroutine constitutive_collectDeltaState +end function constitutive_deltaState !-------------------------------------------------------------------------------------------------- diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 03de4dea3..81119f2e2 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1654,18 +1654,15 @@ logical function stateJump(ipc,ip,el) c = material_phaseMemberAt(ipc,ip,el) p = material_phaseAt(ipc,el) - call constitutive_collectDeltaState(crystallite_S(1:3,1:3,ipc,ip,el), & + stateJump = .not. constitutive_deltaState(crystallite_S(1:3,1:3,ipc,ip,el), & crystallite_Fe(1:3,1:3,ipc,ip,el), & crystallite_Fi(1:3,1:3,ipc,ip,el), & ipc,ip,el) + if(.not. stateJump) return myOffset = plasticState(p)%offsetDeltaState mySize = plasticState(p)%sizeDeltaState - if( any(IEEE_is_NaN(plasticState(p)%deltaState(1:mySize,c)))) then - stateJump = .false. - return - endif plasticState(p)%state(myOffset + 1:myOffset + mySize,c) = & plasticState(p)%state(myOffset + 1:myOffset + mySize,c) + plasticState(p)%deltaState(1:mySize,c) @@ -1673,16 +1670,10 @@ logical function stateJump(ipc,ip,el) do mySource = 1, phase_Nsources(p) myOffset = sourceState(p)%p(mySource)%offsetDeltaState mySize = sourceState(p)%p(mySource)%sizeDeltaState - if (any(IEEE_is_NaN(sourceState(p)%p(mySource)%deltaState(1:mySize,c)))) then - stateJump = .false. - return - endif sourceState(p)%p(mySource)%state(myOffset + 1: myOffset + mySize,c) = & sourceState(p)%p(mySource)%state(myOffset + 1: myOffset + mySize,c) + sourceState(p)%p(mySource)%deltaState(1:mySize,c) enddo - stateJump = .true. - end function stateJump From ec53e4c318328f5d928f45650e09842bda7851ae Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 08:39:49 +0200 Subject: [PATCH 004/186] avoid writing to public variable crystallite_todo --- src/crystallite.f90 | 152 ++++++++++++++++++++++---------------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 81119f2e2..caedf7ef5 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1016,10 +1016,10 @@ subroutine integrateStateFPI real(pReal), dimension(:), allocatable :: plastic_dotState_p1, plastic_dotState_p2 real(pReal), dimension(constitutive_source_maxSizeDotState,2,maxval(phase_Nsources)) :: source_dotState logical :: & - nonlocalBroken + nonlocalBroken, broken nonlocalBroken = .false. - !$OMP PARALLEL DO PRIVATE(sizeDotState,r,zeta,p,c,plastic_dotState_p1, plastic_dotState_p2,source_dotState) + !$OMP PARALLEL DO PRIVATE(sizeDotState,r,zeta,p,c,plastic_dotState_p1, plastic_dotState_p2,source_dotState,broken) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) @@ -1027,15 +1027,15 @@ subroutine integrateStateFPI p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) - crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle sizeDotState = plasticState(p)%sizeDotState plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & @@ -1060,16 +1060,16 @@ subroutine integrateStateFPI source_dotState(1:sizeDotState,1,s) = sourceState(p)%p(s)%dotState(:,c) enddo - crystallite_todo(g,i,e) = integrateStress(g,i,e) - if(.not. crystallite_todo(g,i,e)) exit iteration + broken = .not. integrateStress(g,i,e) + if(broken) exit iteration - crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(.not. crystallite_todo(g,i,e)) exit iteration + if(broken) exit iteration sizeDotState = plasticState(p)%sizeDotState zeta = damper(plasticState(p)%dotState(:,c),plastic_dotState_p1,plastic_dotState_p2) @@ -1102,12 +1102,12 @@ subroutine integrateStateFPI enddo if(crystallite_converged(g,i,e)) then - crystallite_todo(g,i,e) = stateJump(g,i,e) + broken = .not. stateJump(g,i,e) exit iteration endif enddo iteration - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. endif @@ -1155,10 +1155,10 @@ subroutine integrateStateEuler s, & sizeDotState logical :: & - nonlocalBroken + nonlocalBroken, broken nonlocalBroken = .false. - !$OMP PARALLEL DO PRIVATE (sizeDotState,p,c) + !$OMP PARALLEL DO PRIVATE (sizeDotState,p,c,broken) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) @@ -1166,15 +1166,15 @@ subroutine integrateStateEuler p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) - crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle sizeDotState = plasticState(p)%sizeDotState plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & @@ -1187,16 +1187,16 @@ subroutine integrateStateEuler * crystallite_subdt(g,i,e) enddo - crystallite_todo(g,i,e) = stateJump(g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + broken = .not. stateJump(g,i,e) + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle - crystallite_todo(g,i,e) = integrateStress(g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + broken = .not. integrateStress(g,i,e) + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - crystallite_converged(g,i,e) = crystallite_todo(g,i,e) + crystallite_converged(g,i,e) = .not. broken endif enddo; enddo; enddo @@ -1221,13 +1221,13 @@ subroutine integrateStateAdaptiveEuler s, & sizeDotState logical :: & - nonlocalBroken + nonlocalBroken, broken real(pReal), dimension(constitutive_plasticity_maxSizeDotState) :: residuum_plastic real(pReal), dimension(constitutive_source_maxSizeDotState,maxval(phase_Nsources)) :: residuum_source nonlocalBroken = .false. - !$OMP PARALLEL DO PRIVATE(sizeDotState,p,c,residuum_plastic,residuum_source) + !$OMP PARALLEL DO PRIVATE(sizeDotState,p,c,residuum_plastic,residuum_source,broken) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) @@ -1235,15 +1235,15 @@ subroutine integrateStateAdaptiveEuler p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) - crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1259,25 +1259,25 @@ subroutine integrateStateAdaptiveEuler + sourceState(p)%p(s)%dotstate(1:sizeDotState,c) * crystallite_subdt(g,i,e) enddo - crystallite_todo(g,i,e) = stateJump(g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + broken = .not. stateJump(g,i,e) + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle - crystallite_todo(g,i,e) = integrateStress(g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + broken = .not. integrateStress(g,i,e) + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle - crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1333,12 +1333,12 @@ subroutine integrateStateRK4 s, & sizeDotState logical :: & - nonlocalBroken + nonlocalBroken, broken real(pReal), dimension(constitutive_source_maxSizeDotState,4,maxval(phase_Nsources)) :: source_RK4dotState real(pReal), dimension(constitutive_plasticity_maxSizeDotState,4) :: plastic_RK4dotState nonlocalBroken = .false. - !$OMP PARALLEL DO PRIVATE(sizeDotState,p,c,source_RK4dotState,plastic_RK4dotState) + !$OMP PARALLEL DO PRIVATE(sizeDotState,p,c,source_RK4dotState,plastic_RK4dotState,broken) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) @@ -1346,15 +1346,15 @@ subroutine integrateStateRK4 p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) - crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle do stage = 1,3 sizeDotState = plasticState(p)%sizeDotState @@ -1388,24 +1388,24 @@ subroutine integrateStateRK4 * crystallite_subdt(g,i,e) enddo - crystallite_todo(g,i,e) = integrateStress(g,i,e,CC(stage)) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + broken = .not. integrateStress(g,i,e,CC(stage)) + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) exit + if(broken) exit - crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e)*CC(stage), g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) exit + if(broken) exit enddo - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1427,15 +1427,15 @@ subroutine integrateStateRK4 * crystallite_subdt(g,i,e) enddo - crystallite_todo(g,i,e) = stateJump(g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + broken = .not. stateJump(g,i,e) + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle - crystallite_todo(g,i,e) = integrateStress(g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + broken = .not. integrateStress(g,i,e) + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - crystallite_converged(g,i,e) = crystallite_todo(g,i,e) ! consider converged if not broken + crystallite_converged(g,i,e) = .not. broken endif enddo; enddo; enddo @@ -1483,12 +1483,12 @@ subroutine integrateStateRKCK45 s, & sizeDotState logical :: & - nonlocalBroken + nonlocalBroken, broken real(pReal), dimension(constitutive_source_maxSizeDotState,6,maxval(phase_Nsources)) :: source_RKdotState real(pReal), dimension(constitutive_plasticity_maxSizeDotState,6) :: plastic_RKdotState nonlocalBroken = .false. - !$OMP PARALLEL DO PRIVATE(sizeDotState,p,c,plastic_RKdotState,source_RKdotState) + !$OMP PARALLEL DO PRIVATE(sizeDotState,p,c,plastic_RKdotState,source_RKdotState,broken) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) @@ -1496,15 +1496,15 @@ subroutine integrateStateRKCK45 p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) - crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle do stage = 1,5 sizeDotState = plasticState(p)%sizeDotState @@ -1538,23 +1538,23 @@ subroutine integrateStateRKCK45 * crystallite_subdt(g,i,e) enddo - crystallite_todo(g,i,e) = integrateStress(g,i,e,CC(stage)) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + broken = .not. integrateStress(g,i,e,CC(stage)) + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) exit + if(broken) exit - crystallite_todo(g,i,e) = .not. constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & + broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e)*CC(stage), g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) exit + if(broken) exit enddo - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1563,7 +1563,7 @@ subroutine integrateStateRKCK45 plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & + plasticState(p)%dotState (1:sizeDotState,c) & * crystallite_subdt(g,i,e) - crystallite_todo(g,i,e) = converged( matmul(plastic_RKdotState(1:sizeDotState,1:6),DB) & + broken = .not. converged( matmul(plastic_RKdotState(1:sizeDotState,1:6),DB) & * crystallite_subdt(g,i,e), & plasticState(p)%state(1:sizeDotState,c), & plasticState(p)%atol(1:sizeDotState)) @@ -1576,25 +1576,25 @@ subroutine integrateStateRKCK45 sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & * crystallite_subdt(g,i,e) - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. & + broken = broken .and. .not. & converged(matmul(source_RKdotState(1:sizeDotState,1:6,s),DB) & * crystallite_subdt(g,i,e), & sourceState(p)%p(s)%state(1:sizeDotState,c), & sourceState(p)%p(s)%atol(1:sizeDotState)) enddo - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle - crystallite_todo(g,i,e) = stateJump(g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + broken = .not. stateJump(g,i,e) + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - if(.not. crystallite_todo(g,i,e)) cycle + if(broken) cycle - crystallite_todo(g,i,e) = integrateStress(g,i,e) - if(.not. (crystallite_todo(g,i,e) .or. crystallite_localPlasticity(g,i,e))) & + broken = .not. integrateStress(g,i,e) + if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. - crystallite_converged(g,i,e) = crystallite_todo(g,i,e) ! consider converged if not broken + crystallite_converged(g,i,e) = .not. broken endif enddo; enddo; enddo From d50d55cef3ac57d0e86386c8103be832f889b8c2 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 08:54:20 +0200 Subject: [PATCH 005/186] avoid public variables --- src/crystallite.f90 | 50 ++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index caedf7ef5..908d57ef8 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -71,7 +71,6 @@ module crystallite crystallite_requested !< used by upper level (homogenization) to request crystallite calculation logical, dimension(:,:,:), allocatable :: & crystallite_converged, & !< convergence flag - crystallite_todo, & !< flag to indicate need for further computation crystallite_localPlasticity !< indicates this grain to have purely local constitutive law type :: tOutput !< new requested output (per phase) @@ -98,7 +97,7 @@ module crystallite type(tNumerics) :: num ! numerics parameters. Better name? - procedure(), pointer :: integrateState + procedure(integrateStateFPI), pointer :: integrateState public :: & crystallite_init, & @@ -161,7 +160,6 @@ subroutine crystallite_init allocate(crystallite_localPlasticity(cMax,iMax,eMax), source=.true.) allocate(crystallite_requested(cMax,iMax,eMax), source=.false.) - allocate(crystallite_todo(cMax,iMax,eMax), source=.false.) allocate(crystallite_converged(cMax,iMax,eMax), source=.true.) num%subStepMinCryst = config_numerics%getFloat('substepmincryst', defaultVal=1.0e-3_pReal) @@ -301,6 +299,7 @@ function crystallite_stress(dummyArgumentToPreventInternalCompilerErrorWithGCC) e, & !< counter in element loop startIP, endIP, & s + logical, dimension(homogenization_maxNgrains,discretization_nIP,discretization_nElem) :: todo !ToDo: need to set some values to false in hase of different Ngrains #ifdef DEBUG if (iand(debug_level(debug_crystallite),debug_levelSelective) /= 0 & @@ -344,7 +343,7 @@ function crystallite_stress(dummyArgumentToPreventInternalCompilerErrorWithGCC) crystallite_subF0(1:3,1:3,c,i,e) = crystallite_partionedF0(1:3,1:3,c,i,e) crystallite_subFrac(c,i,e) = 0.0_pReal crystallite_subStep(c,i,e) = 1.0_pReal/num%subStepSizeCryst - crystallite_todo(c,i,e) = .true. + todo(c,i,e) = .true. crystallite_converged(c,i,e) = .false. ! pretend failed step of 1/subStepSizeCryst endif homogenizationRequestsCalculation enddo; enddo @@ -361,7 +360,7 @@ function crystallite_stress(dummyArgumentToPreventInternalCompilerErrorWithGCC) endif singleRun NiterationCrystallite = 0 - cutbackLooping: do while (any(crystallite_todo(:,startIP:endIP,FEsolving_execELem(1):FEsolving_execElem(2)))) + cutbackLooping: do while (any(todo(:,startIP:endIP,FEsolving_execELem(1):FEsolving_execElem(2)))) NiterationCrystallite = NiterationCrystallite + 1 #ifdef DEBUG @@ -380,8 +379,8 @@ function crystallite_stress(dummyArgumentToPreventInternalCompilerErrorWithGCC) crystallite_subStep(c,i,e) = min(1.0_pReal - crystallite_subFrac(c,i,e), & num%stepIncreaseCryst * crystallite_subStep(c,i,e)) - crystallite_todo(c,i,e) = crystallite_subStep(c,i,e) > 0.0_pReal ! still time left to integrate on? - if (crystallite_todo(c,i,e)) then + todo(c,i,e) = crystallite_subStep(c,i,e) > 0.0_pReal ! still time left to integrate on? + if (todo(c,i,e)) then crystallite_subF0 (1:3,1:3,c,i,e) = crystallite_subF(1:3,1:3,c,i,e) crystallite_subLp0(1:3,1:3,c,i,e) = crystallite_Lp (1:3,1:3,c,i,e) crystallite_subLi0(1:3,1:3,c,i,e) = crystallite_Li (1:3,1:3,c,i,e) @@ -415,12 +414,12 @@ function crystallite_stress(dummyArgumentToPreventInternalCompilerErrorWithGCC) enddo ! cant restore dotState here, since not yet calculated in first cutback after initialization - crystallite_todo(c,i,e) = crystallite_subStep(c,i,e) > num%subStepMinCryst ! still on track or already done (beyond repair) + todo(c,i,e) = crystallite_subStep(c,i,e) > num%subStepMinCryst ! still on track or already done (beyond repair) endif !-------------------------------------------------------------------------------------------------- ! prepare for integration - if (crystallite_todo(c,i,e)) then + if (todo(c,i,e)) then crystallite_subF(1:3,1:3,c,i,e) = crystallite_subF0(1:3,1:3,c,i,e) & + crystallite_subStep(c,i,e) *( crystallite_partionedF (1:3,1:3,c,i,e) & -crystallite_partionedF0(1:3,1:3,c,i,e)) @@ -438,9 +437,9 @@ function crystallite_stress(dummyArgumentToPreventInternalCompilerErrorWithGCC) !-------------------------------------------------------------------------------------------------- ! integrate --- requires fully defined state array (basic + dependent state) - if (any(crystallite_todo)) call integrateState ! TODO: unroll into proper elementloop to avoid N^2 for single point evaluation + if (any(todo)) call integrateState(todo) ! TODO: unroll into proper elementloop to avoid N^2 for single point evaluation where(.not. crystallite_converged .and. crystallite_subStep > num%subStepMinCryst) & ! do not try non-converged but fully cutbacked any further - crystallite_todo = .true. ! TODO: again unroll this into proper elementloop to avoid N^2 for single point evaluation + todo = .true. ! TODO: again unroll this into proper elementloop to avoid N^2 for single point evaluation enddo cutbackLooping @@ -998,8 +997,9 @@ end function integrateStress !> @brief integrate stress, state with adaptive 1st order explicit Euler method !> using Fixed Point Iteration to adapt the stepsize !-------------------------------------------------------------------------------------------------- -subroutine integrateStateFPI +subroutine integrateStateFPI(todo) + logical, dimension(:,:,:), intent(in) :: todo integer :: & NiterationState, & !< number of iterations in state loop e, & !< element index in element loop @@ -1023,7 +1023,7 @@ subroutine integrateStateFPI do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - if(crystallite_todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then + if(todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) @@ -1144,7 +1144,9 @@ end subroutine integrateStateFPI !-------------------------------------------------------------------------------------------------- !> @brief integrate state with 1st order explicit Euler method !-------------------------------------------------------------------------------------------------- -subroutine integrateStateEuler +subroutine integrateStateEuler(todo) + + logical, dimension(:,:,:), intent(in) :: todo integer :: & e, & !< element index in element loop @@ -1162,7 +1164,7 @@ subroutine integrateStateEuler do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - if(crystallite_todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then + if(todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) @@ -1210,7 +1212,9 @@ end subroutine integrateStateEuler !-------------------------------------------------------------------------------------------------- !> @brief integrate stress, state with 1st order Euler method with adaptive step size !-------------------------------------------------------------------------------------------------- -subroutine integrateStateAdaptiveEuler +subroutine integrateStateAdaptiveEuler(todo) + + logical, dimension(:,:,:), intent(in) :: todo integer :: & e, & ! element index in element loop @@ -1231,7 +1235,7 @@ subroutine integrateStateAdaptiveEuler do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - if(crystallite_todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then + if(todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) @@ -1309,7 +1313,9 @@ end subroutine integrateStateAdaptiveEuler !-------------------------------------------------------------------------------------------------- !> @brief integrate stress, state with 4th order explicit Runge Kutta method !-------------------------------------------------------------------------------------------------- -subroutine integrateStateRK4 +subroutine integrateStateRK4(todo) + + logical, dimension(:,:,:), intent(in) :: todo real(pReal), dimension(3,3), parameter :: & A = reshape([& @@ -1342,7 +1348,7 @@ subroutine integrateStateRK4 do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - if(crystallite_todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then + if(todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) @@ -1450,7 +1456,9 @@ end subroutine integrateStateRK4 !> @brief integrate stress, state with 5th order Runge-Kutta Cash-Karp method with !> adaptive step size (use 5th order solution to advance = "local extrapolation") !-------------------------------------------------------------------------------------------------- -subroutine integrateStateRKCK45 +subroutine integrateStateRKCK45(todo) + + logical, dimension(:,:,:), intent(in) :: todo real(pReal), dimension(5,5), parameter :: & A = reshape([& @@ -1492,7 +1500,7 @@ subroutine integrateStateRKCK45 do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - if(crystallite_todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then + if(todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) From 6eee8f34ac830f4d2db934eb92db66211a4eb886 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 09:01:03 +0200 Subject: [PATCH 006/186] homogeneous mesh --- src/crystallite.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 908d57ef8..4e475343b 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -269,7 +269,7 @@ subroutine crystallite_init #ifdef DEBUG if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0) then write(6,'(a42,1x,i10)') ' # of elements: ', eMax - write(6,'(a42,1x,i10)') 'max # of integration points/element: ', iMax + write(6,'(a42,1x,i10)') ' # of integration points/element: ', iMax write(6,'(a42,1x,i10)') 'max # of constituents/integration point: ', cMax write(6,'(a42,1x,i10)') ' # of nonlocal constituents: ',count(.not. crystallite_localPlasticity) flush(6) From 079596f7cdcaa9ac69c7ccaa5260c51bb1725c30 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 09:23:43 +0200 Subject: [PATCH 007/186] unix standard 0/.false. = OK, 1/.true. = not OK --- src/crystallite.f90 | 46 ++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 4e475343b..4fe8c75dd 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -776,7 +776,7 @@ end subroutine crystallite_results !> @brief calculation of stress (P) with time integration based on a residuum in Lp and !> intermediate acceleration of the Newton-Raphson correction !-------------------------------------------------------------------------------------------------- -logical function integrateStress(ipc,ip,el,timeFraction) +function integrateStress(ipc,ip,el,timeFraction) result(broken) integer, intent(in):: el, & ! element index ip, & ! integration point index @@ -833,11 +833,11 @@ logical function integrateStress(ipc,ip,el,timeFraction) p, & jacoCounterLp, & jacoCounterLi ! counters to check for Jacobian update - logical :: error + logical :: error,broken external :: & dgesv - integrateStress = .false. + broken = .true. if (present(timeFraction)) then dt = crystallite_subdt(ipc,ip,el) * timeFraction @@ -981,7 +981,6 @@ logical function integrateStress(ipc,ip,el,timeFraction) call math_invert33(Fp_new,devNull,error,invFp_new) if (error) return ! error - integrateStress = .true. crystallite_P (1:3,1:3,ipc,ip,el) = matmul(matmul(F,invFp_new),matmul(S,transpose(invFp_new))) crystallite_S (1:3,1:3,ipc,ip,el) = S crystallite_Lp (1:3,1:3,ipc,ip,el) = Lpguess @@ -989,6 +988,7 @@ logical function integrateStress(ipc,ip,el,timeFraction) crystallite_Fp (1:3,1:3,ipc,ip,el) = Fp_new / math_det33(Fp_new)**(1.0_pReal/3.0_pReal) ! regularize crystallite_Fi (1:3,1:3,ipc,ip,el) = Fi_new crystallite_Fe (1:3,1:3,ipc,ip,el) = matmul(matmul(F,invFp_new),invFi_new) + broken = .false. end function integrateStress @@ -1060,7 +1060,7 @@ subroutine integrateStateFPI(todo) source_dotState(1:sizeDotState,1,s) = sourceState(p)%p(s)%dotState(:,c) enddo - broken = .not. integrateStress(g,i,e) + broken = integrateStress(g,i,e) if(broken) exit iteration broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & @@ -1068,7 +1068,6 @@ subroutine integrateStateFPI(todo) crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(broken) exit iteration sizeDotState = plasticState(p)%sizeDotState @@ -1102,7 +1101,7 @@ subroutine integrateStateFPI(todo) enddo if(crystallite_converged(g,i,e)) then - broken = .not. stateJump(g,i,e) + broken = stateJump(g,i,e) exit iteration endif @@ -1189,12 +1188,12 @@ subroutine integrateStateEuler(todo) * crystallite_subdt(g,i,e) enddo - broken = .not. stateJump(g,i,e) + broken = stateJump(g,i,e) if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. if(broken) cycle - broken = .not. integrateStress(g,i,e) + broken = integrateStress(g,i,e) if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. @@ -1263,12 +1262,12 @@ subroutine integrateStateAdaptiveEuler(todo) + sourceState(p)%p(s)%dotstate(1:sizeDotState,c) * crystallite_subdt(g,i,e) enddo - broken = .not. stateJump(g,i,e) + broken = stateJump(g,i,e) if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. if(broken) cycle - broken = .not. integrateStress(g,i,e) + broken = integrateStress(g,i,e) if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. if(broken) cycle @@ -1394,7 +1393,7 @@ subroutine integrateStateRK4(todo) * crystallite_subdt(g,i,e) enddo - broken = .not. integrateStress(g,i,e,CC(stage)) + broken = integrateStress(g,i,e,CC(stage)) if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. if(broken) exit @@ -1433,12 +1432,12 @@ subroutine integrateStateRK4(todo) * crystallite_subdt(g,i,e) enddo - broken = .not. stateJump(g,i,e) + broken = stateJump(g,i,e) if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. if(broken) cycle - broken = .not. integrateStress(g,i,e) + broken = integrateStress(g,i,e) if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. crystallite_converged(g,i,e) = .not. broken @@ -1546,7 +1545,7 @@ subroutine integrateStateRKCK45(todo) * crystallite_subdt(g,i,e) enddo - broken = .not. integrateStress(g,i,e,CC(stage)) + broken = integrateStress(g,i,e,CC(stage)) if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. if(broken) exit @@ -1594,12 +1593,12 @@ subroutine integrateStateRKCK45(todo) nonlocalBroken = .true. if(broken) cycle - broken = .not. stateJump(g,i,e) + broken = stateJump(g,i,e) if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. if(broken) cycle - broken = .not. integrateStress(g,i,e) + broken = integrateStress(g,i,e) if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & nonlocalBroken = .true. crystallite_converged(g,i,e) = .not. broken @@ -1645,7 +1644,7 @@ end function converged !> @brief calculates a jump in the state according to the current state and the current stress !> returns true, if state jump was successfull or not needed. false indicates NaN in delta state !-------------------------------------------------------------------------------------------------- -logical function stateJump(ipc,ip,el) +function stateJump(ipc,ip,el) result(broken) integer, intent(in):: & el, & ! element index @@ -1658,15 +1657,16 @@ logical function stateJump(ipc,ip,el) mySource, & myOffset, & mySize + logical :: broken c = material_phaseMemberAt(ipc,ip,el) p = material_phaseAt(ipc,el) - stateJump = .not. constitutive_deltaState(crystallite_S(1:3,1:3,ipc,ip,el), & - crystallite_Fe(1:3,1:3,ipc,ip,el), & - crystallite_Fi(1:3,1:3,ipc,ip,el), & - ipc,ip,el) - if(.not. stateJump) return + broken = constitutive_deltaState(crystallite_S(1:3,1:3,ipc,ip,el), & + crystallite_Fe(1:3,1:3,ipc,ip,el), & + crystallite_Fi(1:3,1:3,ipc,ip,el), & + ipc,ip,el) + if(broken) return myOffset = plasticState(p)%offsetDeltaState mySize = plasticState(p)%sizeDeltaState From ce61606c0bd2563b0adeaa10d6d03017b290a5f7 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 09:34:49 +0200 Subject: [PATCH 008/186] not needed --- src/material.f90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/material.f90 b/src/material.f90 index aefe44878..2a447c036 100644 --- a/src/material.f90 +++ b/src/material.f90 @@ -11,7 +11,6 @@ module material use results use IO use debug - use numerics use rotations use discretization From b996b6c42ec1e0954b4e4896cd7950b99f0890e5 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 09:56:59 +0200 Subject: [PATCH 009/186] merge functionality --- src/constitutive_plastic_disloUCLA.f90 | 2 +- src/constitutive_plastic_dislotwin.f90 | 2 +- src/constitutive_plastic_isotropic.f90 | 2 +- src/constitutive_plastic_kinehardening.f90 | 2 +- src/constitutive_plastic_none.f90 | 2 +- src/constitutive_plastic_nonlocal.f90 | 2 +- src/constitutive_plastic_phenopowerlaw.f90 | 2 +- src/material.f90 | 65 ++++++---------------- src/source_damage_anisoBrittle.f90 | 2 +- src/source_damage_anisoDuctile.f90 | 2 +- src/source_damage_isoBrittle.f90 | 2 +- src/source_damage_isoDuctile.f90 | 2 +- src/source_thermal_dissipation.f90 | 2 +- src/source_thermal_externalheat.f90 | 2 +- 14 files changed, 31 insertions(+), 60 deletions(-) diff --git a/src/constitutive_plastic_disloUCLA.f90 b/src/constitutive_plastic_disloUCLA.f90 index 6be86f266..90a933910 100644 --- a/src/constitutive_plastic_disloUCLA.f90 +++ b/src/constitutive_plastic_disloUCLA.f90 @@ -209,7 +209,7 @@ module subroutine plastic_disloUCLA_init sizeDotState = size(['rho_mob ','rho_dip ','gamma_sl']) * prm%sum_N_sl sizeState = sizeDotState - call material_allocatePlasticState(p,NipcMyPhase,sizeState,sizeDotState,0) + call material_allocateState(plasticState(p),NipcMyPhase,sizeState,sizeDotState,0) !-------------------------------------------------------------------------------------------------- ! state aliases and initialization diff --git a/src/constitutive_plastic_dislotwin.f90 b/src/constitutive_plastic_dislotwin.f90 index d36e08846..abc46a45e 100644 --- a/src/constitutive_plastic_dislotwin.f90 +++ b/src/constitutive_plastic_dislotwin.f90 @@ -399,7 +399,7 @@ module subroutine plastic_dislotwin_init + size(['f_tr']) * prm%sum_N_tr sizeState = sizeDotState - call material_allocatePlasticState(p,NipcMyPhase,sizeState,sizeDotState,0) + call material_allocateState(plasticState(p),NipcMyPhase,sizeState,sizeDotState,0) !-------------------------------------------------------------------------------------------------- ! locally defined state aliases and initialization of state0 and atol diff --git a/src/constitutive_plastic_isotropic.f90 b/src/constitutive_plastic_isotropic.f90 index 94fc9817d..ecf029124 100644 --- a/src/constitutive_plastic_isotropic.f90 +++ b/src/constitutive_plastic_isotropic.f90 @@ -117,7 +117,7 @@ module subroutine plastic_isotropic_init sizeDotState = size(['xi ','accumulated_shear']) sizeState = sizeDotState - call material_allocatePlasticState(p,NipcMyPhase,sizeState,sizeDotState,0) + call material_allocateState(plasticState(p),NipcMyPhase,sizeState,sizeDotState,0) !-------------------------------------------------------------------------------------------------- ! state aliases and initialization diff --git a/src/constitutive_plastic_kinehardening.f90 b/src/constitutive_plastic_kinehardening.f90 index 5843f5b5e..36b1eedf9 100644 --- a/src/constitutive_plastic_kinehardening.f90 +++ b/src/constitutive_plastic_kinehardening.f90 @@ -164,7 +164,7 @@ module subroutine plastic_kinehardening_init sizeDeltaState = size(['sense ', 'chi0 ', 'gamma0' ]) * prm%sum_N_sl sizeState = sizeDotState + sizeDeltaState - call material_allocatePlasticState(p,NipcMyPhase,sizeState,sizeDotState,sizeDeltaState) + call material_allocateState(plasticState(p),NipcMyPhase,sizeState,sizeDotState,sizeDeltaState) !-------------------------------------------------------------------------------------------------- ! state aliases and initialization diff --git a/src/constitutive_plastic_none.f90 b/src/constitutive_plastic_none.f90 index 7ff1c76f7..667fe5638 100644 --- a/src/constitutive_plastic_none.f90 +++ b/src/constitutive_plastic_none.f90 @@ -29,7 +29,7 @@ module subroutine plastic_none_init if (phase_plasticity(p) /= PLASTICITY_NONE_ID) cycle NipcMyPhase = count(material_phaseAt == p) * discretization_nIP - call material_allocatePlasticState(p,NipcMyPhase,0,0,0) + call material_allocateState(plasticState(p),NipcMyPhase,0,0,0) enddo diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index 58218ac00..35cc7bdd1 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -384,7 +384,7 @@ module subroutine plastic_nonlocal_init 'maxDipoleHeightEdge ','maxDipoleHeightScrew' ]) * prm%sum_N_sl !< other dependent state variables that are not updated by microstructure sizeDeltaState = sizeDotState - call material_allocatePlasticState(p,NipcMyPhase,sizeState,sizeDotState,sizeDeltaState) + call material_allocateState(plasticState(p),NipcMyPhase,sizeState,sizeDotState,sizeDeltaState) plasticState(p)%nonlocal = .true. plasticState(p)%offsetDeltaState = 0 ! ToDo: state structure does not follow convention diff --git a/src/constitutive_plastic_phenopowerlaw.f90 b/src/constitutive_plastic_phenopowerlaw.f90 index a980d6106..12a30478a 100644 --- a/src/constitutive_plastic_phenopowerlaw.f90 +++ b/src/constitutive_plastic_phenopowerlaw.f90 @@ -213,7 +213,7 @@ module subroutine plastic_phenopowerlaw_init + size(['xi_tw ','gamma_tw']) * prm%sum_N_tw sizeState = sizeDotState - call material_allocatePlasticState(p,NipcMyPhase,sizeState,sizeDotState,0) + call material_allocateState(plasticState(p),NipcMyPhase,sizeState,sizeDotState,0) !-------------------------------------------------------------------------------------------------- ! state aliases and initialization diff --git a/src/material.f90 b/src/material.f90 index 2a447c036..749c9a3d8 100644 --- a/src/material.f90 +++ b/src/material.f90 @@ -173,8 +173,7 @@ module material public :: & material_init, & - material_allocatePlasticState, & - material_allocateSourceState, & + material_allocateState, & ELASTICITY_HOOKE_ID ,& PLASTICITY_NONE_ID, & PLASTICITY_ISOTROPIC_ID, & @@ -699,63 +698,35 @@ end subroutine material_parseTexture !-------------------------------------------------------------------------------------------------- -!> @brief allocates the plastic state of a phase +!> @brief Allocate the components of the state structure for a given phase !-------------------------------------------------------------------------------------------------- -subroutine material_allocatePlasticState(phase,NipcMyPhase,& - sizeState,sizeDotState,sizeDeltaState) +subroutine material_allocateState(state, & + NipcMyPhase,sizeState,sizeDotState,sizeDeltaState) + class(tState), intent(out) :: & + state integer, intent(in) :: & - phase, & NipcMyPhase, & sizeState, & sizeDotState, & sizeDeltaState - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%offsetDeltaState = sizeState-sizeDeltaState ! deltaState occupies latter part of state by definition + state%sizeState = sizeState + state%sizeDotState = sizeDotState + state%sizeDeltaState = sizeDeltaState + state%offsetDeltaState = sizeState-sizeDeltaState ! deltaState occupies latter part of state by definition - allocate(plasticState(phase)%atol (sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 (sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NipcMyPhase), source=0.0_pReal) + allocate(state%atol (sizeState), source=0.0_pReal) + allocate(state%state0 (sizeState,NipcMyPhase), source=0.0_pReal) + allocate(state%partionedState0(sizeState,NipcMyPhase), source=0.0_pReal) + allocate(state%subState0 (sizeState,NipcMyPhase), source=0.0_pReal) + allocate(state%state (sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(state%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase),source=0.0_pReal) + allocate(state%deltaState(sizeDeltaState,NipcMyPhase), source=0.0_pReal) -end subroutine material_allocatePlasticState +end subroutine material_allocateState -!-------------------------------------------------------------------------------------------------- -!> @brief allocates the source state of a phase -!-------------------------------------------------------------------------------------------------- -subroutine material_allocateSourceState(phase,of,NipcMyPhase,& - sizeState,sizeDotState,sizeDeltaState) - - integer, intent(in) :: & - phase, & - of, & - NipcMyPhase, & - sizeState, sizeDotState,sizeDeltaState - - sourceState(phase)%p(of)%sizeState = sizeState - sourceState(phase)%p(of)%sizeDotState = sizeDotState - sourceState(phase)%p(of)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(of)%offsetDeltaState = sizeState-sizeDeltaState ! deltaState occupies latter part of state by definition - - allocate(sourceState(phase)%p(of)%atol (sizeState), source=0.0_pReal) - allocate(sourceState(phase)%p(of)%state0 (sizeState,NipcMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(of)%partionedState0 (sizeState,NipcMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(of)%subState0 (sizeState,NipcMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(of)%state (sizeState,NipcMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(of)%dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - - allocate(sourceState(phase)%p(of)%deltaState (sizeDeltaState,NipcMyPhase),source=0.0_pReal) - -end subroutine material_allocateSourceState - end module material diff --git a/src/source_damage_anisoBrittle.f90 b/src/source_damage_anisoBrittle.f90 index 3978be959..b3af24f38 100644 --- a/src/source_damage_anisoBrittle.f90 +++ b/src/source_damage_anisoBrittle.f90 @@ -107,7 +107,7 @@ subroutine source_damage_anisoBrittle_init if (any(prm%critDisp < 0.0_pReal)) extmsg = trim(extmsg)//' anisobrittle_critDisp' NipcMyPhase = count(material_phaseAt==p) * discretization_nIP - call material_allocateSourceState(p,sourceOffset,NipcMyPhase,1,1,0) + call material_allocateState(sourceState(p)%p(sourceOffset),NipcMyPhase,1,1,0) sourceState(p)%p(sourceOffset)%atol = config%getFloat('anisobrittle_atol',defaultVal=1.0e-3_pReal) if(any(sourceState(p)%p(sourceOffset)%atol < 0.0_pReal)) extmsg = trim(extmsg)//' anisobrittle_atol' diff --git a/src/source_damage_anisoDuctile.f90 b/src/source_damage_anisoDuctile.f90 index 2b818e2cf..79cc0c2f7 100644 --- a/src/source_damage_anisoDuctile.f90 +++ b/src/source_damage_anisoDuctile.f90 @@ -89,7 +89,7 @@ subroutine source_damage_anisoDuctile_init if (any(prm%critPlasticStrain < 0.0_pReal)) extmsg = trim(extmsg)//' anisoductile_criticalplasticstrain' NipcMyPhase=count(material_phaseAt==p) * discretization_nIP - call material_allocateSourceState(p,sourceOffset,NipcMyPhase,1,1,0) + call material_allocateState(sourceState(p)%p(sourceOffset),NipcMyPhase,1,1,0) sourceState(p)%p(sourceOffset)%atol = config%getFloat('anisoductile_atol',defaultVal=1.0e-3_pReal) if(any(sourceState(p)%p(sourceOffset)%atol < 0.0_pReal)) extmsg = trim(extmsg)//' anisoductile_atol' diff --git a/src/source_damage_isoBrittle.f90 b/src/source_damage_isoBrittle.f90 index ed6d89a89..9eacb4516 100644 --- a/src/source_damage_isoBrittle.f90 +++ b/src/source_damage_isoBrittle.f90 @@ -83,7 +83,7 @@ subroutine source_damage_isoBrittle_init if (prm%critStrainEnergy <= 0.0_pReal) extmsg = trim(extmsg)//' isobrittle_criticalstrainenergy' NipcMyPhase = count(material_phaseAt==p) * discretization_nIP - call material_allocateSourceState(p,sourceOffset,NipcMyPhase,1,1,1) + call material_allocateState(sourceState(p)%p(sourceOffset),NipcMyPhase,1,1,1) sourceState(p)%p(sourceOffset)%atol = config%getFloat('isobrittle_atol',defaultVal=1.0e-3_pReal) if(any(sourceState(p)%p(sourceOffset)%atol < 0.0_pReal)) extmsg = trim(extmsg)//' isobrittle_atol' diff --git a/src/source_damage_isoDuctile.f90 b/src/source_damage_isoDuctile.f90 index 7024e595a..96754725d 100644 --- a/src/source_damage_isoDuctile.f90 +++ b/src/source_damage_isoDuctile.f90 @@ -82,7 +82,7 @@ subroutine source_damage_isoDuctile_init if (prm%critPlasticStrain <= 0.0_pReal) extmsg = trim(extmsg)//' isoductile_criticalplasticstrain' NipcMyPhase=count(material_phaseAt==p) * discretization_nIP - call material_allocateSourceState(p,sourceOffset,NipcMyPhase,1,1,0) + call material_allocateState(sourceState(p)%p(sourceOffset),NipcMyPhase,1,1,0) sourceState(p)%p(sourceOffset)%atol = config%getFloat('isoductile_atol',defaultVal=1.0e-3_pReal) if(any(sourceState(p)%p(sourceOffset)%atol < 0.0_pReal)) extmsg = trim(extmsg)//' isoductile_atol' diff --git a/src/source_thermal_dissipation.f90 b/src/source_thermal_dissipation.f90 index 521c79077..c323e68b5 100644 --- a/src/source_thermal_dissipation.f90 +++ b/src/source_thermal_dissipation.f90 @@ -67,7 +67,7 @@ subroutine source_thermal_dissipation_init prm%kappa = config%getFloat('dissipation_coldworkcoeff') NipcMyPhase = count(material_phaseAt==p) * discretization_nIP - call material_allocateSourceState(p,sourceOffset,NipcMyPhase,0,0,0) + call material_allocateState(sourceState(p)%p(sourceOffset),NipcMyPhase,0,0,0) end associate enddo diff --git a/src/source_thermal_externalheat.f90 b/src/source_thermal_externalheat.f90 index ade13bef2..06b8a5197 100644 --- a/src/source_thermal_externalheat.f90 +++ b/src/source_thermal_externalheat.f90 @@ -74,7 +74,7 @@ subroutine source_thermal_externalheat_init prm%heat_rate = config%getFloats('externalheat_rate',requiredSize = size(prm%time)) NipcMyPhase = count(material_phaseAt==p) * discretization_nIP - call material_allocateSourceState(p,sourceOffset,NipcMyPhase,1,1,0) + call material_allocateState(sourceState(p)%p(sourceOffset),NipcMyPhase,1,1,0) end associate enddo From 79012c9ffb0c586ac916b42b73452acdd1d41849 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 10:00:12 +0200 Subject: [PATCH 010/186] not needed --- src/prec.f90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/prec.f90 b/src/prec.f90 index dd39ddc05..646f7dd69 100644 --- a/src/prec.f90 +++ b/src/prec.f90 @@ -53,8 +53,7 @@ module prec logical :: & nonlocal = .false. real(pReal), pointer, dimension(:,:) :: & - slipRate, & !< slip rate - accumulatedSlip !< accumulated plastic slip + slipRate !< slip rate end type type :: tSourceState From cde8c65bd18b9f41bd669f8db673f86066bcdc74 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 10:57:53 +0200 Subject: [PATCH 011/186] better store data locally --- src/crystallite.f90 | 12 +++++++++--- src/numerics.f90 | 23 ++++++++++------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 4fe8c75dd..7b3ee4115 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -15,7 +15,6 @@ module crystallite use DAMASK_interface use config use debug - use numerics use rotations use math use FEsolving @@ -83,7 +82,8 @@ module crystallite integer :: & iJacoLpresiduum, & !< frequency of Jacobian update of residuum in Lp nState, & !< state loop limit - nStress !< stress loop limit + nStress, & !< stress loop limit + integrator !< integration scheme (ToDo: better use a string) real(pReal) :: & subStepMinCryst, & !< minimum (relative) size of sub-step allowed during cutback subStepSizeCryst, & !< size of first substep when cutback @@ -175,6 +175,8 @@ subroutine crystallite_init num%iJacoLpresiduum = config_numerics%getInt ('ijacolpresiduum', defaultVal=1) + num%integrator = config_numerics%getInt ('integrator', defaultVal=1) + num%nState = config_numerics%getInt ('nstate', defaultVal=20) num%nStress = config_numerics%getInt ('nstress', defaultVal=40) @@ -191,10 +193,14 @@ subroutine crystallite_init if(num%iJacoLpresiduum < 1) call IO_error(301,ext_msg='iJacoLpresiduum') + if(num%integrator < 1 .or. num%integrator > 5) & + call IO_error(301,ext_msg='integrator') + if(num%nState < 1) call IO_error(301,ext_msg='nState') if(num%nStress< 1) call IO_error(301,ext_msg='nStress') - select case(numerics_integrator) + + select case(num%integrator) case(1) integrateState => integrateStateFPI case(2) diff --git a/src/numerics.f90 b/src/numerics.f90 index a29601322..8d242c71d 100644 --- a/src/numerics.f90 +++ b/src/numerics.f90 @@ -20,8 +20,7 @@ module numerics iJacoStiffness = 1, & !< frequency of stiffness update randomSeed = 0, & !< fixed seeding for pseudo-random number generator, Default 0: use random seed worldrank = 0, & !< MPI worldrank (/=0 for MPI simulations only) - worldsize = 1, & !< MPI worldsize (/=1 for MPI simulations only) - numerics_integrator = 1 !< method used for state integration Default 1: fix-point iteration + worldsize = 1 !< MPI worldsize (/=1 for MPI simulations only) integer(4), protected, public :: & DAMASK_NumThreadsInt = 0 !< value stored in environment variable DAMASK_NUM_THREADS, set to zero if no OpenMP directive real(pReal), protected, public :: & @@ -134,8 +133,6 @@ subroutine numerics_init defgradTolerance = IO_floatValue(line,chunkPos,2) case ('ijacostiffness') iJacoStiffness = IO_intValue(line,chunkPos,2) - case ('integrator') - numerics_integrator = IO_intValue(line,chunkPos,2) case ('usepingpong') usepingpong = IO_intValue(line,chunkPos,2) > 0 case ('unitlength') @@ -176,6 +173,11 @@ subroutine numerics_init case ('maxstaggerediter') stagItMax = IO_intValue(line,chunkPos,2) +#ifdef PETSC + case ('petsc_options') + petsc_options = trim(line(chunkPos(4):)) +#endif + !-------------------------------------------------------------------------------------------------- ! spectral parameters #ifdef Grid @@ -187,8 +189,6 @@ subroutine numerics_init err_stress_tolrel = IO_floatValue(line,chunkPos,2) case ('err_stress_tolabs') err_stress_tolabs = IO_floatValue(line,chunkPos,2) - case ('petsc_options') - petsc_options = trim(line(chunkPos(4):)) case ('err_curl_tolabs') err_curl_tolAbs = IO_floatValue(line,chunkPos,2) case ('err_curl_tolrel') @@ -206,8 +206,6 @@ subroutine numerics_init integrationorder = IO_intValue(line,chunkPos,2) case ('structorder') structorder = IO_intValue(line,chunkPos,2) - case ('petsc_options') - petsc_options = trim(line(chunkPos(4):)) case ('bbarstabilisation') BBarStabilisation = IO_intValue(line,chunkPos,2) > 0 #endif @@ -223,7 +221,6 @@ subroutine numerics_init ! writing parameters to output write(6,'(a24,1x,es8.1)') ' defgradTolerance: ',defgradTolerance write(6,'(a24,1x,i8)') ' iJacoStiffness: ',iJacoStiffness - write(6,'(a24,1x,i8)') ' integrator: ',numerics_integrator write(6,'(a24,1x,L8)') ' use ping pong scheme: ',usepingpong write(6,'(a24,1x,es8.1,/)')' unitlength: ',numerics_unitlength @@ -266,7 +263,6 @@ subroutine numerics_init write(6,'(a24,1x,es8.1)') ' err_curl_tolRel: ',err_curl_tolRel write(6,'(a24,1x,es8.1)') ' polarAlpha: ',polarAlpha write(6,'(a24,1x,es8.1)') ' polarBeta: ',polarBeta - write(6,'(a24,1x,a)') ' PETSc_options: ',trim(petsc_options) #endif !-------------------------------------------------------------------------------------------------- @@ -274,16 +270,17 @@ subroutine numerics_init #ifdef FEM write(6,'(a24,1x,i8)') ' integrationOrder: ',integrationOrder write(6,'(a24,1x,i8)') ' structOrder: ',structOrder - write(6,'(a24,1x,a)') ' PETSc_options: ',trim(petsc_options) write(6,'(a24,1x,L8)') ' B-Bar stabilisation: ',BBarStabilisation #endif +#ifdef PETSC + write(6,'(a24,1x,a)') ' PETSc_options: ',trim(petsc_options) +#endif + !-------------------------------------------------------------------------------------------------- ! sanity checks if (defgradTolerance <= 0.0_pReal) call IO_error(301,ext_msg='defgradTolerance') if (iJacoStiffness < 1) call IO_error(301,ext_msg='iJacoStiffness') - if (numerics_integrator <= 0 .or. numerics_integrator >= 6) & - call IO_error(301,ext_msg='integrator') if (numerics_unitlength <= 0.0_pReal) call IO_error(301,ext_msg='unitlength') if (residualStiffness < 0.0_pReal) call IO_error(301,ext_msg='residualStiffness') if (itmax <= 1) call IO_error(301,ext_msg='itmax') From 97e89f3f88ec4cb67e76160c5c51d1ac27e544fa Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 11:09:30 +0200 Subject: [PATCH 012/186] nonlocal can run in local mode --- src/constitutive_plastic_nonlocal.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index 35cc7bdd1..99ccf9ec4 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -320,6 +320,8 @@ module subroutine plastic_nonlocal_init prm%fEdgeMultiplication = config%getFloat('edgemultiplication') prm%shortRangeStressCorrection = config%keyExists('/shortrangestresscorrection/') + plasticState(p)%nonlocal = config%KeyExists('/nonlocal/') + !-------------------------------------------------------------------------------------------------- ! sanity checks if (any(prm%burgers < 0.0_pReal)) extmsg = trim(extmsg)//' burgers' @@ -386,7 +388,6 @@ module subroutine plastic_nonlocal_init call material_allocateState(plasticState(p),NipcMyPhase,sizeState,sizeDotState,sizeDeltaState) - plasticState(p)%nonlocal = .true. plasticState(p)%offsetDeltaState = 0 ! ToDo: state structure does not follow convention st0%rho => plasticState(p)%state0 (0*prm%sum_N_sl+1:10*prm%sum_N_sl,:) From 5af53f0be75617d1848f3135ddaf9ab534e922fa Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 11:30:01 +0200 Subject: [PATCH 013/186] nonlocal is a property of the phase --- src/crystallite.f90 | 99 ++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 59 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 7b3ee4115..611a7551d 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1029,9 +1029,10 @@ subroutine integrateStateFPI(todo) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - if(todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then + p = material_phaseAt(g,e) + if(todo(g,i,e) .and. .not. (nonlocalBroken .and. plasticState(p)%nonlocal)) then - p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) + c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & @@ -1039,8 +1040,7 @@ subroutine integrateStateFPI(todo) crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1112,8 +1112,7 @@ subroutine integrateStateFPI(todo) endif enddo iteration - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. endif enddo; enddo; enddo @@ -1169,9 +1168,10 @@ subroutine integrateStateEuler(todo) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - if(todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then + p = material_phaseAt(g,e) + if(todo(g,i,e) .and. .not. (nonlocalBroken .and. plasticState(p)%nonlocal)) then - p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) + c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & @@ -1179,8 +1179,7 @@ subroutine integrateStateEuler(todo) crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1195,13 +1194,11 @@ subroutine integrateStateEuler(todo) enddo broken = stateJump(g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = integrateStress(g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. crystallite_converged(g,i,e) = .not. broken @@ -1240,9 +1237,10 @@ subroutine integrateStateAdaptiveEuler(todo) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - if(todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then + p = material_phaseAt(g,e) + if(todo(g,i,e) .and. .not. (nonlocalBroken .and. plasticState(p)%nonlocal)) then - p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) + c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & @@ -1250,8 +1248,7 @@ subroutine integrateStateAdaptiveEuler(todo) crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1269,13 +1266,11 @@ subroutine integrateStateAdaptiveEuler(todo) enddo broken = stateJump(g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = integrateStress(g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & @@ -1284,8 +1279,7 @@ subroutine integrateStateAdaptiveEuler(todo) crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1322,16 +1316,16 @@ subroutine integrateStateRK4(todo) logical, dimension(:,:,:), intent(in) :: todo - real(pReal), dimension(3,3), parameter :: & - A = reshape([& + real(pReal), dimension(3,3), parameter :: & + A = reshape([& 0.5_pReal, 0.0_pReal, 0.0_pReal, & 0.0_pReal, 0.5_pReal, 0.0_pReal, & 0.0_pReal, 0.0_pReal, 1.0_pReal], & [3,3]) - real(pReal), dimension(3), parameter :: & - CC = [0.5_pReal, 0.5_pReal, 1.0_pReal] ! factor giving the fraction of the original timestep used for Runge Kutta Integration - real(pReal), dimension(4), parameter :: & - B = [1.0_pReal/6.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/6.0_pReal] ! weight of slope used for Runge Kutta integration (final weight divided by 6) + real(pReal), dimension(3), parameter :: & + CC = [0.5_pReal, 0.5_pReal, 1.0_pReal] ! factor giving the fraction of the original timestep used for Runge Kutta Integration + real(pReal), dimension(4), parameter :: & + B = [1.0_pReal/6.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/6.0_pReal] ! weight of slope used for Runge Kutta integration (final weight divided by 6) integer :: & e, & ! element index in element loop @@ -1353,9 +1347,11 @@ subroutine integrateStateRK4(todo) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - if(todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then + p = material_phaseAt(g,e) + if(todo(g,i,e) .and. .not. (nonlocalBroken .and. plasticState(p)%nonlocal)) then + + c = material_phaseMemberAt(g,i,e) - p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & @@ -1363,8 +1359,7 @@ subroutine integrateStateRK4(todo) crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle do stage = 1,3 @@ -1400,8 +1395,6 @@ subroutine integrateStateRK4(todo) enddo broken = integrateStress(g,i,e,CC(stage)) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. if(broken) exit broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & @@ -1409,13 +1402,10 @@ subroutine integrateStateRK4(todo) crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e)*CC(stage), g,i,e) - - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. if(broken) exit enddo - + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1439,13 +1429,11 @@ subroutine integrateStateRK4(todo) enddo broken = stateJump(g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = integrateStress(g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. crystallite_converged(g,i,e) = .not. broken endif @@ -1505,9 +1493,10 @@ subroutine integrateStateRKCK45(todo) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - if(todo(g,i,e) .and. (.not. nonlocalBroken .or. crystallite_localPlasticity(g,i,e)) ) then + p = material_phaseAt(g,e) + if(todo(g,i,e) .and. .not. (nonlocalBroken .and. plasticState(p)%nonlocal)) then - p = material_phaseAt(g,e); c = material_phaseMemberAt(g,i,e) + c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & crystallite_partionedF0, & @@ -1515,8 +1504,7 @@ subroutine integrateStateRKCK45(todo) crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle do stage = 1,5 @@ -1552,8 +1540,6 @@ subroutine integrateStateRKCK45(todo) enddo broken = integrateStress(g,i,e,CC(stage)) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. if(broken) exit broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & @@ -1561,12 +1547,10 @@ subroutine integrateStateRKCK45(todo) crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e)*CC(stage), g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. if(broken) exit enddo - + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1595,18 +1579,15 @@ subroutine integrateStateRKCK45(todo) sourceState(p)%p(s)%state(1:sizeDotState,c), & sourceState(p)%p(s)%atol(1:sizeDotState)) enddo - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = stateJump(g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = integrateStress(g,i,e) - if(broken .and. .not. crystallite_localPlasticity(g,i,e)) & - nonlocalBroken = .true. + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. crystallite_converged(g,i,e) = .not. broken endif From b5efaa08a47ea7e0a662b7b7cbf3ca8e4762aa69 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 12:55:49 +0200 Subject: [PATCH 014/186] use already known mappings --- src/constitutive.f90 | 35 ++++++++++++++++++----------------- src/crystallite.f90 | 35 ++++++++++++++++------------------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/constitutive.f90 b/src/constitutive.f90 index 582222dae..e7f5628ed 100644 --- a/src/constitutive.f90 +++ b/src/constitutive.f90 @@ -709,12 +709,14 @@ end subroutine constitutive_hooke_SandItsTangents !-------------------------------------------------------------------------------------------------- !> @brief contains the constitutive equation for calculating the rate of change of microstructure !-------------------------------------------------------------------------------------------------- -function constitutive_collectDotState(S, FArray, Fi, FpArray, subdt, ipc, ip, el) result(broken) +function constitutive_collectDotState(S, FArray, Fi, FpArray, subdt, ipc, ip, el,phase,of) result(broken) integer, intent(in) :: & ipc, & !< component-ID of integration point ip, & !< integration point - el !< element + el, & !< element + phase, & + of real(pReal), intent(in) :: & subdt !< timestep real(pReal), intent(in), dimension(3,3,homogenization_maxNgrains,discretization_nIP,discretization_nElem) :: & @@ -727,17 +729,14 @@ function constitutive_collectDotState(S, FArray, Fi, FpArray, subdt, ipc, ip, el real(pReal), dimension(3,3) :: & Mp integer :: & - phase, & ho, & !< homogenization tme, & !< thermal member position i, & !< counter in source loop - instance, of + instance logical :: broken ho = material_homogenizationAt(el) tme = thermalMapping(ho)%p(ip,el) - of = material_phasememberAt(ipc,ip,el) - phase = material_phaseAt(ipc,el) instance = phase_plasticityInstance(phase) Mp = matmul(matmul(transpose(Fi),Fi),S) @@ -794,12 +793,14 @@ end function constitutive_collectDotState !> @brief for constitutive models having an instantaneous change of state !> will return false if delta state is not needed/supported by the constitutive model !-------------------------------------------------------------------------------------------------- -function constitutive_deltaState(S, Fe, Fi, ipc, ip, el) result(broken) +function constitutive_deltaState(S, Fe, Fi, ipc, ip, el, phase, of) result(broken) integer, intent(in) :: & ipc, & !< component-ID of integration point ip, & !< integration point - el !< element + el, & !< element + phase, & + of real(pReal), intent(in), dimension(3,3) :: & S, & !< 2nd Piola Kirchhoff stress Fe, & !< elastic deformation gradient @@ -808,27 +809,28 @@ function constitutive_deltaState(S, Fe, Fi, ipc, ip, el) result(broken) Mp integer :: & i, & - instance, of, & - phase + instance logical :: & broken - Mp = matmul(matmul(transpose(Fi),Fi),S) - of = material_phasememberAt(ipc,ip,el) - phase = material_phaseAt(ipc,el) - instance = phase_plasticityInstance(material_phaseAt(ipc,el)) + instance = phase_plasticityInstance(phase) plasticityType: select case (phase_plasticity(phase)) case (PLASTICITY_KINEHARDENING_ID) plasticityType call plastic_kinehardening_deltaState(Mp,instance,of) + broken = any(IEEE_is_NaN(plasticState(phase)%deltaState(:,of))) case (PLASTICITY_NONLOCAL_ID) plasticityType call plastic_nonlocal_deltaState(Mp,instance,of,ip,el) + broken = any(IEEE_is_NaN(plasticState(phase)%deltaState(:,of))) + + case default + broken = .false. end select plasticityType - broken = any(IEEE_is_NaN(plasticState(phase)%deltaState(:,of))) + sourceLoop: do i = 1, phase_Nsources(phase) @@ -837,11 +839,10 @@ function constitutive_deltaState(S, Fe, Fi, ipc, ip, el) result(broken) case (SOURCE_damage_isoBrittle_ID) sourceType call source_damage_isoBrittle_deltaState (constitutive_homogenizedC(ipc,ip,el), Fe, & ipc, ip, el) + broken = broken .or. any(IEEE_is_NaN(sourceState(phase)%p(i)%deltaState(:,of))) end select sourceType - broken = broken .or. any(IEEE_is_NaN(sourceState(phase)%p(i)%deltaState(:,of))) - enddo SourceLoop end function constitutive_deltaState diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 611a7551d..054bc2105 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1038,7 +1038,7 @@ subroutine integrateStateFPI(todo) crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e) + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1073,7 +1073,7 @@ subroutine integrateStateFPI(todo) crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e) + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) exit iteration sizeDotState = plasticState(p)%sizeDotState @@ -1107,7 +1107,7 @@ subroutine integrateStateFPI(todo) enddo if(crystallite_converged(g,i,e)) then - broken = stateJump(g,i,e) + broken = stateJump(g,i,e,p,c) exit iteration endif @@ -1177,7 +1177,7 @@ subroutine integrateStateEuler(todo) crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e) + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1193,7 +1193,7 @@ subroutine integrateStateEuler(todo) * crystallite_subdt(g,i,e) enddo - broken = stateJump(g,i,e) + broken = stateJump(g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1246,7 +1246,7 @@ subroutine integrateStateAdaptiveEuler(todo) crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e) + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1265,7 +1265,7 @@ subroutine integrateStateAdaptiveEuler(todo) + sourceState(p)%p(s)%dotstate(1:sizeDotState,c) * crystallite_subdt(g,i,e) enddo - broken = stateJump(g,i,e) + broken = stateJump(g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1277,7 +1277,7 @@ subroutine integrateStateAdaptiveEuler(todo) crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e) + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1357,7 +1357,7 @@ subroutine integrateStateRK4(todo) crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e) + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1401,7 +1401,7 @@ subroutine integrateStateRK4(todo) crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & - crystallite_subdt(g,i,e)*CC(stage), g,i,e) + crystallite_subdt(g,i,e)*CC(stage), g,i,e,p,c) if(broken) exit enddo @@ -1428,7 +1428,7 @@ subroutine integrateStateRK4(todo) * crystallite_subdt(g,i,e) enddo - broken = stateJump(g,i,e) + broken = stateJump(g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1502,7 +1502,7 @@ subroutine integrateStateRKCK45(todo) crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e) + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1546,7 +1546,7 @@ subroutine integrateStateRKCK45(todo) crystallite_partionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & - crystallite_subdt(g,i,e)*CC(stage), g,i,e) + crystallite_subdt(g,i,e)*CC(stage), g,i,e,p,c) if(broken) exit enddo @@ -1582,7 +1582,7 @@ subroutine integrateStateRKCK45(todo) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle - broken = stateJump(g,i,e) + broken = stateJump(g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1631,7 +1631,7 @@ end function converged !> @brief calculates a jump in the state according to the current state and the current stress !> returns true, if state jump was successfull or not needed. false indicates NaN in delta state !-------------------------------------------------------------------------------------------------- -function stateJump(ipc,ip,el) result(broken) +function stateJump(ipc,ip,el,p,c) result(broken) integer, intent(in):: & el, & ! element index @@ -1646,13 +1646,10 @@ function stateJump(ipc,ip,el) result(broken) mySize logical :: broken - c = material_phaseMemberAt(ipc,ip,el) - p = material_phaseAt(ipc,el) - broken = constitutive_deltaState(crystallite_S(1:3,1:3,ipc,ip,el), & crystallite_Fe(1:3,1:3,ipc,ip,el), & crystallite_Fi(1:3,1:3,ipc,ip,el), & - ipc,ip,el) + ipc,ip,el,p,c) if(broken) return myOffset = plasticState(p)%offsetDeltaState From 70dd06c4ecca2e9df9fe3ce19c7618dd0cc1aacc Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 14:42:38 +0200 Subject: [PATCH 015/186] constitutive should handle state jump alone --- src/constitutive.f90 | 21 ++++++++++++++- src/crystallite.f90 | 62 +++++++++++--------------------------------- 2 files changed, 35 insertions(+), 48 deletions(-) diff --git a/src/constitutive.f90 b/src/constitutive.f90 index e7f5628ed..e2c9dbc05 100644 --- a/src/constitutive.f90 +++ b/src/constitutive.f90 @@ -809,7 +809,9 @@ function constitutive_deltaState(S, Fe, Fi, ipc, ip, el, phase, of) result(broke Mp integer :: & i, & - instance + instance, & + myOffset, & + mySize logical :: & broken @@ -831,6 +833,17 @@ function constitutive_deltaState(S, Fe, Fi, ipc, ip, el, phase, of) result(broke end select plasticityType + if(.not. broken) then + select case(phase_plasticity(phase)) + case (PLASTICITY_NONLOCAL_ID,PLASTICITY_KINEHARDENING_ID) + + myOffset = plasticState(phase)%offsetDeltaState + mySize = plasticState(phase)%sizeDeltaState + plasticState(phase)%state(myOffset + 1:myOffset + mySize,of) = & + plasticState(phase)%state(myOffset + 1:myOffset + mySize,of) + plasticState(phase)%deltaState(1:mySize,of) + end select + endif + sourceLoop: do i = 1, phase_Nsources(phase) @@ -840,6 +853,12 @@ function constitutive_deltaState(S, Fe, Fi, ipc, ip, el, phase, of) result(broke call source_damage_isoBrittle_deltaState (constitutive_homogenizedC(ipc,ip,el), Fe, & ipc, ip, el) broken = broken .or. any(IEEE_is_NaN(sourceState(phase)%p(i)%deltaState(:,of))) + if(.not. broken) then + myOffset = sourceState(phase)%p(i)%offsetDeltaState + mySize = sourceState(phase)%p(i)%sizeDeltaState + sourceState(phase)%p(i)%state(myOffset + 1: myOffset + mySize,of) = & + sourceState(phase)%p(i)%state(myOffset + 1: myOffset + mySize,of) + sourceState(phase)%p(i)%deltaState(1:mySize,of) + endif end select sourceType diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 054bc2105..8bceff9a4 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1107,7 +1107,9 @@ subroutine integrateStateFPI(todo) enddo if(crystallite_converged(g,i,e)) then - broken = stateJump(g,i,e,p,c) + broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) exit iteration endif @@ -1193,7 +1195,9 @@ subroutine integrateStateEuler(todo) * crystallite_subdt(g,i,e) enddo - broken = stateJump(g,i,e,p,c) + broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1265,7 +1269,9 @@ subroutine integrateStateAdaptiveEuler(todo) + sourceState(p)%p(s)%dotstate(1:sizeDotState,c) * crystallite_subdt(g,i,e) enddo - broken = stateJump(g,i,e,p,c) + broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1428,7 +1434,9 @@ subroutine integrateStateRK4(todo) * crystallite_subdt(g,i,e) enddo - broken = stateJump(g,i,e,p,c) + broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1582,7 +1590,9 @@ subroutine integrateStateRKCK45(todo) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle - broken = stateJump(g,i,e,p,c) + broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1627,48 +1637,6 @@ logical pure function converged(residuum,state,atol) end function converged -!-------------------------------------------------------------------------------------------------- -!> @brief calculates a jump in the state according to the current state and the current stress -!> returns true, if state jump was successfull or not needed. false indicates NaN in delta state -!-------------------------------------------------------------------------------------------------- -function stateJump(ipc,ip,el,p,c) result(broken) - - integer, intent(in):: & - el, & ! element index - ip, & ! integration point index - ipc ! grain index - - integer :: & - c, & - p, & - mySource, & - myOffset, & - mySize - logical :: broken - - broken = constitutive_deltaState(crystallite_S(1:3,1:3,ipc,ip,el), & - crystallite_Fe(1:3,1:3,ipc,ip,el), & - crystallite_Fi(1:3,1:3,ipc,ip,el), & - ipc,ip,el,p,c) - if(broken) return - - myOffset = plasticState(p)%offsetDeltaState - mySize = plasticState(p)%sizeDeltaState - - - plasticState(p)%state(myOffset + 1:myOffset + mySize,c) = & - plasticState(p)%state(myOffset + 1:myOffset + mySize,c) + plasticState(p)%deltaState(1:mySize,c) - - do mySource = 1, phase_Nsources(p) - myOffset = sourceState(p)%p(mySource)%offsetDeltaState - mySize = sourceState(p)%p(mySource)%sizeDeltaState - sourceState(p)%p(mySource)%state(myOffset + 1: myOffset + mySize,c) = & - sourceState(p)%p(mySource)%state(myOffset + 1: myOffset + mySize,c) + sourceState(p)%p(mySource)%deltaState(1:mySize,c) - enddo - -end function stateJump - - !-------------------------------------------------------------------------------------------------- !> @brief Write current restart information (Field and constitutive data) to file. ! ToDo: Merge data into one file for MPI, move state to constitutive and homogenization, respectively From cf5fcf389b1502da09e86826684563c5391e4d40 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 17:53:07 +0200 Subject: [PATCH 016/186] phase is a property of the element and we have no homogenization for nonlocal --- src/crystallite.f90 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 8bceff9a4..967a34dbb 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -615,14 +615,16 @@ subroutine crystallite_orientations enddo; enddo; enddo !$OMP END PARALLEL DO - nonlocalPresent: if (any(plasticState%nonLocal)) then + nonlocalPresent: if (any(plasticState%nonlocal)) then !$OMP PARALLEL DO do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1),FEsolving_execIP(2) - if (plasticState(material_phaseAt(1,e))%nonLocal) & + if (plasticState(material_phaseAt(1,e))%nonlocal) then + do i = FEsolving_execIP(1),FEsolving_execIP(2) call plastic_nonlocal_updateCompatibility(crystallite_orientation, & phase_plasticityInstance(material_phaseAt(i,e)),i,e) - enddo; enddo + enddo + endif + enddo !$OMP END PARALLEL DO endif nonlocalPresent From d0d963a2cc8f368aca29ee2dcfd610600331051d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 17:58:50 +0200 Subject: [PATCH 017/186] set independent of number of slip systems --- src/constitutive_plastic_nonlocal.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index 99ccf9ec4..d530f6651 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -320,7 +320,6 @@ module subroutine plastic_nonlocal_init prm%fEdgeMultiplication = config%getFloat('edgemultiplication') prm%shortRangeStressCorrection = config%keyExists('/shortrangestresscorrection/') - plasticState(p)%nonlocal = config%KeyExists('/nonlocal/') !-------------------------------------------------------------------------------------------------- ! sanity checks @@ -388,6 +387,7 @@ module subroutine plastic_nonlocal_init call material_allocateState(plasticState(p),NipcMyPhase,sizeState,sizeDotState,sizeDeltaState) + plasticState(p)%nonlocal = config%KeyExists('/nonlocal/') plasticState(p)%offsetDeltaState = 0 ! ToDo: state structure does not follow convention st0%rho => plasticState(p)%state0 (0*prm%sum_N_sl+1:10*prm%sum_N_sl,:) From 3a4bb59057bcaeeac4f476a7ef992f64f0825bea Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Apr 2020 18:58:48 +0200 Subject: [PATCH 018/186] no need to store the same information multiple times --- src/crystallite.f90 | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 967a34dbb..0d905aaa2 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -69,8 +69,7 @@ module crystallite logical, dimension(:,:,:), allocatable, public :: & crystallite_requested !< used by upper level (homogenization) to request crystallite calculation logical, dimension(:,:,:), allocatable :: & - crystallite_converged, & !< convergence flag - crystallite_localPlasticity !< indicates this grain to have purely local constitutive law + crystallite_converged !< convergence flag type :: tOutput !< new requested output (per phase) character(len=pStringLen), allocatable, dimension(:) :: & @@ -158,7 +157,6 @@ subroutine crystallite_init allocate(crystallite_orientation(cMax,iMax,eMax)) - allocate(crystallite_localPlasticity(cMax,iMax,eMax), source=.true.) allocate(crystallite_requested(cMax,iMax,eMax), source=.false.) allocate(crystallite_converged(cMax,iMax,eMax), source=.true.) @@ -238,7 +236,6 @@ subroutine crystallite_init / math_det33(crystallite_Fp0(1:3,1:3,c,i,e))**(1.0_pReal/3.0_pReal) crystallite_Fi0(1:3,1:3,c,i,e) = constitutive_initialFi(c,i,e) crystallite_F0(1:3,1:3,c,i,e) = math_I3 - crystallite_localPlasticity(c,i,e) = phase_localPlasticity(material_phaseAt(c,e)) crystallite_Fe(1:3,1:3,c,i,e) = math_inv33(matmul(crystallite_Fi0(1:3,1:3,c,i,e), & crystallite_Fp0(1:3,1:3,c,i,e))) ! assuming that euler angles are given in internal strain free configuration crystallite_Fp(1:3,1:3,c,i,e) = crystallite_Fp0(1:3,1:3,c,i,e) @@ -248,7 +245,7 @@ subroutine crystallite_init enddo !$OMP END PARALLEL DO - if(any(.not. crystallite_localPlasticity) .and. .not. usePingPong) call IO_error(601) ! exit if nonlocal but no ping-pong ToDo: Why not check earlier? or in nonlocal? + if(any(plasticState%nonlocal) .and. .not. usePingPong) call IO_error(601) ! exit if nonlocal but no ping-pong ToDo: Why not check earlier? or in nonlocal? crystallite_partionedFp0 = crystallite_Fp0 crystallite_partionedFi0 = crystallite_Fi0 @@ -277,7 +274,6 @@ subroutine crystallite_init write(6,'(a42,1x,i10)') ' # of elements: ', eMax write(6,'(a42,1x,i10)') ' # of integration points/element: ', iMax write(6,'(a42,1x,i10)') 'max # of constituents/integration point: ', cMax - write(6,'(a42,1x,i10)') ' # of nonlocal constituents: ',count(.not. crystallite_localPlasticity) flush(6) endif @@ -1606,7 +1602,7 @@ subroutine integrateStateRKCK45(todo) enddo; enddo; enddo !$OMP END PARALLEL DO - if (nonlocalBroken) call nonlocalConvergenceCheck + if(nonlocalBroken) call nonlocalConvergenceCheck end subroutine integrateStateRKCK45 @@ -1617,7 +1613,14 @@ end subroutine integrateStateRKCK45 !-------------------------------------------------------------------------------------------------- subroutine nonlocalConvergenceCheck - where( .not. crystallite_localPlasticity) crystallite_converged = .false. + integer :: e,i,p + + do e = FEsolving_execElem(1),FEsolving_execElem(2) + p = material_phaseAt(1,e) + do i = FEsolving_execIP(1),FEsolving_execIP(2) + if(plasticState(p)%nonlocal) crystallite_converged(1,i,e) = .false. + enddo + enddo end subroutine nonlocalConvergenceCheck From d9806cb7f3ffe9a031b7946f3fbb33c193d4db26 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 2 Apr 2020 00:23:59 +0200 Subject: [PATCH 019/186] do not clutter with nonlocal checks --- src/crystallite.f90 | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 0d905aaa2..7fc51b1c9 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1037,7 +1037,6 @@ subroutine integrateStateFPI(todo) crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1113,7 +1112,6 @@ subroutine integrateStateFPI(todo) enddo iteration if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. - endif enddo; enddo; enddo !$OMP END PARALLEL DO @@ -1178,7 +1176,6 @@ subroutine integrateStateEuler(todo) crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle @@ -1201,9 +1198,7 @@ subroutine integrateStateEuler(todo) broken = integrateStress(g,i,e) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. - crystallite_converged(g,i,e) = .not. broken - endif enddo; enddo; enddo !$OMP END PARALLEL DO @@ -1239,6 +1234,7 @@ subroutine integrateStateAdaptiveEuler(todo) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) + broken = .false. p = material_phaseAt(g,e) if(todo(g,i,e) .and. .not. (nonlocalBroken .and. plasticState(p)%nonlocal)) then @@ -1249,8 +1245,6 @@ subroutine integrateStateAdaptiveEuler(todo) crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) - - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1270,11 +1264,9 @@ subroutine integrateStateAdaptiveEuler(todo) broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = integrateStress(g,i,e) - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & @@ -1282,13 +1274,10 @@ subroutine integrateStateAdaptiveEuler(todo) crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) - - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle sizeDotState = plasticState(p)%sizeDotState - crystallite_converged(g,i,e) = converged(residuum_plastic(1:sizeDotState) & + 0.5_pReal * plasticState(p)%dotState(:,c) * crystallite_subdt(g,i,e), & plasticState(p)%state(1:sizeDotState,c), & @@ -1296,7 +1285,6 @@ subroutine integrateStateAdaptiveEuler(todo) do s = 1, phase_Nsources(p) sizeDotState = sourceState(p)%p(s)%sizeDotState - crystallite_converged(g,i,e) = & crystallite_converged(g,i,e) .and. converged(residuum_source(1:sizeDotState,s) & + 0.5_pReal*sourceState(p)%p(s)%dotState(:,c)*crystallite_subdt(g,i,e), & @@ -1305,6 +1293,7 @@ subroutine integrateStateAdaptiveEuler(todo) enddo endif + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. enddo; enddo; enddo !$OMP END PARALLEL DO @@ -1351,6 +1340,7 @@ subroutine integrateStateRK4(todo) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) + broken = .false. p = material_phaseAt(g,e) if(todo(g,i,e) .and. .not. (nonlocalBroken .and. plasticState(p)%nonlocal)) then @@ -1362,8 +1352,6 @@ subroutine integrateStateRK4(todo) crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) - - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle do stage = 1,3 @@ -1409,7 +1397,6 @@ subroutine integrateStateRK4(todo) if(broken) exit enddo - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1435,14 +1422,13 @@ subroutine integrateStateRK4(todo) broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = integrateStress(g,i,e) - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. crystallite_converged(g,i,e) = .not. broken endif + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. enddo; enddo; enddo !$OMP END PARALLEL DO @@ -1499,6 +1485,7 @@ subroutine integrateStateRKCK45(todo) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) + broken = .false. p = material_phaseAt(g,e) if(todo(g,i,e) .and. .not. (nonlocalBroken .and. plasticState(p)%nonlocal)) then @@ -1509,8 +1496,6 @@ subroutine integrateStateRKCK45(todo) crystallite_Fi(1:3,1:3,g,i,e), & crystallite_partionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) - - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle do stage = 1,5 @@ -1556,7 +1541,6 @@ subroutine integrateStateRKCK45(todo) if(broken) exit enddo - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1585,20 +1569,18 @@ subroutine integrateStateRKCK45(todo) sourceState(p)%p(s)%state(1:sizeDotState,c), & sourceState(p)%p(s)%atol(1:sizeDotState)) enddo - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle broken = integrateStress(g,i,e) - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. crystallite_converged(g,i,e) = .not. broken endif + if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. enddo; enddo; enddo !$OMP END PARALLEL DO From 565cf8239f077c8830dd195cf41bef3ae99fcd51 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 2 Apr 2020 09:29:58 +0200 Subject: [PATCH 020/186] can be done in parallel --- src/crystallite.f90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 7fc51b1c9..595947803 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1597,12 +1597,14 @@ subroutine nonlocalConvergenceCheck integer :: e,i,p + !$OMP PARALLEL DO PRIVATE(p) do e = FEsolving_execElem(1),FEsolving_execElem(2) p = material_phaseAt(1,e) do i = FEsolving_execIP(1),FEsolving_execIP(2) if(plasticState(p)%nonlocal) crystallite_converged(1,i,e) = .false. enddo enddo + !$OMP END PARALLEL DO end subroutine nonlocalConvergenceCheck From ccf62ede52108e998064dc9d18aca0c0ebc73d02 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 11:32:18 +0200 Subject: [PATCH 021/186] bugfix for Cubochoric forward and backward mappings are different --- python/damask/_Lambert.py | 14 ++++++------- src/Lambert.f90 | 42 +++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/python/damask/_Lambert.py b/python/damask/_Lambert.py index b3f159ff6..7e46255dc 100644 --- a/python/damask/_Lambert.py +++ b/python/damask/_Lambert.py @@ -60,7 +60,7 @@ def cube_to_ball(cube): else: # get pyramide and scale by grid parameter ratio p = _get_order(cube) - XYZ = cube[p] * sc + XYZ = cube[p[0]] * sc # intercept all the points along the z-axis if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-300): @@ -82,7 +82,7 @@ def cube_to_ball(cube): ball = np.array([ T[order[1]] * q, T[order[0]] * q, np.sqrt(6.0/np.pi) * XYZ[2] - c ]) # reverse the coordinates back to the regular order according to the original pyramid number - ball = ball[p] + ball = ball[p[1]] return ball @@ -110,7 +110,7 @@ def ball_to_cube(ball): cube = np.zeros(3) else: p = _get_order(ball) - xyz3 = ball[p] + xyz3 = ball[p[0]] # inverse M_3 xyz2 = xyz3[0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[2])) ) @@ -132,7 +132,7 @@ def ball_to_cube(ball): # inverse M_1 cube = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /sc # reverse the coordinates back to the regular order according to the original pyramid number - cube = cube[p] + cube = cube[p[1]] return cube @@ -157,10 +157,10 @@ def _get_order(xyz): """ if (abs(xyz[0])<= xyz[2]) and (abs(xyz[1])<= xyz[2]) or \ (abs(xyz[0])<=-xyz[2]) and (abs(xyz[1])<=-xyz[2]): - return [0,1,2] + return [[0,1,2],[0,1,2]] elif (abs(xyz[2])<= xyz[0]) and (abs(xyz[1])<= xyz[0]) or \ (abs(xyz[2])<=-xyz[0]) and (abs(xyz[1])<=-xyz[0]): - return [1,2,0] + return [[1,2,0],[2,0,1]] elif (abs(xyz[0])<= xyz[1]) and (abs(xyz[2])<= xyz[1]) or \ (abs(xyz[0])<=-xyz[1]) and (abs(xyz[2])<=-xyz[1]): - return [2,0,1] + return [[2,0,1],[1,2,0]] diff --git a/src/Lambert.f90 b/src/Lambert.f90 index d7d3e48df..932fe221b 100644 --- a/src/Lambert.f90 +++ b/src/Lambert.f90 @@ -70,13 +70,13 @@ contains !-------------------------------------------------------------------------- pure function Lambert_CubeToBall(cube) result(ball) - real(pReal), intent(in), dimension(3) :: cube - real(pReal), dimension(3) :: ball, LamXYZ, XYZ - real(pReal), dimension(2) :: T - real(pReal) :: c, s, q - real(pReal), parameter :: eps = 1.0e-8_pReal - integer, dimension(3) :: p - integer, dimension(2) :: order + real(pReal), intent(in), dimension(3) :: cube + real(pReal), dimension(3) :: ball, LamXYZ, XYZ + real(pReal), dimension(2) :: T + real(pReal) :: c, s, q + real(pReal), parameter :: eps = 1.0e-8_pReal + integer, dimension(3,2) :: p + integer, dimension(2) :: order if (maxval(abs(cube)) > AP/2.0+eps) then ball = IEEE_value(cube,IEEE_positive_inf) @@ -89,7 +89,7 @@ pure function Lambert_CubeToBall(cube) result(ball) else center ! get pyramide and scale by grid parameter ratio p = GetPyramidOrder(cube) - XYZ = cube(p) * sc + XYZ = cube(p(:,1)) * sc ! intercept all the points along the z-axis special: if (all(dEq0(XYZ(1:2)))) then @@ -112,7 +112,7 @@ pure function Lambert_CubeToBall(cube) result(ball) endif special ! reverse the coordinates back to order according to the original pyramid number - ball = LamXYZ(p) + ball = LamXYZ(p(:,2)) endif center @@ -126,11 +126,11 @@ end function Lambert_CubeToBall !-------------------------------------------------------------------------- pure function Lambert_BallToCube(xyz) result(cube) - real(pReal), intent(in), dimension(3) :: xyz - real(pReal), dimension(3) :: cube, xyz1, xyz3 - real(pReal), dimension(2) :: Tinv, xyz2 - real(pReal) :: rs, qxy, q2, sq2, q, tt - integer, dimension(3) :: p + real(pReal), intent(in), dimension(3) :: xyz + real(pReal), dimension(3) :: cube, xyz1, xyz3 + real(pReal), dimension(2) :: Tinv, xyz2 + real(pReal) :: rs, qxy, q2, sq2, q, tt + integer, dimension(3,2) :: p rs = norm2(xyz) if (rs > R1) then @@ -142,7 +142,7 @@ pure function Lambert_BallToCube(xyz) result(cube) cube = 0.0_pReal else center p = GetPyramidOrder(xyz) - xyz3 = xyz(p) + xyz3 = xyz(p(:,1)) ! inverse M_3 xyz2 = xyz3(1:2) * sqrt( 2.0*rs/(rs+abs(xyz3(3))) ) @@ -166,7 +166,7 @@ pure function Lambert_BallToCube(xyz) result(cube) xyz1 = [ Tinv(1), Tinv(2), sign(1.0_pReal,xyz3(3)) * rs / pref ] /sc ! reverse the coordinates back to order according to the original pyramid number - cube = xyz1(p) + cube = xyz1(p(:,2)) endif center @@ -180,18 +180,18 @@ end function Lambert_BallToCube !-------------------------------------------------------------------------- pure function GetPyramidOrder(xyz) - real(pReal),intent(in),dimension(3) :: xyz - integer, dimension(3) :: GetPyramidOrder + real(pReal),intent(in),dimension(3) :: xyz + integer, dimension(3,2) :: GetPyramidOrder if (((abs(xyz(1)) <= xyz(3)).and.(abs(xyz(2)) <= xyz(3))) .or. & ((abs(xyz(1)) <= -xyz(3)).and.(abs(xyz(2)) <= -xyz(3)))) then - GetPyramidOrder = [1,2,3] + GetPyramidOrder = reshape([[1,2,3],[1,2,3]],[3,2]) else if (((abs(xyz(3)) <= xyz(1)).and.(abs(xyz(2)) <= xyz(1))) .or. & ((abs(xyz(3)) <= -xyz(1)).and.(abs(xyz(2)) <= -xyz(1)))) then - GetPyramidOrder = [2,3,1] + GetPyramidOrder = reshape([[2,3,1],[3,1,2]],[3,2]) else if (((abs(xyz(1)) <= xyz(2)).and.(abs(xyz(3)) <= xyz(2))) .or. & ((abs(xyz(1)) <= -xyz(2)).and.(abs(xyz(3)) <= -xyz(2)))) then - GetPyramidOrder = [3,1,2] + GetPyramidOrder = reshape([[3,1,2],[2,3,1]],[3,2]) else GetPyramidOrder = -1 ! should be impossible, but might simplify debugging end if From 4e06e9a410a8c0fe224e127aba4a13b73523a68b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 11:52:26 +0200 Subject: [PATCH 022/186] improved numerical stability for corner cases --- python/damask/_Lambert.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/python/damask/_Lambert.py b/python/damask/_Lambert.py index 7e46255dc..26bc67b84 100644 --- a/python/damask/_Lambert.py +++ b/python/damask/_Lambert.py @@ -51,19 +51,20 @@ def cube_to_ball(cube): https://doi.org/10.1088/0965-0393/22/7/075013 """ - if np.abs(np.max(cube))>np.pi**(2./3.) * 0.5: + cube_ = np.clip(cube,None,np.pi**(2./3.) * 0.5) if np.isclose(np.abs(np.max(cube)),np.pi**(2./3.) * 0.5) else cube + if np.abs(np.max(cube_))>np.pi**(2./3.) * 0.5: raise ValueError # transform to the sphere grid via the curved square, and intercept the zero point - if np.allclose(cube,0.0,rtol=0.0,atol=1.0e-300): + if np.allclose(cube_,0.0,rtol=0.0,atol=1.0e-16): ball = np.zeros(3) else: # get pyramide and scale by grid parameter ratio - p = _get_order(cube) - XYZ = cube[p[0]] * sc + p = _get_order(cube_) + XYZ = cube_[p[0]] * sc # intercept all the points along the z-axis - if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-300): + if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-16): ball = np.array([0.0, 0.0, np.sqrt(6.0/np.pi) * XYZ[2]]) else: order = [1,0] if np.abs(XYZ[1]) <= np.abs(XYZ[0]) else [0,1] @@ -102,15 +103,16 @@ def ball_to_cube(ball): https://doi.org/10.1088/0965-0393/22/7/075013 """ - rs = np.linalg.norm(ball) + ball_ = ball/np.linalg.norm(ball) if np.isclose(np.linalg.norm(ball),R1) else ball + rs = np.linalg.norm(ball_) if rs > R1: raise ValueError - if np.allclose(ball,0.0,rtol=0.0,atol=1.0e-300): + if np.allclose(ball_,0.0,rtol=0.0,atol=1.0e-16): cube = np.zeros(3) else: - p = _get_order(ball) - xyz3 = ball[p[0]] + p = _get_order(ball_) + xyz3 = ball_[p[0]] # inverse M_3 xyz2 = xyz3[0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[2])) ) @@ -118,7 +120,7 @@ def ball_to_cube(ball): # inverse M_2 qxy = np.sum(xyz2**2) - if np.isclose(qxy,0.0,rtol=0.0,atol=1.0e-300): + if np.isclose(qxy,0.0,rtol=0.0,atol=1.0e-16): Tinv = np.zeros(2) else: q2 = qxy + np.max(np.abs(xyz2))**2 From b6f5548d8ab27a9d7284bfbaff5be4ab0cfa319c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 12:23:28 +0200 Subject: [PATCH 023/186] correct normalization at the corners --- python/damask/_Lambert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/_Lambert.py b/python/damask/_Lambert.py index 26bc67b84..d9ad55f6e 100644 --- a/python/damask/_Lambert.py +++ b/python/damask/_Lambert.py @@ -103,7 +103,7 @@ def ball_to_cube(ball): https://doi.org/10.1088/0965-0393/22/7/075013 """ - ball_ = ball/np.linalg.norm(ball) if np.isclose(np.linalg.norm(ball),R1) else ball + ball_ = ball/np.linalg.norm(ball)*R1 if np.isclose(np.linalg.norm(ball),R1) else ball rs = np.linalg.norm(ball_) if rs > R1: raise ValueError From 8f88480790eb5680950400cf13186903b298a485 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 12:59:34 +0200 Subject: [PATCH 024/186] better readable error messages --- python/damask/_Lambert.py | 4 ++-- python/damask/_rotation.py | 25 ++++++++++++------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/python/damask/_Lambert.py b/python/damask/_Lambert.py index d9ad55f6e..133c33cca 100644 --- a/python/damask/_Lambert.py +++ b/python/damask/_Lambert.py @@ -53,7 +53,7 @@ def cube_to_ball(cube): """ cube_ = np.clip(cube,None,np.pi**(2./3.) * 0.5) if np.isclose(np.abs(np.max(cube)),np.pi**(2./3.) * 0.5) else cube if np.abs(np.max(cube_))>np.pi**(2./3.) * 0.5: - raise ValueError + raise ValueError('Coordinate outside of the cube: {} {} {}.'.format(*cube)) # transform to the sphere grid via the curved square, and intercept the zero point if np.allclose(cube_,0.0,rtol=0.0,atol=1.0e-16): @@ -106,7 +106,7 @@ def ball_to_cube(ball): ball_ = ball/np.linalg.norm(ball)*R1 if np.isclose(np.linalg.norm(ball),R1) else ball rs = np.linalg.norm(ball_) if rs > R1: - raise ValueError + raise ValueError('Coordinate outside of the sphere: {} {} {}.'.format(*ball)) if np.allclose(ball_,0.0,rtol=0.0,atol=1.0e-16): cube = np.zeros(3) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index bea7aa5e6..1a52df4ba 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -262,9 +262,9 @@ class Rotation: if acceptHomomorph: qu *= -1. else: - raise ValueError('Quaternion has negative first component.\n{}'.format(qu[0])) + raise ValueError('Quaternion has negative first component: {}.'.format(qu[0])) if not np.isclose(np.linalg.norm(qu), 1.0): - raise ValueError('Quaternion is not of unit length.\n{} {} {} {}'.format(*qu)) + raise ValueError('Quaternion is not of unit length: {} {} {} {}.'.format(*qu)) return Rotation(qu) @@ -276,7 +276,7 @@ class Rotation: else np.array(eulers,dtype=float) eu = np.radians(eu) if degrees else eu if np.any(eu < 0.0) or np.any(eu > 2.0*np.pi) or eu[1] > np.pi: - raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π].\n{} {} {}.'.format(*eu)) + raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π]: {} {} {}.'.format(*eu)) return Rotation(Rotation.eu2qu(eu)) @@ -292,9 +292,9 @@ class Rotation: if degrees: ax[ 3] = np.radians(ax[3]) if normalise: ax[0:3] /= np.linalg.norm(ax[0:3]) if ax[3] < 0.0 or ax[3] > np.pi: - raise ValueError('Axis angle rotation angle outside of [0..π].\n{}'.format(ax[3])) + raise ValueError('Axis angle rotation angle outside of [0..π]: {}.'.format(ax[3])) if not np.isclose(np.linalg.norm(ax[0:3]), 1.0): - raise ValueError('Axis angle rotation axis is not of unit length.\n{} {} {}'.format(*ax[0:3])) + raise ValueError('Axis angle rotation axis is not of unit length: {} {} {}.'.format(*ax[0:3])) return Rotation(Rotation.ax2qu(ax)) @@ -312,11 +312,11 @@ class Rotation: (U,S,Vh) = np.linalg.svd(om) # singular value decomposition om = np.dot(U,Vh) if not np.isclose(np.linalg.det(om),1.0): - raise ValueError('matrix is not a proper rotation.\n{}'.format(om)) + raise ValueError('matrix is not a proper rotation: {}.'.format(om)) if not np.isclose(np.dot(om[0],om[1]), 0.0) \ or not np.isclose(np.dot(om[1],om[2]), 0.0) \ or not np.isclose(np.dot(om[2],om[0]), 0.0): - raise ValueError('matrix is not orthogonal.\n{}'.format(om)) + raise ValueError('matrix is not orthogonal: {}.'.format(om)) return Rotation(Rotation.om2qu(om)) @@ -336,9 +336,9 @@ class Rotation: if P > 0: ro[0:3] *= -1 # convert from P=1 to P=-1 if normalise: ro[0:3] /= np.linalg.norm(ro[0:3]) if not np.isclose(np.linalg.norm(ro[0:3]), 1.0): - raise ValueError('Rodrigues rotation axis is not of unit length.\n{} {} {}'.format(*ro[0:3])) + raise ValueError('Rodrigues rotation axis is not of unit length: {} {} {}.'.format(*ro[0:3])) if ro[3] < 0.0: - raise ValueError('Rodrigues rotation angle not positive.\n{}'.format(ro[3])) + raise ValueError('Rodrigues rotation angle not positive: {}.'.format(ro[3])) return Rotation(Rotation.ro2qu(ro)) @@ -383,7 +383,7 @@ class Rotation: """ if not all(isinstance(item, Rotation) for item in rotations): - raise TypeError("Only instances of Rotation can be averaged.") + raise TypeError('Only instances of Rotation can be averaged.') N = len(rotations) if not weights: @@ -503,11 +503,10 @@ class Rotation: @staticmethod def qu2ho(qu): """Quaternion to homochoric vector.""" - omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) - - if iszero(omega): + if np.isclose(qu[0],1.0): ho = np.array([ 0.0, 0.0, 0.0 ]) else: + omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) ho = np.array([qu[1], qu[2], qu[3]]) f = 0.75 * ( omega - np.sin(omega) ) ho = ho/np.linalg.norm(ho) * f**(1./3.) From 10d5b2e791451931f91551f0ba686c7dce1d9952 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 13:41:46 +0200 Subject: [PATCH 025/186] testing some special cases --- python/tests/test_Rotation.py | 64 ++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index c545a7172..a7fa47302 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -4,13 +4,39 @@ import pytest import numpy as np from damask import Rotation - + n = 1000 @pytest.fixture def default(): """A set of n random rotations.""" - return [Rotation.fromRandom() for r in range(n)] + specials =[np.array([ 1.0, 0.0, 0.0, 0.0]), + #----------------------------------------------- + np.array([ 1.0, 1.0, 0.0, 0.0])*np.sqrt(2.)*.5, + np.array([ 1.0, 0.0, 1.0, 0.0])*np.sqrt(2.)*.5, + np.array([ 1.0, 0.0, 0.0, 1.0])*np.sqrt(2.)*.5, + np.array([ 0.0, 1.0, 1.0, 0.0])*np.sqrt(2.)*.5, + np.array([ 0.0, 1.0, 0.0, 1.0])*np.sqrt(2.)*.5, + np.array([ 0.0, 0.0, 1.0, 1.0])*np.sqrt(2.)*.5, + #----------------------------------------------- + np.array([ 1.0,-1.0, 0.0, 0.0])*np.sqrt(2.)*.5, + np.array([ 1.0, 0.0,-1.0, 0.0])*np.sqrt(2.)*.5, + np.array([ 1.0, 0.0, 0.0,-1.0])*np.sqrt(2.)*.5, + np.array([ 0.0, 1.0,-1.0, 0.0])*np.sqrt(2.)*.5, + np.array([ 0.0, 1.0, 0.0,-1.0])*np.sqrt(2.)*.5, + np.array([ 0.0, 0.0, 1.0,-1.0])*np.sqrt(2.)*.5, + #----------------------------------------------- + np.array([ 0.0, 1.0,-1.0, 0.0])*np.sqrt(2.)*.5, + np.array([ 0.0, 1.0, 0.0,-1.0])*np.sqrt(2.)*.5, + np.array([ 0.0, 0.0, 1.0,-1.0])*np.sqrt(2.)*.5, + #----------------------------------------------- + np.array([ 0.0,-1.0,-1.0, 0.0])*np.sqrt(2.)*.5, + np.array([ 0.0,-1.0, 0.0,-1.0])*np.sqrt(2.)*.5, + np.array([ 0.0, 0.0,-1.0,-1.0])*np.sqrt(2.)*.5, + #----------------------------------------------- + ] + return [Rotation.fromQuaternion(s) for s in specials] + \ + [Rotation.fromRandom() for r in range(n-len(specials))] @pytest.fixture def reference_dir(reference_dir_base): @@ -22,35 +48,41 @@ class TestRotation: def test_Eulers(self,default): for rot in default: - assert np.allclose(rot.asQuaternion(), - Rotation.fromEulers(rot.asEulers()).asQuaternion()) + c = Rotation.fromEulers(rot.asEulers()) + ok = np.allclose(rot.asQuaternion(),c.asQuaternion()) + if np.isclose(rot.asQuaternion()[0],0.0,atol=1.e-13,rtol=0.0): + ok = ok or np.allclose(rot.asQuaternion(),c.asQuaternion()*-1.) + assert ok def test_AxisAngle(self,default): for rot in default: - assert np.allclose(rot.asEulers(), - Rotation.fromAxisAngle(rot.asAxisAngle()).asEulers()) + c = Rotation.fromAxisAngle(rot.asAxisAngle()) + assert np.allclose(rot.asEulers(),c.asEulers()) def test_Matrix(self,default): for rot in default: - assert np.allclose(rot.asAxisAngle(), - Rotation.fromMatrix(rot.asMatrix()).asAxisAngle()) + c = Rotation.fromMatrix(rot.asMatrix()) + ok = np.allclose(rot.asAxisAngle(),c.asAxisAngle()) + if np.isclose(rot.asAxisAngle()[3],np.pi): + ok = ok or np.allclose(rot.asAxisAngle(),c.asAxisAngle()*np.array([-1.,-1.,-1.,1.])) + assert ok def test_Rodriques(self,default): for rot in default: - assert np.allclose(rot.asMatrix(), - Rotation.fromRodrigues(rot.asRodrigues()).asMatrix()) + c = Rotation.fromRodrigues(rot.asRodrigues()) + assert np.allclose(rot.asMatrix(),c.asMatrix()) def test_Homochoric(self,default): for rot in default: - assert np.allclose(rot.asRodrigues(), - Rotation.fromHomochoric(rot.asHomochoric()).asRodrigues(),rtol=1.e-4) + c = Rotation.fromHomochoric(rot.asHomochoric()) + assert np.allclose(np.clip(rot.asRodrigues(),None,1.e9),np.clip(c.asRodrigues(),None,1.e9)) def test_Cubochoric(self,default): for rot in default: - assert np.allclose(rot.asHomochoric(), - Rotation.fromCubochoric(rot.asCubochoric()).asHomochoric()) + c = Rotation.fromCubochoric(rot.asCubochoric()) + assert np.allclose(rot.asHomochoric(),c.asHomochoric()) def test_Quaternion(self,default): for rot in default: - assert np.allclose(rot.asCubochoric(), - Rotation.fromQuaternion(rot.asQuaternion()).asCubochoric()) + c = Rotation.fromQuaternion(rot.asQuaternion()) + assert np.allclose(rot.asCubochoric(),c.asCubochoric()) From f365ae104d7a6648166f0a3d46905d2470df1d82 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 17:55:05 +0200 Subject: [PATCH 026/186] adjusting tolerances --- python/damask/_Lambert.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/damask/_Lambert.py b/python/damask/_Lambert.py index 133c33cca..a62f1922a 100644 --- a/python/damask/_Lambert.py +++ b/python/damask/_Lambert.py @@ -51,7 +51,7 @@ def cube_to_ball(cube): https://doi.org/10.1088/0965-0393/22/7/075013 """ - cube_ = np.clip(cube,None,np.pi**(2./3.) * 0.5) if np.isclose(np.abs(np.max(cube)),np.pi**(2./3.) * 0.5) else cube + cube_ = np.clip(cube,None,np.pi**(2./3.) * 0.5) if np.isclose(np.abs(np.max(cube)),np.pi**(2./3.) * 0.5,atol=1e-6) else cube if np.abs(np.max(cube_))>np.pi**(2./3.) * 0.5: raise ValueError('Coordinate outside of the cube: {} {} {}.'.format(*cube)) @@ -103,9 +103,9 @@ def ball_to_cube(ball): https://doi.org/10.1088/0965-0393/22/7/075013 """ - ball_ = ball/np.linalg.norm(ball)*R1 if np.isclose(np.linalg.norm(ball),R1) else ball + ball_ = ball/np.linalg.norm(ball)*R1 if np.isclose(np.linalg.norm(ball),R1,atol=1e-6) else ball rs = np.linalg.norm(ball_) - if rs > R1: + if rs > R1 and not np.isclose(rs,R1): raise ValueError('Coordinate outside of the sphere: {} {} {}.'.format(*ball)) if np.allclose(ball_,0.0,rtol=0.0,atol=1.0e-16): From 1ba01ba0db73831cc5f6453456b073812e0d2e68 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 18:15:50 +0200 Subject: [PATCH 027/186] adjusting tolerances --- python/damask/_rotation.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 1a52df4ba..1325c3b3e 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -459,16 +459,16 @@ class Rotation: q03 = qu[0]**2+qu[3]**2 q12 = qu[1]**2+qu[2]**2 chi = np.sqrt(q03*q12) - - if iszero(chi): - eu = np.array([np.arctan2(-P*2.0*qu[0]*qu[3],qu[0]**2-qu[3]**2), 0.0, 0.0]) if iszero(q12) else \ - np.array([np.arctan2(2.0*qu[1]*qu[2],qu[1]**2-qu[2]**2), np.pi, 0.0]) + if np.abs(chi)< 1.e-6: + eu = np.array([np.arctan2(-P*2.0*qu[0]*qu[3],qu[0]**2-qu[3]**2), 0.0, 0.0]) if np.abs(q12)< 1.e-6 else \ + np.array([np.arctan2( 2.0*qu[1]*qu[2],qu[1]**2-qu[2]**2), np.pi, 0.0]) else: eu = np.array([np.arctan2((-P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-P*qu[0]*qu[1]-qu[2]*qu[3])*chi ), np.arctan2( 2.0*chi, q03-q12 ), np.arctan2(( P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-P*qu[0]*qu[1]+qu[2]*qu[3])*chi )]) # reduce Euler angles to definition range, i.e a lower limit of 0.0 + eu[np.abs(eu)<1.e-6] = 0.0 eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) return eu @@ -481,7 +481,7 @@ class Rotation: """ if iszero(qu[1]**2+qu[2]**2+qu[3]**2): # set axis to [001] if the angle is 0/360 ax = [ 0.0, 0.0, 1.0, 0.0 ] - elif not iszero(qu[0]): + elif np.abs(qu[0]) > 1.e-6: s = np.sign(qu[0])/np.sqrt(qu[1]**2+qu[2]**2+qu[3]**2) omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) ax = [ qu[1]*s, qu[2]*s, qu[3]*s, omega ] @@ -498,6 +498,7 @@ class Rotation: s = np.linalg.norm([qu[1],qu[2],qu[3]]) ro = [0.0,0.0,P,0.0] if iszero(s) else \ [ qu[1]/s, qu[2]/s, qu[3]/s, np.tan(np.arccos(np.clip(qu[0],-1.0,1.0)))] + return np.array(ro) @staticmethod @@ -531,7 +532,7 @@ class Rotation: @staticmethod def om2eu(om): """Rotation matrix to Bunge-Euler angles.""" - if abs(om[2,2]) < 1.0: + if not np.isclose(np.abs(om[2,2]),1.0,1.e-4): zeta = 1.0/np.sqrt(1.0-om[2,2]**2) eu = np.array([np.arctan2(om[2,0]*zeta,-om[2,1]*zeta), np.arccos(om[2,2]), @@ -540,6 +541,7 @@ class Rotation: eu = np.array([np.arctan2( om[0,1],om[0,0]), np.pi*0.5*(1-om[2,2]),0.0]) # following the paper, not the reference implementation # reduce Euler angles to definition range, i.e a lower limit of 0.0 + eu[np.abs(eu)<1.e-6] = 0.0 eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) return eu @@ -552,7 +554,7 @@ class Rotation: t = 0.5*(om.trace() -1.0) ax[3] = np.arccos(np.clip(t,-1.0,1.0)) - if iszero(ax[3]): + if np.abs(ax[3])<1.e-6: ax = [ 0.0, 0.0, 1.0, 0.0] else: w,vr = np.linalg.eig(om) @@ -560,7 +562,7 @@ class Rotation: i = np.where(np.isclose(w,1.0+0.0j))[0][0] ax[0:3] = np.real(vr[0:3,i]) diagDelta = np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) - ax[0:3] = np.where(iszero(diagDelta), ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) + ax[0:3] = np.where(np.abs(diagDelta)<1.e-6, ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) return np.array(ax) @staticmethod @@ -603,7 +605,7 @@ class Rotation: [-c[0]*s[2]-s[0]*c[2]*c[1], -s[0]*s[2]+c[0]*c[2]*c[1], +c[2]*s[1]], [+s[0]*s[1], -c[0]*s[1], +c[1] ]]) - om[np.where(iszero(om))] = 0.0 + om[np.abs(om)<1.e-6] = 0.0 return om @staticmethod @@ -616,7 +618,7 @@ class Rotation: alpha = np.pi if iszero(np.cos(sigma)) else \ 2.0*np.arctan(tau/np.cos(sigma)) - if iszero(alpha): + if np.abs(alpha)<1.e-6: ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) else: ax = -P/tau * np.array([ t*np.cos(delta), t*np.sin(delta), np.sin(sigma) ]) # passive axis angle pair so a minus sign in front @@ -651,7 +653,7 @@ class Rotation: @staticmethod def ax2qu(ax): """Axis angle pair to quaternion.""" - if iszero(ax[3]): + if np.abs(ax[3])<1.e-6: qu = np.array([ 1.0, 0.0, 0.0, 0.0 ]) else: c = np.cos(ax[3]*0.5) @@ -681,7 +683,7 @@ class Rotation: @staticmethod def ax2ro(ax): """Axis angle pair to Rodrigues-Frank vector.""" - if iszero(ax[3]): + if np.abs(ax[3])<1.e-6: ro = [ 0.0, 0.0, P, 0.0 ] else: ro = [ax[0], ax[1], ax[2]] From 3cd8f3d9a0641e46333493e9c5550882553934b0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 18:38:57 +0200 Subject: [PATCH 028/186] testing special orientations with scatter --- python/tests/test_Rotation.py | 139 ++++++++++++++++++++++++---------- 1 file changed, 101 insertions(+), 38 deletions(-) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index a7fa47302..1f69f2025 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -6,35 +6,77 @@ import numpy as np from damask import Rotation n = 1000 +atol=1.e-5 +scatter=1.e-9 @pytest.fixture def default(): """A set of n random rotations.""" - specials =[np.array([ 1.0, 0.0, 0.0, 0.0]), + specials = np.array( + [np.array([ 1.0, 0.0, 0.0, 0.0]), #----------------------------------------------- - np.array([ 1.0, 1.0, 0.0, 0.0])*np.sqrt(2.)*.5, - np.array([ 1.0, 0.0, 1.0, 0.0])*np.sqrt(2.)*.5, - np.array([ 1.0, 0.0, 0.0, 1.0])*np.sqrt(2.)*.5, - np.array([ 0.0, 1.0, 1.0, 0.0])*np.sqrt(2.)*.5, - np.array([ 0.0, 1.0, 0.0, 1.0])*np.sqrt(2.)*.5, - np.array([ 0.0, 0.0, 1.0, 1.0])*np.sqrt(2.)*.5, + np.array([0.0, 1.0, 0.0, 0.0]), + np.array([0.0, 0.0, 1.0, 0.0]), + np.array([0.0, 0.0, 0.0, 1.0]), + np.array([0.0,-1.0, 0.0, 0.0]), + np.array([0.0, 0.0,-1.0, 0.0]), + np.array([0.0, 0.0, 0.0,-1.0]), #----------------------------------------------- - np.array([ 1.0,-1.0, 0.0, 0.0])*np.sqrt(2.)*.5, - np.array([ 1.0, 0.0,-1.0, 0.0])*np.sqrt(2.)*.5, - np.array([ 1.0, 0.0, 0.0,-1.0])*np.sqrt(2.)*.5, - np.array([ 0.0, 1.0,-1.0, 0.0])*np.sqrt(2.)*.5, - np.array([ 0.0, 1.0, 0.0,-1.0])*np.sqrt(2.)*.5, - np.array([ 0.0, 0.0, 1.0,-1.0])*np.sqrt(2.)*.5, + np.array([1.0, 1.0, 0.0, 0.0])/np.sqrt(2.), + np.array([1.0, 0.0, 1.0, 0.0])/np.sqrt(2.), + np.array([1.0, 0.0, 0.0, 1.0])/np.sqrt(2.), + np.array([0.0, 1.0, 1.0, 0.0])/np.sqrt(2.), + np.array([0.0, 1.0, 0.0, 1.0])/np.sqrt(2.), + np.array([0.0, 0.0, 1.0, 1.0])/np.sqrt(2.), #----------------------------------------------- - np.array([ 0.0, 1.0,-1.0, 0.0])*np.sqrt(2.)*.5, - np.array([ 0.0, 1.0, 0.0,-1.0])*np.sqrt(2.)*.5, - np.array([ 0.0, 0.0, 1.0,-1.0])*np.sqrt(2.)*.5, + np.array([1.0,-1.0, 0.0, 0.0])/np.sqrt(2.), + np.array([1.0, 0.0,-1.0, 0.0])/np.sqrt(2.), + np.array([1.0, 0.0, 0.0,-1.0])/np.sqrt(2.), + np.array([0.0, 1.0,-1.0, 0.0])/np.sqrt(2.), + np.array([0.0, 1.0, 0.0,-1.0])/np.sqrt(2.), + np.array([0.0, 0.0, 1.0,-1.0])/np.sqrt(2.), #----------------------------------------------- - np.array([ 0.0,-1.0,-1.0, 0.0])*np.sqrt(2.)*.5, - np.array([ 0.0,-1.0, 0.0,-1.0])*np.sqrt(2.)*.5, - np.array([ 0.0, 0.0,-1.0,-1.0])*np.sqrt(2.)*.5, + np.array([0.0, 1.0,-1.0, 0.0])/np.sqrt(2.), + np.array([0.0, 1.0, 0.0,-1.0])/np.sqrt(2.), + np.array([0.0, 0.0, 1.0,-1.0])/np.sqrt(2.), #----------------------------------------------- - ] + np.array([0.0,-1.0,-1.0, 0.0])/np.sqrt(2.), + np.array([0.0,-1.0, 0.0,-1.0])/np.sqrt(2.), + np.array([0.0, 0.0,-1.0,-1.0])/np.sqrt(2.), + #----------------------------------------------- + np.array([1.0, 1.0, 1.0, 0.0])/np.sqrt(3.), + np.array([1.0, 1.0, 0.0, 1.0])/np.sqrt(3.), + np.array([1.0, 0.0, 1.0, 1.0])/np.sqrt(3.), + np.array([1.0,-1.0, 1.0, 0.0])/np.sqrt(3.), + np.array([1.0,-1.0, 0.0, 1.0])/np.sqrt(3.), + np.array([1.0, 0.0,-1.0, 1.0])/np.sqrt(3.), + np.array([1.0, 1.0,-1.0, 0.0])/np.sqrt(3.), + np.array([1.0, 1.0, 0.0,-1.0])/np.sqrt(3.), + np.array([1.0, 0.0, 1.0,-1.0])/np.sqrt(3.), + np.array([1.0,-1.0,-1.0, 0.0])/np.sqrt(3.), + np.array([1.0,-1.0, 0.0,-1.0])/np.sqrt(3.), + np.array([1.0, 0.0,-1.0,-1.0])/np.sqrt(3.), + #----------------------------------------------- + np.array([0.0, 1.0, 1.0, 1.0])/np.sqrt(3.), + np.array([0.0, 1.0,-1.0, 1.0])/np.sqrt(3.), + np.array([0.0, 1.0, 1.0,-1.0])/np.sqrt(3.), + np.array([0.0,-1.0, 1.0, 1.0])/np.sqrt(3.), + np.array([0.0,-1.0,-1.0, 1.0])/np.sqrt(3.), + np.array([0.0,-1.0, 1.0,-1.0])/np.sqrt(3.), + np.array([0.0,-1.0,-1.0,-1.0])/np.sqrt(3.), + #----------------------------------------------- + np.array([1.0, 1.0, 1.0, 1.0])/2., + np.array([1.0,-1.0, 1.0, 1.0])/2., + np.array([1.0, 1.0,-1.0, 1.0])/2., + np.array([1.0, 1.0, 1.0,-1.0])/2., + np.array([1.0,-1.0,-1.0, 1.0])/2., + np.array([1.0,-1.0, 1.0,-1.0])/2., + np.array([1.0, 1.0,-1.0,-1.0])/2., + np.array([1.0,-1.0,-1.0,-1.0])/2., + ]) + specials += np.broadcast_to(np.random.rand(4)*scatter,specials.shape) + specials /= np.linalg.norm(specials,axis=1).reshape(-1,1) + specials[specials[:,0]<0]*=-1 return [Rotation.fromQuaternion(s) for s in specials] + \ [Rotation.fromRandom() for r in range(n-len(specials))] @@ -48,41 +90,62 @@ class TestRotation: def test_Eulers(self,default): for rot in default: - c = Rotation.fromEulers(rot.asEulers()) - ok = np.allclose(rot.asQuaternion(),c.asQuaternion()) - if np.isclose(rot.asQuaternion()[0],0.0,atol=1.e-13,rtol=0.0): - ok = ok or np.allclose(rot.asQuaternion(),c.asQuaternion()*-1.) + m = rot.asQuaternion() + o = Rotation.fromEulers(rot.asEulers()).asQuaternion() + ok = np.allclose(m,o,atol=atol) + if np.isclose(rot.asQuaternion()[0],0.0,atol=atol): + ok = ok or np.allclose(m*-1.,o,atol=atol) + print(m,o,rot.asQuaternion()) assert ok def test_AxisAngle(self,default): for rot in default: - c = Rotation.fromAxisAngle(rot.asAxisAngle()) - assert np.allclose(rot.asEulers(),c.asEulers()) + m = rot.asEulers() + o = Rotation.fromAxisAngle(rot.asAxisAngle()).asEulers() + u = np.array([np.pi*2,np.pi,np.pi*2]) + ok = np.allclose(m,o,atol=atol) + ok = ok or np.allclose(np.where(np.isclose(m,u),m-u,m),np.where(np.isclose(o,u),o-u,o),atol=atol) + if np.isclose(m[1],0.0,atol=atol) or np.isclose(m[1],np.pi,atol=atol): + sum_phi = np.unwrap([m[0]+m[2],o[0]+o[2]]) + ok = ok or np.isclose(sum_phi[0],sum_phi[1],atol=atol) + print(m,o,rot.asQuaternion()) + assert ok def test_Matrix(self,default): for rot in default: - c = Rotation.fromMatrix(rot.asMatrix()) - ok = np.allclose(rot.asAxisAngle(),c.asAxisAngle()) - if np.isclose(rot.asAxisAngle()[3],np.pi): - ok = ok or np.allclose(rot.asAxisAngle(),c.asAxisAngle()*np.array([-1.,-1.,-1.,1.])) + m = rot.asAxisAngle() + o = Rotation.fromAxisAngle(rot.asAxisAngle()).asAxisAngle() + ok = np.allclose(m,o,atol=atol) + if np.isclose(m[3],np.pi,atol=atol): + ok = ok or np.allclose(m*np.array([-1.,-1.,-1.,1.]),o,atol=atol) + print(m,o,rot.asQuaternion()) assert ok def test_Rodriques(self,default): for rot in default: - c = Rotation.fromRodrigues(rot.asRodrigues()) - assert np.allclose(rot.asMatrix(),c.asMatrix()) + m = rot.asMatrix() + o = Rotation.fromRodrigues(rot.asRodrigues()).asMatrix() + print(m,o) + assert np.allclose(m,o,atol=atol) def test_Homochoric(self,default): for rot in default: - c = Rotation.fromHomochoric(rot.asHomochoric()) - assert np.allclose(np.clip(rot.asRodrigues(),None,1.e9),np.clip(c.asRodrigues(),None,1.e9)) + m = rot.asRodrigues() + o = Rotation.fromHomochoric(rot.asHomochoric()).asRodrigues() + ok = np.allclose(np.clip(m,None,1.e9),np.clip(o,None,1.e9),atol=atol) + print(m,o,rot.asQuaternion()) + ok = ok or np.isclose(m[3],0.0,atol=atol) def test_Cubochoric(self,default): for rot in default: - c = Rotation.fromCubochoric(rot.asCubochoric()) - assert np.allclose(rot.asHomochoric(),c.asHomochoric()) + m = rot.asHomochoric() + o = Rotation.fromCubochoric(rot.asCubochoric()).asHomochoric() + print(m,o,rot.asQuaternion()) + assert np.allclose(m,o,atol=atol*1e2) def test_Quaternion(self,default): for rot in default: - c = Rotation.fromQuaternion(rot.asQuaternion()) - assert np.allclose(rot.asCubochoric(),c.asCubochoric()) + m = rot.asCubochoric() + o = Rotation.fromQuaternion(rot.asQuaternion()).asCubochoric() + print(m,o,rot.asQuaternion()) + assert np.allclose(m,o,atol=atol) From 59e0041fd7a5f323f5656ca0ecff0b5e6aad4de5 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 19:30:50 +0200 Subject: [PATCH 029/186] more scatter, slightly reduced tolerance --- python/tests/test_Rotation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 1f69f2025..fc88e4130 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -6,8 +6,8 @@ import numpy as np from damask import Rotation n = 1000 -atol=1.e-5 -scatter=1.e-9 +atol=1.e-4 +scatter=1.e-2 @pytest.fixture def default(): From 2a063b3bb5888c82d134406e9796723fe10734dc Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 20:23:05 +0200 Subject: [PATCH 030/186] relaxed tolerance not needed --- python/tests/test_Rotation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index fc88e4130..cec0ce22c 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -141,7 +141,7 @@ class TestRotation: m = rot.asHomochoric() o = Rotation.fromCubochoric(rot.asCubochoric()).asHomochoric() print(m,o,rot.asQuaternion()) - assert np.allclose(m,o,atol=atol*1e2) + assert np.allclose(m,o,atol=atol) def test_Quaternion(self,default): for rot in default: From 62ddfe098cebef167fa757e632f8238959e891a6 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 20:30:36 +0200 Subject: [PATCH 031/186] fixed test --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 62bd5ede5..377e4f97a 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 62bd5ede5260cd4e0e3d1c3930c474c1e045aeef +Subproject commit 377e4f97a31ca1aa39a0645430c82bed40158001 From 464620b796d89d2318b06fdde7530207a6e3f783 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 20:50:42 +0200 Subject: [PATCH 032/186] vectorized conversion from ax(is angle) --- python/damask/_rotation.py | 87 +++++++++++++++++++++++++---------- python/tests/test_Rotation.py | 14 +++++- 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 1325c3b3e..a2d26949d 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -653,27 +653,50 @@ class Rotation: @staticmethod def ax2qu(ax): """Axis angle pair to quaternion.""" - if np.abs(ax[3])<1.e-6: - qu = np.array([ 1.0, 0.0, 0.0, 0.0 ]) + if len(ax.shape) == 1: + if np.abs(ax[3])<1.e-6: + qu = np.array([ 1.0, 0.0, 0.0, 0.0 ]) + else: + c = np.cos(ax[3]*0.5) + s = np.sin(ax[3]*0.5) + qu = np.array([ c, ax[0]*s, ax[1]*s, ax[2]*s ]) + return qu else: - c = np.cos(ax[3]*0.5) - s = np.sin(ax[3]*0.5) - qu = np.array([ c, ax[0]*s, ax[1]*s, ax[2]*s ]) - return qu + c = np.cos(ax[...,3:4]*.5) + s = np.sin(ax[...,3:4]*.5) + qu = np.where(np.abs(ax[...,3:4])<1.e-12, + [1.0, 0.0, 0.0, 0.0], + np.block([c, ax[...,:3]*s])) + return qu @staticmethod def ax2om(ax): """Axis angle pair to rotation matrix.""" - c = np.cos(ax[3]) - s = np.sin(ax[3]) - omc = 1.0-c - om=np.diag(ax[0:3]**2*omc + c) + if len(ax.shape) == 1: + c = np.cos(ax[3]) + s = np.sin(ax[3]) + omc = 1.0-c + om=np.diag(ax[0:3]**2*omc + c) - for idx in [[0,1,2],[1,2,0],[2,0,1]]: - q = omc*ax[idx[0]] * ax[idx[1]] - om[idx[0],idx[1]] = q + s*ax[idx[2]] - om[idx[1],idx[0]] = q - s*ax[idx[2]] - return om if P < 0.0 else om.T + for idx in [[0,1,2],[1,2,0],[2,0,1]]: + q = omc*ax[idx[0]] * ax[idx[1]] + om[idx[0],idx[1]] = q + s*ax[idx[2]] + om[idx[1],idx[0]] = q - s*ax[idx[2]] + return om if P < 0.0 else om.T + else: + c = np.cos(ax[...,3:4]) + s = np.sin(ax[...,3:4]) + omc = 1. -c + ax = np.block([c+omc*ax[...,0:1]**2, + omc*ax[...,0:1]*ax[...,1:2] + s*ax[...,2:3], + omc*ax[...,0:1]*ax[...,2:3] - s*ax[...,1:2], + omc*ax[...,0:1]*ax[...,1:2] - s*ax[...,2:3], + c+omc*ax[...,1:2]**2, + omc*ax[...,1:2]*ax[...,2:3] + s*ax[...,0:1], + omc*ax[...,0:1]*ax[...,2:3] + s*ax[...,1:2], + omc*ax[...,1:2]*ax[...,2:3] - s*ax[...,0:1], + c+omc*ax[...,2:3]**2]).reshape(ax.shape[:-1]+(3,3)) + return ax @staticmethod def ax2eu(ax): @@ -683,21 +706,35 @@ class Rotation: @staticmethod def ax2ro(ax): """Axis angle pair to Rodrigues-Frank vector.""" - if np.abs(ax[3])<1.e-6: - ro = [ 0.0, 0.0, P, 0.0 ] + if len(ax.shape) == 1: + if np.abs(ax[3])<1.e-6: + ro = [ 0.0, 0.0, P, 0.0 ] + else: + ro = [ax[0], ax[1], ax[2]] + # 180 degree case + ro += [np.inf] if np.isclose(ax[3],np.pi,atol=1.0e-15,rtol=0.0) else \ + [np.tan(ax[3]*0.5)] + return np.array(ro) else: - ro = [ax[0], ax[1], ax[2]] - # 180 degree case - ro += [np.inf] if np.isclose(ax[3],np.pi,atol=1.0e-15,rtol=0.0) else \ - [np.tan(ax[3]*0.5)] - return np.array(ro) + ro = np.block([ax[...,:3], + np.where(np.isclose(ax[...,3:4],np.pi,atol=1.e-15,rtol=.0), + np.inf, + np.tan(ax[...,3:4]*0.5)) + ]) + ro[np.abs(ax[...,3])<1.e-6] = [.0,.0,P,.0] + return ro @staticmethod def ax2ho(ax): """Axis angle pair to homochoric vector.""" - f = (0.75 * ( ax[3] - np.sin(ax[3]) ))**(1.0/3.0) - ho = ax[0:3] * f - return ho + if len(ax.shape) == 1: + f = (0.75 * ( ax[3] - np.sin(ax[3]) ))**(1.0/3.0) + ho = ax[0:3] * f + return ho + else: + f = (0.75 * ( ax[...,3:4] - np.sin(ax[...,3:4]) ))**(1.0/3.0) + ho = ax[...,:3] * f + return ho @staticmethod def ax2cu(ax): diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index cec0ce22c..13c474ca7 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -78,7 +78,7 @@ def default(): specials /= np.linalg.norm(specials,axis=1).reshape(-1,1) specials[specials[:,0]<0]*=-1 return [Rotation.fromQuaternion(s) for s in specials] + \ - [Rotation.fromRandom() for r in range(n-len(specials))] + [Rotation.fromRandom() for _ in range(n-len(specials))] @pytest.fixture def reference_dir(reference_dir_base): @@ -149,3 +149,15 @@ class TestRotation: o = Rotation.fromQuaternion(rot.asQuaternion()).asCubochoric() print(m,o,rot.asQuaternion()) assert np.allclose(m,o,atol=atol) + + @pytest.mark.parametrize('conversion',[Rotation.ax2qu, + Rotation.ax2om, + Rotation.ax2ro, + Rotation.ax2ho, + ]) + def test_axisAngle_vectorization(self,default,conversion): + ax = np.array([rot.asAxisAngle() for rot in default]) + dev_null = conversion(ax.reshape(ax.shape[0]//2,-1,4)) + co = conversion(ax) + for a,c in zip(ax,co): + assert np.allclose(conversion(a),c) From da30fb8396e384d1012370df9023d722b1410514 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Apr 2020 23:11:48 +0200 Subject: [PATCH 033/186] qu(aternion) and eu(ler) vectorized and tested --- python/damask/_rotation.py | 265 ++++++++++++++++++++++++---------- python/tests/test_Rotation.py | 22 +++ 2 files changed, 208 insertions(+), 79 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index a2d26949d..9296f57b4 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -441,32 +441,68 @@ class Rotation: #---------- Quaternion ---------- @staticmethod def qu2om(qu): - """Quaternion to rotation matrix.""" - qq = qu[0]**2-(qu[1]**2 + qu[2]**2 + qu[3]**2) - om = np.diag(qq + 2.0*np.array([qu[1],qu[2],qu[3]])**2) + if len(qu.shape) == 1: + """Quaternion to rotation matrix.""" + qq = qu[0]**2-(qu[1]**2 + qu[2]**2 + qu[3]**2) + om = np.diag(qq + 2.0*np.array([qu[1],qu[2],qu[3]])**2) - om[1,0] = 2.0*(qu[2]*qu[1]+qu[0]*qu[3]) - om[0,1] = 2.0*(qu[1]*qu[2]-qu[0]*qu[3]) - om[2,1] = 2.0*(qu[3]*qu[2]+qu[0]*qu[1]) - om[1,2] = 2.0*(qu[2]*qu[3]-qu[0]*qu[1]) - om[0,2] = 2.0*(qu[1]*qu[3]+qu[0]*qu[2]) - om[2,0] = 2.0*(qu[3]*qu[1]-qu[0]*qu[2]) - return om if P > 0.0 else om.T + om[1,0] = 2.0*(qu[2]*qu[1]+qu[0]*qu[3]) + om[0,1] = 2.0*(qu[1]*qu[2]-qu[0]*qu[3]) + om[2,1] = 2.0*(qu[3]*qu[2]+qu[0]*qu[1]) + om[1,2] = 2.0*(qu[2]*qu[3]-qu[0]*qu[1]) + om[0,2] = 2.0*(qu[1]*qu[3]+qu[0]*qu[2]) + om[2,0] = 2.0*(qu[3]*qu[1]-qu[0]*qu[2]) + return om if P > 0.0 else om.T + else: + qq = qu[...,0:1]**2-(qu[...,1:2]**2 + qu[...,2:3]**2 + qu[...,3:4]**2) + om = np.block([qq + 2.0*qu[...,1:2]**2, + 2.0*(qu[...,2:3]*qu[...,1:2]+qu[...,0:1]*qu[...,3:4]), + 2.0*(qu[...,3:4]*qu[...,1:2]-qu[...,0:1]*qu[...,2:3]), + 2.0*(qu[...,1:2]*qu[...,2:3]-qu[...,0:1]*qu[...,3:4]), + qq + 2.0*qu[...,2:3]**2, + 2.0*(qu[...,3:4]*qu[...,2:3]+qu[...,0:1]*qu[...,1:2]), + 2.0*(qu[...,1:2]*qu[...,3:4]+qu[...,0:1]*qu[...,2:3]), + 2.0*(qu[...,2:3]*qu[...,3:4]-qu[...,0:1]*qu[...,1:2]), + qq + 2.0*qu[...,3:4]**2, + ]).reshape(qu.shape[:-1]+(3,3)) + return om # TODO: TRANSPOSE FOR P = 1 @staticmethod def qu2eu(qu): """Quaternion to Bunge-Euler angles.""" - q03 = qu[0]**2+qu[3]**2 - q12 = qu[1]**2+qu[2]**2 - chi = np.sqrt(q03*q12) - if np.abs(chi)< 1.e-6: - eu = np.array([np.arctan2(-P*2.0*qu[0]*qu[3],qu[0]**2-qu[3]**2), 0.0, 0.0]) if np.abs(q12)< 1.e-6 else \ - np.array([np.arctan2( 2.0*qu[1]*qu[2],qu[1]**2-qu[2]**2), np.pi, 0.0]) + if len(qu.shape) == 1: + q03 = qu[0]**2+qu[3]**2 + q12 = qu[1]**2+qu[2]**2 + chi = np.sqrt(q03*q12) + if np.abs(q03)< 1.e-6: + eu = np.array([np.arctan2(-P*2.0*qu[0]*qu[3],qu[0]**2-qu[3]**2), 0.0, 0.0]) + elif np.abs(q12)< 1.e-6: + eu = np.array([np.arctan2( 2.0*qu[1]*qu[2],qu[1]**2-qu[2]**2), np.pi, 0.0]) + else: + eu = np.array([np.arctan2((-P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-P*qu[0]*qu[1]-qu[2]*qu[3])*chi ), + np.arctan2( 2.0*chi, q03-q12 ), + np.arctan2(( P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-P*qu[0]*qu[1]+qu[2]*qu[3])*chi )]) else: - eu = np.array([np.arctan2((-P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-P*qu[0]*qu[1]-qu[2]*qu[3])*chi ), - np.arctan2( 2.0*chi, q03-q12 ), - np.arctan2(( P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-P*qu[0]*qu[1]+qu[2]*qu[3])*chi )]) + q02 = qu[...,0:1]*qu[...,2:3] + q13 = qu[...,1:2]*qu[...,3:4] + q01 = qu[...,0:1]*qu[...,1:2] + q23 = qu[...,2:3]*qu[...,3:4] + q03_s = qu[...,0:1]**2+qu[...,3:4]**2 + q12_s = qu[...,1:2]**2+qu[...,2:3]**2 + chi = np.sqrt(q03_s*q12_s) + eu = np.where(np.abs(q12_s) < 1.0e-6, + np.block([np.arctan2(-P*2.0*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2), + np.zeros(qu.shape[:-1]+(2,))]), + np.block([np.arctan2((-P*q02+q13)*chi, (-P*q01-q23)*chi), + np.arctan2( 2.0*chi, q03_s-q12_s ), + np.arctan2(( P*q02+q13)*chi, (-P*q01+q23)*chi)]) + ) + eu = np.where(np.abs(q03_s) < 1.0e-6, + np.block([np.arctan2( 2.0*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2), + np.ones( qu.shape[:-1]+(1,))*np.pi, + np.zeros(qu.shape[:-1]+(1,))]), + eu) # TODO: Where not needed # reduce Euler angles to definition range, i.e a lower limit of 0.0 eu[np.abs(eu)<1.e-6] = 0.0 eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) @@ -479,38 +515,66 @@ class Rotation: Modified version of the original formulation, should be numerically more stable """ - if iszero(qu[1]**2+qu[2]**2+qu[3]**2): # set axis to [001] if the angle is 0/360 - ax = [ 0.0, 0.0, 1.0, 0.0 ] - elif np.abs(qu[0]) > 1.e-6: - s = np.sign(qu[0])/np.sqrt(qu[1]**2+qu[2]**2+qu[3]**2) - omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) - ax = [ qu[1]*s, qu[2]*s, qu[3]*s, omega ] + if len(qu.shape) == 1: + if iszero(np.sum(qu[1:4]**2)): # set axis to [001] if the angle is 0/360 + ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) + elif np.abs(qu[0]) > 1.e-6: + s = np.sign(qu[0])/np.sqrt(qu[1]**2+qu[2]**2+qu[3]**2) + omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) + ax = ax = np.array([ qu[1]*s, qu[2]*s, qu[3]*s, omega ]) + else: + ax = ax = np.array([ qu[1], qu[2], qu[3], np.pi]) else: - ax = [ qu[1], qu[2], qu[3], np.pi] - return np.array(ax) + with np.errstate(divide='ignore'): + s = np.sign(qu[...,0:1])/np.sqrt(qu[...,1:2]**2+qu[...,2:3]**2+qu[...,3:4]**2) + omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) + + ax = np.where(qu[...,0:1] < 1.0e-6, + np.block([qu[...,1:4],np.ones(qu.shape[:-1]+(1,))*np.pi]), + np.block([qu[...,1:4]*s,omega])) + ax = np.where(np.expand_dims(np.sum(np.abs(qu[:,1:4])**2,axis=-1) < 1.0e-6,-1), + [0.0, 0.0, 1.0, 0.0], ax) # TODO: Where not needed + return ax + @staticmethod def qu2ro(qu): """Quaternion to Rodrigues-Frank vector.""" - if iszero(qu[0]): - ro = [qu[1], qu[2], qu[3], np.inf] + if len(qu.shape) == 1: + if iszero(qu[0]): + ro = np.array([qu[1], qu[2], qu[3], np.inf]) + else: + s = np.linalg.norm([qu[1],qu[2],qu[3]]) + ro = np.array([0.0,0.0,P,0.0] if iszero(s) else \ + [ qu[1]/s, qu[2]/s, qu[3]/s, np.tan(np.arccos(np.clip(qu[0],-1.0,1.0)))]) else: - s = np.linalg.norm([qu[1],qu[2],qu[3]]) - ro = [0.0,0.0,P,0.0] if iszero(s) else \ - [ qu[1]/s, qu[2]/s, qu[3]/s, np.tan(np.arccos(np.clip(qu[0],-1.0,1.0)))] - - return np.array(ro) + s = np.expand_dims(np.linalg.norm(qu[...,1:4],axis=1),-1) + ro = np.where(np.abs(s) < 1.0e-12, + [0.0,0.0,P,0.0], + np.block([qu[...,1:2]/s,qu[...,2:3]/s,qu[...,3:4]/s, + np.tan(np.arccos(np.clip(qu[:,0:1],-1.0,1.0))) + ]) + ) + ro = np.where(np.abs(qu[...,0:1]) < 1.0e-12, + np.block([qu[...,1:2], qu[...,2:3], qu[...,3:4], np.ones(qu.shape[:-1]+(1,))*np.inf]),ro) # TODO: Where not needed + return ro @staticmethod def qu2ho(qu): """Quaternion to homochoric vector.""" - if np.isclose(qu[0],1.0): - ho = np.array([ 0.0, 0.0, 0.0 ]) + if len(qu.shape) == 1: + if np.isclose(qu[0],1.0): + ho = np.zeros(3) + else: + omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) + ho = np.array([qu[1], qu[2], qu[3]]) + f = 0.75 * ( omega - np.sin(omega) ) + ho = ho/np.linalg.norm(ho) * f**(1./3.) else: - omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) - ho = np.array([qu[1], qu[2], qu[3]]) - f = 0.75 * ( omega - np.sin(omega) ) - ho = ho/np.linalg.norm(ho) * f**(1./3.) + omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) + ho = np.where(np.abs(omega) < 1.0e-12, + np.zeros(3), + qu[...,1:4]/np.linalg.norm(qu[...,1:4],axis=1).reshape(qu.shape[:-1]+(1,)) * (0.75*(omega - np.sin(omega)))**(1./3.)) return ho @staticmethod @@ -555,7 +619,7 @@ class Rotation: ax[3] = np.arccos(np.clip(t,-1.0,1.0)) if np.abs(ax[3])<1.e-6: - ax = [ 0.0, 0.0, 1.0, 0.0] + ax = np.array([ 0.0, 0.0, 1.0, 0.0]) else: w,vr = np.linalg.eig(om) # next, find the eigenvalue (1,0j) @@ -563,7 +627,7 @@ class Rotation: ax[0:3] = np.real(vr[0:3,i]) diagDelta = np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) ax[0:3] = np.where(np.abs(diagDelta)<1.e-6, ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) - return np.array(ax) + return ax @staticmethod def om2ro(om): @@ -585,57 +649,102 @@ class Rotation: @staticmethod def eu2qu(eu): """Bunge-Euler angles to quaternion.""" - ee = 0.5*eu - cPhi = np.cos(ee[1]) - sPhi = np.sin(ee[1]) - qu = np.array([ cPhi*np.cos(ee[0]+ee[2]), - -P*sPhi*np.cos(ee[0]-ee[2]), - -P*sPhi*np.sin(ee[0]-ee[2]), - -P*cPhi*np.sin(ee[0]+ee[2]) ]) - if qu[0] < 0.0: qu*=-1 + if len(eu.shape) == 1: + ee = 0.5*eu + cPhi = np.cos(ee[1]) + sPhi = np.sin(ee[1]) + qu = np.array([ cPhi*np.cos(ee[0]+ee[2]), + -P*sPhi*np.cos(ee[0]-ee[2]), + -P*sPhi*np.sin(ee[0]-ee[2]), + -P*cPhi*np.sin(ee[0]+ee[2]) ]) + if qu[0] < 0.0: qu*=-1 + else: + ee = 0.5*eu + cPhi = np.cos(ee[...,1:2]) + sPhi = np.sin(ee[...,1:2]) + qu = np.block([ cPhi*np.cos(ee[...,0:1]+ee[...,2:3]), + -P*sPhi*np.cos(ee[...,0:1]-ee[...,2:3]), + -P*sPhi*np.sin(ee[...,0:1]-ee[...,2:3]), + -P*cPhi*np.sin(ee[...,0:1]+ee[...,2:3])]) + qu[qu[...,0]<0.0]*=-1 return qu + @staticmethod def eu2om(eu): """Bunge-Euler angles to rotation matrix.""" - c = np.cos(eu) - s = np.sin(eu) + if len(eu.shape) == 1: + c = np.cos(eu) + s = np.sin(eu) - om = np.array([[+c[0]*c[2]-s[0]*s[2]*c[1], +s[0]*c[2]+c[0]*s[2]*c[1], +s[2]*s[1]], - [-c[0]*s[2]-s[0]*c[2]*c[1], -s[0]*s[2]+c[0]*c[2]*c[1], +c[2]*s[1]], - [+s[0]*s[1], -c[0]*s[1], +c[1] ]]) - - om[np.abs(om)<1.e-6] = 0.0 + om = np.array([[+c[0]*c[2]-s[0]*s[2]*c[1], +s[0]*c[2]+c[0]*s[2]*c[1], +s[2]*s[1]], + [-c[0]*s[2]-s[0]*c[2]*c[1], -s[0]*s[2]+c[0]*c[2]*c[1], +c[2]*s[1]], + [+s[0]*s[1], -c[0]*s[1], +c[1] ]]) + else: + c = np.cos(eu) + s = np.sin(eu) + om = np.block([+c[...,0:1]*c[...,2:3]-s[...,0:1]*s[...,2:3]*c[...,1:2], + +s[...,0:1]*c[...,2:3]+c[...,0:1]*s[...,2:3]*c[...,1:2], + +s[...,2:3]*s[...,1:2], + -c[...,0:1]*s[...,2:3]-s[...,0:1]*c[...,2:3]*c[...,1:2], + -s[...,0:1]*s[...,2:3]+c[...,0:1]*c[...,2:3]*c[...,1:2], + +c[...,2:3]*s[...,1:2], + +s[...,0:1]*s[...,1:2], + -c[...,0:1]*s[...,1:2], + +c[...,1:2] + ]).reshape(eu.shape[:-1]+(3,3)) + om[np.abs(om)<1.e-12] = 0.0 return om @staticmethod def eu2ax(eu): """Bunge-Euler angles to axis angle pair.""" - t = np.tan(eu[1]*0.5) - sigma = 0.5*(eu[0]+eu[2]) - delta = 0.5*(eu[0]-eu[2]) - tau = np.linalg.norm([t,np.sin(sigma)]) - alpha = np.pi if iszero(np.cos(sigma)) else \ - 2.0*np.arctan(tau/np.cos(sigma)) + if len(eu.shape) == 1: + t = np.tan(eu[1]*0.5) + sigma = 0.5*(eu[0]+eu[2]) + delta = 0.5*(eu[0]-eu[2]) + tau = np.linalg.norm([t,np.sin(sigma)]) + alpha = np.pi if iszero(np.cos(sigma)) else \ + 2.0*np.arctan(tau/np.cos(sigma)) - if np.abs(alpha)<1.e-6: - ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) + if np.abs(alpha)<1.e-6: + ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) + else: + ax = -P/tau * np.array([ t*np.cos(delta), t*np.sin(delta), np.sin(sigma) ]) # passive axis angle pair so a minus sign in front + ax = np.append(ax,alpha) + if alpha < 0.0: ax *= -1.0 # ensure alpha is positive else: - ax = -P/tau * np.array([ t*np.cos(delta), t*np.sin(delta), np.sin(sigma) ]) # passive axis angle pair so a minus sign in front - ax = np.append(ax,alpha) - if alpha < 0.0: ax *= -1.0 # ensure alpha is positive + t = np.tan(eu[...,1:2]*0.5) + sigma = 0.5*(eu[...,0:1]+eu[...,2:3]) + delta = 0.5*(eu[...,0:1]-eu[...,2:3]) + tau = np.linalg.norm(np.block([t,np.sin(sigma)]),axis=-1).reshape(-1,1) + alpha = np.where(np.abs(np.cos(sigma))<1.e-12,np.pi,2.0*np.arctan(tau/np.cos(sigma))) + ax = np.where(np.broadcast_to(np.abs(alpha)<1.0e-12,eu.shape[:-1]+(4,)), + [0.0,0.0,1.0,0.0], + np.block([-P/tau*t*np.cos(delta), + -P/tau*t*np.sin(delta), + -P/tau* np.sin(sigma), + alpha + ])) + ax[(alpha<0.0).squeeze()] *=-1 return ax @staticmethod def eu2ro(eu): """Bunge-Euler angles to Rodrigues-Frank vector.""" - ro = Rotation.eu2ax(eu) # convert to axis angle pair representation - if ro[3] >= np.pi: # Differs from original implementation. check convention 5 - ro[3] = np.inf - elif iszero(ro[3]): - ro = np.array([ 0.0, 0.0, P, 0.0 ]) + if len(eu.shape) == 1: + ro = Rotation.eu2ax(eu) # convert to axis angle pair representation + if ro[3] >= np.pi: # Differs from original implementation. check convention 5 + ro[3] = np.inf + elif iszero(ro[3]): + ro = np.array([ 0.0, 0.0, P, 0.0 ]) + else: + ro[3] = np.tan(ro[3]*0.5) else: - ro[3] = np.tan(ro[3]*0.5) + ax = Rotation.eu2ax(eu) + ro = np.block([ax[:,:3],np.tan(ax[:,3:4]*.5)]) + ro[ax[:,3]>=np.pi,3] = np.inf + ro[np.abs(ax[:,3])<1.e-16] = [ 0.0, 0.0, P, 0.0 ] return ro @staticmethod @@ -664,9 +773,7 @@ class Rotation: else: c = np.cos(ax[...,3:4]*.5) s = np.sin(ax[...,3:4]*.5) - qu = np.where(np.abs(ax[...,3:4])<1.e-12, - [1.0, 0.0, 0.0, 0.0], - np.block([c, ax[...,:3]*s])) + qu = np.where(np.abs(ax[...,3:4])<1.e-12,[1.0, 0.0, 0.0, 0.0],np.block([c, ax[...,:3]*s])) return qu @staticmethod @@ -687,7 +794,7 @@ class Rotation: c = np.cos(ax[...,3:4]) s = np.sin(ax[...,3:4]) omc = 1. -c - ax = np.block([c+omc*ax[...,0:1]**2, + om = np.block([c+omc*ax[...,0:1]**2, omc*ax[...,0:1]*ax[...,1:2] + s*ax[...,2:3], omc*ax[...,0:1]*ax[...,2:3] - s*ax[...,1:2], omc*ax[...,0:1]*ax[...,1:2] - s*ax[...,2:3], @@ -696,7 +803,7 @@ class Rotation: omc*ax[...,0:1]*ax[...,2:3] + s*ax[...,1:2], omc*ax[...,1:2]*ax[...,2:3] - s*ax[...,0:1], c+omc*ax[...,2:3]**2]).reshape(ax.shape[:-1]+(3,3)) - return ax + return om # TODO: TRANSPOSE FOR P = 1 @staticmethod def ax2eu(ax): diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 13c474ca7..eaf614b4e 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -150,6 +150,28 @@ class TestRotation: print(m,o,rot.asQuaternion()) assert np.allclose(m,o,atol=atol) + @pytest.mark.parametrize('conversion',[Rotation.qu2om, + Rotation.qu2eu, + Rotation.qu2ax, + Rotation.qu2ro, + Rotation.qu2ho]) + def test_quaternion_vectorization(self,default,conversion): + qu = np.array([rot.asQuaternion() for rot in default]) + co = conversion(qu) + for q,c in zip(qu,co): + assert np.allclose(conversion(q),c) + + @pytest.mark.parametrize('conversion',[Rotation.eu2qu, + Rotation.eu2om, + Rotation.eu2ax, + Rotation.eu2ro, + ]) + def test_Euler_vectorization(self,default,conversion): + qu = np.array([rot.asEulers() for rot in default]) + co = conversion(qu) + for q,c in zip(qu,co): + assert np.allclose(conversion(q),c) + @pytest.mark.parametrize('conversion',[Rotation.ax2qu, Rotation.ax2om, Rotation.ax2ro, From 43e7639f778156f1c97c87dfd4001e4dd507e66f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 9 Apr 2020 00:47:43 +0200 Subject: [PATCH 034/186] WIP: implementing orientation matrix conversions --- python/damask/_rotation.py | 24 ++++++++++++++++-------- python/tests/test_Rotation.py | 8 ++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 9296f57b4..06a400fad 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -596,19 +596,27 @@ class Rotation: @staticmethod def om2eu(om): """Rotation matrix to Bunge-Euler angles.""" - if not np.isclose(np.abs(om[2,2]),1.0,1.e-4): - zeta = 1.0/np.sqrt(1.0-om[2,2]**2) - eu = np.array([np.arctan2(om[2,0]*zeta,-om[2,1]*zeta), - np.arccos(om[2,2]), - np.arctan2(om[0,2]*zeta, om[1,2]*zeta)]) + if len(om.shape) == 2: + if not np.isclose(np.abs(om[2,2]),1.0,1.e-4): + zeta = 1.0/np.sqrt(1.0-om[2,2]**2) + eu = np.array([np.arctan2(om[2,0]*zeta,-om[2,1]*zeta), + np.arccos(om[2,2]), + np.arctan2(om[0,2]*zeta, om[1,2]*zeta)]) + else: + eu = np.array([np.arctan2( om[0,1],om[0,0]), np.pi*0.5*(1-om[2,2]),0.0]) # following the paper, not the reference implementation else: - eu = np.array([np.arctan2( om[0,1],om[0,0]), np.pi*0.5*(1-om[2,2]),0.0]) # following the paper, not the reference implementation - - # reduce Euler angles to definition range, i.e a lower limit of 0.0 + with np.errstate(divide='ignore'): + zeta = 1.0/np.sqrt(1.0-om[...,2,2:3]**2) + eu = np.block([np.arctan2(om[...,2,0:1]*zeta,-om[...,2,1:2]*zeta), + np.arccos(om[...,2,2:3]), + np.arctan2(om[...,0,2:3]*zeta,+om[...,1,2:3]*zeta) + ]) + # TODO Special case not implemented! eu[np.abs(eu)<1.e-6] = 0.0 eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) return eu + @staticmethod def om2ax(om): """Rotation matrix to axis angle pair.""" diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index eaf614b4e..448145c45 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -161,6 +161,14 @@ class TestRotation: for q,c in zip(qu,co): assert np.allclose(conversion(q),c) + @pytest.mark.parametrize('conversion',[Rotation.om2eu, + ]) + def test_matrix_vectorization(self,default,conversion): + qu = np.array([rot.asMatrix() for rot in default]) + co = conversion(qu) + for q,c in zip(qu,co): + assert np.allclose(conversion(q),c) + @pytest.mark.parametrize('conversion',[Rotation.eu2qu, Rotation.eu2om, Rotation.eu2ax, From cbfde73a29dbfe71d65860314a60fba119ad9687 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 9 Apr 2020 07:40:20 +0200 Subject: [PATCH 035/186] more testing and related fixes --- python/damask/_rotation.py | 108 +++++++++++++++++++--------------- python/tests/test_Rotation.py | 10 ++-- 2 files changed, 67 insertions(+), 51 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 06a400fad..b6c5ff0c7 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -474,7 +474,7 @@ class Rotation: q03 = qu[0]**2+qu[3]**2 q12 = qu[1]**2+qu[2]**2 chi = np.sqrt(q03*q12) - if np.abs(q03)< 1.e-6: + if np.abs(chi)< 1.e-6: eu = np.array([np.arctan2(-P*2.0*qu[0]*qu[3],qu[0]**2-qu[3]**2), 0.0, 0.0]) elif np.abs(q12)< 1.e-6: eu = np.array([np.arctan2( 2.0*qu[1]*qu[2],qu[1]**2-qu[2]**2), np.pi, 0.0]) @@ -491,14 +491,14 @@ class Rotation: q12_s = qu[...,1:2]**2+qu[...,2:3]**2 chi = np.sqrt(q03_s*q12_s) - eu = np.where(np.abs(q12_s) < 1.0e-6, + eu = np.where(np.abs(chi) < 1.0e-6, np.block([np.arctan2(-P*2.0*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2), np.zeros(qu.shape[:-1]+(2,))]), np.block([np.arctan2((-P*q02+q13)*chi, (-P*q01-q23)*chi), np.arctan2( 2.0*chi, q03_s-q12_s ), np.arctan2(( P*q02+q13)*chi, (-P*q01+q23)*chi)]) ) - eu = np.where(np.abs(q03_s) < 1.0e-6, + eu = np.where(np.logical_and(np.abs(q03_s) < 1.0e-6, np.abs(chi) > 1.0e-6), np.block([np.arctan2( 2.0*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2), np.ones( qu.shape[:-1]+(1,))*np.pi, np.zeros(qu.shape[:-1]+(1,))]), @@ -525,18 +525,15 @@ class Rotation: else: ax = ax = np.array([ qu[1], qu[2], qu[3], np.pi]) else: - with np.errstate(divide='ignore'): + with np.errstate(invalid='ignore',divide='ignore'): s = np.sign(qu[...,0:1])/np.sqrt(qu[...,1:2]**2+qu[...,2:3]**2+qu[...,3:4]**2) - omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) - + omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) + ax = np.where(np.expand_dims(np.sum(np.abs(qu[:,1:4])**2,axis=-1) < 1.0e-6,-1), + [0.0, 0.0, 1.0, 0.0], np.block([qu[...,1:4]*s,omega])) ax = np.where(qu[...,0:1] < 1.0e-6, - np.block([qu[...,1:4],np.ones(qu.shape[:-1]+(1,))*np.pi]), - np.block([qu[...,1:4]*s,omega])) - ax = np.where(np.expand_dims(np.sum(np.abs(qu[:,1:4])**2,axis=-1) < 1.0e-6,-1), - [0.0, 0.0, 1.0, 0.0], ax) # TODO: Where not needed + np.block([qu[...,1:4],np.ones(qu.shape[:-1]+(1,))*np.pi]),ax) # TODO: Where not needed return ax - @staticmethod def qu2ro(qu): """Quaternion to Rodrigues-Frank vector.""" @@ -548,12 +545,13 @@ class Rotation: ro = np.array([0.0,0.0,P,0.0] if iszero(s) else \ [ qu[1]/s, qu[2]/s, qu[3]/s, np.tan(np.arccos(np.clip(qu[0],-1.0,1.0)))]) else: - s = np.expand_dims(np.linalg.norm(qu[...,1:4],axis=1),-1) - ro = np.where(np.abs(s) < 1.0e-12, - [0.0,0.0,P,0.0], - np.block([qu[...,1:2]/s,qu[...,2:3]/s,qu[...,3:4]/s, - np.tan(np.arccos(np.clip(qu[:,0:1],-1.0,1.0))) - ]) + with np.errstate(invalid='ignore',divide='ignore'): + s = np.expand_dims(np.linalg.norm(qu[...,1:4],axis=1),-1) + ro = np.where(np.abs(s) < 1.0e-12, + [0.0,0.0,P,0.0], + np.block([qu[...,1:2]/s,qu[...,2:3]/s,qu[...,3:4]/s, + np.tan(np.arccos(np.clip(qu[:,0:1],-1.0,1.0))) + ]) ) ro = np.where(np.abs(qu[...,0:1]) < 1.0e-12, np.block([qu[...,1:2], qu[...,2:3], qu[...,3:4], np.ones(qu.shape[:-1]+(1,))*np.inf]),ro) # TODO: Where not needed @@ -571,10 +569,12 @@ class Rotation: f = 0.75 * ( omega - np.sin(omega) ) ho = ho/np.linalg.norm(ho) * f**(1./3.) else: - omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) - ho = np.where(np.abs(omega) < 1.0e-12, - np.zeros(3), - qu[...,1:4]/np.linalg.norm(qu[...,1:4],axis=1).reshape(qu.shape[:-1]+(1,)) * (0.75*(omega - np.sin(omega)))**(1./3.)) + with np.errstate(invalid='ignore'): + omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) + ho = np.where(np.abs(omega) < 1.0e-12, + np.zeros(3), + qu[...,1:4]/np.linalg.norm(qu[...,1:4],axis=1).reshape(qu.shape[:-1]+(1,)) \ + * (0.75*(omega - np.sin(omega)))**(1./3.)) return ho @staticmethod @@ -605,13 +605,18 @@ class Rotation: else: eu = np.array([np.arctan2( om[0,1],om[0,0]), np.pi*0.5*(1-om[2,2]),0.0]) # following the paper, not the reference implementation else: - with np.errstate(divide='ignore'): - zeta = 1.0/np.sqrt(1.0-om[...,2,2:3]**2) - eu = np.block([np.arctan2(om[...,2,0:1]*zeta,-om[...,2,1:2]*zeta), - np.arccos(om[...,2,2:3]), - np.arctan2(om[...,0,2:3]*zeta,+om[...,1,2:3]*zeta) - ]) - # TODO Special case not implemented! + with np.errstate(invalid='ignore',divide='ignore'): + zeta = 1.0/np.sqrt(1.0-om[...,2,2:3]**2) + eu = np.where(np.isclose(np.abs(om[...,2,2:3]),1.0,1e-4), + np.block([np.arctan2(om[...,0,1:2],om[...,0,0:1]), + np.pi*0.5*(1-om[...,2,2:3]), + np.zeros(om.shape[:-2]+(1,)), + ]), + np.block([np.arctan2(om[...,2,0:1]*zeta,-om[...,2,1:2]*zeta), + np.arccos(om[...,2,2:3]), + np.arctan2(om[...,0,2:3]*zeta,+om[...,1,2:3]*zeta) + ]) + ) eu[np.abs(eu)<1.e-6] = 0.0 eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) return eu @@ -620,22 +625,30 @@ class Rotation: @staticmethod def om2ax(om): """Rotation matrix to axis angle pair.""" - ax=np.empty(4) + if len(om.shape) == 2: + ax=np.empty(4) - # first get the rotation angle - t = 0.5*(om.trace() -1.0) - ax[3] = np.arccos(np.clip(t,-1.0,1.0)) + # first get the rotation angle + t = 0.5*(om.trace() -1.0) + ax[3] = np.arccos(np.clip(t,-1.0,1.0)) - if np.abs(ax[3])<1.e-6: - ax = np.array([ 0.0, 0.0, 1.0, 0.0]) + if np.abs(ax[3])<1.e-6: + ax = np.array([ 0.0, 0.0, 1.0, 0.0]) + else: + w,vr = np.linalg.eig(om) + # next, find the eigenvalue (1,0j) + i = np.where(np.isclose(w,1.0+0.0j))[0][0] + ax[0:3] = np.real(vr[0:3,i]) + diagDelta = np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) + ax[0:3] = np.where(np.abs(diagDelta)<1.e-6, ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) + return ax else: + diag_delta = np.block([om[...,1,2:3]-om[...,2,1:2], + om[...,2,0:1]-om[...,0,2:3], + om[...,0,1:2]-om[...,1,0:1] + ]) w,vr = np.linalg.eig(om) - # next, find the eigenvalue (1,0j) - i = np.where(np.isclose(w,1.0+0.0j))[0][0] - ax[0:3] = np.real(vr[0:3,i]) - diagDelta = np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) - ax[0:3] = np.where(np.abs(diagDelta)<1.e-6, ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) - return ax + # TODO ------------------ @staticmethod def om2ro(om): @@ -727,13 +740,14 @@ class Rotation: delta = 0.5*(eu[...,0:1]-eu[...,2:3]) tau = np.linalg.norm(np.block([t,np.sin(sigma)]),axis=-1).reshape(-1,1) alpha = np.where(np.abs(np.cos(sigma))<1.e-12,np.pi,2.0*np.arctan(tau/np.cos(sigma))) - ax = np.where(np.broadcast_to(np.abs(alpha)<1.0e-12,eu.shape[:-1]+(4,)), - [0.0,0.0,1.0,0.0], - np.block([-P/tau*t*np.cos(delta), - -P/tau*t*np.sin(delta), - -P/tau* np.sin(sigma), - alpha - ])) + with np.errstate(invalid='ignore',divide='ignore'): + ax = np.where(np.broadcast_to(np.abs(alpha)<1.0e-12,eu.shape[:-1]+(4,)), + [0.0,0.0,1.0,0.0], + np.block([-P/tau*t*np.cos(delta), + -P/tau*t*np.sin(delta), + -P/tau* np.sin(sigma), + alpha + ])) ax[(alpha<0.0).squeeze()] *=-1 return ax diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 448145c45..875a05d99 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -5,7 +5,7 @@ import numpy as np from damask import Rotation -n = 1000 +n = 1100 atol=1.e-4 scatter=1.e-2 @@ -74,10 +74,12 @@ def default(): np.array([1.0, 1.0,-1.0,-1.0])/2., np.array([1.0,-1.0,-1.0,-1.0])/2., ]) - specials += np.broadcast_to(np.random.rand(4)*scatter,specials.shape) - specials /= np.linalg.norm(specials,axis=1).reshape(-1,1) - specials[specials[:,0]<0]*=-1 + specials_scatter = specials + np.broadcast_to(np.random.rand(4)*scatter,specials.shape) + specials_scatter /= np.linalg.norm(specials_scatter,axis=1).reshape(-1,1) + specials_scatter[specials_scatter[:,0]<0]*=-1 + return [Rotation.fromQuaternion(s) for s in specials] + \ + [Rotation.fromQuaternion(s) for s in specials_scatter] + \ [Rotation.fromRandom() for _ in range(n-len(specials))] @pytest.fixture From b025c1838eebad6ac53d4bda0cfaf8a8bc73a8fa Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 9 Apr 2020 12:52:12 +0200 Subject: [PATCH 036/186] simplified --- python/damask/_rotation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index b6c5ff0c7..97f494947 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -528,7 +528,7 @@ class Rotation: with np.errstate(invalid='ignore',divide='ignore'): s = np.sign(qu[...,0:1])/np.sqrt(qu[...,1:2]**2+qu[...,2:3]**2+qu[...,3:4]**2) omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) - ax = np.where(np.expand_dims(np.sum(np.abs(qu[:,1:4])**2,axis=-1) < 1.0e-6,-1), + ax = np.where(np.sum(np.abs(qu[:,1:4])**2,axis=-1,keepdims=True) < 1.0e-6, [0.0, 0.0, 1.0, 0.0], np.block([qu[...,1:4]*s,omega])) ax = np.where(qu[...,0:1] < 1.0e-6, np.block([qu[...,1:4],np.ones(qu.shape[:-1]+(1,))*np.pi]),ax) # TODO: Where not needed @@ -541,12 +541,12 @@ class Rotation: if iszero(qu[0]): ro = np.array([qu[1], qu[2], qu[3], np.inf]) else: - s = np.linalg.norm([qu[1],qu[2],qu[3]]) + s = np.linalg.norm(qu[1:4]) ro = np.array([0.0,0.0,P,0.0] if iszero(s) else \ [ qu[1]/s, qu[2]/s, qu[3]/s, np.tan(np.arccos(np.clip(qu[0],-1.0,1.0)))]) else: with np.errstate(invalid='ignore',divide='ignore'): - s = np.expand_dims(np.linalg.norm(qu[...,1:4],axis=1),-1) + s = np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True) ro = np.where(np.abs(s) < 1.0e-12, [0.0,0.0,P,0.0], np.block([qu[...,1:2]/s,qu[...,2:3]/s,qu[...,3:4]/s, @@ -573,7 +573,7 @@ class Rotation: omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) ho = np.where(np.abs(omega) < 1.0e-12, np.zeros(3), - qu[...,1:4]/np.linalg.norm(qu[...,1:4],axis=1).reshape(qu.shape[:-1]+(1,)) \ + qu[...,1:4]/np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True) \ * (0.75*(omega - np.sin(omega)))**(1./3.)) return ho @@ -738,7 +738,7 @@ class Rotation: t = np.tan(eu[...,1:2]*0.5) sigma = 0.5*(eu[...,0:1]+eu[...,2:3]) delta = 0.5*(eu[...,0:1]-eu[...,2:3]) - tau = np.linalg.norm(np.block([t,np.sin(sigma)]),axis=-1).reshape(-1,1) + tau = np.linalg.norm(np.block([t,np.sin(sigma)]),axis=-1,keepdims=True) alpha = np.where(np.abs(np.cos(sigma))<1.e-12,np.pi,2.0*np.arctan(tau/np.cos(sigma))) with np.errstate(invalid='ignore',divide='ignore'): ax = np.where(np.broadcast_to(np.abs(alpha)<1.0e-12,eu.shape[:-1]+(4,)), From e502573e05a6071ce1dd74e9249a66a31a3d6910 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 9 Apr 2020 14:20:43 +0200 Subject: [PATCH 037/186] polishing --- python/damask/_rotation.py | 16 +++++++++++++--- python/tests/test_Rotation.py | 30 +++++++++++++++++++----------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 97f494947..4756e94c2 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -640,15 +640,25 @@ class Rotation: i = np.where(np.isclose(w,1.0+0.0j))[0][0] ax[0:3] = np.real(vr[0:3,i]) diagDelta = np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) - ax[0:3] = np.where(np.abs(diagDelta)<1.e-6, ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) - return ax + ax[0:3] = np.where(np.abs(diagDelta)<0, ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) else: diag_delta = np.block([om[...,1,2:3]-om[...,2,1:2], om[...,2,0:1]-om[...,0,2:3], om[...,0,1:2]-om[...,1,0:1] ]) + t = 0.5*(om.trace(axis2=-2,axis1=-1) -1.0).reshape(om.shape[:-2]+(1,)) w,vr = np.linalg.eig(om) - # TODO ------------------ + # mask duplicated real eigenvalues + w[np.isclose(w[...,0],1.0+0.0j),1:] = 0. + w[np.isclose(w[...,1],1.0+0.0j),2:] = 0. + ax = np.where(np.abs(diag_delta)<0, + np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,)), + np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,)) \ + * np.abs(diag_delta)*np.sign(-P*diag_delta)) + ax = np.block([ax,np.arccos(np.clip(t,-1.0,1.0))]) + ax[np.abs(ax[...,3])<1.e-6] = [ 0.0, 0.0, 1.0, 0.0] + return ax + @staticmethod def om2ro(om): diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 875a05d99..6bb0f5160 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -80,7 +80,7 @@ def default(): return [Rotation.fromQuaternion(s) for s in specials] + \ [Rotation.fromQuaternion(s) for s in specials_scatter] + \ - [Rotation.fromRandom() for _ in range(n-len(specials))] + [Rotation.fromRandom() for _ in range(n-len(specials)-len(specials_scatter))] @pytest.fixture def reference_dir(reference_dir_base): @@ -159,17 +159,22 @@ class TestRotation: Rotation.qu2ho]) def test_quaternion_vectorization(self,default,conversion): qu = np.array([rot.asQuaternion() for rot in default]) + #dev_null = conversion(qu.reshape(qu.shape[0]//2,-1,4)) co = conversion(qu) for q,c in zip(qu,co): - assert np.allclose(conversion(q),c) + print(q,c) + assert np.allclose(conversion(q),c) @pytest.mark.parametrize('conversion',[Rotation.om2eu, + #Rotation.om2ax, ]) def test_matrix_vectorization(self,default,conversion): - qu = np.array([rot.asMatrix() for rot in default]) - co = conversion(qu) - for q,c in zip(qu,co): - assert np.allclose(conversion(q),c) + om = np.array([rot.asMatrix() for rot in default]) + #dev_null = conversion(om.reshape(om.shape[0]//2,-1,3,3)) + co = conversion(om) + for o,c in zip(om,co): + print(o,c) + assert np.allclose(conversion(o),c) @pytest.mark.parametrize('conversion',[Rotation.eu2qu, Rotation.eu2om, @@ -177,10 +182,12 @@ class TestRotation: Rotation.eu2ro, ]) def test_Euler_vectorization(self,default,conversion): - qu = np.array([rot.asEulers() for rot in default]) - co = conversion(qu) - for q,c in zip(qu,co): - assert np.allclose(conversion(q),c) + eu = np.array([rot.asEulers() for rot in default]) + #dev_null = conversion(eu.reshape(eu.shape[0]//2,-1,3)) + co = conversion(eu) + for e,c in zip(eu,co): + print(e,c) + assert np.allclose(conversion(e),c) @pytest.mark.parametrize('conversion',[Rotation.ax2qu, Rotation.ax2om, @@ -192,4 +199,5 @@ class TestRotation: dev_null = conversion(ax.reshape(ax.shape[0]//2,-1,4)) co = conversion(ax) for a,c in zip(ax,co): - assert np.allclose(conversion(a),c) + print(a,c) + assert np.allclose(conversion(a),c) From bab3581b1194c74e5ca3c217db8d2ad1e78b0531 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 9 Apr 2020 15:01:01 +0200 Subject: [PATCH 038/186] need to transpose eigenvectors to find the correct one --- python/damask/_rotation.py | 22 ++++++++++++---------- python/tests/test_Rotation.py | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 4756e94c2..3336eb6c0 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -631,7 +631,6 @@ class Rotation: # first get the rotation angle t = 0.5*(om.trace() -1.0) ax[3] = np.arccos(np.clip(t,-1.0,1.0)) - if np.abs(ax[3])<1.e-6: ax = np.array([ 0.0, 0.0, 1.0, 0.0]) else: @@ -639,22 +638,25 @@ class Rotation: # next, find the eigenvalue (1,0j) i = np.where(np.isclose(w,1.0+0.0j))[0][0] ax[0:3] = np.real(vr[0:3,i]) - diagDelta = np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) - ax[0:3] = np.where(np.abs(diagDelta)<0, ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) + diagDelta = -P*np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) + diagDelta[np.abs(diagDelta)<1.e-6] = 1.0 + ax[0:3] = np.where(np.abs(diagDelta)<0, ax[0:3],np.abs(ax[0:3])*np.sign(diagDelta)) else: - diag_delta = np.block([om[...,1,2:3]-om[...,2,1:2], - om[...,2,0:1]-om[...,0,2:3], - om[...,0,1:2]-om[...,1,0:1] - ]) + diag_delta = -P*np.block([om[...,1,2:3]-om[...,2,1:2], + om[...,2,0:1]-om[...,0,2:3], + om[...,0,1:2]-om[...,1,0:1] + ]) + diag_delta[np.abs(diag_delta)<1.e-6] = 1.0 t = 0.5*(om.trace(axis2=-2,axis1=-1) -1.0).reshape(om.shape[:-2]+(1,)) w,vr = np.linalg.eig(om) # mask duplicated real eigenvalues w[np.isclose(w[...,0],1.0+0.0j),1:] = 0. w[np.isclose(w[...,1],1.0+0.0j),2:] = 0. + vr = np.swapaxes(vr,-1,-2) ax = np.where(np.abs(diag_delta)<0, - np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,)), - np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,)) \ - * np.abs(diag_delta)*np.sign(-P*diag_delta)) + np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,)), + np.abs(np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,))) \ + *np.sign(diag_delta)) ax = np.block([ax,np.arccos(np.clip(t,-1.0,1.0))]) ax[np.abs(ax[...,3])<1.e-6] = [ 0.0, 0.0, 1.0, 0.0] return ax diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 6bb0f5160..02d561b66 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -166,7 +166,7 @@ class TestRotation: assert np.allclose(conversion(q),c) @pytest.mark.parametrize('conversion',[Rotation.om2eu, - #Rotation.om2ax, + Rotation.om2ax, ]) def test_matrix_vectorization(self,default,conversion): om = np.array([rot.asMatrix() for rot in default]) From c7508d85f604d0de461b532069d5820b6fc46048 Mon Sep 17 00:00:00 2001 From: Franz Roters Date: Fri, 10 Apr 2020 15:48:08 +0200 Subject: [PATCH 039/186] now with python documentation --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 62bd5ede5..aa0b9fe99 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 62bd5ede5260cd4e0e3d1c3930c474c1e045aeef +Subproject commit aa0b9fe992ce0bfc172989ab006893ddb8939c1e From b375af83a3dcedc8dae6ef564ab0c1800d396a7a Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 10 Apr 2020 15:52:54 +0200 Subject: [PATCH 040/186] bugfix for issue introduced in last merge --- src/crystallite.f90 | 55 +-------------------------------------------- 1 file changed, 1 insertion(+), 54 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 743bcf73b..f0b5ecf08 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -301,7 +301,7 @@ function crystallite_stress(dummyArgumentToPreventInternalCompilerErrorWithGCC) e, & !< counter in element loop startIP, endIP, & s - logical, dimension(homogenization_maxNgrains,discretization_nIP,discretization_nElem) :: todo !ToDo: need to set some values to false in has of different Ngrains + logical, dimension(homogenization_maxNgrains,discretization_nIP,discretization_nElem) :: todo !ToDo: need to set some values to false for different Ngrains #ifdef DEBUG if (iand(debug_level(debug_crystallite),debug_levelSelective) /= 0 & @@ -1626,59 +1626,6 @@ logical pure function converged(residuum,state,atol) end function converged -!-------------------------------------------------------------------------------------------------- -!> @brief calculates a jump in the state according to the current state and the current stress -!> returns true, if state jump was successfull or not needed. false indicates NaN in delta state -!-------------------------------------------------------------------------------------------------- -logical function stateJump(ipc,ip,el) - - integer, intent(in):: & - el, & ! element index - ip, & ! integration point index - ipc ! grain index - - integer :: & - c, & - p, & - mySource, & - myOffset, & - mySize - - c = material_phaseMemberAt(ipc,ip,el) - p = material_phaseAt(ipc,el) - - call constitutive_collectDeltaState(crystallite_S(1:3,1:3,ipc,ip,el), & - crystallite_Fe(1:3,1:3,ipc,ip,el), & - crystallite_Fi(1:3,1:3,ipc,ip,el), & - ipc,ip,el) - - myOffset = plasticState(p)%offsetDeltaState - mySize = plasticState(p)%sizeDeltaState - - if( any(IEEE_is_NaN(plasticState(p)%deltaState(1:mySize,c)))) then - stateJump = .false. - return - endif - - plasticState(p)%state(myOffset + 1:myOffset + mySize,c) = & - plasticState(p)%state(myOffset + 1:myOffset + mySize,c) + plasticState(p)%deltaState(1:mySize,c) - - do mySource = 1, phase_Nsources(p) - myOffset = sourceState(p)%p(mySource)%offsetDeltaState - mySize = sourceState(p)%p(mySource)%sizeDeltaState - if (any(IEEE_is_NaN(sourceState(p)%p(mySource)%deltaState(1:mySize,c)))) then - stateJump = .false. - return - endif - sourceState(p)%p(mySource)%state(myOffset + 1: myOffset + mySize,c) = & - sourceState(p)%p(mySource)%state(myOffset + 1: myOffset + mySize,c) + sourceState(p)%p(mySource)%deltaState(1:mySize,c) - enddo - - stateJump = .true. - -end function stateJump - - !-------------------------------------------------------------------------------------------------- !> @brief Write current restart information (Field and constitutive data) to file. ! ToDo: Merge data into one file for MPI, move state to constitutive and homogenization, respectively From c929581029a666f719e12cb6643e54da9b31e765 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 10 Apr 2020 18:20:40 +0200 Subject: [PATCH 041/186] [skip ci] updated version information after successful test of v2.0.3-2245-gc7508d85 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 2d8aa9597..804287b93 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2243-gbb03483b +v2.0.3-2245-gc7508d85 From 399a0f1b66cd771b60f7f61c113227ea9018e255 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 10 Apr 2020 18:53:59 +0200 Subject: [PATCH 042/186] store information about state size only once --- src/crystallite.f90 | 79 ++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index f0b5ecf08..f405fc930 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1012,7 +1012,9 @@ subroutine integrateStateFPI(todo) p, & c, & s, & - sizeDotState + size_pl + integer, dimension(maxval(phase_Nsources)) :: & + size_so real(pReal) :: & zeta real(pReal), dimension(max(constitutive_plasticity_maxSizeDotState,constitutive_source_maxSizeDotState)) :: & @@ -1023,7 +1025,7 @@ subroutine integrateStateFPI(todo) nonlocalBroken, broken nonlocalBroken = .false. - !$OMP PARALLEL DO PRIVATE(sizeDotState,r,zeta,p,c,plastic_dotState_p1, plastic_dotState_p2,source_dotState,broken) + !$OMP PARALLEL DO PRIVATE(size_pl,size_so,r,zeta,p,c,plastic_dotState_p1, plastic_dotState_p2,source_dotState,broken) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) @@ -1040,17 +1042,17 @@ subroutine integrateStateFPI(todo) if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. if(broken) cycle - sizeDotState = plasticState(p)%sizeDotState - plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & - + plasticState(p)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - plastic_dotState_p2 = 0.0_pReal * plasticState(p)%dotState (1:sizeDotState,c) ! ToDo can be done smarter/clearer + size_pl = plasticState(p)%sizeDotState + plasticState(p)%state(1:size_pl,c) = plasticState(p)%subState0(1:size_pl,c) & + + plasticState(p)%dotState (1:size_pl,c) & + * crystallite_subdt(g,i,e) + plastic_dotState_p2 = 0.0_pReal * plasticState(p)%dotState (1:size_pl,c) do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & - + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - source_dotState(1:sizeDotState,2,s) = 0.0_pReal + size_so(s) = sourceState(p)%p(s)%sizeDotState + sourceState(p)%p(s)%state(1:size_so(s),c) = sourceState(p)%p(s)%subState0(1:size_so(s),c) & + + sourceState(p)%p(s)%dotState (1:size_so(s),c) & + * crystallite_subdt(g,i,e) + source_dotState(1:size_so(s),2,s) = 0.0_pReal enddo iteration: do NiterationState = 1, num%nState @@ -1058,49 +1060,46 @@ subroutine integrateStateFPI(todo) if(nIterationState > 1) plastic_dotState_p2 = plastic_dotState_p1 plastic_dotState_p1 = plasticState(p)%dotState(:,c) do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - if(nIterationState > 1) source_dotState(1:sizeDotState,2,s) = source_dotState(1:sizeDotState,1,s) - source_dotState(1:sizeDotState,1,s) = sourceState(p)%p(s)%dotState(:,c) + if(nIterationState > 1) source_dotState(1:size_so(s),2,s) = source_dotState(1:size_so(s),1,s) + source_dotState(1:size_so(s),1,s) = sourceState(p)%p(s)%dotState(:,c) enddo broken = integrateStress(g,i,e) if(broken) exit iteration broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) + crystallite_partionedF0, & + crystallite_Fi(1:3,1:3,g,i,e), & + crystallite_partionedFp0, & + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) exit iteration - sizeDotState = plasticState(p)%sizeDotState zeta = damper(plasticState(p)%dotState(:,c),plastic_dotState_p1,plastic_dotState_p2) plasticState(p)%dotState(:,c) = plasticState(p)%dotState(:,c) * zeta & + plastic_dotState_p1 * (1.0_pReal - zeta) - r(1:SizeDotState) = plasticState(p)%state (1:sizeDotState,c) & - - plasticState(p)%subState0(1:sizeDotState,c) & - - plasticState(p)%dotState (1:sizeDotState,c) * crystallite_subdt(g,i,e) - plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%state(1:sizeDotState,c) & - - r(1:sizeDotState) - crystallite_converged(g,i,e) = converged(r(1:sizeDotState), & - plasticState(p)%state(1:sizeDotState,c), & - plasticState(p)%atol(1:sizeDotState)) + r(1:size_pl) = plasticState(p)%state (1:size_pl,c) & + - plasticState(p)%subState0(1:size_pl,c) & + - plasticState(p)%dotState (1:size_pl,c) * crystallite_subdt(g,i,e) + plasticState(p)%state(1:size_pl,c) = plasticState(p)%state(1:size_pl,c) & + - r(1:size_pl) + crystallite_converged(g,i,e) = converged(r(1:size_pl), & + plasticState(p)%state(1:size_pl,c), & + plasticState(p)%atol(1:size_pl)) do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState zeta = damper(sourceState(p)%p(s)%dotState(:,c), & - source_dotState(1:sizeDotState,1,s),& - source_dotState(1:sizeDotState,2,s)) + source_dotState(1:size_so(s),1,s),& + source_dotState(1:size_so(s),2,s)) sourceState(p)%p(s)%dotState(:,c) = sourceState(p)%p(s)%dotState(:,c) * zeta & - + source_dotState(1:sizeDotState,1,s)* (1.0_pReal - zeta) - r(1:sizeDotState) = sourceState(p)%p(s)%state (1:sizeDotState,c) & - - sourceState(p)%p(s)%subState0(1:sizeDotState,c) & - - sourceState(p)%p(s)%dotState (1:sizeDotState,c) * crystallite_subdt(g,i,e) - sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%state(1:sizeDotState,c) & - - r(1:sizeDotState) + + source_dotState(1:size_so(s),1,s)* (1.0_pReal - zeta) + r(1:size_so(s)) = sourceState(p)%p(s)%state (1:size_so(s),c) & + - sourceState(p)%p(s)%subState0(1:size_so(s),c) & + - sourceState(p)%p(s)%dotState (1:size_so(s),c) * crystallite_subdt(g,i,e) + sourceState(p)%p(s)%state(1:size_so(s),c) = sourceState(p)%p(s)%state(1:size_so(s),c) & + - r(1:size_so(s)) crystallite_converged(g,i,e) = & - crystallite_converged(g,i,e) .and. converged(r(1:sizeDotState), & - sourceState(p)%p(s)%state(1:sizeDotState,c), & - sourceState(p)%p(s)%atol(1:sizeDotState)) + crystallite_converged(g,i,e) .and. converged(r(1:size_so(s)), & + sourceState(p)%p(s)%state(1:size_so(s),c), & + sourceState(p)%p(s)%atol(1:size_so(s))) enddo if(crystallite_converged(g,i,e)) then From 1d5b1a17cd2795de3cb80eaafbbc6bafaebd0020 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 10 Apr 2020 19:36:29 +0200 Subject: [PATCH 043/186] same style for plastic and source --- src/crystallite.f90 | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index f405fc930..2d4b9785d 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1019,13 +1019,14 @@ subroutine integrateStateFPI(todo) zeta real(pReal), dimension(max(constitutive_plasticity_maxSizeDotState,constitutive_source_maxSizeDotState)) :: & r ! state residuum - real(pReal), dimension(:), allocatable :: plastic_dotState_p1, plastic_dotState_p2 + real(pReal), dimension(constitutive_plasticity_maxSizeDotState,2) :: & + plastic_dotState real(pReal), dimension(constitutive_source_maxSizeDotState,2,maxval(phase_Nsources)) :: source_dotState logical :: & nonlocalBroken, broken nonlocalBroken = .false. - !$OMP PARALLEL DO PRIVATE(size_pl,size_so,r,zeta,p,c,plastic_dotState_p1, plastic_dotState_p2,source_dotState,broken) + !$OMP PARALLEL DO PRIVATE(size_pl,size_so,r,zeta,p,c,plastic_dotState,source_dotState,broken) do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) @@ -1046,7 +1047,7 @@ subroutine integrateStateFPI(todo) plasticState(p)%state(1:size_pl,c) = plasticState(p)%subState0(1:size_pl,c) & + plasticState(p)%dotState (1:size_pl,c) & * crystallite_subdt(g,i,e) - plastic_dotState_p2 = 0.0_pReal * plasticState(p)%dotState (1:size_pl,c) + plastic_dotState(1:size_pl,2) = 0.0_pReal do s = 1, phase_Nsources(p) size_so(s) = sourceState(p)%p(s)%sizeDotState sourceState(p)%p(s)%state(1:size_so(s),c) = sourceState(p)%p(s)%subState0(1:size_so(s),c) & @@ -1057,8 +1058,8 @@ subroutine integrateStateFPI(todo) iteration: do NiterationState = 1, num%nState - if(nIterationState > 1) plastic_dotState_p2 = plastic_dotState_p1 - plastic_dotState_p1 = plasticState(p)%dotState(:,c) + if(nIterationState > 1) plastic_dotState(1:size_pl,2) = plastic_dotState(1:size_pl,1) + plastic_dotState(1:size_pl,1) = plasticState(p)%dotState(:,c) do s = 1, phase_Nsources(p) if(nIterationState > 1) source_dotState(1:size_so(s),2,s) = source_dotState(1:size_so(s),1,s) source_dotState(1:size_so(s),1,s) = sourceState(p)%p(s)%dotState(:,c) @@ -1074,9 +1075,10 @@ subroutine integrateStateFPI(todo) crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) exit iteration - zeta = damper(plasticState(p)%dotState(:,c),plastic_dotState_p1,plastic_dotState_p2) + zeta = damper(plasticState(p)%dotState(:,c),plastic_dotState(1:size_pl,1),& + plastic_dotState(1:size_pl,2)) plasticState(p)%dotState(:,c) = plasticState(p)%dotState(:,c) * zeta & - + plastic_dotState_p1 * (1.0_pReal - zeta) + + plastic_dotState(1:size_pl,1) * (1.0_pReal - zeta) r(1:size_pl) = plasticState(p)%state (1:size_pl,c) & - plasticState(p)%subState0(1:size_pl,c) & - plasticState(p)%dotState (1:size_pl,c) * crystallite_subdt(g,i,e) From 3bfa2d679cb0f95998ed9746d46fa21e8f2dc9ad Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 11:36:37 +0200 Subject: [PATCH 044/186] simpler/correct logic for eu2om --- python/damask/_rotation.py | 24 ++++++++++++------------ src/rotations.f90 | 11 +++++------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 3336eb6c0..e58de982f 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -474,9 +474,9 @@ class Rotation: q03 = qu[0]**2+qu[3]**2 q12 = qu[1]**2+qu[2]**2 chi = np.sqrt(q03*q12) - if np.abs(chi)< 1.e-6: + if np.abs(q12) < 1.e-6: eu = np.array([np.arctan2(-P*2.0*qu[0]*qu[3],qu[0]**2-qu[3]**2), 0.0, 0.0]) - elif np.abs(q12)< 1.e-6: + elif np.abs(q03) < 1.e-6: eu = np.array([np.arctan2( 2.0*qu[1]*qu[2],qu[1]**2-qu[2]**2), np.pi, 0.0]) else: eu = np.array([np.arctan2((-P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-P*qu[0]*qu[1]-qu[2]*qu[3])*chi ), @@ -491,14 +491,14 @@ class Rotation: q12_s = qu[...,1:2]**2+qu[...,2:3]**2 chi = np.sqrt(q03_s*q12_s) - eu = np.where(np.abs(chi) < 1.0e-6, + eu = np.where(np.abs(q12_s) < 1.0e-6, np.block([np.arctan2(-P*2.0*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2), np.zeros(qu.shape[:-1]+(2,))]), np.block([np.arctan2((-P*q02+q13)*chi, (-P*q01-q23)*chi), np.arctan2( 2.0*chi, q03_s-q12_s ), np.arctan2(( P*q02+q13)*chi, (-P*q01+q23)*chi)]) ) - eu = np.where(np.logical_and(np.abs(q03_s) < 1.0e-6, np.abs(chi) > 1.0e-6), + eu = np.where(np.logical_and(np.abs(q03_s) < 1.0e-6, np.abs(q12_s) >= 1.0e-6), np.block([np.arctan2( 2.0*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2), np.ones( qu.shape[:-1]+(1,))*np.pi, np.zeros(qu.shape[:-1]+(1,))]), @@ -550,7 +550,7 @@ class Rotation: ro = np.where(np.abs(s) < 1.0e-12, [0.0,0.0,P,0.0], np.block([qu[...,1:2]/s,qu[...,2:3]/s,qu[...,3:4]/s, - np.tan(np.arccos(np.clip(qu[:,0:1],-1.0,1.0))) + np.tan(np.arccos(np.clip(qu[...,0:1],-1.0,1.0))) ]) ) ro = np.where(np.abs(qu[...,0:1]) < 1.0e-12, @@ -686,10 +686,10 @@ class Rotation: ee = 0.5*eu cPhi = np.cos(ee[1]) sPhi = np.sin(ee[1]) - qu = np.array([ cPhi*np.cos(ee[0]+ee[2]), - -P*sPhi*np.cos(ee[0]-ee[2]), - -P*sPhi*np.sin(ee[0]-ee[2]), - -P*cPhi*np.sin(ee[0]+ee[2]) ]) + qu = np.array([ cPhi*np.cos(ee[0]+ee[2]), + -P*sPhi*np.cos(ee[0]-ee[2]), + -P*sPhi*np.sin(ee[0]-ee[2]), + -P*cPhi*np.sin(ee[0]+ee[2]) ]) if qu[0] < 0.0: qu*=-1 else: ee = 0.5*eu @@ -776,9 +776,9 @@ class Rotation: ro[3] = np.tan(ro[3]*0.5) else: ax = Rotation.eu2ax(eu) - ro = np.block([ax[:,:3],np.tan(ax[:,3:4]*.5)]) - ro[ax[:,3]>=np.pi,3] = np.inf - ro[np.abs(ax[:,3])<1.e-16] = [ 0.0, 0.0, P, 0.0 ] + ro = np.block([ax[...,:3],np.tan(ax[...,3:4]*.5)]) + ro[ax[...,3]>=np.pi,3] = np.inf + ro[np.abs(ax[...,3])<1.e-16] = [ 0.0, 0.0, P, 0.0 ] return ro @staticmethod diff --git a/src/rotations.f90 b/src/rotations.f90 index 7ce366f74..1630326ad 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -432,18 +432,17 @@ pure function qu2eu(qu) result(eu) real(pReal), intent(in), dimension(4) :: qu real(pReal), dimension(3) :: eu - real(pReal) :: q12, q03, chi, chiInv + real(pReal) :: q12, q03, chi q03 = qu(1)**2+qu(4)**2 q12 = qu(2)**2+qu(3)**2 chi = sqrt(q03*q12) - degenerated: if (dEq0(chi)) then - eu = merge([atan2(-P*2.0_pReal*qu(1)*qu(4),qu(1)**2-qu(4)**2), 0.0_pReal, 0.0_pReal], & - [atan2( 2.0_pReal*qu(2)*qu(3),qu(2)**2-qu(3)**2), PI, 0.0_pReal], & - dEq0(q12)) + degenerated: if (dEq0(q12)) then + eu = [atan2(-P*2.0_pReal*qu(1)*qu(4),qu(1)**2-qu(4)**2), 0.0_pReal, 0.0_pReal] + elseif (dEq0(q03)) then + eu = [atan2( 2.0_pReal*qu(2)*qu(3),qu(2)**2-qu(3)**2), PI, 0.0_pReal] else degenerated - chiInv = 1.0_pReal/chi eu = [atan2((-P*qu(1)*qu(3)+qu(2)*qu(4))*chi, (-P*qu(1)*qu(2)-qu(3)*qu(4))*chi ), & atan2( 2.0_pReal*chi, q03-q12 ), & atan2(( P*qu(1)*qu(3)+qu(2)*qu(4))*chi, (-P*qu(1)*qu(2)+qu(3)*qu(4))*chi )] From 4e759d6c9869bea71229ee8a0ec50d0926024c1f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 12:37:21 +0200 Subject: [PATCH 045/186] more tests for orientation conversion ensure that all parameters are within range and check if multidimensional arrays at least run --- python/damask/_Lambert.py | 2 +- python/tests/test_Rotation.py | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/python/damask/_Lambert.py b/python/damask/_Lambert.py index a62f1922a..59abe7f64 100644 --- a/python/damask/_Lambert.py +++ b/python/damask/_Lambert.py @@ -105,7 +105,7 @@ def ball_to_cube(ball): """ ball_ = ball/np.linalg.norm(ball)*R1 if np.isclose(np.linalg.norm(ball),R1,atol=1e-6) else ball rs = np.linalg.norm(ball_) - if rs > R1 and not np.isclose(rs,R1): + if rs > R1+1.e-9: raise ValueError('Coordinate outside of the sphere: {} {} {}.'.format(*ball)) if np.allclose(ball_,0.0,rtol=0.0,atol=1.0e-16): diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 02d561b66..b3d3d881d 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -98,7 +98,7 @@ class TestRotation: if np.isclose(rot.asQuaternion()[0],0.0,atol=atol): ok = ok or np.allclose(m*-1.,o,atol=atol) print(m,o,rot.asQuaternion()) - assert ok + assert ok and np.isclose(np.linalg.norm(o),1.0) def test_AxisAngle(self,default): for rot in default: @@ -111,7 +111,7 @@ class TestRotation: sum_phi = np.unwrap([m[0]+m[2],o[0]+o[2]]) ok = ok or np.isclose(sum_phi[0],sum_phi[1],atol=atol) print(m,o,rot.asQuaternion()) - assert ok + assert ok and (np.zeros(3)-1.e-9 <= o).all() and (o <= np.array([np.pi*2.,np.pi,np.pi*2.])+1.e-9).all() def test_Matrix(self,default): for rot in default: @@ -121,36 +121,41 @@ class TestRotation: if np.isclose(m[3],np.pi,atol=atol): ok = ok or np.allclose(m*np.array([-1.,-1.,-1.,1.]),o,atol=atol) print(m,o,rot.asQuaternion()) - assert ok + assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) and o[3]<=np.pi++1.e-9 def test_Rodriques(self,default): for rot in default: m = rot.asMatrix() o = Rotation.fromRodrigues(rot.asRodrigues()).asMatrix() + ok = np.allclose(m,o,atol=atol) print(m,o) - assert np.allclose(m,o,atol=atol) + assert ok and np.isclose(np.linalg.det(o),1.0) def test_Homochoric(self,default): + cutoff = np.tan(np.pi*.5*(1.-1e-4)) for rot in default: m = rot.asRodrigues() o = Rotation.fromHomochoric(rot.asHomochoric()).asRodrigues() - ok = np.allclose(np.clip(m,None,1.e9),np.clip(o,None,1.e9),atol=atol) - print(m,o,rot.asQuaternion()) + ok = np.allclose(np.clip(m,None,cutoff),np.clip(o,None,cutoff),atol=atol) ok = ok or np.isclose(m[3],0.0,atol=atol) + print(m,o,rot.asQuaternion()) + assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) def test_Cubochoric(self,default): for rot in default: m = rot.asHomochoric() o = Rotation.fromCubochoric(rot.asCubochoric()).asHomochoric() + ok = np.allclose(m,o,atol=atol) print(m,o,rot.asQuaternion()) - assert np.allclose(m,o,atol=atol) + assert ok and np.linalg.norm(o) < (3.*np.pi/4.)**(1./3.) + 1.e-9 def test_Quaternion(self,default): for rot in default: m = rot.asCubochoric() o = Rotation.fromQuaternion(rot.asQuaternion()).asCubochoric() + ok = np.allclose(m,o,atol=atol) print(m,o,rot.asQuaternion()) - assert np.allclose(m,o,atol=atol) + assert ok and o.max() < np.pi**(2./3.)*0.5+1.e-9 @pytest.mark.parametrize('conversion',[Rotation.qu2om, Rotation.qu2eu, @@ -159,7 +164,7 @@ class TestRotation: Rotation.qu2ho]) def test_quaternion_vectorization(self,default,conversion): qu = np.array([rot.asQuaternion() for rot in default]) - #dev_null = conversion(qu.reshape(qu.shape[0]//2,-1,4)) + dev_null = conversion(qu.reshape(qu.shape[0]//2,-1,4)) co = conversion(qu) for q,c in zip(qu,co): print(q,c) @@ -170,7 +175,7 @@ class TestRotation: ]) def test_matrix_vectorization(self,default,conversion): om = np.array([rot.asMatrix() for rot in default]) - #dev_null = conversion(om.reshape(om.shape[0]//2,-1,3,3)) + dev_null = conversion(om.reshape(om.shape[0]//2,-1,3,3)) co = conversion(om) for o,c in zip(om,co): print(o,c) @@ -183,7 +188,7 @@ class TestRotation: ]) def test_Euler_vectorization(self,default,conversion): eu = np.array([rot.asEulers() for rot in default]) - #dev_null = conversion(eu.reshape(eu.shape[0]//2,-1,3)) + dev_null = conversion(eu.reshape(eu.shape[0]//2,-1,3)) co = conversion(eu) for e,c in zip(eu,co): print(e,c) From 99655c9f61060547ff76cfde2121e324f5587cb9 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 13:57:05 +0200 Subject: [PATCH 046/186] more vectorized functions --- python/damask/_rotation.py | 45 ++++++++++++++++++++++------------- python/tests/test_Rotation.py | 32 ++++++++++++++++++++----- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index e58de982f..56c5d0593 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -767,8 +767,8 @@ class Rotation: def eu2ro(eu): """Bunge-Euler angles to Rodrigues-Frank vector.""" if len(eu.shape) == 1: - ro = Rotation.eu2ax(eu) # convert to axis angle pair representation - if ro[3] >= np.pi: # Differs from original implementation. check convention 5 + ro = Rotation.eu2ax(eu) # convert to axis angle pair representation + if ro[3] >= np.pi: # Differs from original implementation. check convention 5 ro[3] = np.inf elif iszero(ro[3]): ro = np.array([ 0.0, 0.0, P, 0.0 ]) @@ -902,27 +902,38 @@ class Rotation: @staticmethod def ro2ax(ro): """Rodrigues-Frank vector to axis angle pair.""" - ta = ro[3] - - if iszero(ta): - ax = [ 0.0, 0.0, 1.0, 0.0 ] - elif not np.isfinite(ta): - ax = [ ro[0], ro[1], ro[2], np.pi ] + if len(ro.shape) == 1: + if np.abs(ro[3]) < 1.e-6: + ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) + elif not np.isfinite(ro[3]): + ax = np.array([ ro[0], ro[1], ro[2], np.pi ]) + else: + angle = 2.0*np.arctan(ro[3]) + ta = np.linalg.norm(ro[0:3]) + ax = np.array([ ro[0]*ta, ro[1]*ta, ro[2]*ta, angle ]) else: - angle = 2.0*np.arctan(ta) - ta = 1.0/np.linalg.norm(ro[0:3]) - ax = [ ro[0]/ta, ro[1]/ta, ro[2]/ta, angle ] - return np.array(ax) + with np.errstate(invalid='ignore',divide='ignore'): + ax = np.where(np.isfinite(ro[...,3:4]), + np.block([ro[...,0:3]*np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True),2.*np.arctan(ro[...,3:4])]), + np.block([ro[...,0:3],np.broadcast_to(np.pi,ro[...,3:4].shape)])) + ax[np.abs(ro[...,3]) < 1.e-6] = np.array([ 0.0, 0.0, 1.0, 0.0 ]) + return ax @staticmethod def ro2ho(ro): """Rodrigues-Frank vector to homochoric vector.""" - if iszero(np.sum(ro[0:3]**2.0)): - ho = [ 0.0, 0.0, 0.0 ] + if len(ro.shape) == 1: + if np.sum(ro[0:3]**2.0) < 1.e-6: + ho = np.zeros(3) + else: + f = 2.0*np.arctan(ro[3]) -np.sin(2.0*np.arctan(ro[3])) if np.isfinite(ro[3]) else np.pi + ho = ro[0:3] * (0.75*f)**(1.0/3.0) else: - f = 2.0*np.arctan(ro[3]) -np.sin(2.0*np.arctan(ro[3])) if np.isfinite(ro[3]) else np.pi - ho = ro[0:3] * (0.75*f)**(1.0/3.0) - return np.array(ho) + f = np.where(np.isfinite(ro[...,3:4]),2.0*np.arctan(ro[...,3:4]) -np.sin(2.0*np.arctan(ro[...,3:4])),np.pi) + ho = np.where(np.broadcast_to(np.sum(ro[...,0:3]**2.0,axis=-1,keepdims=True) < 1.e-6,ro[...,0:3].shape), + np.zeros(3), ro[...,0:3]* (0.75*f)**(1.0/3.0)) + + return ho @staticmethod def ro2cu(ro): diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index b3d3d881d..544e088c7 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -123,7 +123,7 @@ class TestRotation: print(m,o,rot.asQuaternion()) assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) and o[3]<=np.pi++1.e-9 - def test_Rodriques(self,default): + def test_Rodrigues(self,default): for rot in default: m = rot.asMatrix() o = Rotation.fromRodrigues(rot.asRodrigues()).asMatrix() @@ -164,18 +164,21 @@ class TestRotation: Rotation.qu2ho]) def test_quaternion_vectorization(self,default,conversion): qu = np.array([rot.asQuaternion() for rot in default]) - dev_null = conversion(qu.reshape(qu.shape[0]//2,-1,4)) + conversion(qu.reshape(qu.shape[0]//2,-1,4)) co = conversion(qu) for q,c in zip(qu,co): print(q,c) assert np.allclose(conversion(q),c) - @pytest.mark.parametrize('conversion',[Rotation.om2eu, + @pytest.mark.parametrize('conversion',[Rotation.om2qu, + Rotation.om2eu, Rotation.om2ax, + Rotation.om2ro, + Rotation.om2ho, ]) def test_matrix_vectorization(self,default,conversion): om = np.array([rot.asMatrix() for rot in default]) - dev_null = conversion(om.reshape(om.shape[0]//2,-1,3,3)) + conversion(om.reshape(om.shape[0]//2,-1,3,3)) co = conversion(om) for o,c in zip(om,co): print(o,c) @@ -185,10 +188,11 @@ class TestRotation: Rotation.eu2om, Rotation.eu2ax, Rotation.eu2ro, + Rotation.eu2ho, ]) def test_Euler_vectorization(self,default,conversion): eu = np.array([rot.asEulers() for rot in default]) - dev_null = conversion(eu.reshape(eu.shape[0]//2,-1,3)) + conversion(eu.reshape(eu.shape[0]//2,-1,3)) co = conversion(eu) for e,c in zip(eu,co): print(e,c) @@ -196,13 +200,29 @@ class TestRotation: @pytest.mark.parametrize('conversion',[Rotation.ax2qu, Rotation.ax2om, + Rotation.ax2eu, Rotation.ax2ro, Rotation.ax2ho, ]) def test_axisAngle_vectorization(self,default,conversion): ax = np.array([rot.asAxisAngle() for rot in default]) - dev_null = conversion(ax.reshape(ax.shape[0]//2,-1,4)) + conversion(ax.reshape(ax.shape[0]//2,-1,4)) co = conversion(ax) for a,c in zip(ax,co): print(a,c) assert np.allclose(conversion(a),c) + + + @pytest.mark.parametrize('conversion',[Rotation.ro2qu, + Rotation.ro2om, + Rotation.ro2eu, + Rotation.ro2ax, + Rotation.ro2ho, + ]) + def test_Rodrigues_vectorization(self,default,conversion): + ro = np.array([rot.asRodrigues() for rot in default]) + conversion(ro.reshape(ro.shape[0]//2,-1,4)) + co = conversion(ro) + for r,c in zip(ro,co): + print(r,c) + assert np.allclose(conversion(r),c) From cb9daccdd7eb21808b9940815f9d56b0af35835a Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 16:14:40 +0200 Subject: [PATCH 047/186] homochoric representation vectorized --- python/damask/_rotation.py | 28 ++++++++++++++++++++-------- python/tests/test_Rotation.py | 14 ++++++++++++++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 56c5d0593..e63bd1205 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -968,19 +968,31 @@ class Rotation: +0.0001703481934140054, -0.00012062065004116828, +0.000059719705868660826, -0.00001980756723965647, +0.000003953714684212874, -0.00000036555001439719544]) - # normalize h and store the magnitude - hmag_squared = np.sum(ho**2.) - if iszero(hmag_squared): - ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) - else: - hm = hmag_squared + if len(ho.shape) == 1: + # normalize h and store the magnitude + hmag_squared = np.sum(ho**2.) + if iszero(hmag_squared): + ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) + else: + hm = hmag_squared - # convert the magnitude to the rotation angle + # convert the magnitude to the rotation angle + s = tfit[0] + tfit[1] * hmag_squared + for i in range(2,16): + hm *= hmag_squared + s += tfit[i] * hm + ax = np.append(ho/np.sqrt(hmag_squared),2.0*np.arccos(np.clip(s,-1.0,1.0))) + else: + hmag_squared = np.sum(ho**2.,axis=-1,keepdims=True) + hm = hmag_squared.copy() s = tfit[0] + tfit[1] * hmag_squared for i in range(2,16): hm *= hmag_squared s += tfit[i] * hm - ax = np.append(ho/np.sqrt(hmag_squared),2.0*np.arccos(np.clip(s,-1.0,1.0))) + with np.errstate(invalid='ignore',divide='ignore'): + ax = np.where(np.broadcast_to(np.abs(hmag_squared)<1.e-6,ho.shape[:-1]+(4,)), + np.array([ 0.0, 0.0, 1.0, 0.0 ]), + np.block([ho/np.sqrt(hmag_squared),2.0*np.arccos(np.clip(s,-1.0,1.0))])) return ax @staticmethod diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 544e088c7..2ac819f4c 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -226,3 +226,17 @@ class TestRotation: for r,c in zip(ro,co): print(r,c) assert np.allclose(conversion(r),c) + + @pytest.mark.parametrize('conversion',[Rotation.ho2qu, + Rotation.ho2om, + Rotation.ho2eu, + Rotation.ho2ax, + Rotation.ho2ro, + ]) + def test_homochoric_vectorization(self,default,conversion): + ho = np.array([rot.asHomochoric() for rot in default]) + conversion(ho.reshape(ho.shape[0]//2,-1,3)) + co = conversion(ho) + for h,c in zip(ho,co): + print(h,c) + assert np.allclose(conversion(h),c) From 6e6f512c385bb3158cbaea08b885b1c9dd236f8e Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 17:05:52 +0200 Subject: [PATCH 048/186] fixed test --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 377e4f97a..85e4cb8e5 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 377e4f97a31ca1aa39a0645430c82bed40158001 +Subproject commit 85e4cb8e5b1bd437a6649457457cfd67b64e5a51 From 51104bfc13650f1637a4a675038face3cdb659ea Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 17:19:12 +0200 Subject: [PATCH 049/186] do not transpose for the standard case --- python/damask/_rotation.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index e63bd1205..a20db5aa8 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -446,13 +446,13 @@ class Rotation: qq = qu[0]**2-(qu[1]**2 + qu[2]**2 + qu[3]**2) om = np.diag(qq + 2.0*np.array([qu[1],qu[2],qu[3]])**2) - om[1,0] = 2.0*(qu[2]*qu[1]+qu[0]*qu[3]) - om[0,1] = 2.0*(qu[1]*qu[2]-qu[0]*qu[3]) - om[2,1] = 2.0*(qu[3]*qu[2]+qu[0]*qu[1]) - om[1,2] = 2.0*(qu[2]*qu[3]-qu[0]*qu[1]) - om[0,2] = 2.0*(qu[1]*qu[3]+qu[0]*qu[2]) - om[2,0] = 2.0*(qu[3]*qu[1]-qu[0]*qu[2]) - return om if P > 0.0 else om.T + om[0,1] = 2.0*(qu[2]*qu[1]+qu[0]*qu[3]) + om[1,0] = 2.0*(qu[1]*qu[2]-qu[0]*qu[3]) + om[1,2] = 2.0*(qu[3]*qu[2]+qu[0]*qu[1]) + om[2,1] = 2.0*(qu[2]*qu[3]-qu[0]*qu[1]) + om[2,0] = 2.0*(qu[1]*qu[3]+qu[0]*qu[2]) + om[0,2] = 2.0*(qu[3]*qu[1]-qu[0]*qu[2]) + return om if P < 0.0 else om.T else: qq = qu[...,0:1]**2-(qu[...,1:2]**2 + qu[...,2:3]**2 + qu[...,3:4]**2) om = np.block([qq + 2.0*qu[...,1:2]**2, From fac33ec408b94ab9a193cbc9176a90f1dcdd6b63 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 17:23:54 +0200 Subject: [PATCH 050/186] polishing --- python/damask/_rotation.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index a20db5aa8..42b097a78 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -452,7 +452,6 @@ class Rotation: om[2,1] = 2.0*(qu[2]*qu[3]-qu[0]*qu[1]) om[2,0] = 2.0*(qu[1]*qu[3]+qu[0]*qu[2]) om[0,2] = 2.0*(qu[3]*qu[1]-qu[0]*qu[2]) - return om if P < 0.0 else om.T else: qq = qu[...,0:1]**2-(qu[...,1:2]**2 + qu[...,2:3]**2 + qu[...,3:4]**2) om = np.block([qq + 2.0*qu[...,1:2]**2, @@ -465,7 +464,7 @@ class Rotation: 2.0*(qu[...,2:3]*qu[...,3:4]-qu[...,0:1]*qu[...,1:2]), qq + 2.0*qu[...,3:4]**2, ]).reshape(qu.shape[:-1]+(3,3)) - return om # TODO: TRANSPOSE FOR P = 1 + return om if P < 0.0 else np.swapaxes(om,(-1,-2)) @staticmethod def qu2eu(qu): @@ -823,7 +822,6 @@ class Rotation: q = omc*ax[idx[0]] * ax[idx[1]] om[idx[0],idx[1]] = q + s*ax[idx[2]] om[idx[1],idx[0]] = q - s*ax[idx[2]] - return om if P < 0.0 else om.T else: c = np.cos(ax[...,3:4]) s = np.sin(ax[...,3:4]) @@ -837,7 +835,7 @@ class Rotation: omc*ax[...,0:1]*ax[...,2:3] + s*ax[...,1:2], omc*ax[...,1:2]*ax[...,2:3] - s*ax[...,0:1], c+omc*ax[...,2:3]**2]).reshape(ax.shape[:-1]+(3,3)) - return om # TODO: TRANSPOSE FOR P = 1 + return om if P < 0.0 else np.swapaxes(om,(-1,-2)) @staticmethod def ax2eu(ax): @@ -989,7 +987,7 @@ class Rotation: for i in range(2,16): hm *= hmag_squared s += tfit[i] * hm - with np.errstate(invalid='ignore',divide='ignore'): + with np.errstate(invalid='ignore'): ax = np.where(np.broadcast_to(np.abs(hmag_squared)<1.e-6,ho.shape[:-1]+(4,)), np.array([ 0.0, 0.0, 1.0, 0.0 ]), np.block([ho/np.sqrt(hmag_squared),2.0*np.arccos(np.clip(s,-1.0,1.0))])) From 296a75d452741386ff1c5710eadae60ddfcf130d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 17:58:15 +0200 Subject: [PATCH 051/186] where not needed --- python/damask/_rotation.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 42b097a78..e728ab6ed 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -501,7 +501,7 @@ class Rotation: np.block([np.arctan2( 2.0*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2), np.ones( qu.shape[:-1]+(1,))*np.pi, np.zeros(qu.shape[:-1]+(1,))]), - eu) # TODO: Where not needed + eu) # TODO: Where can be nested # reduce Euler angles to definition range, i.e a lower limit of 0.0 eu[np.abs(eu)<1.e-6] = 0.0 eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) @@ -515,7 +515,7 @@ class Rotation: Modified version of the original formulation, should be numerically more stable """ if len(qu.shape) == 1: - if iszero(np.sum(qu[1:4]**2)): # set axis to [001] if the angle is 0/360 + if np.abs(np.sum(qu[1:4]**2)) < 1.e-6: # set axis to [001] if the angle is 0/360 ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) elif np.abs(qu[0]) > 1.e-6: s = np.sign(qu[0])/np.sqrt(qu[1]**2+qu[2]**2+qu[3]**2) @@ -546,14 +546,13 @@ class Rotation: else: with np.errstate(invalid='ignore',divide='ignore'): s = np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True) - ro = np.where(np.abs(s) < 1.0e-12, - [0.0,0.0,P,0.0], + ro = np.where(np.broadcast_to(np.abs(qu[...,0:1]) < 1.0e-12,qu.shape), + np.block([qu[...,1:2], qu[...,2:3], qu[...,3:4], np.ones(qu.shape[:-1]+(1,))*np.inf]), np.block([qu[...,1:2]/s,qu[...,2:3]/s,qu[...,3:4]/s, np.tan(np.arccos(np.clip(qu[...,0:1],-1.0,1.0))) ]) ) - ro = np.where(np.abs(qu[...,0:1]) < 1.0e-12, - np.block([qu[...,1:2], qu[...,2:3], qu[...,3:4], np.ones(qu.shape[:-1]+(1,))*np.inf]),ro) # TODO: Where not needed + ro[np.abs(s).squeeze(-1) < 1.0e-12] = [0.0,0.0,P,0.0] return ro @staticmethod @@ -1033,4 +1032,7 @@ class Rotation: @staticmethod def cu2ho(cu): """Cubochoric vector to homochoric vector.""" - return cube_to_ball(cu) + if len(cu.shape) == 1: + return cube_to_ball(cu) + else: + raise NotImplementedError From 8c61f67e3453249f02b40ef82ea8ad97781cc395 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 18:14:15 +0200 Subject: [PATCH 052/186] cleaning --- python/damask/_rotation.py | 10 +++++----- python/tests/test_Rotation.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index e728ab6ed..4c164376c 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -517,7 +517,7 @@ class Rotation: if len(qu.shape) == 1: if np.abs(np.sum(qu[1:4]**2)) < 1.e-6: # set axis to [001] if the angle is 0/360 ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) - elif np.abs(qu[0]) > 1.e-6: + elif qu[0] > 1.e-6: s = np.sign(qu[0])/np.sqrt(qu[1]**2+qu[2]**2+qu[3]**2) omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) ax = ax = np.array([ qu[1]*s, qu[2]*s, qu[3]*s, omega ]) @@ -527,10 +527,10 @@ class Rotation: with np.errstate(invalid='ignore',divide='ignore'): s = np.sign(qu[...,0:1])/np.sqrt(qu[...,1:2]**2+qu[...,2:3]**2+qu[...,3:4]**2) omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) - ax = np.where(np.sum(np.abs(qu[:,1:4])**2,axis=-1,keepdims=True) < 1.0e-6, - [0.0, 0.0, 1.0, 0.0], np.block([qu[...,1:4]*s,omega])) - ax = np.where(qu[...,0:1] < 1.0e-6, - np.block([qu[...,1:4],np.ones(qu.shape[:-1]+(1,))*np.pi]),ax) # TODO: Where not needed + ax = np.where(np.broadcast_to(qu[...,0:1] < 1.0e-6,qu.shape), + np.block([qu[...,1:4],np.ones(qu.shape[:-1]+(1,))*np.pi]), + np.block([qu[...,1:4]*s,omega])) + ax[np.sum(np.abs(qu[...,1:4])**2,axis=-1) < 1.0e-6,] = [0.0, 0.0, 1.0, 0.0] return ax @staticmethod diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 2ac819f4c..0007a2aec 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -167,7 +167,7 @@ class TestRotation: conversion(qu.reshape(qu.shape[0]//2,-1,4)) co = conversion(qu) for q,c in zip(qu,co): - print(q,c) + #print(q,c) assert np.allclose(conversion(q),c) @pytest.mark.parametrize('conversion',[Rotation.om2qu, From c57f96cd6eb3e369f5ce8bd4a8b3fab2ca2d51dd Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 18:32:06 +0200 Subject: [PATCH 053/186] also missing --- python/damask/_rotation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 4c164376c..b2a08d77b 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -1000,7 +1000,10 @@ class Rotation: @staticmethod def ho2cu(ho): """Homochoric vector to cubochoric vector.""" - return ball_to_cube(ho) + if len(ho.shape) == 1: + return ball_to_cube(ho) + else: + raise NotImplementedError #---------- Cubochoric ---------- From c0c37fe6a5c95cf823011b0a3adb54c389c83eef Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 20:42:46 +0200 Subject: [PATCH 054/186] polishing --- python/damask/_rotation.py | 8 ++++---- python/tests/test_Rotation.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index b2a08d77b..c4f0b3c23 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -502,7 +502,7 @@ class Rotation: np.ones( qu.shape[:-1]+(1,))*np.pi, np.zeros(qu.shape[:-1]+(1,))]), eu) # TODO: Where can be nested - # reduce Euler angles to definition range, i.e a lower limit of 0.0 + # reduce Euler angles to definition range eu[np.abs(eu)<1.e-6] = 0.0 eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) return eu @@ -530,7 +530,7 @@ class Rotation: ax = np.where(np.broadcast_to(qu[...,0:1] < 1.0e-6,qu.shape), np.block([qu[...,1:4],np.ones(qu.shape[:-1]+(1,))*np.pi]), np.block([qu[...,1:4]*s,omega])) - ax[np.sum(np.abs(qu[...,1:4])**2,axis=-1) < 1.0e-6,] = [0.0, 0.0, 1.0, 0.0] + ax[np.sum(np.abs(qu[...,1:4])**2,axis=-1) < 1.0e-6,] = [0.0, 0.0, 1.0, 0.0] return ax @staticmethod @@ -559,10 +559,10 @@ class Rotation: def qu2ho(qu): """Quaternion to homochoric vector.""" if len(qu.shape) == 1: - if np.isclose(qu[0],1.0): + omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) + if np.abs(omega) < 1.0e-12: ho = np.zeros(3) else: - omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) ho = np.array([qu[1], qu[2], qu[3]]) f = 0.75 * ( omega - np.sin(omega) ) ho = ho/np.linalg.norm(ho) * f**(1./3.) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 0007a2aec..2ac819f4c 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -167,7 +167,7 @@ class TestRotation: conversion(qu.reshape(qu.shape[0]//2,-1,4)) co = conversion(qu) for q,c in zip(qu,co): - #print(q,c) + print(q,c) assert np.allclose(conversion(q),c) @pytest.mark.parametrize('conversion',[Rotation.om2qu, From f41a47ce8b223210a81ece0fa549816d7e8b6b39 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 11 Apr 2020 23:27:25 +0200 Subject: [PATCH 055/186] polishing and slightly stricter tolerances --- python/damask/_rotation.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index c4f0b3c23..e83c5fd1d 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -473,9 +473,9 @@ class Rotation: q03 = qu[0]**2+qu[3]**2 q12 = qu[1]**2+qu[2]**2 chi = np.sqrt(q03*q12) - if np.abs(q12) < 1.e-6: + if np.abs(q12) < 1.e-8: eu = np.array([np.arctan2(-P*2.0*qu[0]*qu[3],qu[0]**2-qu[3]**2), 0.0, 0.0]) - elif np.abs(q03) < 1.e-6: + elif np.abs(q03) < 1.e-8: eu = np.array([np.arctan2( 2.0*qu[1]*qu[2],qu[1]**2-qu[2]**2), np.pi, 0.0]) else: eu = np.array([np.arctan2((-P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-P*qu[0]*qu[1]-qu[2]*qu[3])*chi ), @@ -490,18 +490,18 @@ class Rotation: q12_s = qu[...,1:2]**2+qu[...,2:3]**2 chi = np.sqrt(q03_s*q12_s) - eu = np.where(np.abs(q12_s) < 1.0e-6, - np.block([np.arctan2(-P*2.0*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2), - np.zeros(qu.shape[:-1]+(2,))]), - np.block([np.arctan2((-P*q02+q13)*chi, (-P*q01-q23)*chi), - np.arctan2( 2.0*chi, q03_s-q12_s ), - np.arctan2(( P*q02+q13)*chi, (-P*q01+q23)*chi)]) + eu = np.where(np.abs(q12_s) < 1.0e-8, + np.block([np.arctan2(-P*2.0*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2), + np.zeros(qu.shape[:-1]+(2,))]), + np.where(np.abs(q03_s) < 1.0e-8, + np.block([np.arctan2( 2.0*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2), + np.broadcast_to(np.pi,qu.shape[:-1]+(1,)), + np.zeros(qu.shape[:-1]+(1,))]), + np.block([np.arctan2((-P*q02+q13)*chi, (-P*q01-q23)*chi), + np.arctan2( 2.0*chi, q03_s-q12_s ), + np.arctan2(( P*q02+q13)*chi, (-P*q01+q23)*chi)]) + ) ) - eu = np.where(np.logical_and(np.abs(q03_s) < 1.0e-6, np.abs(q12_s) >= 1.0e-6), - np.block([np.arctan2( 2.0*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2), - np.ones( qu.shape[:-1]+(1,))*np.pi, - np.zeros(qu.shape[:-1]+(1,))]), - eu) # TODO: Where can be nested # reduce Euler angles to definition range eu[np.abs(eu)<1.e-6] = 0.0 eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) @@ -528,7 +528,7 @@ class Rotation: s = np.sign(qu[...,0:1])/np.sqrt(qu[...,1:2]**2+qu[...,2:3]**2+qu[...,3:4]**2) omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) ax = np.where(np.broadcast_to(qu[...,0:1] < 1.0e-6,qu.shape), - np.block([qu[...,1:4],np.ones(qu.shape[:-1]+(1,))*np.pi]), + np.block([qu[...,1:4],np.broadcast_to(np.pi,qu.shape[:-1]+(1,))]), np.block([qu[...,1:4]*s,omega])) ax[np.sum(np.abs(qu[...,1:4])**2,axis=-1) < 1.0e-6,] = [0.0, 0.0, 1.0, 0.0] return ax @@ -547,7 +547,7 @@ class Rotation: with np.errstate(invalid='ignore',divide='ignore'): s = np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True) ro = np.where(np.broadcast_to(np.abs(qu[...,0:1]) < 1.0e-12,qu.shape), - np.block([qu[...,1:2], qu[...,2:3], qu[...,3:4], np.ones(qu.shape[:-1]+(1,))*np.inf]), + np.block([qu[...,1:2], qu[...,2:3], qu[...,3:4], np.broadcast_to(np.inf,qu.shape[:-1]+(1,))]), np.block([qu[...,1:2]/s,qu[...,2:3]/s,qu[...,3:4]/s, np.tan(np.arccos(np.clip(qu[...,0:1],-1.0,1.0))) ]) @@ -805,7 +805,7 @@ class Rotation: else: c = np.cos(ax[...,3:4]*.5) s = np.sin(ax[...,3:4]*.5) - qu = np.where(np.abs(ax[...,3:4])<1.e-12,[1.0, 0.0, 0.0, 0.0],np.block([c, ax[...,:3]*s])) + qu = np.where(np.abs(ax[...,3:4])<1.e-6,[1.0, 0.0, 0.0, 0.0],np.block([c, ax[...,:3]*s])) return qu @staticmethod @@ -988,7 +988,7 @@ class Rotation: s += tfit[i] * hm with np.errstate(invalid='ignore'): ax = np.where(np.broadcast_to(np.abs(hmag_squared)<1.e-6,ho.shape[:-1]+(4,)), - np.array([ 0.0, 0.0, 1.0, 0.0 ]), + [ 0.0, 0.0, 1.0, 0.0 ], np.block([ho/np.sqrt(hmag_squared),2.0*np.arccos(np.clip(s,-1.0,1.0))])) return ax From 8aa95776d60b9dfc52ffe8b0a65759a7480288b5 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 12 Apr 2020 00:17:48 +0200 Subject: [PATCH 056/186] change to test not needed --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 85e4cb8e5..232a094c7 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 85e4cb8e5b1bd437a6649457457cfd67b64e5a51 +Subproject commit 232a094c715bcbbd1c6652c4dc4a4a50d402b82f From 04fbc38a4b8b27f49a3c982b5946cb2da33f60a1 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 12 Apr 2020 01:19:11 +0200 Subject: [PATCH 057/186] keep namespace clean and avoid overwriting in fromXXX functions --- python/damask/_rotation.py | 58 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index e83c5fd1d..b68ce4d8e 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -2,7 +2,7 @@ import numpy as np from ._Lambert import ball_to_cube, cube_to_ball -P = -1 +_P = -1 def iszero(a): return np.isclose(a,0.0,atol=1.0e-12,rtol=0.0) @@ -89,7 +89,7 @@ class Rotation: other_q = other.quaternion[0] other_p = other.quaternion[1:] R = self.__class__(np.append(self_q*other_q - np.dot(self_p,other_p), - self_q*other_p + other_q*self_p + P * np.cross(self_p,other_p))) + self_q*other_p + other_q*self_p + _P * np.cross(self_p,other_p))) return R.standardize() elif isinstance(other, (tuple,np.ndarray)): if isinstance(other,tuple) or other.shape == (3,): # rotate a single (3)-vector or meshgrid @@ -97,7 +97,7 @@ class Rotation: B = 2.0 * ( self.quaternion[1]*other[0] + self.quaternion[2]*other[1] + self.quaternion[3]*other[2]) - C = 2.0 * P*self.quaternion[0] + C = 2.0 * _P*self.quaternion[0] return np.array([ A*other[0] + B*self.quaternion[1] + C*(self.quaternion[2]*other[2] - self.quaternion[3]*other[1]), @@ -464,7 +464,7 @@ class Rotation: 2.0*(qu[...,2:3]*qu[...,3:4]-qu[...,0:1]*qu[...,1:2]), qq + 2.0*qu[...,3:4]**2, ]).reshape(qu.shape[:-1]+(3,3)) - return om if P < 0.0 else np.swapaxes(om,(-1,-2)) + return om if _P < 0.0 else np.swapaxes(om,(-1,-2)) @staticmethod def qu2eu(qu): @@ -474,13 +474,13 @@ class Rotation: q12 = qu[1]**2+qu[2]**2 chi = np.sqrt(q03*q12) if np.abs(q12) < 1.e-8: - eu = np.array([np.arctan2(-P*2.0*qu[0]*qu[3],qu[0]**2-qu[3]**2), 0.0, 0.0]) + eu = np.array([np.arctan2(-_P*2.0*qu[0]*qu[3],qu[0]**2-qu[3]**2), 0.0, 0.0]) elif np.abs(q03) < 1.e-8: eu = np.array([np.arctan2( 2.0*qu[1]*qu[2],qu[1]**2-qu[2]**2), np.pi, 0.0]) else: - eu = np.array([np.arctan2((-P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-P*qu[0]*qu[1]-qu[2]*qu[3])*chi ), + eu = np.array([np.arctan2((-_P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-_P*qu[0]*qu[1]-qu[2]*qu[3])*chi ), np.arctan2( 2.0*chi, q03-q12 ), - np.arctan2(( P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-P*qu[0]*qu[1]+qu[2]*qu[3])*chi )]) + np.arctan2(( _P*qu[0]*qu[2]+qu[1]*qu[3])*chi, (-_P*qu[0]*qu[1]+qu[2]*qu[3])*chi )]) else: q02 = qu[...,0:1]*qu[...,2:3] q13 = qu[...,1:2]*qu[...,3:4] @@ -491,15 +491,15 @@ class Rotation: chi = np.sqrt(q03_s*q12_s) eu = np.where(np.abs(q12_s) < 1.0e-8, - np.block([np.arctan2(-P*2.0*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2), + np.block([np.arctan2(-_P*2.0*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2), np.zeros(qu.shape[:-1]+(2,))]), np.where(np.abs(q03_s) < 1.0e-8, np.block([np.arctan2( 2.0*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2), np.broadcast_to(np.pi,qu.shape[:-1]+(1,)), np.zeros(qu.shape[:-1]+(1,))]), - np.block([np.arctan2((-P*q02+q13)*chi, (-P*q01-q23)*chi), + np.block([np.arctan2((-_P*q02+q13)*chi, (-_P*q01-q23)*chi), np.arctan2( 2.0*chi, q03_s-q12_s ), - np.arctan2(( P*q02+q13)*chi, (-P*q01+q23)*chi)]) + np.arctan2(( _P*q02+q13)*chi, (-_P*q01+q23)*chi)]) ) ) # reduce Euler angles to definition range @@ -541,7 +541,7 @@ class Rotation: ro = np.array([qu[1], qu[2], qu[3], np.inf]) else: s = np.linalg.norm(qu[1:4]) - ro = np.array([0.0,0.0,P,0.0] if iszero(s) else \ + ro = np.array([0.0,0.0,_P,0.0] if iszero(s) else \ [ qu[1]/s, qu[2]/s, qu[3]/s, np.tan(np.arccos(np.clip(qu[0],-1.0,1.0)))]) else: with np.errstate(invalid='ignore',divide='ignore'): @@ -552,7 +552,7 @@ class Rotation: np.tan(np.arccos(np.clip(qu[...,0:1],-1.0,1.0))) ]) ) - ro[np.abs(s).squeeze(-1) < 1.0e-12] = [0.0,0.0,P,0.0] + ro[np.abs(s).squeeze(-1) < 1.0e-12] = [0.0,0.0,_P,0.0] return ro @staticmethod @@ -636,11 +636,11 @@ class Rotation: # next, find the eigenvalue (1,0j) i = np.where(np.isclose(w,1.0+0.0j))[0][0] ax[0:3] = np.real(vr[0:3,i]) - diagDelta = -P*np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) + diagDelta = -_P*np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) diagDelta[np.abs(diagDelta)<1.e-6] = 1.0 ax[0:3] = np.where(np.abs(diagDelta)<0, ax[0:3],np.abs(ax[0:3])*np.sign(diagDelta)) else: - diag_delta = -P*np.block([om[...,1,2:3]-om[...,2,1:2], + diag_delta = -_P*np.block([om[...,1,2:3]-om[...,2,1:2], om[...,2,0:1]-om[...,0,2:3], om[...,0,1:2]-om[...,1,0:1] ]) @@ -685,18 +685,18 @@ class Rotation: cPhi = np.cos(ee[1]) sPhi = np.sin(ee[1]) qu = np.array([ cPhi*np.cos(ee[0]+ee[2]), - -P*sPhi*np.cos(ee[0]-ee[2]), - -P*sPhi*np.sin(ee[0]-ee[2]), - -P*cPhi*np.sin(ee[0]+ee[2]) ]) + -_P*sPhi*np.cos(ee[0]-ee[2]), + -_P*sPhi*np.sin(ee[0]-ee[2]), + -_P*cPhi*np.sin(ee[0]+ee[2]) ]) if qu[0] < 0.0: qu*=-1 else: ee = 0.5*eu cPhi = np.cos(ee[...,1:2]) sPhi = np.sin(ee[...,1:2]) qu = np.block([ cPhi*np.cos(ee[...,0:1]+ee[...,2:3]), - -P*sPhi*np.cos(ee[...,0:1]-ee[...,2:3]), - -P*sPhi*np.sin(ee[...,0:1]-ee[...,2:3]), - -P*cPhi*np.sin(ee[...,0:1]+ee[...,2:3])]) + -_P*sPhi*np.cos(ee[...,0:1]-ee[...,2:3]), + -_P*sPhi*np.sin(ee[...,0:1]-ee[...,2:3]), + -_P*cPhi*np.sin(ee[...,0:1]+ee[...,2:3])]) qu[qu[...,0]<0.0]*=-1 return qu @@ -741,7 +741,7 @@ class Rotation: if np.abs(alpha)<1.e-6: ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) else: - ax = -P/tau * np.array([ t*np.cos(delta), t*np.sin(delta), np.sin(sigma) ]) # passive axis angle pair so a minus sign in front + ax = -_P/tau * np.array([ t*np.cos(delta), t*np.sin(delta), np.sin(sigma) ]) # passive axis angle pair so a minus sign in front ax = np.append(ax,alpha) if alpha < 0.0: ax *= -1.0 # ensure alpha is positive else: @@ -753,9 +753,9 @@ class Rotation: with np.errstate(invalid='ignore',divide='ignore'): ax = np.where(np.broadcast_to(np.abs(alpha)<1.0e-12,eu.shape[:-1]+(4,)), [0.0,0.0,1.0,0.0], - np.block([-P/tau*t*np.cos(delta), - -P/tau*t*np.sin(delta), - -P/tau* np.sin(sigma), + np.block([-_P/tau*t*np.cos(delta), + -_P/tau*t*np.sin(delta), + -_P/tau* np.sin(sigma), alpha ])) ax[(alpha<0.0).squeeze()] *=-1 @@ -769,14 +769,14 @@ class Rotation: if ro[3] >= np.pi: # Differs from original implementation. check convention 5 ro[3] = np.inf elif iszero(ro[3]): - ro = np.array([ 0.0, 0.0, P, 0.0 ]) + ro = np.array([ 0.0, 0.0, _P, 0.0 ]) else: ro[3] = np.tan(ro[3]*0.5) else: ax = Rotation.eu2ax(eu) ro = np.block([ax[...,:3],np.tan(ax[...,3:4]*.5)]) ro[ax[...,3]>=np.pi,3] = np.inf - ro[np.abs(ax[...,3])<1.e-16] = [ 0.0, 0.0, P, 0.0 ] + ro[np.abs(ax[...,3])<1.e-16] = [ 0.0, 0.0, _P, 0.0 ] return ro @staticmethod @@ -834,7 +834,7 @@ class Rotation: omc*ax[...,0:1]*ax[...,2:3] + s*ax[...,1:2], omc*ax[...,1:2]*ax[...,2:3] - s*ax[...,0:1], c+omc*ax[...,2:3]**2]).reshape(ax.shape[:-1]+(3,3)) - return om if P < 0.0 else np.swapaxes(om,(-1,-2)) + return om if _P < 0.0 else np.swapaxes(om,(-1,-2)) @staticmethod def ax2eu(ax): @@ -846,7 +846,7 @@ class Rotation: """Axis angle pair to Rodrigues-Frank vector.""" if len(ax.shape) == 1: if np.abs(ax[3])<1.e-6: - ro = [ 0.0, 0.0, P, 0.0 ] + ro = [ 0.0, 0.0, _P, 0.0 ] else: ro = [ax[0], ax[1], ax[2]] # 180 degree case @@ -859,7 +859,7 @@ class Rotation: np.inf, np.tan(ax[...,3:4]*0.5)) ]) - ro[np.abs(ax[...,3])<1.e-6] = [.0,.0,P,.0] + ro[np.abs(ax[...,3])<1.e-6] = [.0,.0,_P,.0] return ro @staticmethod From 3d10266fbc759da1c54b8c15996e2f5d837714c2 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 12 Apr 2020 01:29:11 +0200 Subject: [PATCH 058/186] similar style as for other conversions --- python/damask/_Lambert.py | 4 ---- python/damask/_rotation.py | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/python/damask/_Lambert.py b/python/damask/_Lambert.py index 59abe7f64..a823764e9 100644 --- a/python/damask/_Lambert.py +++ b/python/damask/_Lambert.py @@ -52,8 +52,6 @@ def cube_to_ball(cube): """ cube_ = np.clip(cube,None,np.pi**(2./3.) * 0.5) if np.isclose(np.abs(np.max(cube)),np.pi**(2./3.) * 0.5,atol=1e-6) else cube - if np.abs(np.max(cube_))>np.pi**(2./3.) * 0.5: - raise ValueError('Coordinate outside of the cube: {} {} {}.'.format(*cube)) # transform to the sphere grid via the curved square, and intercept the zero point if np.allclose(cube_,0.0,rtol=0.0,atol=1.0e-16): @@ -105,8 +103,6 @@ def ball_to_cube(ball): """ ball_ = ball/np.linalg.norm(ball)*R1 if np.isclose(np.linalg.norm(ball),R1,atol=1e-6) else ball rs = np.linalg.norm(ball_) - if rs > R1+1.e-9: - raise ValueError('Coordinate outside of the sphere: {} {} {}.'.format(*ball)) if np.allclose(ball_,0.0,rtol=0.0,atol=1.0e-16): cube = np.zeros(3) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index b68ce4d8e..dcd61822f 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -350,6 +350,9 @@ class Rotation: else np.array(homochoric,dtype=float) if P > 0: ho *= -1 # convert from P=1 to P=-1 + if np.linalg.norm(ho) > (3.*np.pi/4.)**(1./3.)+1e-9: + raise ValueError('Coordinate outside of the sphere: {} {} {}.'.format(ho)) + return Rotation(Rotation.ho2qu(ho)) @staticmethod @@ -358,6 +361,10 @@ class Rotation: cu = cubochoric if isinstance(cubochoric, np.ndarray) and cubochoric.dtype == np.dtype(float) \ else np.array(cubochoric,dtype=float) + + if np.abs(np.max(cu))>np.pi**(2./3.) * 0.5+1e-9: + raise ValueError('Coordinate outside of the cube: {} {} {}.'.format(*cu)) + ho = Rotation.cu2ho(cu) if P > 0: ho *= -1 # convert from P=1 to P=-1 From 99ec48aba4712a0e1996bf8d91b0250364ab7496 Mon Sep 17 00:00:00 2001 From: Test User Date: Sun, 12 Apr 2020 19:42:46 +0200 Subject: [PATCH 059/186] [skip ci] updated version information after successful test of v2.0.3-2255-gc74ffae8 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 804287b93..0e875200a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2245-gc7508d85 +v2.0.3-2255-gc74ffae8 From 95e41e0b3f7961c1570124237baee585b989a15a Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 14 Apr 2020 07:22:30 +0200 Subject: [PATCH 060/186] not needed (just linear interpolation) --- src/homogenization.f90 | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 50331cbdd..cef3c2c5b 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -161,7 +161,6 @@ subroutine homogenization_init allocate(materialpoint_dPdF(3,3,3,3,discretization_nIP,discretization_nElem), source=0.0_pReal) materialpoint_F0 = spread(spread(math_I3,3,discretization_nIP),4,discretization_nElem) ! initialize to identity materialpoint_F = materialpoint_F0 ! initialize to identity - allocate(materialpoint_subF0(3,3,discretization_nIP,discretization_nElem), source=0.0_pReal) allocate(materialpoint_subF(3,3,discretization_nIP,discretization_nElem), source=0.0_pReal) allocate(materialpoint_P(3,3,discretization_nIP,discretization_nElem), source=0.0_pReal) allocate(materialpoint_subFrac(discretization_nIP,discretization_nElem), source=0.0_pReal) @@ -238,8 +237,6 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) enddo - - materialpoint_subF0(1:3,1:3,i,e) = materialpoint_F0(1:3,1:3,i,e) materialpoint_subFrac(i,e) = 0.0_pReal materialpoint_subStep(i,e) = 1.0_pReal/num%subStepSizeHomog ! <> materialpoint_converged(i,e) = .false. ! pretend failed step of twice the required size @@ -326,8 +323,6 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) damageState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & damageState(material_homogenizationAt(e))%State (:,material_homogenizationMemberAt(i,e)) - materialpoint_subF0(1:3,1:3,i,e) = materialpoint_subF(1:3,1:3,i,e) - endif steppingNeeded else converged @@ -390,9 +385,9 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) if (materialpoint_subStep(i,e) > num%subStepMinHomog) then materialpoint_requested(i,e) = .true. - materialpoint_subF(1:3,1:3,i,e) = materialpoint_subF0(1:3,1:3,i,e) & - + materialpoint_subStep(i,e) * (materialpoint_F(1:3,1:3,i,e) & - - materialpoint_F0(1:3,1:3,i,e)) + materialpoint_subF(1:3,1:3,i,e) = materialpoint_F0(1:3,1:3,i,e) & + + (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) & + * (materialpoint_subStep(i,e)+materialpoint_subFrac(i,e)) materialpoint_subdt(i,e) = materialpoint_subStep(i,e) * dt materialpoint_doneAndHappy(1:2,i,e) = [.false.,.true.] endif From d616c1dda8764af5a333b426ab84a3161c424b65 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 14 Apr 2020 07:45:39 +0200 Subject: [PATCH 061/186] better use explicit arguments --- src/homogenization.f90 | 46 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index cef3c2c5b..157b688f5 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -414,7 +414,7 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) IpLooping2: do i = FEsolving_execIP(1),FEsolving_execIP(2) if ( materialpoint_requested(i,e) .and. & ! process requested but... .not. materialpoint_doneAndHappy(1,i,e)) then ! ...not yet done material points - call partitionDeformation(i,e) ! partition deformation onto constituents + call partitionDeformation(materialpoint_subF(1:3,1:3,i,e),i,e) ! partition deformation onto constituents crystallite_dt(1:myNgrains,i,e) = materialpoint_subdt(i,e) ! propagate materialpoint dt to grains crystallite_requested(1:myNgrains,i,e) = .true. ! request calculation for constituents else @@ -441,7 +441,9 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) if (.not. materialpoint_converged(i,e)) then materialpoint_doneAndHappy(1:2,i,e) = [.true.,.false.] else - materialpoint_doneAndHappy(1:2,i,e) = updateState(i,e) + materialpoint_doneAndHappy(1:2,i,e) = updateState(materialpoint_subdt(i,e), & + materialpoint_subF(1:3,1:3,i,e), & + i,e) materialpoint_converged(i,e) = all(materialpoint_doneAndHappy(1:2,i,e)) ! converged if done and happy endif endif @@ -476,26 +478,28 @@ end subroutine materialpoint_stressAndItsTangent !-------------------------------------------------------------------------------------------------- !> @brief partition material point def grad onto constituents !-------------------------------------------------------------------------------------------------- -subroutine partitionDeformation(ip,el) +subroutine partitionDeformation(subF,ip,el) - integer, intent(in) :: & + real(pReal), intent(in), dimension(3,3) :: & + subF + integer, intent(in) :: & ip, & !< integration point el !< element number chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) case (HOMOGENIZATION_NONE_ID) chosenHomogenization - crystallite_partionedF(1:3,1:3,1,ip,el) = materialpoint_subF(1:3,1:3,ip,el) + crystallite_partionedF(1:3,1:3,1,ip,el) = subF case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization call mech_isostrain_partitionDeformation(& crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - materialpoint_subF(1:3,1:3,ip,el)) + subF) case (HOMOGENIZATION_RGC_ID) chosenHomogenization call mech_RGC_partitionDeformation(& crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - materialpoint_subF(1:3,1:3,ip,el),& + subF,& ip, & el) end select chosenHomogenization @@ -507,9 +511,13 @@ end subroutine partitionDeformation !> @brief update the internal state of the homogenization scheme and tell whether "done" and !> "happy" with result !-------------------------------------------------------------------------------------------------- -function updateState(ip,el) +function updateState(subdt,subF,ip,el) - integer, intent(in) :: & + real(pReal), intent(in) :: & + subdt !< current time step + real(pReal), intent(in), dimension(3,3) :: & + subF + integer, intent(in) :: & ip, & !< integration point el !< element number logical, dimension(2) :: updateState @@ -519,21 +527,21 @@ function updateState(ip,el) case (HOMOGENIZATION_RGC_ID) chosenHomogenization updateState = & updateState .and. & - mech_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - crystallite_partionedF0(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el),& - materialpoint_subF(1:3,1:3,ip,el),& - materialpoint_subdt(ip,el), & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - ip, & - el) + mech_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + crystallite_partionedF0(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el),& + subF,& + subdt, & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + ip, & + el) end select chosenHomogenization chosenThermal: select case (thermal_type(material_homogenizationAt(el))) case (THERMAL_adiabatic_ID) chosenThermal updateState = & updateState .and. & - thermal_adiabatic_updateState(materialpoint_subdt(ip,el), & + thermal_adiabatic_updateState(subdt, & ip, & el) end select chosenThermal @@ -542,7 +550,7 @@ function updateState(ip,el) case (DAMAGE_local_ID) chosenDamage updateState = & updateState .and. & - damage_local_updateState(materialpoint_subdt(ip,el), & + damage_local_updateState(subdt, & ip, & el) end select chosenDamage From 08948867441d9dd212da62ee71e10f2353d697ef Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 14 Apr 2020 07:57:25 +0200 Subject: [PATCH 062/186] can be calculated when needed --- src/homogenization.f90 | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 157b688f5..d6112fe8d 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -43,8 +43,7 @@ module homogenization materialpoint_subF !< def grad of IP to be reached at end of homog inc real(pReal), dimension(:,:), allocatable :: & materialpoint_subFrac, & - materialpoint_subStep, & - materialpoint_subdt + materialpoint_subStep logical, dimension(:,:), allocatable :: & materialpoint_requested, & materialpoint_converged @@ -165,7 +164,6 @@ subroutine homogenization_init allocate(materialpoint_P(3,3,discretization_nIP,discretization_nElem), source=0.0_pReal) allocate(materialpoint_subFrac(discretization_nIP,discretization_nElem), source=0.0_pReal) allocate(materialpoint_subStep(discretization_nIP,discretization_nElem), source=0.0_pReal) - allocate(materialpoint_subdt(discretization_nIP,discretization_nElem), source=0.0_pReal) allocate(materialpoint_requested(discretization_nIP,discretization_nElem), source=.false.) allocate(materialpoint_converged(discretization_nIP,discretization_nElem), source=.true.) allocate(materialpoint_doneAndHappy(2,discretization_nIP,discretization_nElem), source=.true.) @@ -388,7 +386,6 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) materialpoint_subF(1:3,1:3,i,e) = materialpoint_F0(1:3,1:3,i,e) & + (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) & * (materialpoint_subStep(i,e)+materialpoint_subFrac(i,e)) - materialpoint_subdt(i,e) = materialpoint_subStep(i,e) * dt materialpoint_doneAndHappy(1:2,i,e) = [.false.,.true.] endif enddo IpLooping1 @@ -415,7 +412,7 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) if ( materialpoint_requested(i,e) .and. & ! process requested but... .not. materialpoint_doneAndHappy(1,i,e)) then ! ...not yet done material points call partitionDeformation(materialpoint_subF(1:3,1:3,i,e),i,e) ! partition deformation onto constituents - crystallite_dt(1:myNgrains,i,e) = materialpoint_subdt(i,e) ! propagate materialpoint dt to grains + crystallite_dt(1:myNgrains,i,e) = dt*materialpoint_subStep(i,e) ! propagate materialpoint dt to grains crystallite_requested(1:myNgrains,i,e) = .true. ! request calculation for constituents else crystallite_requested(1:myNgrains,i,e) = .false. ! calculation for constituents not required anymore @@ -441,7 +438,7 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) if (.not. materialpoint_converged(i,e)) then materialpoint_doneAndHappy(1:2,i,e) = [.true.,.false.] else - materialpoint_doneAndHappy(1:2,i,e) = updateState(materialpoint_subdt(i,e), & + materialpoint_doneAndHappy(1:2,i,e) = updateState(dt*materialpoint_subStep(i,e), & materialpoint_subF(1:3,1:3,i,e), & i,e) materialpoint_converged(i,e) = all(materialpoint_doneAndHappy(1:2,i,e)) ! converged if done and happy From 0de4520580f87f68328c38f3ca1c3a574ca07984 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 14 Apr 2020 08:24:28 +0200 Subject: [PATCH 063/186] directly calculate subF --- src/homogenization.f90 | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index d6112fe8d..543388f1c 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -38,9 +38,6 @@ module homogenization real(pReal), dimension(:,:,:,:,:,:), allocatable, public :: & materialpoint_dPdF !< tangent of first P--K stress at IP - real(pReal), dimension(:,:,:,:), allocatable :: & - materialpoint_subF0, & !< def grad of IP at beginning of homogenization increment - materialpoint_subF !< def grad of IP to be reached at end of homog inc real(pReal), dimension(:,:), allocatable :: & materialpoint_subFrac, & materialpoint_subStep @@ -160,7 +157,6 @@ subroutine homogenization_init allocate(materialpoint_dPdF(3,3,3,3,discretization_nIP,discretization_nElem), source=0.0_pReal) materialpoint_F0 = spread(spread(math_I3,3,discretization_nIP),4,discretization_nElem) ! initialize to identity materialpoint_F = materialpoint_F0 ! initialize to identity - allocate(materialpoint_subF(3,3,discretization_nIP,discretization_nElem), source=0.0_pReal) allocate(materialpoint_P(3,3,discretization_nIP,discretization_nElem), source=0.0_pReal) allocate(materialpoint_subFrac(discretization_nIP,discretization_nElem), source=0.0_pReal) allocate(materialpoint_subStep(discretization_nIP,discretization_nElem), source=0.0_pReal) @@ -200,6 +196,8 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) e, & !< element number mySource, & myNgrains + real(pReal), dimension(3,3) :: & + subF #ifdef DEBUG if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0) then @@ -383,9 +381,6 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) if (materialpoint_subStep(i,e) > num%subStepMinHomog) then materialpoint_requested(i,e) = .true. - materialpoint_subF(1:3,1:3,i,e) = materialpoint_F0(1:3,1:3,i,e) & - + (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) & - * (materialpoint_subStep(i,e)+materialpoint_subFrac(i,e)) materialpoint_doneAndHappy(1:2,i,e) = [.false.,.true.] endif enddo IpLooping1 @@ -405,13 +400,16 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) ! deformation partitioning ! based on materialpoint_subF0,.._subF,crystallite_partionedF0, and homogenization_state, ! results in crystallite_partionedF - !$OMP PARALLEL DO PRIVATE(myNgrains) + !$OMP PARALLEL DO PRIVATE(myNgrains,subF) elementLooping2: do e = FEsolving_execElem(1),FEsolving_execElem(2) myNgrains = homogenization_Ngrains(material_homogenizationAt(e)) IpLooping2: do i = FEsolving_execIP(1),FEsolving_execIP(2) if ( materialpoint_requested(i,e) .and. & ! process requested but... .not. materialpoint_doneAndHappy(1,i,e)) then ! ...not yet done material points - call partitionDeformation(materialpoint_subF(1:3,1:3,i,e),i,e) ! partition deformation onto constituents + subF = materialpoint_F0(1:3,1:3,i,e) & + + (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) & + * (materialpoint_subStep(i,e)+materialpoint_subFrac(i,e)) + call partitionDeformation(subF,i,e) ! partition deformation onto constituents crystallite_dt(1:myNgrains,i,e) = dt*materialpoint_subStep(i,e) ! propagate materialpoint dt to grains crystallite_requested(1:myNgrains,i,e) = .true. ! request calculation for constituents else @@ -430,7 +428,7 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) !-------------------------------------------------------------------------------------------------- ! state update - !$OMP PARALLEL DO + !$OMP PARALLEL DO PRIVATE(subF) elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) IpLooping3: do i = FEsolving_execIP(1),FEsolving_execIP(2) if ( materialpoint_requested(i,e) .and. & @@ -438,8 +436,11 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) if (.not. materialpoint_converged(i,e)) then materialpoint_doneAndHappy(1:2,i,e) = [.true.,.false.] else + subF = materialpoint_F0(1:3,1:3,i,e) & + + (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) & + * (materialpoint_subStep(i,e)+materialpoint_subFrac(i,e)) materialpoint_doneAndHappy(1:2,i,e) = updateState(dt*materialpoint_subStep(i,e), & - materialpoint_subF(1:3,1:3,i,e), & + subF, & i,e) materialpoint_converged(i,e) = all(materialpoint_doneAndHappy(1:2,i,e)) ! converged if done and happy endif From 912c064b575d9166f6e649e05c7ad9bebd86c521 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 14 Apr 2020 09:38:32 +0200 Subject: [PATCH 064/186] indicate read-only public variables --- src/homogenization.f90 | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 543388f1c..795bcce35 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -27,15 +27,17 @@ module homogenization implicit none private -!-------------------------------------------------------------------------------------------------- -! General variables for the homogenization at a material point logical, public :: & terminallyIll = .false. !< at least one material point is terminally ill - real(pReal), dimension(:,:,:,:), allocatable, public :: & + +!-------------------------------------------------------------------------------------------------- +! General variables for the homogenization at a material point + real(pReal), dimension(:,:,:,:), allocatable, public :: & materialpoint_F0, & !< def grad of IP at start of FE increment - materialpoint_F, & !< def grad of IP to be reached at end of FE increment + materialpoint_F !< def grad of IP to be reached at end of FE increment + real(pReal), dimension(:,:,:,:), allocatable, public, protected :: & materialpoint_P !< first P--K stress of IP - real(pReal), dimension(:,:,:,:,:,:), allocatable, public :: & + real(pReal), dimension(:,:,:,:,:,:), allocatable, public, protected :: & materialpoint_dPdF !< tangent of first P--K stress at IP real(pReal), dimension(:,:), allocatable :: & @@ -49,7 +51,7 @@ module homogenization type :: tNumerics integer :: & - nMPstate !< materialpoint state loop limit + nMPstate !< materialpoint state loop limit real(pReal) :: & subStepMinHomog, & !< minimum (relative) size of sub-step allowed during cutback in homogenization subStepSizeHomog, & !< size of first substep when cutback in homogenization From 9d831cf268c464b2ba0e45168be189db0f332dc1 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 14 Apr 2020 09:43:18 +0200 Subject: [PATCH 065/186] not needed as module variable --- src/homogenization.f90 | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 795bcce35..7c532834e 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -40,15 +40,6 @@ module homogenization real(pReal), dimension(:,:,:,:,:,:), allocatable, public, protected :: & materialpoint_dPdF !< tangent of first P--K stress at IP - real(pReal), dimension(:,:), allocatable :: & - materialpoint_subFrac, & - materialpoint_subStep - logical, dimension(:,:), allocatable :: & - materialpoint_requested, & - materialpoint_converged - logical, dimension(:,:,:), allocatable :: & - materialpoint_doneAndHappy - type :: tNumerics integer :: & nMPstate !< materialpoint state loop limit @@ -160,11 +151,6 @@ subroutine homogenization_init materialpoint_F0 = spread(spread(math_I3,3,discretization_nIP),4,discretization_nElem) ! initialize to identity materialpoint_F = materialpoint_F0 ! initialize to identity allocate(materialpoint_P(3,3,discretization_nIP,discretization_nElem), source=0.0_pReal) - allocate(materialpoint_subFrac(discretization_nIP,discretization_nElem), source=0.0_pReal) - allocate(materialpoint_subStep(discretization_nIP,discretization_nElem), source=0.0_pReal) - allocate(materialpoint_requested(discretization_nIP,discretization_nElem), source=.false.) - allocate(materialpoint_converged(discretization_nIP,discretization_nElem), source=.true.) - allocate(materialpoint_doneAndHappy(2,discretization_nIP,discretization_nElem), source=.true.) write(6,'(/,a)') ' <<<+- homogenization init -+>>>'; flush(6) @@ -200,6 +186,14 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) myNgrains real(pReal), dimension(3,3) :: & subF + real(pReal), dimension(discretization_nIP,discretization_nElem) :: & + materialpoint_subFrac, & + materialpoint_subStep + logical, dimension(discretization_nIP,discretization_nElem) :: & + materialpoint_requested, & + materialpoint_converged + logical, dimension(2,discretization_nIP,discretization_nElem) :: & + materialpoint_doneAndHappy #ifdef DEBUG if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0) then From bf970bb146c4045432b78f5506858f8f0e216a28 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 14 Apr 2020 09:49:03 +0200 Subject: [PATCH 066/186] 2 space indentation --- src/homogenization.f90 | 158 ++++++++++++++++++++--------------------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 7c532834e..eab1e86c1 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -474,29 +474,29 @@ end subroutine materialpoint_stressAndItsTangent !-------------------------------------------------------------------------------------------------- subroutine partitionDeformation(subF,ip,el) - real(pReal), intent(in), dimension(3,3) :: & - subF - integer, intent(in) :: & - ip, & !< integration point - el !< element number + real(pReal), intent(in), dimension(3,3) :: & + subF + integer, intent(in) :: & + ip, & !< integration point + el !< element number - chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) + chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) - case (HOMOGENIZATION_NONE_ID) chosenHomogenization - crystallite_partionedF(1:3,1:3,1,ip,el) = subF + case (HOMOGENIZATION_NONE_ID) chosenHomogenization + crystallite_partionedF(1:3,1:3,1,ip,el) = subF - case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization - call mech_isostrain_partitionDeformation(& + case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization + call mech_isostrain_partitionDeformation(& + crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + subF) + + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + call mech_RGC_partitionDeformation(& crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - subF) - - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - call mech_RGC_partitionDeformation(& - crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - subF,& - ip, & - el) - end select chosenHomogenization + subF,& + ip, & + el) + end select chosenHomogenization end subroutine partitionDeformation @@ -507,47 +507,47 @@ end subroutine partitionDeformation !-------------------------------------------------------------------------------------------------- function updateState(subdt,subF,ip,el) - real(pReal), intent(in) :: & - subdt !< current time step - real(pReal), intent(in), dimension(3,3) :: & - subF - integer, intent(in) :: & - ip, & !< integration point - el !< element number - logical, dimension(2) :: updateState + real(pReal), intent(in) :: & + subdt !< current time step + real(pReal), intent(in), dimension(3,3) :: & + subF + integer, intent(in) :: & + ip, & !< integration point + el !< element number + logical, dimension(2) :: updateState - updateState = .true. - chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - updateState = & - updateState .and. & - mech_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - crystallite_partionedF0(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el),& - subF,& - subdt, & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - ip, & - el) - end select chosenHomogenization + updateState = .true. + chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + updateState = & + updateState .and. & + mech_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + crystallite_partionedF0(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el),& + subF,& + subdt, & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + ip, & + el) + end select chosenHomogenization - chosenThermal: select case (thermal_type(material_homogenizationAt(el))) - case (THERMAL_adiabatic_ID) chosenThermal - updateState = & - updateState .and. & - thermal_adiabatic_updateState(subdt, & - ip, & - el) - end select chosenThermal + chosenThermal: select case (thermal_type(material_homogenizationAt(el))) + case (THERMAL_adiabatic_ID) chosenThermal + updateState = & + updateState .and. & + thermal_adiabatic_updateState(subdt, & + ip, & + el) + end select chosenThermal - chosenDamage: select case (damage_type(material_homogenizationAt(el))) - case (DAMAGE_local_ID) chosenDamage - updateState = & - updateState .and. & - damage_local_updateState(subdt, & - ip, & - el) - end select chosenDamage + chosenDamage: select case (damage_type(material_homogenizationAt(el))) + case (DAMAGE_local_ID) chosenDamage + updateState = & + updateState .and. & + damage_local_updateState(subdt, & + ip, & + el) + end select chosenDamage end function updateState @@ -557,31 +557,31 @@ end function updateState !-------------------------------------------------------------------------------------------------- subroutine averageStressAndItsTangent(ip,el) - integer, intent(in) :: & - ip, & !< integration point - el !< element number + integer, intent(in) :: & + ip, & !< integration point + el !< element number - chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) - case (HOMOGENIZATION_NONE_ID) chosenHomogenization - materialpoint_P(1:3,1:3,ip,el) = crystallite_P(1:3,1:3,1,ip,el) - materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el) = crystallite_dPdF(1:3,1:3,1:3,1:3,1,ip,el) + chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) + case (HOMOGENIZATION_NONE_ID) chosenHomogenization + materialpoint_P(1:3,1:3,ip,el) = crystallite_P(1:3,1:3,1,ip,el) + materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el) = crystallite_dPdF(1:3,1:3,1:3,1:3,1,ip,el) - case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization - call mech_isostrain_averageStressAndItsTangent(& - materialpoint_P(1:3,1:3,ip,el), & - materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& - crystallite_P(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - homogenization_typeInstance(material_homogenizationAt(el))) + case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization + call mech_isostrain_averageStressAndItsTangent(& + materialpoint_P(1:3,1:3,ip,el), & + materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& + crystallite_P(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + homogenization_typeInstance(material_homogenizationAt(el))) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - call mech_RGC_averageStressAndItsTangent(& - materialpoint_P(1:3,1:3,ip,el), & - materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& - crystallite_P(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - homogenization_typeInstance(material_homogenizationAt(el))) - end select chosenHomogenization + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + call mech_RGC_averageStressAndItsTangent(& + materialpoint_P(1:3,1:3,ip,el), & + materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& + crystallite_P(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + homogenization_typeInstance(material_homogenizationAt(el))) + end select chosenHomogenization end subroutine averageStressAndItsTangent From 69857176b2311513da4f4fcd824923ca4f097274 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 14 Apr 2020 11:13:07 +0200 Subject: [PATCH 067/186] search and replace error --- python/damask/grid_filters.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/python/damask/grid_filters.py b/python/damask/grid_filters.py index 8106ed905..5134fd15e 100644 --- a/python/damask/grid_filters.py +++ b/python/damask/grid_filters.py @@ -41,8 +41,8 @@ def curl(size,field): e[0, 2, 1] = e[2, 1, 0] = e[1, 0, 2] = -1.0 field_fourier = _np.fft.rfftn(field,axes=(0,1,2)) - curl_ = (_np.einsum('slm,ijkl,ijkm ->ijks', e,k_s,field_fourier)*2.0j*_np.pi if n == 3 else # vector, 3 -> 3 - _np.einsum('slm,ijkl,ijknm->ijksn',e,k_s,field_fourier)*2.0j*_np.pi) # tensor, 3x3 -> 3x3 + curl_ = (_np.einsum('slm,ijkl,ijkm ->ijks', e,k_s,field_fourier)*2.0j*_np.pi if n == 3 else # vector, 3 -> 3 + _np.einsum('slm,ijkl,ijknm->ijksn',e,k_s,field_fourier)*2.0j*_np.pi) # tensor, 3x3 -> 3x3 return _np.fft.irfftn(curl_,axes=(0,1,2),s=field.shape[:3]) @@ -61,8 +61,8 @@ def divergence(size,field): k_s = _ks(size,field.shape[:3],True) field_fourier = _np.fft.rfftn(field,axes=(0,1,2)) - div_ = (_np.einsum('ijkl,ijkl ->ijk', k_s,field_fourier)*2.0j*_np.pi if n == 3 else # vector, 3 -> 1 - _np.einsum('ijkm,ijklm->ijkl',k_s,field_fourier)*2.0j*_np.pi) # tensor, 3x3 -> 3 + div_ = (_np.einsum('ijkl,ijkl ->ijk', k_s,field_fourier)*2.0j*_np.pi if n == 3 else # vector, 3 -> 1 + _np.einsum('ijkm,ijklm->ijkl',k_s,field_fourier)*2.0j*_np.pi) # tensor, 3x3 -> 3 return _np.fft.irfftn(div_,axes=(0,1,2),s=field.shape[:3]) @@ -81,8 +81,8 @@ def gradient(size,field): k_s = _ks(size,field.shape[:3],True) field_fourier = _np.fft.rfftn(field,axes=(0,1,2)) - grad_ = (_np.einsum('ijkl,ijkm->ijkm', field_fourier,k_s)*2.0j*_np.pi if n == 1 else # scalar, 1 -> 3 - _np.einsum('ijkl,ijkm->ijklm',field_fourier,k_s)*2.0j*_np.pi) # vector, 3 -> 3x3 + grad_ = (_np.einsum('ijkl,ijkm->ijkm', field_fourier,k_s)*2.0j*_np.pi if n == 1 else # scalar, 1 -> 3 + _np.einsum('ijkl,ijkm->ijklm',field_fourier,k_s)*2.0j*_np.pi) # vector, 3 -> 3x3 return _np.fft.irfftn(grad_,axes=(0,1,2),s=field.shape[:3]) @@ -217,7 +217,7 @@ def cell_coord0_gridSizeOrigin(coord0,ordered=True): raise ValueError('Regular grid spacing violated.') if ordered and not _np.allclose(coord0.reshape(tuple(grid[::-1])+(3,)),cell_coord0(grid,size,origin)): - raise ValueError('I_nput data is not a regular grid.') + raise ValueError('Input data is not a regular grid.') return (grid,size,origin) @@ -363,7 +363,7 @@ def node_coord0_gridSizeOrigin(coord0,ordered=False): raise ValueError('Regular grid spacing violated.') if ordered and not _np.allclose(coord0.reshape(tuple((grid+1)[::-1])+(3,)),node_coord0(grid,size,origin)): - raise ValueError('I_nput data is not a regular grid.') + raise ValueError('Input data is not a regular grid.') return (grid,size,origin) From c7e62777585cd33eb871a3c2473e766062c0a497 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 14 Apr 2020 15:34:38 +0200 Subject: [PATCH 068/186] not needed https://stackoverflow.com/questions/19687233 --- src/homogenization.f90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index eab1e86c1..40a6e7280 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -321,7 +321,6 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) if ( (myNgrains == 1 .and. materialpoint_subStep(i,e) <= 1.0 ) .or. & ! single grain already tried internal subStepping in crystallite num%subStepSizeHomog * materialpoint_subStep(i,e) <= num%subStepMinHomog ) then ! would require too small subStep ! cutback makes no sense - !$OMP FLUSH(terminallyIll) if (.not. terminallyIll) then ! so first signals terminally ill... !$OMP CRITICAL (write2out) write(6,*) 'Integration point ', i,' at element ', e, ' terminally ill' From d3eba4151966f3132aacc9f30f3c58e1b40282db Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Tue, 14 Apr 2020 12:21:35 -0400 Subject: [PATCH 069/186] [skip ci] fixed bug of double execution of np.degrees in asAxisAngle --- python/damask/_rotation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index bea7aa5e6..ff4025ddc 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -206,7 +206,7 @@ class Rotation: """ ax = Rotation.qu2ax(self.quaternion) if degrees: ax[3] = np.degrees(ax[3]) - return (ax[:3],np.degrees(ax[3])) if pair else ax + return (ax[:3],ax[3]) if pair else ax def asMatrix(self): """Rotation matrix.""" From ca26dbe3819e84ad1bdb84238d2ea0e776ea7c9f Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 15 Apr 2020 03:38:45 +0200 Subject: [PATCH 070/186] [skip ci] updated version information after successful test of v2.0.3-2291-g03aa6f9c --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0e875200a..458484abe 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2255-gc74ffae8 +v2.0.3-2291-g03aa6f9c From ae95a96c88804d6f304f32d0fa8ca24d4966ab1e Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 15 Apr 2020 08:53:25 +0200 Subject: [PATCH 071/186] better readable --- src/homogenization.f90 | 54 +++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 40a6e7280..2d3807d18 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -207,7 +207,7 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) #endif !-------------------------------------------------------------------------------------------------- -! initialize restoration points of ... +! initialize restoration points do e = FEsolving_execElem(1),FEsolving_execElem(2) myNgrains = homogenization_Ngrains(material_homogenizationAt(e)) do i = FEsolving_execIP(1),FEsolving_execIP(2); @@ -230,21 +230,21 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) enddo materialpoint_subFrac(i,e) = 0.0_pReal - materialpoint_subStep(i,e) = 1.0_pReal/num%subStepSizeHomog ! <> - materialpoint_converged(i,e) = .false. ! pretend failed step of twice the required size + materialpoint_converged(i,e) = .false. ! pretend failed step ... + materialpoint_subStep(i,e) = 1.0_pReal/num%subStepSizeHomog ! ... larger then the requested calculation materialpoint_requested(i,e) = .true. ! everybody requires calculation if (homogState(material_homogenizationAt(e))%sizeState > 0) & homogState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & - homogState(material_homogenizationAt(e))%State0( :,material_homogenizationMemberAt(i,e)) ! ...internal homogenization state + homogState(material_homogenizationAt(e))%State0( :,material_homogenizationMemberAt(i,e)) if (thermalState(material_homogenizationAt(e))%sizeState > 0) & thermalState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & - thermalState(material_homogenizationAt(e))%State0( :,material_homogenizationMemberAt(i,e)) ! ...internal thermal state + thermalState(material_homogenizationAt(e))%State0( :,material_homogenizationMemberAt(i,e)) if (damageState(material_homogenizationAt(e))%sizeState > 0) & damageState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & - damageState(material_homogenizationAt(e))%State0( :,material_homogenizationMemberAt(i,e)) ! ...internal damage state + damageState(material_homogenizationAt(e))%State0( :,material_homogenizationMemberAt(i,e)) enddo enddo @@ -277,24 +277,13 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) steppingNeeded: if (materialpoint_subStep(i,e) > num%subStepMinHomog) then - ! wind forward grain starting point of... - crystallite_partionedF0 (1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedF(1:3,1:3,1:myNgrains,i,e) - - crystallite_partionedFp0 (1:3,1:3,1:myNgrains,i,e) = & - crystallite_Fp (1:3,1:3,1:myNgrains,i,e) - - crystallite_partionedLp0 (1:3,1:3,1:myNgrains,i,e) = & - crystallite_Lp (1:3,1:3,1:myNgrains,i,e) - - crystallite_partionedFi0 (1:3,1:3,1:myNgrains,i,e) = & - crystallite_Fi (1:3,1:3,1:myNgrains,i,e) - - crystallite_partionedLi0 (1:3,1:3,1:myNgrains,i,e) = & - crystallite_Li (1:3,1:3,1:myNgrains,i,e) - - crystallite_partionedS0 (1:3,1:3,1:myNgrains,i,e) = & - crystallite_S (1:3,1:3,1:myNgrains,i,e) + ! wind forward grain starting point + crystallite_partionedF0 (1:3,1:3,1:myNgrains,i,e) = crystallite_partionedF(1:3,1:3,1:myNgrains,i,e) + crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) = crystallite_Fp (1:3,1:3,1:myNgrains,i,e) + crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) = crystallite_Lp (1:3,1:3,1:myNgrains,i,e) + crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) = crystallite_Fi (1:3,1:3,1:myNgrains,i,e) + crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) = crystallite_Li (1:3,1:3,1:myNgrains,i,e) + crystallite_partionedS0 (1:3,1:3,1:myNgrains,i,e) = crystallite_S (1:3,1:3,1:myNgrains,i,e) do g = 1,myNgrains plasticState (material_phaseAt(g,e))%partionedState0(:,material_phasememberAt(g,i,e)) = & @@ -341,19 +330,14 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) #endif !-------------------------------------------------------------------------------------------------- -! restore... +! restore if (materialpoint_subStep(i,e) < 1.0_pReal) then ! protect against fake cutback from \Delta t = 2 to 1. Maybe that "trick" is not necessary anymore at all? I.e. start with \Delta t = 1 - crystallite_Lp(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) - crystallite_Li(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) + crystallite_Lp(1:3,1:3,1:myNgrains,i,e) = crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) + crystallite_Li(1:3,1:3,1:myNgrains,i,e) = crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) endif ! maybe protecting everything from overwriting (not only L) makes even more sense - crystallite_Fp(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) - crystallite_Fi(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) - crystallite_S(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedS0(1:3,1:3,1:myNgrains,i,e) + crystallite_Fp(1:3,1:3,1:myNgrains,i,e) = crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) + crystallite_Fi(1:3,1:3,1:myNgrains,i,e) = crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) + crystallite_S (1:3,1:3,1:myNgrains,i,e) = crystallite_partionedS0 (1:3,1:3,1:myNgrains,i,e) do g = 1, myNgrains plasticState (material_phaseAt(g,e))%state( :,material_phasememberAt(g,i,e)) = & plasticState (material_phaseAt(g,e))%partionedState0(:,material_phasememberAt(g,i,e)) From 6e48585de1bd6a84851cdea20ba490965cd47ff5 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 15 Apr 2020 13:09:05 +0200 Subject: [PATCH 072/186] prefix for local variables not needed --- src/homogenization.f90 | 85 +++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 2d3807d18..8b6d80089 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -187,13 +187,13 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) real(pReal), dimension(3,3) :: & subF real(pReal), dimension(discretization_nIP,discretization_nElem) :: & - materialpoint_subFrac, & - materialpoint_subStep + subFrac, & + subStep logical, dimension(discretization_nIP,discretization_nElem) :: & - materialpoint_requested, & - materialpoint_converged + requested, & + converged logical, dimension(2,discretization_nIP,discretization_nElem) :: & - materialpoint_doneAndHappy + doneAndHappy #ifdef DEBUG if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0) then @@ -229,10 +229,10 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) enddo - materialpoint_subFrac(i,e) = 0.0_pReal - materialpoint_converged(i,e) = .false. ! pretend failed step ... - materialpoint_subStep(i,e) = 1.0_pReal/num%subStepSizeHomog ! ... larger then the requested calculation - materialpoint_requested(i,e) = .true. ! everybody requires calculation + subFrac(i,e) = 0.0_pReal + converged(i,e) = .false. ! pretend failed step ... + subStep(i,e) = 1.0_pReal/num%subStepSizeHomog ! ... larger then the requested calculation + requested(i,e) = .true. ! everybody requires calculation if (homogState(material_homogenizationAt(e))%sizeState > 0) & homogState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & @@ -251,31 +251,30 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) NiterationHomog = 0 cutBackLooping: do while (.not. terminallyIll .and. & - any(materialpoint_subStep(:,FEsolving_execELem(1):FEsolving_execElem(2)) > num%subStepMinHomog)) + any(subStep(:,FEsolving_execELem(1):FEsolving_execElem(2)) > num%subStepMinHomog)) !$OMP PARALLEL DO PRIVATE(myNgrains) elementLooping1: do e = FEsolving_execElem(1),FEsolving_execElem(2) myNgrains = homogenization_Ngrains(material_homogenizationAt(e)) IpLooping1: do i = FEsolving_execIP(1),FEsolving_execIP(2) - converged: if (materialpoint_converged(i,e)) then + if (converged(i,e)) then #ifdef DEBUG if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0 & .and. ((e == debug_e .and. i == debug_i) & .or. .not. iand(debug_level(debug_homogenization),debug_levelSelective) /= 0)) then write(6,'(a,1x,f12.8,1x,a,1x,f12.8,1x,a,i8,1x,i2/)') '<< HOMOG >> winding forward from', & - materialpoint_subFrac(i,e), 'to current materialpoint_subFrac', & - materialpoint_subFrac(i,e)+materialpoint_subStep(i,e),'in materialpoint_stressAndItsTangent at el ip',e,i + subFrac(i,e), 'to current subFrac', & + subFrac(i,e)+subStep(i,e),'in materialpoint_stressAndItsTangent at el ip',e,i endif #endif !--------------------------------------------------------------------------------------------------- ! calculate new subStep and new subFrac - materialpoint_subFrac(i,e) = materialpoint_subFrac(i,e) + materialpoint_subStep(i,e) - materialpoint_subStep(i,e) = min(1.0_pReal-materialpoint_subFrac(i,e), & - num%stepIncreaseHomog*materialpoint_subStep(i,e)) ! introduce flexibility for step increase/acceleration + subFrac(i,e) = subFrac(i,e) + subStep(i,e) + subStep(i,e) = min(1.0_pReal-subFrac(i,e),num%stepIncreaseHomog*subStep(i,e)) ! introduce flexibility for step increase/acceleration - steppingNeeded: if (materialpoint_subStep(i,e) > num%subStepMinHomog) then + steppingNeeded: if (subStep(i,e) > num%subStepMinHomog) then ! wind forward grain starting point crystallite_partionedF0 (1:3,1:3,1:myNgrains,i,e) = crystallite_partionedF(1:3,1:3,1:myNgrains,i,e) @@ -306,9 +305,9 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) endif steppingNeeded - else converged - if ( (myNgrains == 1 .and. materialpoint_subStep(i,e) <= 1.0 ) .or. & ! single grain already tried internal subStepping in crystallite - num%subStepSizeHomog * materialpoint_subStep(i,e) <= num%subStepMinHomog ) then ! would require too small subStep + else + if ( (myNgrains == 1 .and. subStep(i,e) <= 1.0 ) .or. & ! single grain already tried internal subStepping in crystallite + num%subStepSizeHomog * subStep(i,e) <= num%subStepMinHomog ) then ! would require too small subStep ! cutback makes no sense if (.not. terminallyIll) then ! so first signals terminally ill... !$OMP CRITICAL (write2out) @@ -317,21 +316,21 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) endif terminallyIll = .true. ! ...and kills all others else ! cutback makes sense - materialpoint_subStep(i,e) = num%subStepSizeHomog * materialpoint_subStep(i,e) ! crystallite had severe trouble, so do a significant cutback + subStep(i,e) = num%subStepSizeHomog * subStep(i,e) ! crystallite had severe trouble, so do a significant cutback #ifdef DEBUG if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0 & .and. ((e == debug_e .and. i == debug_i) & .or. .not. iand(debug_level(debug_homogenization), debug_levelSelective) /= 0)) then write(6,'(a,1x,f12.8,a,i8,1x,i2/)') & - '<< HOMOG >> cutback step in materialpoint_stressAndItsTangent with new materialpoint_subStep:',& - materialpoint_subStep(i,e),' at el ip',e,i + '<< HOMOG >> cutback step in materialpoint_stressAndItsTangent with new subStep:',& + subStep(i,e),' at el ip',e,i endif #endif !-------------------------------------------------------------------------------------------------- ! restore - if (materialpoint_subStep(i,e) < 1.0_pReal) then ! protect against fake cutback from \Delta t = 2 to 1. Maybe that "trick" is not necessary anymore at all? I.e. start with \Delta t = 1 + if (subStep(i,e) < 1.0_pReal) then ! protect against fake cutback from \Delta t = 2 to 1. Maybe that "trick" is not necessary anymore at all? I.e. start with \Delta t = 1 crystallite_Lp(1:3,1:3,1:myNgrains,i,e) = crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) crystallite_Li(1:3,1:3,1:myNgrains,i,e) = crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) endif ! maybe protecting everything from overwriting (not only L) makes even more sense @@ -356,11 +355,11 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) damageState(material_homogenizationAt(e))%State( :,material_homogenizationMemberAt(i,e)) = & damageState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) endif - endif converged + endif - if (materialpoint_subStep(i,e) > num%subStepMinHomog) then - materialpoint_requested(i,e) = .true. - materialpoint_doneAndHappy(1:2,i,e) = [.false.,.true.] + if (subStep(i,e) > num%subStepMinHomog) then + requested(i,e) = .true. + doneAndHappy(1:2,i,e) = [.false.,.true.] endif enddo IpLooping1 enddo elementLooping1 @@ -369,8 +368,8 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) NiterationMPstate = 0 convergenceLooping: do while (.not. terminallyIll .and. & - any( materialpoint_requested(:,FEsolving_execELem(1):FEsolving_execElem(2)) & - .and. .not. materialpoint_doneAndHappy(1,:,FEsolving_execELem(1):FEsolving_execElem(2)) & + any( requested(:,FEsolving_execELem(1):FEsolving_execElem(2)) & + .and. .not. doneAndHappy(1,:,FEsolving_execELem(1):FEsolving_execElem(2)) & ) .and. & NiterationMPstate < num%nMPstate) NiterationMPstate = NiterationMPstate + 1 @@ -383,13 +382,11 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) elementLooping2: do e = FEsolving_execElem(1),FEsolving_execElem(2) myNgrains = homogenization_Ngrains(material_homogenizationAt(e)) IpLooping2: do i = FEsolving_execIP(1),FEsolving_execIP(2) - if ( materialpoint_requested(i,e) .and. & ! process requested but... - .not. materialpoint_doneAndHappy(1,i,e)) then ! ...not yet done material points + if(requested(i,e) .and. .not. doneAndHappy(1,i,e)) then ! requested but not yet done subF = materialpoint_F0(1:3,1:3,i,e) & - + (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) & - * (materialpoint_subStep(i,e)+materialpoint_subFrac(i,e)) + + (materialpoint_F(1:3,1:3,i,e)-materialpoint_F0(1:3,1:3,i,e))*(subStep(i,e)+subFrac(i,e)) call partitionDeformation(subF,i,e) ! partition deformation onto constituents - crystallite_dt(1:myNgrains,i,e) = dt*materialpoint_subStep(i,e) ! propagate materialpoint dt to grains + crystallite_dt(1:myNgrains,i,e) = dt*subStep(i,e) ! propagate materialpoint dt to grains crystallite_requested(1:myNgrains,i,e) = .true. ! request calculation for constituents else crystallite_requested(1:myNgrains,i,e) = .false. ! calculation for constituents not required anymore @@ -403,25 +400,21 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) ! based on crystallite_partionedF0,.._partionedF ! incrementing by crystallite_dt - materialpoint_converged = crystallite_stress() !ToDo: MD not sure if that is the best logic + converged = crystallite_stress() !ToDo: MD not sure if that is the best logic !-------------------------------------------------------------------------------------------------- ! state update !$OMP PARALLEL DO PRIVATE(subF) elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) IpLooping3: do i = FEsolving_execIP(1),FEsolving_execIP(2) - if ( materialpoint_requested(i,e) .and. & - .not. materialpoint_doneAndHappy(1,i,e)) then - if (.not. materialpoint_converged(i,e)) then - materialpoint_doneAndHappy(1:2,i,e) = [.true.,.false.] + if (requested(i,e) .and. .not. doneAndHappy(1,i,e)) then + if (.not. converged(i,e)) then + doneAndHappy(1:2,i,e) = [.true.,.false.] else subF = materialpoint_F0(1:3,1:3,i,e) & - + (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) & - * (materialpoint_subStep(i,e)+materialpoint_subFrac(i,e)) - materialpoint_doneAndHappy(1:2,i,e) = updateState(dt*materialpoint_subStep(i,e), & - subF, & - i,e) - materialpoint_converged(i,e) = all(materialpoint_doneAndHappy(1:2,i,e)) ! converged if done and happy + + (materialpoint_F(1:3,1:3,i,e)-materialpoint_F0(1:3,1:3,i,e))*(subStep(i,e)+subFrac(i,e)) + doneAndHappy(1:2,i,e) = updateState(dt*subStep(i,e),subF,i,e) + converged(i,e) = all(doneAndHappy(1:2,i,e)) ! converged if done and happy endif endif enddo IpLooping3 From 875b3b632165c6db9fc89aeb238774ca0fdbe9b4 Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 15 Apr 2020 19:00:06 +0200 Subject: [PATCH 073/186] [skip ci] updated version information after successful test of v2.0.3-2303-g2a6132b7 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 458484abe..7be7a7f6c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2291-g03aa6f9c +v2.0.3-2303-g2a6132b7 From a4c52ec1fad29359a1faa889f6cb7456e676b2b7 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 15 Apr 2020 21:56:20 +0200 Subject: [PATCH 074/186] extra variable not needed --- src/homogenization.f90 | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 8b6d80089..62150899e 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -184,8 +184,6 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) e, & !< element number mySource, & myNgrains - real(pReal), dimension(3,3) :: & - subF real(pReal), dimension(discretization_nIP,discretization_nElem) :: & subFrac, & subStep @@ -376,16 +374,15 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) !-------------------------------------------------------------------------------------------------- ! deformation partitioning -! based on materialpoint_subF0,.._subF,crystallite_partionedF0, and homogenization_state, -! results in crystallite_partionedF - !$OMP PARALLEL DO PRIVATE(myNgrains,subF) + !$OMP PARALLEL DO PRIVATE(myNgrains) elementLooping2: do e = FEsolving_execElem(1),FEsolving_execElem(2) myNgrains = homogenization_Ngrains(material_homogenizationAt(e)) IpLooping2: do i = FEsolving_execIP(1),FEsolving_execIP(2) if(requested(i,e) .and. .not. doneAndHappy(1,i,e)) then ! requested but not yet done - subF = materialpoint_F0(1:3,1:3,i,e) & - + (materialpoint_F(1:3,1:3,i,e)-materialpoint_F0(1:3,1:3,i,e))*(subStep(i,e)+subFrac(i,e)) - call partitionDeformation(subF,i,e) ! partition deformation onto constituents + call partitionDeformation(materialpoint_F0(1:3,1:3,i,e) & + + (materialpoint_F(1:3,1:3,i,e)-materialpoint_F0(1:3,1:3,i,e))& + *(subStep(i,e)+subFrac(i,e)), & + i,e) crystallite_dt(1:myNgrains,i,e) = dt*subStep(i,e) ! propagate materialpoint dt to grains crystallite_requested(1:myNgrains,i,e) = .true. ! request calculation for constituents else @@ -397,23 +394,22 @@ subroutine materialpoint_stressAndItsTangent(updateJaco,dt) !-------------------------------------------------------------------------------------------------- ! crystallite integration -! based on crystallite_partionedF0,.._partionedF -! incrementing by crystallite_dt - converged = crystallite_stress() !ToDo: MD not sure if that is the best logic !-------------------------------------------------------------------------------------------------- ! state update - !$OMP PARALLEL DO PRIVATE(subF) + !$OMP PARALLEL DO elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) IpLooping3: do i = FEsolving_execIP(1),FEsolving_execIP(2) if (requested(i,e) .and. .not. doneAndHappy(1,i,e)) then if (.not. converged(i,e)) then doneAndHappy(1:2,i,e) = [.true.,.false.] else - subF = materialpoint_F0(1:3,1:3,i,e) & - + (materialpoint_F(1:3,1:3,i,e)-materialpoint_F0(1:3,1:3,i,e))*(subStep(i,e)+subFrac(i,e)) - doneAndHappy(1:2,i,e) = updateState(dt*subStep(i,e),subF,i,e) + doneAndHappy(1:2,i,e) = updateState(dt*subStep(i,e), & + materialpoint_F0(1:3,1:3,i,e) & + + (materialpoint_F(1:3,1:3,i,e)-materialpoint_F0(1:3,1:3,i,e)) & + *(subStep(i,e)+subFrac(i,e)), & + i,e) converged(i,e) = all(doneAndHappy(1:2,i,e)) ! converged if done and happy endif endif From 2ad5bfbc3b593683a346c39ad974ca9f180e9bef Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 17 Apr 2020 08:17:32 +0200 Subject: [PATCH 075/186] preparing modularization --- src/crystallite.f90 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index d8cd5ab98..c7ab7fba8 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1476,8 +1476,8 @@ subroutine integrateStateRKCK45(todo) sizeDotState logical :: & nonlocalBroken, broken - real(pReal), dimension(constitutive_source_maxSizeDotState,6,maxval(phase_Nsources)) :: source_RKdotState - real(pReal), dimension(constitutive_plasticity_maxSizeDotState,6) :: plastic_RKdotState + real(pReal), dimension(constitutive_source_maxSizeDotState,size(B),maxval(phase_Nsources)) :: source_RKdotState + real(pReal), dimension(constitutive_plasticity_maxSizeDotState,size(B)) :: plastic_RKdotState nonlocalBroken = .false. !$OMP PARALLEL DO PRIVATE(sizeDotState,p,c,plastic_RKdotState,source_RKdotState,broken) @@ -1497,7 +1497,7 @@ subroutine integrateStateRKCK45(todo) crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) cycle - do stage = 1,5 + do stage = 1,size(A,1) sizeDotState = plasticState(p)%sizeDotState plastic_RKdotState(1:sizeDotState,stage) = plasticState(p)%dotState(:,c) plasticState(p)%dotState(:,c) = A(1,stage) * plastic_RKdotState(1:sizeDotState,1) @@ -1544,12 +1544,12 @@ subroutine integrateStateRKCK45(todo) sizeDotState = plasticState(p)%sizeDotState - plastic_RKdotState(1:sizeDotState,6) = plasticState (p)%dotState(:,c) - plasticState(p)%dotState(:,c) = matmul(plastic_RKdotState(1:sizeDotState,1:6),B) + plastic_RKdotState(1:sizeDotState,size(B)) = plasticState (p)%dotState(:,c) + plasticState(p)%dotState(:,c) = matmul(plastic_RKdotState(1:sizeDotState,1:size(B)),B) plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & + plasticState(p)%dotState (1:sizeDotState,c) & * crystallite_subdt(g,i,e) - broken = .not. converged( matmul(plastic_RKdotState(1:sizeDotState,1:6),DB) & + broken = .not. converged( matmul(plastic_RKdotState(1:sizeDotState,1:size(DB)),DB) & * crystallite_subdt(g,i,e), & plasticState(p)%state(1:sizeDotState,c), & plasticState(p)%atol(1:sizeDotState)) @@ -1558,12 +1558,12 @@ subroutine integrateStateRKCK45(todo) sizeDotState = sourceState(p)%p(s)%sizeDotState source_RKdotState(1:sizeDotState,6,s) = sourceState(p)%p(s)%dotState(:,c) - sourceState(p)%p(s)%dotState(:,c) = matmul(source_RKdotState(1:sizeDotState,1:6,s),B) + sourceState(p)%p(s)%dotState(:,c) = matmul(source_RKdotState(1:sizeDotState,1:size(B),s),B) sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & * crystallite_subdt(g,i,e) broken = broken .and. .not. & - converged(matmul(source_RKdotState(1:sizeDotState,1:6,s),DB) & + converged(matmul(source_RKdotState(1:sizeDotState,1:size(DB),s),DB) & * crystallite_subdt(g,i,e), & sourceState(p)%p(s)%state(1:sizeDotState,c), & sourceState(p)%p(s)%atol(1:sizeDotState)) From 667d371f2ea0ea157a7e097bdf37bc62f8b7dd29 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 17 Apr 2020 08:24:35 +0200 Subject: [PATCH 076/186] avoid code duplication --- src/crystallite.f90 | 136 +++++++------------------------------------- 1 file changed, 22 insertions(+), 114 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index c7ab7fba8..5c01371bc 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1319,119 +1319,7 @@ subroutine integrateStateRK4(todo) real(pReal), dimension(4), parameter :: & B = [1.0_pReal/6.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/6.0_pReal] ! weight of slope used for Runge Kutta integration (final weight divided by 6) - integer :: & - e, & ! element index in element loop - i, & ! integration point index in ip loop - g, & ! grain index in grain loop - stage, & ! stage index in integration stage loop - n, & - p, & - c, & - s, & - sizeDotState - logical :: & - nonlocalBroken, broken - - real(pReal), dimension(constitutive_source_maxSizeDotState,4,maxval(phase_Nsources)) :: source_RK4dotState - real(pReal), dimension(constitutive_plasticity_maxSizeDotState,4) :: plastic_RK4dotState - nonlocalBroken = .false. - !$OMP PARALLEL DO PRIVATE(sizeDotState,p,c,source_RK4dotState,plastic_RK4dotState,broken) - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1),FEsolving_execIP(2) - do g = 1,homogenization_Ngrains(material_homogenizationAt(e)) - broken = .false. - p = material_phaseAt(g,e) - if(todo(g,i,e) .and. .not. (nonlocalBroken .and. plasticState(p)%nonlocal)) then - - c = material_phaseMemberAt(g,i,e) - - - broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) - if(broken) cycle - - do stage = 1,3 - sizeDotState = plasticState(p)%sizeDotState - plastic_RK4dotState(1:sizeDotState,stage) = plasticState(p)%dotState(:,c) - plasticState(p)%dotState(:,c) = A(1,stage) * plastic_RK4dotState(1:sizeDotState,1) - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - source_RK4dotState(1:sizeDotState,stage,s) = sourceState(p)%p(s)%dotState(:,c) - sourceState(p)%p(s)%dotState(:,c) = A(1,stage) * source_RK4dotState(1:sizeDotState,1,s) - enddo - - do n = 2, stage - sizeDotState = plasticState(p)%sizeDotState - plasticState(p)%dotState(:,c) = plasticState(p)%dotState(:,c) & - + A(n,stage) * plastic_RK4dotState(1:sizeDotState,n) - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - sourceState(p)%p(s)%dotState(:,c) = sourceState(p)%p(s)%dotState(:,c) & - + A(n,stage) * source_RK4dotState(1:sizeDotState,n,s) - enddo - enddo - - sizeDotState = plasticState(p)%sizeDotState - plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & - + plasticState(p)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & - + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - enddo - - broken = integrateStress(g,i,e,CC(stage)) - if(broken) exit - - broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & - crystallite_subdt(g,i,e)*CC(stage), g,i,e,p,c) - if(broken) exit - - enddo - if(broken) cycle - - sizeDotState = plasticState(p)%sizeDotState - - plastic_RK4dotState(1:sizeDotState,4) = plasticState (p)%dotState(:,c) - - plasticState(p)%dotState(:,c) = matmul(plastic_RK4dotState(1:sizeDotState,1:4),B) - plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & - + plasticState(p)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - - source_RK4dotState(1:sizeDotState,4,s) = sourceState(p)%p(s)%dotState(:,c) - - sourceState(p)%p(s)%dotState(:,c) = matmul(source_RK4dotState(1:sizeDotState,1:4,s),B) - sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & - + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - enddo - - broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) - if(broken) cycle - - broken = integrateStress(g,i,e) - crystallite_converged(g,i,e) = .not. broken - - endif - if(broken .and. plasticState(p)%nonlocal) nonlocalBroken = .true. - enddo; enddo; enddo - !$OMP END PARALLEL DO - - if (nonlocalBroken) call nonlocalConvergenceCheck + call integrateStateRK(todo,A,B,CC) end subroutine integrateStateRK4 @@ -1464,6 +1352,24 @@ subroutine integrateStateRKCK45(todo) real(pReal), dimension(5), parameter :: & CC = [0.2_pReal, 0.3_pReal, 0.6_pReal, 1.0_pReal, 0.875_pReal] !< coefficients in Butcher tableau (fractions of original time step in stages 2 to 6) + call integrateStateRK(todo,A,B,CC,DB) + + +end subroutine integrateStateRKCK45 + + +!-------------------------------------------------------------------------------------------------- +!> @brief integrate stress, state with 5th order Runge-Kutta Cash-Karp method with +!> adaptive step size (use 5th order solution to advance = "local extrapolation") +!-------------------------------------------------------------------------------------------------- +subroutine integrateStateRK(todo,A,B,CC,DB) + + logical, dimension(:,:,:), intent(in) :: todo + + real(pReal), dimension(:,:), intent(in) :: A + real(pReal), dimension(:), intent(in) :: B, CC + real(pReal), dimension(:), intent(in), optional :: DB + integer :: & e, & ! element index in element loop i, & ! integration point index in ip loop @@ -1549,6 +1455,7 @@ subroutine integrateStateRKCK45(todo) plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & + plasticState(p)%dotState (1:sizeDotState,c) & * crystallite_subdt(g,i,e) + if(present(DB)) & broken = .not. converged( matmul(plastic_RKdotState(1:sizeDotState,1:size(DB)),DB) & * crystallite_subdt(g,i,e), & plasticState(p)%state(1:sizeDotState,c), & @@ -1562,6 +1469,7 @@ subroutine integrateStateRKCK45(todo) sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & * crystallite_subdt(g,i,e) + if(present(DB)) & broken = broken .and. .not. & converged(matmul(source_RKdotState(1:sizeDotState,1:size(DB),s),DB) & * crystallite_subdt(g,i,e), & @@ -1585,7 +1493,7 @@ subroutine integrateStateRKCK45(todo) if(nonlocalBroken) call nonlocalConvergenceCheck -end subroutine integrateStateRKCK45 +end subroutine integrateStateRK !-------------------------------------------------------------------------------------------------- From 7fffa26d7fe580fe59786060eca29990748d3d18 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 17 Apr 2020 10:04:10 +0200 Subject: [PATCH 077/186] bugfix: size depends on shape --- src/crystallite.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 5c01371bc..cf02d784e 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1464,7 +1464,7 @@ subroutine integrateStateRK(todo,A,B,CC,DB) do s = 1, phase_Nsources(p) sizeDotState = sourceState(p)%p(s)%sizeDotState - source_RKdotState(1:sizeDotState,6,s) = sourceState(p)%p(s)%dotState(:,c) + source_RKdotState(1:sizeDotState,size(B),s) = sourceState(p)%p(s)%dotState(:,c) sourceState(p)%p(s)%dotState(:,c) = matmul(source_RKdotState(1:sizeDotState,1:size(B),s),B) sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & From 65c3831add7a60451ba1e8f0f3d2db3e5895e66b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 17 Apr 2020 10:17:00 +0200 Subject: [PATCH 078/186] polishing --- src/crystallite.f90 | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index cf02d784e..54e1701e8 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1301,9 +1301,9 @@ subroutine integrateStateAdaptiveEuler(todo) end subroutine integrateStateAdaptiveEuler -!-------------------------------------------------------------------------------------------------- -!> @brief integrate stress, state with 4th order explicit Runge Kutta method -!-------------------------------------------------------------------------------------------------- +!--------------------------------------------------------------------------------------------------- +!> @brief Integrate state (including stress integration) with the classig Runge Kutta method +!--------------------------------------------------------------------------------------------------- subroutine integrateStateRK4(todo) logical, dimension(:,:,:), intent(in) :: todo @@ -1312,22 +1312,20 @@ subroutine integrateStateRK4(todo) A = reshape([& 0.5_pReal, 0.0_pReal, 0.0_pReal, & 0.0_pReal, 0.5_pReal, 0.0_pReal, & - 0.0_pReal, 0.0_pReal, 1.0_pReal], & - [3,3]) + 0.0_pReal, 0.0_pReal, 1.0_pReal],[3,3]) real(pReal), dimension(3), parameter :: & - CC = [0.5_pReal, 0.5_pReal, 1.0_pReal] ! factor giving the fraction of the original timestep used for Runge Kutta Integration + C = [0.5_pReal, 0.5_pReal, 1.0_pReal] real(pReal), dimension(4), parameter :: & - B = [1.0_pReal/6.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/6.0_pReal] ! weight of slope used for Runge Kutta integration (final weight divided by 6) + B = [1.0_pReal/6.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/6.0_pReal] - call integrateStateRK(todo,A,B,CC) + call integrateStateRK(todo,A,B,C) end subroutine integrateStateRK4 -!-------------------------------------------------------------------------------------------------- -!> @brief integrate stress, state with 5th order Runge-Kutta Cash-Karp method with -!> adaptive step size (use 5th order solution to advance = "local extrapolation") -!-------------------------------------------------------------------------------------------------- +!--------------------------------------------------------------------------------------------------- +!> @brief Integrate state (including stress integration) with the Cash-Carp method +!--------------------------------------------------------------------------------------------------- subroutine integrateStateRKCK45(todo) logical, dimension(:,:,:), intent(in) :: todo @@ -1339,21 +1337,20 @@ subroutine integrateStateRKCK45(todo) .0_pReal, .0_pReal, 1.2_pReal, -70.0_pReal/27.0_pReal, 575.0_pReal/13824.0_pReal, & .0_pReal, .0_pReal, .0_pReal, 35.0_pReal/27.0_pReal, 44275.0_pReal/110592.0_pReal, & .0_pReal, .0_pReal, .0_pReal, .0_pReal, 253.0_pReal/4096.0_pReal], & - [5,5], order=[2,1]) !< coefficients in Butcher tableau (used for preliminary integration in stages 2 to 6) + [5,5], order=[2,1]) real(pReal), dimension(6), parameter :: & B = & [37.0_pReal/378.0_pReal, .0_pReal, 250.0_pReal/621.0_pReal, & - 125.0_pReal/594.0_pReal, .0_pReal, 512.0_pReal/1771.0_pReal], & !< coefficients in Butcher tableau (used for final integration and error estimate) + 125.0_pReal/594.0_pReal, .0_pReal, 512.0_pReal/1771.0_pReal], & DB = B - & [2825.0_pReal/27648.0_pReal, .0_pReal, 18575.0_pReal/48384.0_pReal,& - 13525.0_pReal/55296.0_pReal, 277.0_pReal/14336.0_pReal, 0.25_pReal] !< coefficients in Butcher tableau (used for final integration and error estimate) + 13525.0_pReal/55296.0_pReal, 277.0_pReal/14336.0_pReal, 0.25_pReal] real(pReal), dimension(5), parameter :: & - CC = [0.2_pReal, 0.3_pReal, 0.6_pReal, 1.0_pReal, 0.875_pReal] !< coefficients in Butcher tableau (fractions of original time step in stages 2 to 6) - - call integrateStateRK(todo,A,B,CC,DB) + C = [0.2_pReal, 0.3_pReal, 0.6_pReal, 1.0_pReal, 0.875_pReal] + call integrateStateRK(todo,A,B,C,DB) end subroutine integrateStateRKCK45 From a51d27858eb4508e9ec3e4efe327257bd1abf361 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 17 Apr 2020 11:51:39 +0200 Subject: [PATCH 079/186] polishing --- src/crystallite.f90 | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 54e1701e8..1a7ed3e58 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1302,7 +1302,7 @@ end subroutine integrateStateAdaptiveEuler !--------------------------------------------------------------------------------------------------- -!> @brief Integrate state (including stress integration) with the classig Runge Kutta method +!> @brief Integrate state (including stress integration) with the classic Runge Kutta method !--------------------------------------------------------------------------------------------------- subroutine integrateStateRK4(todo) @@ -1312,7 +1312,8 @@ subroutine integrateStateRK4(todo) A = reshape([& 0.5_pReal, 0.0_pReal, 0.0_pReal, & 0.0_pReal, 0.5_pReal, 0.0_pReal, & - 0.0_pReal, 0.0_pReal, 1.0_pReal],[3,3]) + 0.0_pReal, 0.0_pReal, 1.0_pReal], + shape(A)) real(pReal), dimension(3), parameter :: & C = [0.5_pReal, 0.5_pReal, 1.0_pReal] real(pReal), dimension(4), parameter :: & @@ -1332,23 +1333,21 @@ subroutine integrateStateRKCK45(todo) real(pReal), dimension(5,5), parameter :: & A = reshape([& - .2_pReal, .075_pReal, .3_pReal, -11.0_pReal/54.0_pReal, 1631.0_pReal/55296.0_pReal, & - .0_pReal, .225_pReal, -.9_pReal, 2.5_pReal, 175.0_pReal/512.0_pReal, & - .0_pReal, .0_pReal, 1.2_pReal, -70.0_pReal/27.0_pReal, 575.0_pReal/13824.0_pReal, & - .0_pReal, .0_pReal, .0_pReal, 35.0_pReal/27.0_pReal, 44275.0_pReal/110592.0_pReal, & - .0_pReal, .0_pReal, .0_pReal, .0_pReal, 253.0_pReal/4096.0_pReal], & - [5,5], order=[2,1]) - + 1._pReal/5._pReal, .0_pReal, .0_pReal, .0_pReal, .0_pReal, & + 3._pReal/40._pReal, 9._pReal/40._pReal, .0_pReal, .0_pReal, .0_pReal, & + 3_pReal/10._pReal, -9._pReal/10._pReal, 6._pReal/5._pReal, .0_pReal, .0_pReal, & + -11._pReal/54._pReal, 5._pReal/2._pReal, -70.0_pReal/27.0_pReal, 35.0_pReal/27.0_pReal, .0_pReal, & + 1631._pReal/55296._pReal,175._pReal/512._pReal,575._pReal/13824._pReal,44275._pReal/110592._pReal,253._pReal/4096._pReal],& + shape(A)) + real(pReal), dimension(5), parameter :: & + C = [0.2_pReal, 0.3_pReal, 0.6_pReal, 1.0_pReal, 0.875_pReal] real(pReal), dimension(6), parameter :: & B = & [37.0_pReal/378.0_pReal, .0_pReal, 250.0_pReal/621.0_pReal, & 125.0_pReal/594.0_pReal, .0_pReal, 512.0_pReal/1771.0_pReal], & DB = B - & [2825.0_pReal/27648.0_pReal, .0_pReal, 18575.0_pReal/48384.0_pReal,& - 13525.0_pReal/55296.0_pReal, 277.0_pReal/14336.0_pReal, 0.25_pReal] - - real(pReal), dimension(5), parameter :: & - C = [0.2_pReal, 0.3_pReal, 0.6_pReal, 1.0_pReal, 0.875_pReal] + 13525.0_pReal/55296.0_pReal, 277.0_pReal/14336.0_pReal, 1._pReal/4._pReal] call integrateStateRK(todo,A,B,C,DB) @@ -1356,8 +1355,8 @@ end subroutine integrateStateRKCK45 !-------------------------------------------------------------------------------------------------- -!> @brief integrate stress, state with 5th order Runge-Kutta Cash-Karp method with -!> adaptive step size (use 5th order solution to advance = "local extrapolation") +!> @brief Integrate state (including stress integration) with an explicit Runge-Kutta method or an +!! embedded explicit Runge-Kutta method !-------------------------------------------------------------------------------------------------- subroutine integrateStateRK(todo,A,B,CC,DB) From cf53e1e8e6318abfaaef6055fb1ca0685fb9ccc9 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 17 Apr 2020 11:55:43 +0200 Subject: [PATCH 080/186] bugfix: wrong logic for RK and source state --- src/crystallite.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 1a7ed3e58..a8b2af239 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1466,7 +1466,7 @@ subroutine integrateStateRK(todo,A,B,CC,DB) + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & * crystallite_subdt(g,i,e) if(present(DB)) & - broken = broken .and. .not. & + broken = broken .or. .not. & converged(matmul(source_RKdotState(1:sizeDotState,1:size(DB),s),DB) & * crystallite_subdt(g,i,e), & sourceState(p)%p(s)%state(1:sizeDotState,c), & From 328dcf01019553d07fadbcc641e894da25f511ad Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 17 Apr 2020 11:58:03 +0200 Subject: [PATCH 081/186] polishing --- src/crystallite.f90 | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index a8b2af239..3904ff023 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1312,7 +1312,7 @@ subroutine integrateStateRK4(todo) A = reshape([& 0.5_pReal, 0.0_pReal, 0.0_pReal, & 0.0_pReal, 0.5_pReal, 0.0_pReal, & - 0.0_pReal, 0.0_pReal, 1.0_pReal], + 0.0_pReal, 0.0_pReal, 1.0_pReal],& shape(A)) real(pReal), dimension(3), parameter :: & C = [0.5_pReal, 0.5_pReal, 1.0_pReal] @@ -1452,10 +1452,10 @@ subroutine integrateStateRK(todo,A,B,CC,DB) + plasticState(p)%dotState (1:sizeDotState,c) & * crystallite_subdt(g,i,e) if(present(DB)) & - broken = .not. converged( matmul(plastic_RKdotState(1:sizeDotState,1:size(DB)),DB) & - * crystallite_subdt(g,i,e), & - plasticState(p)%state(1:sizeDotState,c), & - plasticState(p)%atol(1:sizeDotState)) + broken = .not. converged( matmul(plastic_RKdotState(1:sizeDotState,1:size(DB)),DB) & + * crystallite_subdt(g,i,e), & + plasticState(p)%state(1:sizeDotState,c), & + plasticState(p)%atol(1:sizeDotState)) do s = 1, phase_Nsources(p) sizeDotState = sourceState(p)%p(s)%sizeDotState @@ -1466,11 +1466,10 @@ subroutine integrateStateRK(todo,A,B,CC,DB) + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & * crystallite_subdt(g,i,e) if(present(DB)) & - broken = broken .or. .not. & - converged(matmul(source_RKdotState(1:sizeDotState,1:size(DB),s),DB) & - * crystallite_subdt(g,i,e), & - sourceState(p)%p(s)%state(1:sizeDotState,c), & - sourceState(p)%p(s)%atol(1:sizeDotState)) + broken = broken .or. .not. converged(matmul(source_RKdotState(1:sizeDotState,1:size(DB),s),DB) & + * crystallite_subdt(g,i,e), & + sourceState(p)%p(s)%state(1:sizeDotState,c), & + sourceState(p)%p(s)%atol(1:sizeDotState)) enddo if(broken) cycle From 064f4d9d9d3d18c61f12946d2cfbb9710a32beb1 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 17 Apr 2020 13:18:20 +0200 Subject: [PATCH 082/186] polishing --- src/crystallite.f90 | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 3904ff023..7a13d228e 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -1240,10 +1240,10 @@ subroutine integrateStateAdaptiveEuler(todo) c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) + crystallite_partionedF0, & + crystallite_Fi(1:3,1:3,g,i,e), & + crystallite_partionedFp0, & + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) cycle sizeDotState = plasticState(p)%sizeDotState @@ -1269,10 +1269,10 @@ subroutine integrateStateAdaptiveEuler(todo) if(broken) cycle broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) + crystallite_partionedF0, & + crystallite_Fi(1:3,1:3,g,i,e), & + crystallite_partionedFp0, & + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) cycle @@ -1393,10 +1393,10 @@ subroutine integrateStateRK(todo,A,B,CC,DB) c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) + crystallite_partionedF0, & + crystallite_Fi(1:3,1:3,g,i,e), & + crystallite_partionedFp0, & + crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) cycle do stage = 1,size(A,1) @@ -1435,10 +1435,10 @@ subroutine integrateStateRK(todo,A,B,CC,DB) if(broken) exit broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & - crystallite_subdt(g,i,e)*CC(stage), g,i,e,p,c) + crystallite_partionedF0, & + crystallite_Fi(1:3,1:3,g,i,e), & + crystallite_partionedFp0, & + crystallite_subdt(g,i,e)*CC(stage), g,i,e,p,c) if(broken) exit enddo From e06251e53eb48986d53db06f95412557398c9308 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 19 Apr 2020 14:20:34 +0200 Subject: [PATCH 083/186] proper doxygen style --- src/quaternions.f90 | 76 ++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/quaternions.f90 b/src/quaternions.f90 index 8d62fe6aa..991f970ab 100644 --- a/src/quaternions.f90 +++ b/src/quaternions.f90 @@ -63,27 +63,27 @@ module quaternions module procedure assign_quat__ module procedure assign_vec__ end interface assignment (=) - + interface quaternion module procedure init__ end interface quaternion - + interface abs procedure abs__ end interface abs - + interface dot_product procedure dot_product__ end interface dot_product - + interface conjg module procedure conjg__ end interface conjg - + interface exp module procedure exp__ end interface exp - + interface log module procedure log__ end interface log @@ -95,7 +95,7 @@ module quaternions interface aimag module procedure aimag__ end interface aimag - + public :: & quaternions_init, & assignment(=), & @@ -118,7 +118,7 @@ end subroutine quaternions_init !--------------------------------------------------------------------------------------------------- -!> construct a quaternion from a 4-vector +!> @brief construct a quaternion from a 4-vector !--------------------------------------------------------------------------------------------------- type(quaternion) pure function init__(array) @@ -133,7 +133,7 @@ end function init__ !--------------------------------------------------------------------------------------------------- -!> assign a quaternion +!> @brief assign a quaternion !--------------------------------------------------------------------------------------------------- elemental pure subroutine assign_quat__(self,other) @@ -141,12 +141,12 @@ elemental pure subroutine assign_quat__(self,other) type(quaternion), intent(in) :: other self = [other%w,other%x,other%y,other%z] - + end subroutine assign_quat__ !--------------------------------------------------------------------------------------------------- -!> assign a 4-vector +!> @brief assign a 4-vector !--------------------------------------------------------------------------------------------------- pure subroutine assign_vec__(self,other) @@ -162,7 +162,7 @@ end subroutine assign_vec__ !--------------------------------------------------------------------------------------------------- -!> add a quaternion +!> @brief add a quaternion !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function add__(self,other) @@ -170,24 +170,24 @@ type(quaternion) elemental pure function add__(self,other) add__ = [ self%w, self%x, self%y ,self%z] & + [other%w, other%x, other%y,other%z] - + end function add__ !--------------------------------------------------------------------------------------------------- -!> return (unary positive operator) +!> @brief return (unary positive operator) !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function pos__(self) class(quaternion), intent(in) :: self pos__ = self * (+1.0_pReal) - + end function pos__ !--------------------------------------------------------------------------------------------------- -!> subtract a quaternion +!> @brief subtract a quaternion !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function sub__(self,other) @@ -195,24 +195,24 @@ type(quaternion) elemental pure function sub__(self,other) sub__ = [ self%w, self%x, self%y ,self%z] & - [other%w, other%x, other%y,other%z] - + end function sub__ !--------------------------------------------------------------------------------------------------- -!> negate (unary negative operator) +!> @brief negate (unary negative operator) !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function neg__(self) class(quaternion), intent(in) :: self neg__ = self * (-1.0_pReal) - + end function neg__ !--------------------------------------------------------------------------------------------------- -!> multiply with a quaternion +!> @brief multiply with a quaternion !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function mul_quat__(self,other) @@ -227,7 +227,7 @@ end function mul_quat__ !--------------------------------------------------------------------------------------------------- -!> multiply with a scalar +!> @brief multiply with a scalar !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function mul_scal__(self,scal) @@ -235,12 +235,12 @@ type(quaternion) elemental pure function mul_scal__(self,scal) real(pReal), intent(in) :: scal mul_scal__ = [self%w,self%x,self%y,self%z]*scal - + end function mul_scal__ !--------------------------------------------------------------------------------------------------- -!> divide by a quaternion +!> @brief divide by a quaternion !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function div_quat__(self,other) @@ -252,7 +252,7 @@ end function div_quat__ !--------------------------------------------------------------------------------------------------- -!> divide by a scalar +!> @brief divide by a scalar !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function div_scal__(self,scal) @@ -265,7 +265,7 @@ end function div_scal__ !--------------------------------------------------------------------------------------------------- -!> test equality +!> @brief test equality !--------------------------------------------------------------------------------------------------- logical elemental pure function eq__(self,other) @@ -278,7 +278,7 @@ end function eq__ !--------------------------------------------------------------------------------------------------- -!> test inequality +!> @brief test inequality !--------------------------------------------------------------------------------------------------- logical elemental pure function neq__(self,other) @@ -290,7 +290,7 @@ end function neq__ !--------------------------------------------------------------------------------------------------- -!> raise to the power of a quaternion +!> @brief raise to the power of a quaternion !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function pow_quat__(self,expon) @@ -303,7 +303,7 @@ end function pow_quat__ !--------------------------------------------------------------------------------------------------- -!> raise to the power of a scalar +!> @brief raise to the power of a scalar !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function pow_scal__(self,expon) @@ -316,7 +316,7 @@ end function pow_scal__ !--------------------------------------------------------------------------------------------------- -!> take exponential +!> @brief take exponential !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function exp__(a) @@ -336,7 +336,7 @@ end function exp__ !--------------------------------------------------------------------------------------------------- -!> take logarithm +!> @brief take logarithm !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function log__(a) @@ -356,7 +356,7 @@ end function log__ !--------------------------------------------------------------------------------------------------- -!> return norm +!> @brief return norm !--------------------------------------------------------------------------------------------------- real(pReal) elemental pure function abs__(self) @@ -368,7 +368,7 @@ end function abs__ !--------------------------------------------------------------------------------------------------- -!> calculate dot product +!> @brief calculate dot product !--------------------------------------------------------------------------------------------------- real(pReal) elemental pure function dot_product__(a,b) @@ -380,7 +380,7 @@ end function dot_product__ !--------------------------------------------------------------------------------------------------- -!> take conjugate complex +!> @brief take conjugate complex !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function conjg__(self) @@ -392,7 +392,7 @@ end function conjg__ !--------------------------------------------------------------------------------------------------- -!> homomorph +!> @brief homomorph !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function homomorphed(self) @@ -404,7 +404,7 @@ end function homomorphed !--------------------------------------------------------------------------------------------------- -!> return as plain array +!> @brief return as plain array !--------------------------------------------------------------------------------------------------- pure function asArray(self) @@ -417,7 +417,7 @@ end function asArray !--------------------------------------------------------------------------------------------------- -!> real part (scalar) +!> @brief real part (scalar) !--------------------------------------------------------------------------------------------------- pure function real__(self) @@ -430,7 +430,7 @@ end function real__ !--------------------------------------------------------------------------------------------------- -!> imaginary part (3-vector) +!> @brief imaginary part (3-vector) !--------------------------------------------------------------------------------------------------- pure function aimag__(self) @@ -443,7 +443,7 @@ end function aimag__ !--------------------------------------------------------------------------------------------------- -!> inverse +!> @brief inverse !--------------------------------------------------------------------------------------------------- type(quaternion) elemental pure function inverse(self) From bce5ed62d5813cee8e112940ca434d61aad90cda Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 10:13:15 +0200 Subject: [PATCH 084/186] polishing --- python/damask/grid_filters.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/damask/grid_filters.py b/python/damask/grid_filters.py index 5134fd15e..d8b136a6b 100644 --- a/python/damask/grid_filters.py +++ b/python/damask/grid_filters.py @@ -146,7 +146,7 @@ def cell_displacement_avg(size,F): """ F_avg = _np.average(F,axis=(0,1,2)) - return _np.einsum('ml,ijkl->ijkm',F_avg-_np.eye(3),cell_coord0(F.shape[:3][::-1],size)) + return _np.einsum('ml,ijkl->ijkm',F_avg - _np.eye(3),cell_coord0(F.shape[:3][::-1],size)) def cell_displacement(size,F): @@ -250,8 +250,8 @@ def node_coord0(grid,size,origin=_np.zeros(3)): """ return _np.mgrid[origin[0]:size[0]+origin[0]:(grid[0]+1)*1j, - origin[1]:size[1]+origin[1]:(grid[1]+1)*1j, - origin[2]:size[2]+origin[2]:(grid[2]+1)*1j].T + origin[1]:size[1]+origin[1]:(grid[1]+1)*1j, + origin[2]:size[2]+origin[2]:(grid[2]+1)*1j].T def node_displacement_fluct(size,F): @@ -282,7 +282,7 @@ def node_displacement_avg(size,F): """ F_avg = _np.average(F,axis=(0,1,2)) - return _np.einsum('ml,ijkl->ijkm',F_avg-_np.eye(3),node_coord0(F.shape[:3][::-1],size)) + return _np.einsum('ml,ijkl->ijkm',F_avg - _np.eye(3),node_coord0(F.shape[:3][::-1],size)) def node_displacement(size,F): From 9979eb58f44174e1cf3c1333f5654dd31a896115 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 12:41:03 +0200 Subject: [PATCH 085/186] consistent layout for grid data has now always the shape ([x,y,z,...]) with x fastest. For conversion from or to linear layout ([x*y*z,...]), e.g. storage in ASCII table, reshape needs to have the 'F' option. Credits to Vitesh and Fran for pointing this out. --- processing/post/addCurl.py | 7 ++- processing/post/addDisplacement.py | 14 ++--- processing/post/addDivergence.py | 7 ++- processing/post/addGradient.py | 7 ++- python/damask/_geom.py | 7 +-- python/damask/grid_filters.py | 88 ++++++++++++++++-------------- python/tests/test_grid_filters.py | 14 ++--- 7 files changed, 75 insertions(+), 69 deletions(-) diff --git a/processing/post/addCurl.py b/processing/post/addCurl.py index 87d1ab2f6..17459a2df 100755 --- a/processing/post/addCurl.py +++ b/processing/post/addCurl.py @@ -49,9 +49,10 @@ for name in filenames: for label in options.labels: field = table.get(label) shape = (3,) if np.prod(field.shape)//np.prod(grid) == 3 else (3,3) # vector or tensor - field = field.reshape(np.append(grid[::-1],shape)) + field = field.reshape(tuple(grid)+(-1,),order='F').reshape(tuple(grid)+shape) + curl = damask.grid_filters.curl(size,field) table.add('curlFFT({})'.format(label), - damask.grid_filters.curl(size[::-1],field).reshape(-1,np.prod(shape)), + curl.reshape(tuple(grid)+(-1,)).reshape(-1,np.prod(shape),order='F'), scriptID+' '+' '.join(sys.argv[1:])) - + table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/addDisplacement.py b/processing/post/addDisplacement.py index f74d876bc..a9424f5e1 100755 --- a/processing/post/addDisplacement.py +++ b/processing/post/addDisplacement.py @@ -51,23 +51,23 @@ for name in filenames: table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) grid,size,origin = damask.grid_filters.cell_coord0_gridSizeOrigin(table.get(options.pos)) - - F = table.get(options.f).reshape(np.append(grid[::-1],(3,3))) + + F = table.get(options.f).reshape(tuple(grid)+(-1,),order='F').reshape(tuple(grid)+(3,3)) if options.nodal: - table = damask.Table(damask.grid_filters.node_coord0(grid[::-1],size[::-1]).reshape(-1,3), + table = damask.Table(damask.grid_filters.node_coord0(grid,size).reshape(-1,3,order='F'), {'pos':(3,)}) table.add('avg({}).{}'.format(options.f,options.pos), - damask.grid_filters.node_displacement_avg(size[::-1],F).reshape(-1,3), + damask.grid_filters.node_displacement_avg(size,F).reshape(-1,3,order='F'), scriptID+' '+' '.join(sys.argv[1:])) table.add('fluct({}).{}'.format(options.f,options.pos), - damask.grid_filters.node_displacement_fluct(size[::-1],F).reshape(-1,3), + damask.grid_filters.node_displacement_fluct(size,F).reshape(-1,3,order='F'), scriptID+' '+' '.join(sys.argv[1:])) table.to_ASCII(sys.stdout if name is None else os.path.splitext(name)[0]+'_nodal.txt') else: table.add('avg({}).{}'.format(options.f,options.pos), - damask.grid_filters.cell_displacement_avg(size[::-1],F).reshape(-1,3), + damask.grid_filters.cell_displacement_avg(size,F).reshape(-1,3,order='F'), scriptID+' '+' '.join(sys.argv[1:])) table.add('fluct({}).{}'.format(options.f,options.pos), - damask.grid_filters.cell_displacement_fluct(size[::-1],F).reshape(-1,3), + damask.grid_filters.cell_displacement_fluct(size,F).reshape(-1,3,order='F'), scriptID+' '+' '.join(sys.argv[1:])) table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/addDivergence.py b/processing/post/addDivergence.py index 2619bc499..50048b44e 100755 --- a/processing/post/addDivergence.py +++ b/processing/post/addDivergence.py @@ -49,9 +49,10 @@ for name in filenames: for label in options.labels: field = table.get(label) shape = (3,) if np.prod(field.shape)//np.prod(grid) == 3 else (3,3) # vector or tensor - field = field.reshape(np.append(grid[::-1],shape)) + field = field.reshape(tuple(grid)+(-1,),order='F').reshape(tuple(grid)+shape) + div = damask.grid_filters.divergence(size,field) table.add('divFFT({})'.format(label), - damask.grid_filters.divergence(size[::-1],field).reshape(-1,np.prod(shape)//3), + div.reshape(tuple(grid)+(-1,)).reshape(-1,np.prod(shape)//3,order='F'), scriptID+' '+' '.join(sys.argv[1:])) - + table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/addGradient.py b/processing/post/addGradient.py index 409b2ce6d..c6df0eacf 100755 --- a/processing/post/addGradient.py +++ b/processing/post/addGradient.py @@ -49,9 +49,10 @@ for name in filenames: for label in options.labels: field = table.get(label) shape = (1,) if np.prod(field.shape)//np.prod(grid) == 1 else (3,) # scalar or vector - field = field.reshape(np.append(grid[::-1],shape)) + field = field.reshape(tuple(grid)+(-1,),order='F').reshape(tuple(grid)+shape) + grad = damask.grid_filters.gradient(size,field) table.add('gradFFT({})'.format(label), - damask.grid_filters.gradient(size[::-1],field).reshape(-1,np.prod(shape)*3), + grad.reshape(tuple(grid)+(-1,)).reshape(-1,np.prod(shape)*3,order='F'), scriptID+' '+' '.join(sys.argv[1:])) - + table.to_ASCII(sys.stdout if name is None else name) diff --git a/python/damask/_geom.py b/python/damask/_geom.py index e2c2428fe..a33e855d8 100644 --- a/python/damask/_geom.py +++ b/python/damask/_geom.py @@ -357,7 +357,6 @@ class Geom: seeds_p = np.vstack((seeds_p-np.array([0.,size[1],0.]),seeds_p,seeds_p+np.array([0.,size[1],0.]))) seeds_p = np.vstack((seeds_p-np.array([0.,0.,size[2]]),seeds_p,seeds_p+np.array([0.,0.,size[2]]))) coords = grid_filters.cell_coord0(grid*3,size*3,-size).reshape(-1,3,order='F') - else: weights_p = weights.flatten() seeds_p = seeds @@ -370,10 +369,10 @@ class Geom: microstructure = np.array(result.get()) if periodic: - microstructure = microstructure.reshape(grid*3) + microstructure = microstructure.reshape(grid*3,order='F') microstructure = microstructure[grid[0]:grid[0]*2,grid[1]:grid[1]*2,grid[2]:grid[2]*2]%seeds.shape[0] else: - microstructure = microstructure.reshape(grid) + microstructure = microstructure.reshape(grid,order='F') #comments = 'geom.py:from_Laguerre_tessellation v{}'.format(version) return Geom(microstructure+1,size,homogenization=1) @@ -401,7 +400,7 @@ class Geom: devNull,microstructure = KDTree.query(coords) #comments = 'geom.py:from_Voronoi_tessellation v{}'.format(version) - return Geom(microstructure.reshape(grid)+1,size,homogenization=1) + return Geom(microstructure.reshape(grid,order='F')+1,size,homogenization=1) def to_file(self,fname,pack=None): diff --git a/python/damask/grid_filters.py b/python/damask/grid_filters.py index d8b136a6b..0c1c3867a 100644 --- a/python/damask/grid_filters.py +++ b/python/damask/grid_filters.py @@ -7,7 +7,7 @@ def _ks(size,grid,first_order=False): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. """ @@ -19,8 +19,7 @@ def _ks(size,grid,first_order=False): k_si = _np.arange(grid[2]//2+1)/size[2] - kk, kj, ki = _np.meshgrid(k_sk,k_sj,k_si,indexing = 'ij') - return _np.concatenate((ki[:,:,:,None],kj[:,:,:,None],kk[:,:,:,None]),axis = 3) + return _np.stack(_np.meshgrid(k_sk,k_sj,k_si,indexing = 'ij'), axis=-1) def curl(size,field): @@ -29,7 +28,7 @@ def curl(size,field): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. """ @@ -53,7 +52,7 @@ def divergence(size,field): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. """ @@ -73,7 +72,7 @@ def gradient(size,field): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. """ @@ -93,9 +92,9 @@ def cell_coord0(grid,size,origin=_np.zeros(3)): Parameters ---------- - grid : numpy.ndarray + grid : numpy.ndarray of shape (3) number of grid points. - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. origin : numpy.ndarray, optional physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. @@ -103,7 +102,11 @@ def cell_coord0(grid,size,origin=_np.zeros(3)): """ start = origin + size/grid*.5 end = origin + size - size/grid*.5 - return _np.mgrid[start[0]:end[0]:grid[0]*1j,start[1]:end[1]:grid[1]*1j,start[2]:end[2]:grid[2]*1j].T + + return _np.stack(_np.meshgrid(_np.linspace(start[0],end[0],grid[0]), + _np.linspace(start[1],end[1],grid[1]), + _np.linspace(start[2],end[2],grid[2]),indexing = 'ij'), + axis = -1) def cell_displacement_fluct(size,F): @@ -112,7 +115,7 @@ def cell_displacement_fluct(size,F): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. F : numpy.ndarray deformation gradient field. @@ -139,14 +142,14 @@ def cell_displacement_avg(size,F): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. F : numpy.ndarray deformation gradient field. """ F_avg = _np.average(F,axis=(0,1,2)) - return _np.einsum('ml,ijkl->ijkm',F_avg - _np.eye(3),cell_coord0(F.shape[:3][::-1],size)) + return _np.einsum('ml,ijkl->ijkm',F_avg - _np.eye(3),cell_coord0(F.shape[:3],size)) def cell_displacement(size,F): @@ -155,7 +158,7 @@ def cell_displacement(size,F): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. F : numpy.ndarray deformation gradient field. @@ -170,30 +173,30 @@ def cell_coord(size,F,origin=_np.zeros(3)): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. F : numpy.ndarray deformation gradient field. - origin : numpy.ndarray, optional + origin : numpy.ndarray of shape (3), optional physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. """ - return cell_coord0(F.shape[:3][::-1],size,origin) + cell_displacement(size,F) + return cell_coord0(F.shape[:3],size,origin) + cell_displacement(size,F) def cell_coord0_gridSizeOrigin(coord0,ordered=True): """ - Return grid 'DNA', i.e. grid, size, and origin from array of cell positions. + Return grid 'DNA', i.e. grid, size, and origin from 1D array of cell positions. Parameters ---------- - coord0 : numpy.ndarray - array of undeformed cell coordinates. + coord0 : numpy.ndarray of shape (:,3) + undeformed cell coordinates. ordered : bool, optional expect coord0 data to be ordered (x fast, z slow). """ - coords = [_np.unique(coord0[:,i]) for i in range(3)] + coords = [_np.unique(coord0[:,i]) for i in range(3)] # _np.unique(coord0, axis=1) mincorner = _np.array(list(map(min,coords))) maxcorner = _np.array(list(map(max,coords))) grid = _np.array(list(map(len,coords)),'i') @@ -216,7 +219,7 @@ def cell_coord0_gridSizeOrigin(coord0,ordered=True): _np.allclose(coords[2],_np.linspace(start[2],end[2],grid[2])): raise ValueError('Regular grid spacing violated.') - if ordered and not _np.allclose(coord0.reshape(tuple(grid[::-1])+(3,)),cell_coord0(grid,size,origin)): + if ordered and not _np.allclose(coord0.reshape(tuple(grid)+(3,),order='F'),cell_coord0(grid,size,origin)): raise ValueError('Input data is not a regular grid.') return (grid,size,origin) @@ -241,17 +244,18 @@ def node_coord0(grid,size,origin=_np.zeros(3)): Parameters ---------- - grid : numpy.ndarray + grid : numpy.ndarray of shape (3) number of grid points. - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. - origin : numpy.ndarray, optional + origin : numpy.ndarray of shape (3), optional physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. """ - return _np.mgrid[origin[0]:size[0]+origin[0]:(grid[0]+1)*1j, - origin[1]:size[1]+origin[1]:(grid[1]+1)*1j, - origin[2]:size[2]+origin[2]:(grid[2]+1)*1j].T + return _np.stack(_np.meshgrid(_np.linspace(origin[0],size[0]+origin[0],grid[0]+1), + _np.linspace(origin[1],size[1]+origin[1],grid[1]+1), + _np.linspace(origin[2],size[2]+origin[2],grid[2]+1),indexing = 'ij'), + axis = -1) def node_displacement_fluct(size,F): @@ -260,7 +264,7 @@ def node_displacement_fluct(size,F): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. F : numpy.ndarray deformation gradient field. @@ -275,14 +279,14 @@ def node_displacement_avg(size,F): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. F : numpy.ndarray deformation gradient field. """ F_avg = _np.average(F,axis=(0,1,2)) - return _np.einsum('ml,ijkl->ijkm',F_avg - _np.eye(3),node_coord0(F.shape[:3][::-1],size)) + return _np.einsum('ml,ijkl->ijkm',F_avg - _np.eye(3),node_coord0(F.shape[:3],size)) def node_displacement(size,F): @@ -291,7 +295,7 @@ def node_displacement(size,F): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. F : numpy.ndarray deformation gradient field. @@ -306,15 +310,15 @@ def node_coord(size,F,origin=_np.zeros(3)): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size of the periodic field. F : numpy.ndarray deformation gradient field. - origin : numpy.ndarray, optional + origin : numpy.ndarray of shape (3), optional physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. """ - return node_coord0(F.shape[:3][::-1],size,origin) + node_displacement(size,F) + return node_coord0(F.shape[:3],size,origin) + node_displacement(size,F) def cell_2_node(cell_data): @@ -335,19 +339,19 @@ def node_2_cell(node_data): return c[:-1,:-1,:-1] -def node_coord0_gridSizeOrigin(coord0,ordered=False): +def node_coord0_gridSizeOrigin(coord0,ordered=True): """ - Return grid 'DNA', i.e. grid, size, and origin from array of nodal positions. + Return grid 'DNA', i.e. grid, size, and origin from 1D array of nodal positions. Parameters ---------- - coord0 : numpy.ndarray - array of undeformed nodal coordinates. + coord0 : numpy.ndarray of shape (:,3) + undeformed nodal coordinates. ordered : bool, optional expect coord0 data to be ordered (x fast, z slow). """ - coords = [_np.unique(coord0[:,i]) for i in range(3)] + coords = [_np.unique(coord0[:,i]) for i in range(3)] # _np.unique(coord0, axis=1) mincorner = _np.array(list(map(min,coords))) maxcorner = _np.array(list(map(max,coords))) grid = _np.array(list(map(len,coords)),'i') - 1 @@ -362,7 +366,7 @@ def node_coord0_gridSizeOrigin(coord0,ordered=False): _np.allclose(coords[2],_np.linspace(mincorner[2],maxcorner[2],grid[2]+1)): raise ValueError('Regular grid spacing violated.') - if ordered and not _np.allclose(coord0.reshape(tuple((grid+1)[::-1])+(3,)),node_coord0(grid,size,origin)): + if ordered and not _np.allclose(coord0.reshape(tuple(grid+1)+(3,),order='F'),node_coord0(grid,size,origin)): raise ValueError('Input data is not a regular grid.') return (grid,size,origin) @@ -374,7 +378,7 @@ def regrid(size,F,new_grid): Parameters ---------- - size : numpy.ndarray + size : numpy.ndarray of shape (3) physical size F : numpy.ndarray deformation gradient field @@ -382,7 +386,7 @@ def regrid(size,F,new_grid): new grid for undeformed coordinates """ - c = cell_coord0(F.shape[:3][::-1],size) \ + c = cell_coord0(F.shape[:3],size) \ + cell_displacement_avg(size,F) \ + cell_displacement_fluct(size,F) diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index acbdbf688..3152072b7 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -4,18 +4,18 @@ import numpy as np from damask import grid_filters class TestGridFilters: - + def test_cell_coord0(self): size = np.random.random(3) grid = np.random.randint(8,32,(3)) coord = grid_filters.cell_coord0(grid,size) - assert np.allclose(coord[0,0,0],size/grid*.5) and coord.shape == tuple(grid[::-1]) + (3,) + assert np.allclose(coord[0,0,0],size/grid*.5) and coord.shape == tuple(grid) + (3,) def test_node_coord0(self): size = np.random.random(3) grid = np.random.randint(8,32,(3)) coord = grid_filters.node_coord0(grid,size) - assert np.allclose(coord[-1,-1,-1],size) and coord.shape == tuple(grid[::-1]+1) + (3,) + assert np.allclose(coord[-1,-1,-1],size) and coord.shape == tuple(grid+1) + (3,) def test_coord0(self): size = np.random.random(3) @@ -31,7 +31,7 @@ class TestGridFilters: size = np.random.random(3) origin = np.random.random(3) coord0 = eval('grid_filters.{}_coord0(grid,size,origin)'.format(mode)) # noqa - _grid,_size,_origin = eval('grid_filters.{}_coord0_gridSizeOrigin(coord0.reshape(-1,3))'.format(mode)) + _grid,_size,_origin = eval('grid_filters.{}_coord0_gridSizeOrigin(coord0.reshape(-1,3,order="F"))'.format(mode)) assert np.allclose(grid,_grid) and np.allclose(size,_size) and np.allclose(origin,_origin) def test_displacement_fluct_equivalence(self): @@ -57,9 +57,9 @@ class TestGridFilters: shifted = eval('grid_filters.{}_coord0(grid,size,origin)'.format(mode)) unshifted = eval('grid_filters.{}_coord0(grid,size)'.format(mode)) if mode == 'cell': - assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(grid[::-1]) +(3,))) + assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(grid) +(3,))) elif mode == 'node': - assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(grid[::-1]+1)+(3,))) + assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(grid+1)+(3,))) @pytest.mark.parametrize('function',[grid_filters.cell_displacement_avg, grid_filters.node_displacement_avg]) @@ -83,5 +83,5 @@ class TestGridFilters: def test_regrid(self): size = np.random.random(3) grid = np.random.randint(8,32,(3)) - F = np.broadcast_to(np.eye(3), tuple(grid[::-1])+(3,3)) + F = np.broadcast_to(np.eye(3), tuple(grid)+(3,3)) assert all(grid_filters.regrid(size,F,grid) == np.arange(grid.prod())) From 02dde3c2556a4e8c7ccf83a4b21670e9cc713083 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 13:10:13 +0200 Subject: [PATCH 086/186] test also invalid operations --- python/tests/test_grid_filters.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index 3152072b7..9eba75298 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -80,6 +80,11 @@ class TestGridFilters: F = np.broadcast_to(np.random.random((3,3)), tuple(grid)+(3,3)) assert np.allclose(function(size,F),0.0) + def test_invalid_coordinates(self): + invalid_coordinates = np.random.random((np.random.randint(12,52),3)) + with pytest.raises(ValueError): + grid_filters.coord0_check(invalid_coordinates) + def test_regrid(self): size = np.random.random(3) grid = np.random.randint(8,32,(3)) From f519e62cd5713d2ba5b80ec574e695ec358969cf Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 13:56:33 +0200 Subject: [PATCH 087/186] testing data layout checks --- python/damask/grid_filters.py | 20 +++++++++--------- python/tests/test_grid_filters.py | 34 +++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/python/damask/grid_filters.py b/python/damask/grid_filters.py index 0c1c3867a..2ee99d276 100644 --- a/python/damask/grid_filters.py +++ b/python/damask/grid_filters.py @@ -196,7 +196,7 @@ def cell_coord0_gridSizeOrigin(coord0,ordered=True): expect coord0 data to be ordered (x fast, z slow). """ - coords = [_np.unique(coord0[:,i]) for i in range(3)] # _np.unique(coord0, axis=1) + coords = [_np.unique(coord0[:,i]) for i in range(3)] mincorner = _np.array(list(map(min,coords))) maxcorner = _np.array(list(map(max,coords))) grid = _np.array(list(map(len,coords)),'i') @@ -214,13 +214,13 @@ def cell_coord0_gridSizeOrigin(coord0,ordered=True): start = origin + delta*.5 end = origin - delta*.5 + size - if not _np.allclose(coords[0],_np.linspace(start[0],end[0],grid[0])) and \ - _np.allclose(coords[1],_np.linspace(start[1],end[1],grid[1])) and \ - _np.allclose(coords[2],_np.linspace(start[2],end[2],grid[2])): + if not (_np.allclose(coords[0],_np.linspace(start[0],end[0],grid[0])) and \ + _np.allclose(coords[1],_np.linspace(start[1],end[1],grid[1])) and \ + _np.allclose(coords[2],_np.linspace(start[2],end[2],grid[2]))): raise ValueError('Regular grid spacing violated.') if ordered and not _np.allclose(coord0.reshape(tuple(grid)+(3,),order='F'),cell_coord0(grid,size,origin)): - raise ValueError('Input data is not a regular grid.') + raise ValueError('Input data is not ordered (x fast, z slow).') return (grid,size,origin) @@ -351,7 +351,7 @@ def node_coord0_gridSizeOrigin(coord0,ordered=True): expect coord0 data to be ordered (x fast, z slow). """ - coords = [_np.unique(coord0[:,i]) for i in range(3)] # _np.unique(coord0, axis=1) + coords = [_np.unique(coord0[:,i]) for i in range(3)] mincorner = _np.array(list(map(min,coords))) maxcorner = _np.array(list(map(max,coords))) grid = _np.array(list(map(len,coords)),'i') - 1 @@ -361,13 +361,13 @@ def node_coord0_gridSizeOrigin(coord0,ordered=True): if (grid+1).prod() != len(coord0): raise ValueError('Data count {} does not match grid {}.'.format(len(coord0),grid)) - if not _np.allclose(coords[0],_np.linspace(mincorner[0],maxcorner[0],grid[0]+1)) and \ - _np.allclose(coords[1],_np.linspace(mincorner[1],maxcorner[1],grid[1]+1)) and \ - _np.allclose(coords[2],_np.linspace(mincorner[2],maxcorner[2],grid[2]+1)): + if not (_np.allclose(coords[0],_np.linspace(mincorner[0],maxcorner[0],grid[0]+1)) and \ + _np.allclose(coords[1],_np.linspace(mincorner[1],maxcorner[1],grid[1]+1)) and \ + _np.allclose(coords[2],_np.linspace(mincorner[2],maxcorner[2],grid[2]+1))): raise ValueError('Regular grid spacing violated.') if ordered and not _np.allclose(coord0.reshape(tuple(grid+1)+(3,),order='F'),node_coord0(grid,size,origin)): - raise ValueError('Input data is not a regular grid.') + raise ValueError('Input data is not ordered (x fast, z slow).') return (grid,size,origin) diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index 9eba75298..eb359006a 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -80,10 +80,40 @@ class TestGridFilters: F = np.broadcast_to(np.random.random((3,3)), tuple(grid)+(3,3)) assert np.allclose(function(size,F),0.0) - def test_invalid_coordinates(self): + @pytest.mark.parametrize('function',[grid_filters.coord0_check, + grid_filters.node_coord0_gridSizeOrigin, + grid_filters.cell_coord0_gridSizeOrigin]) + def test_invalid_coordinates(self,function): invalid_coordinates = np.random.random((np.random.randint(12,52),3)) with pytest.raises(ValueError): - grid_filters.coord0_check(invalid_coordinates) + function(invalid_coordinates) + + @pytest.mark.parametrize('function',[grid_filters.node_coord0_gridSizeOrigin, + grid_filters.cell_coord0_gridSizeOrigin]) + def test_uneven_spaced_coordinates(self,function): + start = np.random.random(3) + end = np.random.random(3)*10. + start + grid = np.random.randint(8,32,(3)) + uneven = np.stack(np.meshgrid(np.logspace(start[0],end[0],grid[0]), + np.logspace(start[1],end[1],grid[1]), + np.logspace(start[2],end[2],grid[2]),indexing = 'ij'), + axis = -1).reshape((grid.prod(),3),order='F') + with pytest.raises(ValueError): + function(uneven) + + @pytest.mark.parametrize('mode',[True,False]) + @pytest.mark.parametrize('function',[grid_filters.node_coord0_gridSizeOrigin, + grid_filters.cell_coord0_gridSizeOrigin]) + def test_unordered_coordinates(self,function,mode): + origin = np.random.random(3) + size = np.random.random(3)*10.+origin + grid = np.random.randint(8,32,(3)) + unordered = grid_filters.node_coord0(grid,size,origin).reshape(-1,3) + if mode: + with pytest.raises(ValueError): + function(unordered,mode) + else: + function(unordered,mode) def test_regrid(self): size = np.random.random(3) From a367128436fb099c3fe4f8b920f61b31e169f1f4 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 13:57:33 +0200 Subject: [PATCH 088/186] not used anymore --- processing/post/addDisplacement.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/processing/post/addDisplacement.py b/processing/post/addDisplacement.py index a9424f5e1..6f4a60192 100755 --- a/processing/post/addDisplacement.py +++ b/processing/post/addDisplacement.py @@ -5,8 +5,6 @@ import sys from io import StringIO from optparse import OptionParser -import numpy as np - import damask From 8465c3ab1b7b19a84b4aa00c56b7aada29131ea1 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 19:13:45 +0200 Subject: [PATCH 089/186] adjusting to new data layout --- processing/pre/geom_fromVoronoiTessellation.py | 2 +- processing/pre/seeds_fromGeom.py | 8 ++++---- processing/pre/seeds_fromRandom.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/processing/pre/geom_fromVoronoiTessellation.py b/processing/pre/geom_fromVoronoiTessellation.py index df40176d8..2b4da133b 100755 --- a/processing/pre/geom_fromVoronoiTessellation.py +++ b/processing/pre/geom_fromVoronoiTessellation.py @@ -224,7 +224,7 @@ for name in filenames: header = [scriptID + ' ' + ' '.join(sys.argv[1:])]\ + config_header - geom = damask.Geom(indices.reshape(grid),size,origin, + geom = damask.Geom(indices.reshape(grid,order='F'),size,origin, homogenization=options.homogenization,comments=header) damask.util.croak(geom) diff --git a/processing/pre/seeds_fromGeom.py b/processing/pre/seeds_fromGeom.py index 80dc0d6f5..0b741a077 100755 --- a/processing/pre/seeds_fromGeom.py +++ b/processing/pre/seeds_fromGeom.py @@ -45,7 +45,7 @@ options.blacklist = [int(i) for i in options.blacklist] for name in filenames: damask.util.report(scriptName,name) - + geom = damask.Geom.from_file(StringIO(''.join(sys.stdin.read())) if name is None else name) microstructure = geom.get_microstructure().reshape((-1,1),order='F') @@ -53,9 +53,9 @@ for name in filenames: np.full(geom.grid.prod(),True,dtype=bool), np.in1d(microstructure,options.blacklist,invert=True) if options.blacklist else \ np.full(geom.grid.prod(),True,dtype=bool)) - - seeds = damask.grid_filters.cell_coord0(geom.grid,geom.size).reshape(-1,3) - + + seeds = damask.grid_filters.cell_coord0(geom.grid,geom.size).reshape(-1,3,order='F') + comments = geom.comments \ + [scriptID + ' ' + ' '.join(sys.argv[1:]), 'grid\ta {}\tb {}\tc {}'.format(*geom.grid), diff --git a/processing/pre/seeds_fromRandom.py b/processing/pre/seeds_fromRandom.py index 2de513c2c..be690713c 100755 --- a/processing/pre/seeds_fromRandom.py +++ b/processing/pre/seeds_fromRandom.py @@ -128,7 +128,7 @@ for name in filenames: if not options.selective: - coords = damask.grid_filters.cell_coord0(grid,size).reshape(-1,3) + coords = damask.grid_filters.cell_coord0(grid,size).reshape(-1,3,order='F') seeds = coords[np.random.choice(np.prod(grid), options.N, replace=False)] \ + np.broadcast_to(size/grid,(options.N,3))*(np.random.rand(options.N,3)*.5-.25) # wobble without leaving grid else: From 4db91fff03ab68f68cf26ac2c5311fd10c82b8c8 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 20:14:27 +0200 Subject: [PATCH 090/186] simplified --- python/damask/_geom.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/damask/_geom.py b/python/damask/_geom.py index a33e855d8..f01277f95 100644 --- a/python/damask/_geom.py +++ b/python/damask/_geom.py @@ -322,11 +322,10 @@ class Geom: if i != grid.prod(): raise TypeError('Invalid file: expected {} entries, found {}'.format(grid.prod(),i)) - microstructure = microstructure.reshape(grid,order='F') - if not np.any(np.mod(microstructure.flatten(),1) != 0.0): # no float present + if not np.any(np.mod(microstructure,1) != 0.0): # no float present microstructure = microstructure.astype('int') - return Geom(microstructure.reshape(grid),size,origin,homogenization,comments) + return Geom(microstructure.reshape(grid,order='F'),size,origin,homogenization,comments) @staticmethod From 1ccda22ae354de44c78da730543ccd7b747cb906 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 20:16:25 +0200 Subject: [PATCH 091/186] nothing to flatten here --- python/damask/_geom.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/damask/_geom.py b/python/damask/_geom.py index f01277f95..8010cd167 100644 --- a/python/damask/_geom.py +++ b/python/damask/_geom.py @@ -351,13 +351,13 @@ class Geom: """ if periodic: - weights_p = np.tile(weights,27).flatten(order='F') # Laguerre weights (1,2,3,1,2,3,...,1,2,3) + weights_p = np.tile(weights,27) # Laguerre weights (1,2,3,1,2,3,...,1,2,3) seeds_p = np.vstack((seeds -np.array([size[0],0.,0.]),seeds, seeds +np.array([size[0],0.,0.]))) seeds_p = np.vstack((seeds_p-np.array([0.,size[1],0.]),seeds_p,seeds_p+np.array([0.,size[1],0.]))) seeds_p = np.vstack((seeds_p-np.array([0.,0.,size[2]]),seeds_p,seeds_p+np.array([0.,0.,size[2]]))) coords = grid_filters.cell_coord0(grid*3,size*3,-size).reshape(-1,3,order='F') else: - weights_p = weights.flatten() + weights_p = weights seeds_p = seeds coords = grid_filters.cell_coord0(grid,size).reshape(-1,3,order='F') From 25d29bf438d00390f105bbdff29c6c85ddc3472d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 20:24:55 +0200 Subject: [PATCH 092/186] no need for Fortran order forward/backward --- python/damask/_geom.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python/damask/_geom.py b/python/damask/_geom.py index 8010cd167..892000b7c 100644 --- a/python/damask/_geom.py +++ b/python/damask/_geom.py @@ -355,11 +355,11 @@ class Geom: seeds_p = np.vstack((seeds -np.array([size[0],0.,0.]),seeds, seeds +np.array([size[0],0.,0.]))) seeds_p = np.vstack((seeds_p-np.array([0.,size[1],0.]),seeds_p,seeds_p+np.array([0.,size[1],0.]))) seeds_p = np.vstack((seeds_p-np.array([0.,0.,size[2]]),seeds_p,seeds_p+np.array([0.,0.,size[2]]))) - coords = grid_filters.cell_coord0(grid*3,size*3,-size).reshape(-1,3,order='F') + coords = grid_filters.cell_coord0(grid*3,size*3,-size).reshape(-1,3) else: weights_p = weights seeds_p = seeds - coords = grid_filters.cell_coord0(grid,size).reshape(-1,3,order='F') + coords = grid_filters.cell_coord0(grid,size).reshape(-1,3) pool = multiprocessing.Pool(processes = int(Environment().options['DAMASK_NUM_THREADS'])) result = pool.map_async(partial(Geom._find_closest_seed,seeds_p,weights_p), [coord for coord in coords]) @@ -368,10 +368,10 @@ class Geom: microstructure = np.array(result.get()) if periodic: - microstructure = microstructure.reshape(grid*3,order='F') + microstructure = microstructure.reshape(grid*3) microstructure = microstructure[grid[0]:grid[0]*2,grid[1]:grid[1]*2,grid[2]:grid[2]*2]%seeds.shape[0] else: - microstructure = microstructure.reshape(grid,order='F') + microstructure = microstructure.reshape(grid) #comments = 'geom.py:from_Laguerre_tessellation v{}'.format(version) return Geom(microstructure+1,size,homogenization=1) @@ -394,12 +394,12 @@ class Geom: perform a periodic tessellation. Defaults to True. """ - coords = grid_filters.cell_coord0(grid,size).reshape(-1,3,order='F') + coords = grid_filters.cell_coord0(grid,size).reshape(-1,3) KDTree = spatial.cKDTree(seeds,boxsize=size) if periodic else spatial.cKDTree(seeds) devNull,microstructure = KDTree.query(coords) #comments = 'geom.py:from_Voronoi_tessellation v{}'.format(version) - return Geom(microstructure.reshape(grid,order='F')+1,size,homogenization=1) + return Geom(microstructure.reshape(grid)+1,size,homogenization=1) def to_file(self,fname,pack=None): From a8b75a23c5f746fec18fd771db2c02dbe30fb320 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 20:40:47 +0200 Subject: [PATCH 093/186] simplified --- processing/pre/geom_fromVoronoiTessellation.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/processing/pre/geom_fromVoronoiTessellation.py b/processing/pre/geom_fromVoronoiTessellation.py index 2b4da133b..e6755c28e 100755 --- a/processing/pre/geom_fromVoronoiTessellation.py +++ b/processing/pre/geom_fromVoronoiTessellation.py @@ -24,22 +24,22 @@ def findClosestSeed(seeds, weights, point): def Laguerre_tessellation(grid, size, seeds, weights, origin = np.zeros(3), periodic = True, cpus = 2): if periodic: - weights_p = np.tile(weights,27).flatten(order='F') # Laguerre weights (1,2,3,1,2,3,...,1,2,3) + weights_p = np.tile(weights.squeeze(),27) # Laguerre weights (1,2,3,1,2,3,...,1,2,3) seeds_p = np.vstack((seeds -np.array([size[0],0.,0.]),seeds, seeds +np.array([size[0],0.,0.]))) seeds_p = np.vstack((seeds_p-np.array([0.,size[1],0.]),seeds_p,seeds_p+np.array([0.,size[1],0.]))) seeds_p = np.vstack((seeds_p-np.array([0.,0.,size[2]]),seeds_p,seeds_p+np.array([0.,0.,size[2]]))) - coords = damask.grid_filters.cell_coord0(grid*3,size*3,-origin-size).reshape(-1,3,order='F') + coords = damask.grid_filters.cell_coord0(grid*3,size*3,-origin-size).reshape(-1,3) else: - weights_p = weights.flatten() + weights_p = weights.squeeze() seeds_p = seeds - coords = damask.grid_filters.cell_coord0(grid,size,-origin).reshape(-1,3,order='F') + coords = damask.grid_filters.cell_coord0(grid,size,-origin).reshape(-1,3) if cpus > 1: pool = multiprocessing.Pool(processes = cpus) result = pool.map_async(partial(findClosestSeed,seeds_p,weights_p), [coord for coord in coords]) pool.close() pool.join() - closest_seed = np.array(result.get()) + closest_seed = np.array(result.get()).reshape(-1,3) else: closest_seed= np.array([findClosestSeed(seeds_p,weights_p,coord) for coord in coords]) @@ -52,7 +52,7 @@ def Laguerre_tessellation(grid, size, seeds, weights, origin = np.zeros(3), peri def Voronoi_tessellation(grid, size, seeds, origin = np.zeros(3), periodic = True): - coords = damask.grid_filters.cell_coord0(grid,size,-origin).reshape(-1,3,order='F') + coords = damask.grid_filters.cell_coord0(grid,size,-origin).reshape(-1,3) KDTree = spatial.cKDTree(seeds,boxsize=size) if periodic else spatial.cKDTree(seeds) devNull,closest_seed = KDTree.query(coords) @@ -224,7 +224,7 @@ for name in filenames: header = [scriptID + ' ' + ' '.join(sys.argv[1:])]\ + config_header - geom = damask.Geom(indices.reshape(grid,order='F'),size,origin, + geom = damask.Geom(indices.reshape(grid),size,origin, homogenization=options.homogenization,comments=header) damask.util.croak(geom) From 9a54c326e23a5e876cd18febb154452591f7904a Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 21:28:23 +0200 Subject: [PATCH 094/186] adopted to new data layout --- processing/post/averageDown.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/processing/post/averageDown.py b/processing/post/averageDown.py index 39d925d19..341cc748d 100755 --- a/processing/post/averageDown.py +++ b/processing/post/averageDown.py @@ -61,7 +61,7 @@ if any(shift != 0): prefix += 'shift{:+}{:+}{:+}_'.format(*shift) for name in filenames: damask.util.report(scriptName,name) - + table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) if (options.grid is None or options.size is None): @@ -87,11 +87,11 @@ for name in filenames: origin = list(-(packing//2)) + [0])\ [::packing[0],::packing[1],::packing[2],:].reshape((packedGrid.prod(),-1),order = 'F') - + table = damask.Table(averagedDown,table.shapes,table.comments) coords = damask.grid_filters.cell_coord0(packedGrid,size,shift/packedGrid*size+origin) - table.set(options.pos, coords.reshape(-1,3)) + table.set(options.pos, coords.reshape(-1,3,order='F')) outname = os.path.join(os.path.dirname(name),prefix+os.path.basename(name)) From 4278ba32ae2ddd71a4522bfe390e0f7efec518a8 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 21:44:38 +0200 Subject: [PATCH 095/186] adopting to standard data layout --- processing/post/addCompatibilityMismatch.py | 55 ++++++++++----------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/processing/post/addCompatibilityMismatch.py b/processing/post/addCompatibilityMismatch.py index 0678e78ba..7cab9c2ca 100755 --- a/processing/post/addCompatibilityMismatch.py +++ b/processing/post/addCompatibilityMismatch.py @@ -16,8 +16,8 @@ scriptID = ' '.join([scriptName,damask.version]) def volTetrahedron(coords): """ Return the volume of the tetrahedron with given vertices or sides. - - Ifvertices are given they must be in a NumPy array with shape (4,3): the + + If vertices are given they must be in a NumPy array with shape (4,3): the position vectors of the 4 vertices in 3 dimensions; if the six sides are given, they must be an array of length 6. If both are given, the sides will be used in the calculation. @@ -62,19 +62,18 @@ def volTetrahedron(coords): def volumeMismatch(size,F,nodes): """ Calculates the volume mismatch. - - volume mismatch is defined as the difference between volume of reconstructed + + volume mismatch is defined as the difference between volume of reconstructed (compatible) cube and determinant of deformation gradient at Fourier point. """ coords = np.empty([8,3]) - vMismatch = np.empty(grid[::-1]) - volInitial = size.prod()/grid.prod() - + vMismatch = np.empty(F.shape[:3]) + #-------------------------------------------------------------------------------------------------- # calculate actual volume and volume resulting from deformation gradient - for k in range(grid[2]): + for k in range(grid[0]): for j in range(grid[1]): - for i in range(grid[0]): + for i in range(grid[2]): coords[0,0:3] = nodes[k, j, i ,0:3] coords[1,0:3] = nodes[k ,j, i+1,0:3] coords[2,0:3] = nodes[k ,j+1,i+1,0:3] @@ -91,21 +90,21 @@ def volumeMismatch(size,F,nodes): + abs(volTetrahedron([coords[6,0:3],coords[4,0:3],coords[1,0:3],coords[5,0:3]])) \ + abs(volTetrahedron([coords[6,0:3],coords[4,0:3],coords[1,0:3],coords[0,0:3]]))) \ /np.linalg.det(F[k,j,i,0:3,0:3]) - return vMismatch/volInitial + return vMismatch/(size.prod()/grid.prod()) def shapeMismatch(size,F,nodes,centres): """ Routine to calculate the shape mismatch. - + shape mismatch is defined as difference between the vectors from the central point to the corners of reconstructed (combatible) volume element and the vectors calculated by deforming the initial volume element with the current deformation gradient. """ coordsInitial = np.empty([8,3]) - sMismatch = np.empty(grid[::-1]) - + sMismatch = np.empty(F.shape[:3]) + #-------------------------------------------------------------------------------------------------- # initial positions coordsInitial[0,0:3] = [-size[0]/grid[0],-size[1]/grid[1],-size[2]/grid[2]] @@ -117,21 +116,21 @@ def shapeMismatch(size,F,nodes,centres): coordsInitial[6,0:3] = [+size[0]/grid[0],+size[1]/grid[1],+size[2]/grid[2]] coordsInitial[7,0:3] = [-size[0]/grid[0],+size[1]/grid[1],+size[2]/grid[2]] coordsInitial = coordsInitial/2.0 - + #-------------------------------------------------------------------------------------------------- # compare deformed original and deformed positions to actual positions - for k in range(grid[2]): + for k in range(grid[0]): for j in range(grid[1]): - for i in range(grid[0]): + for i in range(grid[2]): sMismatch[k,j,i] = \ + np.linalg.norm(nodes[k, j, i ,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[0,0:3]))\ - + np.linalg.norm(nodes[k, j, i+1,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[1,0:3]))\ - + np.linalg.norm(nodes[k, j+1,i+1,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[2,0:3]))\ + + np.linalg.norm(nodes[k+1,j, i ,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[1,0:3]))\ + + np.linalg.norm(nodes[k+1,j+1,i ,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[2,0:3]))\ + np.linalg.norm(nodes[k, j+1,i ,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[3,0:3]))\ - + np.linalg.norm(nodes[k+1,j, i ,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[4,0:3]))\ + + np.linalg.norm(nodes[k, j, i+1,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[4,0:3]))\ + np.linalg.norm(nodes[k+1,j, i+1,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[5,0:3]))\ + np.linalg.norm(nodes[k+1,j+1,i+1,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[6,0:3]))\ - + np.linalg.norm(nodes[k+1,j+1,i ,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[7,0:3])) + + np.linalg.norm(nodes[k ,j+1,i+1,0:3] - centres[k,j,i,0:3] - np.dot(F[k,j,i,:,:], coordsInitial[7,0:3])) return sMismatch @@ -174,24 +173,24 @@ if filenames == []: filenames = [None] for name in filenames: damask.util.report(scriptName,name) - + table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) grid,size,origin = damask.grid_filters.cell_coord0_gridSizeOrigin(table.get(options.pos)) - F = table.get(options.defgrad).reshape(grid[2],grid[1],grid[0],3,3) + F = table.get(options.defgrad).reshape(tuple(grid)+(-1,),order='F').reshape(tuple(grid)+(3,3)) nodes = damask.grid_filters.node_coord(size,F) - + if options.shape: centers = damask.grid_filters.cell_coord(size,F) - shapeMismatch = shapeMismatch( size,table.get(options.defgrad).reshape(grid[2],grid[1],grid[0],3,3),nodes,centers) + shapeMismatch = shapeMismatch(size,F,nodes,centers) table.add('shapeMismatch(({}))'.format(options.defgrad), - shapeMismatch.reshape(-1,1), + shapeMismatch.reshape(-1,1,order='F'), scriptID+' '+' '.join(sys.argv[1:])) - + if options.volume: - volumeMismatch = volumeMismatch(size,table.get(options.defgrad).reshape(grid[2],grid[1],grid[0],3,3),nodes) + volumeMismatch = volumeMismatch(size,F,nodes) table.add('volMismatch(({}))'.format(options.defgrad), - volumeMismatch.reshape(-1,1), + volumeMismatch.reshape(-1,1,order='F'), scriptID+' '+' '.join(sys.argv[1:])) table.to_ASCII(sys.stdout if name is None else name) From 85f831d5b44594db2c6460e693715a0d92d77164 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 22:14:57 +0200 Subject: [PATCH 096/186] simplified --- processing/post/addCompatibilityMismatch.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/processing/post/addCompatibilityMismatch.py b/processing/post/addCompatibilityMismatch.py index 7cab9c2ca..59eafc077 100755 --- a/processing/post/addCompatibilityMismatch.py +++ b/processing/post/addCompatibilityMismatch.py @@ -93,7 +93,6 @@ def volumeMismatch(size,F,nodes): return vMismatch/(size.prod()/grid.prod()) - def shapeMismatch(size,F,nodes,centres): """ Routine to calculate the shape mismatch. @@ -102,20 +101,19 @@ def shapeMismatch(size,F,nodes,centres): the corners of reconstructed (combatible) volume element and the vectors calculated by deforming the initial volume element with the current deformation gradient. """ - coordsInitial = np.empty([8,3]) sMismatch = np.empty(F.shape[:3]) #-------------------------------------------------------------------------------------------------- # initial positions - coordsInitial[0,0:3] = [-size[0]/grid[0],-size[1]/grid[1],-size[2]/grid[2]] - coordsInitial[1,0:3] = [+size[0]/grid[0],-size[1]/grid[1],-size[2]/grid[2]] - coordsInitial[2,0:3] = [+size[0]/grid[0],+size[1]/grid[1],-size[2]/grid[2]] - coordsInitial[3,0:3] = [-size[0]/grid[0],+size[1]/grid[1],-size[2]/grid[2]] - coordsInitial[4,0:3] = [-size[0]/grid[0],-size[1]/grid[1],+size[2]/grid[2]] - coordsInitial[5,0:3] = [+size[0]/grid[0],-size[1]/grid[1],+size[2]/grid[2]] - coordsInitial[6,0:3] = [+size[0]/grid[0],+size[1]/grid[1],+size[2]/grid[2]] - coordsInitial[7,0:3] = [-size[0]/grid[0],+size[1]/grid[1],+size[2]/grid[2]] - coordsInitial = coordsInitial/2.0 + delta = size/grid*.5 + coordsInitial = np.vstack((delta * np.array((-1,-1,-1)), + delta * np.array((+1,-1,-1)), + delta * np.array((+1,+1,-1)), + delta * np.array((-1,+1,-1)), + delta * np.array((-1,-1,+1)), + delta * np.array((+1,-1,+1)), + delta * np.array((+1,+1,+1)), + delta * np.array((-1,+1,+1)))) #-------------------------------------------------------------------------------------------------- # compare deformed original and deformed positions to actual positions From 93db1b37cacc4ccf6b0ac3d3fbaa7660f19d76c5 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 22:26:29 +0200 Subject: [PATCH 097/186] some useful information --- python/damask/grid_filters.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/python/damask/grid_filters.py b/python/damask/grid_filters.py index 2ee99d276..3925c8db3 100644 --- a/python/damask/grid_filters.py +++ b/python/damask/grid_filters.py @@ -1,3 +1,17 @@ +""" +Filters for operations on regular grids. + +Notes +----- +The grids are defined as (x,y,z,...) where x is fastest and z is slowest. +This convention is consistent with the geom file format. +When converting to/from a plain list (e.g. storage in ASCII table), +the following operations are required for tensorial: + +D3 = D1.reshape(grid+(-1,),order='F').reshape(grid+(3,3)) +D1 = D3.reshape(grid+(-1,)).reshape(-1,9,order='F') + +""" from scipy import spatial as _spatial import numpy as _np From 00cb17ccfaf867a6f7e4f321a7153f89eec34098 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 22:47:19 +0200 Subject: [PATCH 098/186] commenting --- python/damask/grid_filters.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/python/damask/grid_filters.py b/python/damask/grid_filters.py index 3925c8db3..f74bc92ac 100644 --- a/python/damask/grid_filters.py +++ b/python/damask/grid_filters.py @@ -6,7 +6,7 @@ Notes The grids are defined as (x,y,z,...) where x is fastest and z is slowest. This convention is consistent with the geom file format. When converting to/from a plain list (e.g. storage in ASCII table), -the following operations are required for tensorial: +the following operations are required for tensorial data: D3 = D1.reshape(grid+(-1,),order='F').reshape(grid+(3,3)) D1 = D3.reshape(grid+(-1,)).reshape(-1,9,order='F') @@ -23,6 +23,10 @@ def _ks(size,grid,first_order=False): ---------- size : numpy.ndarray of shape (3) physical size of the periodic field. + grid : numpy.ndarray of shape (3) + number of grid points. + first_order : bool, optional + correction for first order derivatives, defaults to False. """ k_sk = _np.where(_np.arange(grid[0])>grid[0]//2,_np.arange(grid[0])-grid[0],_np.arange(grid[0]))/size[0] @@ -44,6 +48,8 @@ def curl(size,field): ---------- size : numpy.ndarray of shape (3) physical size of the periodic field. + field : numpy.ndarray of shape (:,:,:,3) or (:,:,:,3,3) + periodic field of which the curl is calculated. """ n = _np.prod(field.shape[3:]) @@ -68,6 +74,8 @@ def divergence(size,field): ---------- size : numpy.ndarray of shape (3) physical size of the periodic field. + field : numpy.ndarray of shape (:,:,:,3) or (:,:,:,3,3) + periodic field of which the divergence is calculated. """ n = _np.prod(field.shape[3:]) @@ -82,12 +90,14 @@ def divergence(size,field): def gradient(size,field): """ - Calculate gradient of a vector or scalar field in Fourier space. + Calculate gradient of a scalar or tensor field in Fourier space. Parameters ---------- size : numpy.ndarray of shape (3) physical size of the periodic field. + field : numpy.ndarray of shape (:,:,:,1) or (:,:,:,3) + periodic field of which the gradient is calculated. """ n = _np.prod(field.shape[3:]) @@ -394,9 +404,9 @@ def regrid(size,F,new_grid): ---------- size : numpy.ndarray of shape (3) physical size - F : numpy.ndarray + F : numpy.ndarray of shape (:,:,:,3,3) deformation gradient field - new_grid : numpy.ndarray + new_grid : numpy.ndarray of shape (3) new grid for undeformed coordinates """ From 528378eba22536d7b377db1de9f47d68923f51ce Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 22:51:51 +0200 Subject: [PATCH 099/186] polishing/bugfix * HDF5 data has x fast, therefore reshape needs to be aware of 'F' order * Datatype for True/False is 'bool' in python, not 'Boolean' --- python/damask/_result.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/python/damask/_result.py b/python/damask/_result.py index ee7d696a9..65ac7a01b 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -105,7 +105,7 @@ class Result: select from 'set', 'add', and 'del' what : str attribute to change (must be from self.selection) - datasets : list of str or Boolean + datasets : list of str or bool name of datasets as list, supports ? and * wildcards. True is equivalent to [*], False is equivalent to [] @@ -197,7 +197,7 @@ class Result: ---------- what : str attribute to change (must be from self.selection) - datasets : list of str or Boolean + datasets : list of str or bool name of datasets as list, supports ? and * wildcards. True is equivalent to [*], False is equivalent to [] @@ -213,7 +213,7 @@ class Result: ---------- what : str attribute to change (must be from self.selection) - datasets : list of str or Boolean + datasets : list of str or bool name of datasets as list, supports ? and * wildcards. True is equivalent to [*], False is equivalent to [] @@ -229,7 +229,7 @@ class Result: ---------- what : str attribute to change (must be from self.selection) - datasets : list of str or Boolean + datasets : list of str or bool name of datasets as list, supports ? and * wildcards. True is equivalent to [*], False is equivalent to [] @@ -256,10 +256,10 @@ class Result: datasets : iterable or str component : int homogenization component to consider for constituent data - tagged : Boolean + tagged : bool tag Table.column name with '#component' defaults to False - split : Boolean + split : bool split Table by increment and return dictionary of Tables defaults to True @@ -320,7 +320,7 @@ class Result: Parameters ---------- - datasets : iterable or str or Boolean + datasets : iterable or str or bool Examples -------- @@ -454,7 +454,7 @@ class Result: def cell_coordinates(self): """Return initial coordinates of the cell centers.""" if self.structured: - return grid_filters.cell_coord0(self.grid,self.size,self.origin).reshape(-1,3) + return grid_filters.cell_coord0(self.grid,self.size,self.origin).reshape(-1,3,order='F') else: with h5py.File(self.fname,'r') as f: return f['geometry/x_c'][()] From 7084fc9616d5833fc554faf471c2d2d3bb3754d4 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 20 Apr 2020 23:19:38 +0200 Subject: [PATCH 100/186] adjusting to consistent data layout --- processing/post/blowUp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/processing/post/blowUp.py b/processing/post/blowUp.py index 316b74753..23c6b2ef2 100755 --- a/processing/post/blowUp.py +++ b/processing/post/blowUp.py @@ -59,13 +59,13 @@ for name in filenames: packing = np.array(options.packing,'i') outSize = grid*packing - data = table.data.values.reshape(tuple(grid)+(-1,)) - blownUp = ndimage.interpolation.zoom(data,tuple(packing)+(1,),order=0,mode='nearest').reshape(outSize.prod(),-1) + data = table.data.values.reshape(tuple(grid)+(-1,),order='F') + blownUp = ndimage.interpolation.zoom(data,tuple(packing)+(1,),order=0,mode='nearest').reshape(outSize.prod(),-1,order='F') table = damask.Table(blownUp,table.shapes,table.comments) coords = damask.grid_filters.cell_coord0(outSize,size,origin) - table.set(options.pos,coords.reshape(-1,3)) + table.set(options.pos,coords.reshape(-1,3,order='F')) table.set('elem',np.arange(1,outSize.prod()+1)) outname = os.path.join(os.path.dirname(name),prefix+os.path.basename(name)) From 4a05cdbbbb0b6fa977ecf083c6ca8c0bddff1e93 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 21 Apr 2020 03:26:26 +0200 Subject: [PATCH 101/186] copy and paste error --- python/damask/grid_filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/grid_filters.py b/python/damask/grid_filters.py index f74bc92ac..eaee42924 100644 --- a/python/damask/grid_filters.py +++ b/python/damask/grid_filters.py @@ -90,7 +90,7 @@ def divergence(size,field): def gradient(size,field): """ - Calculate gradient of a scalar or tensor field in Fourier space. + Calculate gradient of a scalar or vector field in Fourier space. Parameters ---------- From 23fc58699f28468baacb057e6f1a393cd88aea7b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 15 Apr 2020 23:00:00 +0200 Subject: [PATCH 102/186] vectorize Rotation.fromXXX functions --- python/.coveragerc | 3 + python/damask/_rotation.py | 172 ++++++++++++++++++---------------- python/damask/mechanics.py | 12 +-- python/tests/test_Rotation.py | 13 +++ 4 files changed, 114 insertions(+), 86 deletions(-) diff --git a/python/.coveragerc b/python/.coveragerc index c712d2595..5daa25bb2 100644 --- a/python/.coveragerc +++ b/python/.coveragerc @@ -1,2 +1,5 @@ [run] omit = tests/* + damask/_asciitable.py + damask/_test.py + damask/config/* diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index dcd61822f..8a2441012 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -1,6 +1,7 @@ import numpy as np from ._Lambert import ball_to_cube, cube_to_ball +from . import mechanics _P = -1 @@ -61,6 +62,8 @@ class Rotation: def __repr__(self): """Orientation displayed as unit quaternion, rotation matrix, and Bunge-Euler angles.""" + if self.quaternion.shape != (4,): + raise NotImplementedError return '\n'.join([ 'Quaternion: (real={:.3f}, imag=<{:+.3f}, {:+.3f}, {:+.3f}>)'.format(*(self.quaternion)), 'Matrix:\n{}'.format(self.asMatrix()), @@ -116,7 +119,7 @@ class Rotation: def inverse(self): """In-place inverse rotation/backward rotation.""" - self.quaternion[1:] *= -1 + self.quaternion[...,1:] *= -1 return self def inversed(self): @@ -125,12 +128,12 @@ class Rotation: def standardize(self): - """In-place quaternion representation with positive q.""" - if self.quaternion[0] < 0.0: self.quaternion*=-1 + """In-place quaternion representation with positive real part.""" + self.quaternion[self.quaternion[...,0] < 0.0] *= -1 return self def standardized(self): - """Quaternion representation with positive q.""" + """Quaternion representation with positive real.""" return self.copy().standardize() @@ -165,7 +168,7 @@ class Rotation: def asQuaternion(self): """ - Unit quaternion [q, p_1, p_2, p_3] unless quaternion == True: damask.quaternion object. + Unit quaternion [q, p_1, p_2, p_3]. Parameters ---------- @@ -251,107 +254,106 @@ class Rotation: # static constructors. The input data needs to follow the convention, options allow to # relax these convections @staticmethod - def fromQuaternion(quaternion, - acceptHomomorph = False, - P = -1): + def from_quaternion(quaternion, + acceptHomomorph = False, + P = -1): - qu = quaternion if isinstance(quaternion,np.ndarray) and quaternion.dtype == np.dtype(float) \ - else np.array(quaternion,dtype=float) - if P > 0: qu[1:4] *= -1 # convert from P=1 to P=-1 - if qu[0] < 0.0: - if acceptHomomorph: - qu *= -1. - else: - raise ValueError('Quaternion has negative first component: {}.'.format(qu[0])) - if not np.isclose(np.linalg.norm(qu), 1.0): - raise ValueError('Quaternion is not of unit length: {} {} {} {}.'.format(*qu)) + qu = np.array(quaternion,dtype=float) + + if P > 0: qu[...,1:4] *= -1 # convert from P=1 to P=-1 + if acceptHomomorph: + qu[qu[...,0] < 0.0] *= -1 + else: + if np.any(qu[...,0] < 0.0): + raise ValueError('Quaternions need to have positive first(real) component.') + if not np.all(np.isclose(np.linalg.norm(qu,axis=-1), 1.0)): + raise ValueError('Quaternions need to have unit length.') return Rotation(qu) @staticmethod - def fromEulers(eulers, - degrees = False): + def from_Eulers(eulers, + degrees = False): + + eu = np.array(eulers,dtype=float) - eu = eulers if isinstance(eulers, np.ndarray) and eulers.dtype == np.dtype(float) \ - else np.array(eulers,dtype=float) eu = np.radians(eu) if degrees else eu - if np.any(eu < 0.0) or np.any(eu > 2.0*np.pi) or eu[1] > np.pi: - raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π]: {} {} {}.'.format(*eu)) + if np.any(eu < 0.0) or np.any(eu > 2.0*np.pi) or np.any(eu[...,1] > np.pi): # ToDo: No separate check for PHI + raise ValueError('Euler angles need to be in [0..2π],[0..π],[0..2π].') return Rotation(Rotation.eu2qu(eu)) @staticmethod - def fromAxisAngle(angleAxis, - degrees = False, - normalise = False, - P = -1): + def from_axis_angle(axis_angle, + degrees = False, + normalise = False, + P = -1): - ax = angleAxis if isinstance(angleAxis, np.ndarray) and angleAxis.dtype == np.dtype(float) \ - else np.array(angleAxis,dtype=float) - if P > 0: ax[0:3] *= -1 # convert from P=1 to P=-1 - if degrees: ax[ 3] = np.radians(ax[3]) - if normalise: ax[0:3] /= np.linalg.norm(ax[0:3]) - if ax[3] < 0.0 or ax[3] > np.pi: - raise ValueError('Axis angle rotation angle outside of [0..π]: {}.'.format(ax[3])) - if not np.isclose(np.linalg.norm(ax[0:3]), 1.0): - raise ValueError('Axis angle rotation axis is not of unit length: {} {} {}.'.format(*ax[0:3])) + ax = np.array(axis_angle,dtype=float) + + if P > 0: ax[...,0:3] *= -1 # convert from P=1 to P=-1 + if degrees: ax[..., 3] = np.radians(ax[...,3]) + if normalise: ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1) + if np.any(ax[...,3] < 0.0) or np.any(ax[...,3] > np.pi): + raise ValueError('Axis angle rotation angle outside of [0..π].') + if not np.all(np.isclose(np.linalg.norm(ax[...,0:3],axis=-1), 1.0)): + raise ValueError('Axis angle rotation axis is not of unit length.') return Rotation(Rotation.ax2qu(ax)) @staticmethod - def fromBasis(basis, - orthonormal = True, - reciprocal = False, - ): + def from_basis(basis, + orthonormal = True, + reciprocal = False): + + om = np.array(basis,dtype=float) - om = basis if isinstance(basis, np.ndarray) else np.array(basis).reshape(3,3) if reciprocal: - om = np.linalg.inv(om.T/np.pi) # transform reciprocal basis set + om = np.linalg.inv(mechanics.transpose(om)/np.pi) # transform reciprocal basis set orthonormal = False # contains stretch if not orthonormal: (U,S,Vh) = np.linalg.svd(om) # singular value decomposition - om = np.dot(U,Vh) - if not np.isclose(np.linalg.det(om),1.0): + om = np.einsum('...ij,...jl->...il',U,Vh) + if not np.all(np.isclose(np.linalg.det(om),1.0)): raise ValueError('matrix is not a proper rotation: {}.'.format(om)) - if not np.isclose(np.dot(om[0],om[1]), 0.0) \ - or not np.isclose(np.dot(om[1],om[2]), 0.0) \ - or not np.isclose(np.dot(om[2],om[0]), 0.0): - raise ValueError('matrix is not orthogonal: {}.'.format(om)) + if not np.all(np.isclose(np.einsum('...i,...i',om[...,0],om[...,1]), 0.0)) \ + or not np.all(np.isclose(np.einsum('...i,...i',om[...,1],om[...,2]), 0.0)) \ + or not np.all(np.isclose(np.einsum('...i,...i',om[...,2],om[...,0]), 0.0)): + raise ValueError('matrix is not orthogonal.') return Rotation(Rotation.om2qu(om)) @staticmethod - def fromMatrix(om, - ): + def from_matrix(om): - return Rotation.fromBasis(om) + return Rotation.from_basis(om) @staticmethod - def fromRodrigues(rodrigues, - normalise = False, - P = -1): + def from_Rodrigues(rodrigues, + normalise = False, + P = -1): - ro = rodrigues if isinstance(rodrigues, np.ndarray) and rodrigues.dtype == np.dtype(float) \ - else np.array(rodrigues,dtype=float) - if P > 0: ro[0:3] *= -1 # convert from P=1 to P=-1 - if normalise: ro[0:3] /= np.linalg.norm(ro[0:3]) - if not np.isclose(np.linalg.norm(ro[0:3]), 1.0): - raise ValueError('Rodrigues rotation axis is not of unit length: {} {} {}.'.format(*ro[0:3])) - if ro[3] < 0.0: - raise ValueError('Rodrigues rotation angle not positive: {}.'.format(ro[3])) + ro = np.array(rodrigues,dtype=float) + + if P > 0: ro[...,0:3] *= -1 # convert from P=1 to P=-1 + if normalise: ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1) + if np.any(ro[...,3] < 0.0): + raise ValueError('Rodrigues rotation angle not positive.') + if not np.all(np.isclose(np.linalg.norm(ro[...,0:3],axis=-1), 1.0)): + raise ValueError('Rodrigues rotation axis is not of unit length.') return Rotation(Rotation.ro2qu(ro)) @staticmethod - def fromHomochoric(homochoric, - P = -1): + def from_homochoric(homochoric, + P = -1): + + ho = np.array(homochoric,dtype=float) - ho = homochoric if isinstance(homochoric, np.ndarray) and homochoric.dtype == np.dtype(float) \ - else np.array(homochoric,dtype=float) if P > 0: ho *= -1 # convert from P=1 to P=-1 - if np.linalg.norm(ho) > (3.*np.pi/4.)**(1./3.)+1e-9: - raise ValueError('Coordinate outside of the sphere: {} {} {}.'.format(ho)) + if np.any(np.linalg.norm(ho,axis=-1) > (3.*np.pi/4.)**(1./3.)+1e-9): + raise ValueError('Coordinate outside of the sphere.') return Rotation(Rotation.ho2qu(ho)) @@ -359,8 +361,7 @@ class Rotation: def fromCubochoric(cubochoric, P = -1): - cu = cubochoric if isinstance(cubochoric, np.ndarray) and cubochoric.dtype == np.dtype(float) \ - else np.array(cubochoric,dtype=float) + cu = np.array(cubochoric,dtype=float) if np.abs(np.max(cu))>np.pi**(2./3.) * 0.5+1e-9: raise ValueError('Coordinate outside of the cube: {} {} {}.'.format(*cu)) @@ -403,17 +404,28 @@ class Rotation: return Rotation.fromQuaternion(np.real(vec.T[eig.argmax()]),acceptHomomorph = True) - @staticmethod - def fromRandom(): - r = np.random.random(3) - A = np.sqrt(r[2]) - B = np.sqrt(1.0-r[2]) - return Rotation(np.array([np.cos(2.0*np.pi*r[0])*A, - np.sin(2.0*np.pi*r[1])*B, - np.cos(2.0*np.pi*r[1])*B, - np.sin(2.0*np.pi*r[0])*A])).standardize() + def from_random(shape=None): + if shape is None: + r = np.random.random(3) + else: + r = np.random.random(tuple(shape)+(3,)) + A = np.sqrt(r[...,2]) + B = np.sqrt(1.0-r[...,2]) + return Rotation(np.block([np.cos(2.0*np.pi*r[...,0])*A, + np.sin(2.0*np.pi*r[...,1])*B, + np.cos(2.0*np.pi*r[...,1])*B, + np.sin(2.0*np.pi*r[...,0])*A])).standardize() + # for compatibility (old names do not follow convention) + fromQuaternion = from_quaternion + fromEulers = from_Eulers + fromAxisAngle = from_axis_angle + fromBasis = from_basis + fromMatrix = from_matrix + fromRodrigues = from_Rodrigues + fromHomochoric = from_homochoric + fromRandom = from_random #################################################################################################### # Code below available according to the following conditions on https://github.com/MarDiehl/3Drotations diff --git a/python/damask/mechanics.py b/python/damask/mechanics.py index 674ff9c5a..8d19e9b85 100644 --- a/python/damask/mechanics.py +++ b/python/damask/mechanics.py @@ -135,16 +135,16 @@ def PK2(P,F): Parameters ---------- - P : numpy.ndarray of shape (:,3,3) or (3,3) + P : numpy.ndarray of shape (...,3,3) or (3,3) First Piola-Kirchhoff stress. - F : numpy.ndarray of shape (:,3,3) or (3,3) + F : numpy.ndarray of shape (...,3,3) or (3,3) Deformation gradient. """ if np.shape(F) == np.shape(P) == (3,3): S = np.dot(np.linalg.inv(F),P) else: - S = np.einsum('ijk,ikl->ijl',np.linalg.inv(F),P) + S = np.einsum('...jk,...kl->...jl',np.linalg.inv(F),P) return symmetric(S) @@ -241,7 +241,7 @@ def symmetric(T): Parameters ---------- - T : numpy.ndarray of shape (:,3,3) or (3,3) + T : numpy.ndarray of shape (...,3,3) or (3,3) Tensor of which the symmetrized values are computed. """ @@ -254,12 +254,12 @@ def transpose(T): Parameters ---------- - T : numpy.ndarray of shape (:,3,3) or (3,3) + T : numpy.ndarray of shape (...,3,3) or (3,3) Tensor of which the transpose is computed. """ return T.T if np.shape(T) == (3,3) else \ - np.transpose(T,(0,2,1)) + np.swapaxes(T,axis2=-2,axis1=-1) def _polar_decomposition(T,requested): diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 2ac819f4c..8150e35f8 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -157,6 +157,19 @@ class TestRotation: print(m,o,rot.asQuaternion()) assert ok and o.max() < np.pi**(2./3.)*0.5+1.e-9 + @pytest.mark.parametrize('function,invalid',[(Rotation.from_quaternion, np.array([-1,0,0,0])), + (Rotation.from_quaternion, np.array([1,1,1,0])), + (Rotation.from_Eulers, np.array([1,4,0])), + (Rotation.from_axis_angle, np.array([1,0,0,4])), + (Rotation.from_axis_angle, np.array([1,1,0,1])), + (Rotation.from_matrix, np.random.rand(3,3)), + (Rotation.from_Rodrigues, np.array([1,0,0,-1])), + (Rotation.from_Rodrigues, np.array([1,1,0,1])), + (Rotation.from_homochoric, np.array([2,2,2])) ]) + def test_invalid(self,function,invalid): + with pytest.raises(ValueError): + function(invalid) + @pytest.mark.parametrize('conversion',[Rotation.qu2om, Rotation.qu2eu, Rotation.qu2ax, From ac75b9e4cac2d10f04a80f9a63c9d4799e4fbf1f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 21 Apr 2020 11:17:15 +0200 Subject: [PATCH 103/186] improved reporting + test --- python/damask/_result.py | 18 ++++++++++++------ python/tests/test_Result.py | 4 ++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/python/damask/_result.py b/python/damask/_result.py index ee7d696a9..0d84847fb 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -68,12 +68,12 @@ class Result: self.con_physics = [] for c in self.constituents: self.con_physics += f['/'.join([self.increments[0],'constituent',c])].keys() - self.con_physics = list(set(self.con_physics)) # make unique + self.con_physics = list(set(self.con_physics)) # make unique self.mat_physics = [] for m in self.materialpoints: self.mat_physics += f['/'.join([self.increments[0],'materialpoint',m])].keys() - self.mat_physics = list(set(self.mat_physics)) # make unique + self.mat_physics = list(set(self.mat_physics)) # make unique self.selection = {'increments': self.increments, 'constituents': self.constituents,'materialpoints': self.materialpoints, @@ -86,13 +86,19 @@ class Result: def __repr__(self): """Show selected data.""" all_selected_increments = self.selection['increments'] + self.pick('increments',all_selected_increments[0:1]) first = self.list_data() + self.pick('increments',all_selected_increments[-1:]) - last = self.list_data() + last = '' if len(all_selected_increments) < 2 else self.list_data() + self.pick('increments',all_selected_increments) - in_between = ''.join(['\n{}\n ...\n'.format(inc) for inc in all_selected_increments[1:-2]]) - return util.srepr(first+ in_between + last) + + in_between = '' if len(all_selected_increments) < 3 else \ + ''.join(['\n{}\n ...\n'.format(inc) for inc in all_selected_increments[1:-2]]) + + return util.srepr(first + in_between + last) def _manage_selection(self,action,what,datasets): @@ -1009,7 +1015,7 @@ class Result: continue lock.acquire() with h5py.File(self.fname, 'a') as f: - try: + try: # ToDo: Replace if exists? dataset = f[result[0]].create_dataset(result[1]['label'],data=result[1]['data']) for l,v in result[1]['meta'].items(): dataset.attrs[l]=v.encode() diff --git a/python/tests/test_Result.py b/python/tests/test_Result.py index a90430096..c117f33f7 100644 --- a/python/tests/test_Result.py +++ b/python/tests/test_Result.py @@ -24,6 +24,10 @@ def reference_dir(reference_dir_base): class TestResult: + def test_self_report(self,default): + print(default) + + def test_time_increments(self,default): shape = default.read_dataset(default.get_dataset_location('F'),0).shape default.set_by_time(0.0,20.0) From ae3eca5f98a21c745c3dc3ba780517a5848c8bdc Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 21 Apr 2020 11:59:42 +0200 Subject: [PATCH 104/186] fix for vectorized from_random --- python/damask/_rotation.py | 45 ++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 8a2441012..69a725e99 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -265,9 +265,9 @@ class Rotation: qu[qu[...,0] < 0.0] *= -1 else: if np.any(qu[...,0] < 0.0): - raise ValueError('Quaternions need to have positive first(real) component.') + raise ValueError('Quaternion with negative first (real) component.') if not np.all(np.isclose(np.linalg.norm(qu,axis=-1), 1.0)): - raise ValueError('Quaternions need to have unit length.') + raise ValueError('Quaternion is not of unit length.') return Rotation(qu) @@ -279,7 +279,7 @@ class Rotation: eu = np.radians(eu) if degrees else eu if np.any(eu < 0.0) or np.any(eu > 2.0*np.pi) or np.any(eu[...,1] > np.pi): # ToDo: No separate check for PHI - raise ValueError('Euler angles need to be in [0..2π],[0..π],[0..2π].') + raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π].') return Rotation(Rotation.eu2qu(eu)) @@ -315,11 +315,11 @@ class Rotation: (U,S,Vh) = np.linalg.svd(om) # singular value decomposition om = np.einsum('...ij,...jl->...il',U,Vh) if not np.all(np.isclose(np.linalg.det(om),1.0)): - raise ValueError('matrix is not a proper rotation: {}.'.format(om)) + raise ValueError('Orientation matrix has determinant ≠ 1.') if not np.all(np.isclose(np.einsum('...i,...i',om[...,0],om[...,1]), 0.0)) \ or not np.all(np.isclose(np.einsum('...i,...i',om[...,1],om[...,2]), 0.0)) \ or not np.all(np.isclose(np.einsum('...i,...i',om[...,2],om[...,0]), 0.0)): - raise ValueError('matrix is not orthogonal.') + raise ValueError('Orientation matrix is not orthogonal.') return Rotation(Rotation.om2qu(om)) @@ -338,9 +338,9 @@ class Rotation: if P > 0: ro[...,0:3] *= -1 # convert from P=1 to P=-1 if normalise: ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1) if np.any(ro[...,3] < 0.0): - raise ValueError('Rodrigues rotation angle not positive.') + raise ValueError('Rodrigues vector rotation angle not positive.') if not np.all(np.isclose(np.linalg.norm(ro[...,0:3],axis=-1), 1.0)): - raise ValueError('Rodrigues rotation axis is not of unit length.') + raise ValueError('Rodrigues vector rotation axis is not of unit length.') return Rotation(Rotation.ro2qu(ro)) @@ -353,7 +353,7 @@ class Rotation: if P > 0: ho *= -1 # convert from P=1 to P=-1 if np.any(np.linalg.norm(ho,axis=-1) > (3.*np.pi/4.)**(1./3.)+1e-9): - raise ValueError('Coordinate outside of the sphere.') + raise ValueError('Homochoric coordinate outside of the sphere.') return Rotation(Rotation.ho2qu(ho)) @@ -364,7 +364,7 @@ class Rotation: cu = np.array(cubochoric,dtype=float) if np.abs(np.max(cu))>np.pi**(2./3.) * 0.5+1e-9: - raise ValueError('Coordinate outside of the cube: {} {} {}.'.format(*cu)) + raise ValueError('Cubochoric coordinate outside of the cube: {} {} {}.'.format(*cu)) ho = Rotation.cu2ho(cu) if P > 0: ho *= -1 # convert from P=1 to P=-1 @@ -408,14 +408,20 @@ class Rotation: def from_random(shape=None): if shape is None: r = np.random.random(3) - else: + elif hasattr(shape, '__iter__'): r = np.random.random(tuple(shape)+(3,)) + else: + r = np.random.random((shape,3)) + A = np.sqrt(r[...,2]) B = np.sqrt(1.0-r[...,2]) - return Rotation(np.block([np.cos(2.0*np.pi*r[...,0])*A, - np.sin(2.0*np.pi*r[...,1])*B, - np.cos(2.0*np.pi*r[...,1])*B, - np.sin(2.0*np.pi*r[...,0])*A])).standardize() + q = np.stack([np.cos(2.0*np.pi*r[...,0])*A, + np.sin(2.0*np.pi*r[...,1])*B, + np.cos(2.0*np.pi*r[...,1])*B, + np.sin(2.0*np.pi*r[...,0])*A],axis=-1) + + return Rotation(q.reshape(r.shape[:-1]+(4,)) if shape is not None else q).standardize() + # for compatibility (old names do not follow convention) fromQuaternion = from_quaternion @@ -820,12 +826,11 @@ class Rotation: c = np.cos(ax[3]*0.5) s = np.sin(ax[3]*0.5) qu = np.array([ c, ax[0]*s, ax[1]*s, ax[2]*s ]) - return qu else: c = np.cos(ax[...,3:4]*.5) s = np.sin(ax[...,3:4]*.5) qu = np.where(np.abs(ax[...,3:4])<1.e-6,[1.0, 0.0, 0.0, 0.0],np.block([c, ax[...,:3]*s])) - return qu + return qu @staticmethod def ax2om(ax): @@ -871,7 +876,7 @@ class Rotation: # 180 degree case ro += [np.inf] if np.isclose(ax[3],np.pi,atol=1.0e-15,rtol=0.0) else \ [np.tan(ax[3]*0.5)] - return np.array(ro) + ro = np.array(ro) else: ro = np.block([ax[...,:3], np.where(np.isclose(ax[...,3:4],np.pi,atol=1.e-15,rtol=.0), @@ -879,7 +884,7 @@ class Rotation: np.tan(ax[...,3:4]*0.5)) ]) ro[np.abs(ax[...,3])<1.e-6] = [.0,.0,_P,.0] - return ro + return ro @staticmethod def ax2ho(ax): @@ -887,11 +892,10 @@ class Rotation: if len(ax.shape) == 1: f = (0.75 * ( ax[3] - np.sin(ax[3]) ))**(1.0/3.0) ho = ax[0:3] * f - return ho else: f = (0.75 * ( ax[...,3:4] - np.sin(ax[...,3:4]) ))**(1.0/3.0) ho = ax[...,:3] * f - return ho + return ho @staticmethod def ax2cu(ax): @@ -948,7 +952,6 @@ class Rotation: f = np.where(np.isfinite(ro[...,3:4]),2.0*np.arctan(ro[...,3:4]) -np.sin(2.0*np.arctan(ro[...,3:4])),np.pi) ho = np.where(np.broadcast_to(np.sum(ro[...,0:3]**2.0,axis=-1,keepdims=True) < 1.e-6,ro[...,0:3].shape), np.zeros(3), ro[...,0:3]* (0.75*f)**(1.0/3.0)) - return ho @staticmethod From 75d723837650bdb89b68b5eddfd1b41e583303e9 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 21 Apr 2020 12:27:50 +0200 Subject: [PATCH 105/186] vectorized as_XXX --- python/damask/_rotation.py | 42 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 69a725e99..b9be2a606 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -166,7 +166,7 @@ class Rotation: ################################################################################################ # convert to different orientation representations (numpy arrays) - def asQuaternion(self): + def as_quaternion(self): """ Unit quaternion [q, p_1, p_2, p_3]. @@ -178,8 +178,8 @@ class Rotation: """ return self.quaternion - def asEulers(self, - degrees = False): + def as_Eulers(self, + degrees = False): """ Bunge-Euler angles: (φ_1, ϕ, φ_2). @@ -193,9 +193,9 @@ class Rotation: if degrees: eu = np.degrees(eu) return eu - def asAxisAngle(self, - degrees = False, - pair = False): + def as_axis_angle(self, + degrees = False, + pair = False): """ Axis angle representation [n_1, n_2, n_3, ω] unless pair == True: ([n_1, n_2, n_3], ω). @@ -208,15 +208,15 @@ class Rotation: """ ax = Rotation.qu2ax(self.quaternion) - if degrees: ax[3] = np.degrees(ax[3]) - return (ax[:3],np.degrees(ax[3])) if pair else ax + if degrees: ax[...,3] = np.degrees(ax[...,3]) + return (ax[...,:3],ax[...,3]) if pair else ax - def asMatrix(self): + def as_matrix(self): """Rotation matrix.""" return Rotation.qu2om(self.quaternion) - def asRodrigues(self, - vector = False): + def as_Rodrigues(self, + vector = False): """ Rodrigues-Frank vector representation [n_1, n_2, n_3, tan(ω/2)] unless vector == True: [n_1, n_2, n_3] * tan(ω/2). @@ -227,9 +227,9 @@ class Rotation: """ ro = Rotation.qu2ro(self.quaternion) - return ro[:3]*ro[3] if vector else ro + return ro[...,:3]*ro[...,3] if vector else ro - def asHomochoric(self): + def as_homochoric(self): """Homochoric vector: (h_1, h_2, h_3).""" return Rotation.qu2ho(self.quaternion) @@ -237,7 +237,7 @@ class Rotation: """Cubochoric vector: (c_1, c_2, c_3).""" return Rotation.qu2cu(self.quaternion) - def asM(self): + def M(self): # ToDo not sure about the name: as_M or M? we do not have a from_M """ Intermediate representation supporting quaternion averaging. @@ -247,12 +247,20 @@ class Rotation: https://doi.org/10.2514/1.28949 """ - return np.outer(self.quaternion,self.quaternion) + return np.einsum('...i,...j',self.quaternion,self.quaternion) + # for compatibility (old names do not follow convention) + asM = M + asQuaternion = as_quaternion + asEulers = as_Eulers + asAxisAngle = as_axis_angle + asMatrix = as_matrix + asRodrigues = as_Rodrigues + asHomochoric = as_homochoric ################################################################################################ - # static constructors. The input data needs to follow the convention, options allow to - # relax these convections + # Static constructors. The input data needs to follow the conventions, options allow to + # relax the conventions. @staticmethod def from_quaternion(quaternion, acceptHomomorph = False, From b1be4e7ac80a122cde6df4f69970374f180679aa Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 21 Apr 2020 13:22:24 +0200 Subject: [PATCH 106/186] rotation class does not take care of correct shape anymore --- processing/post/addOrientations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/processing/post/addOrientations.py b/processing/post/addOrientations.py index 137b8121e..e1752b0a4 100755 --- a/processing/post/addOrientations.py +++ b/processing/post/addOrientations.py @@ -172,7 +172,7 @@ for name in filenames: elif inputtype == 'matrix': d = representations['matrix'][1] - o = damask.Rotation.fromMatrix(list(map(float,table.data[column:column+d]))) + o = damask.Rotation.fromMatrix(np.array(list(map(float,table.data[column:column+d]))).reshape(3,3)) elif inputtype == 'frame': M = np.array(list(map(float,table.data[column[0]:column[0]+3] + \ From 97a5880d76311c83e5864f642f24e1d3e51d14cc Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 21 Apr 2020 13:22:55 +0200 Subject: [PATCH 107/186] ensure correct shape --- python/damask/_rotation.py | 14 ++++++++++++++ python/tests/test_Rotation.py | 11 +++++++++++ 2 files changed, 25 insertions(+) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index b9be2a606..6076b4add 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -267,6 +267,8 @@ class Rotation: P = -1): qu = np.array(quaternion,dtype=float) + if qu.shape[:-2:-1] != (4,): + raise ValueError('Invalid shape.') if P > 0: qu[...,1:4] *= -1 # convert from P=1 to P=-1 if acceptHomomorph: @@ -284,6 +286,8 @@ class Rotation: degrees = False): eu = np.array(eulers,dtype=float) + if eu.shape[:-2:-1] != (3,): + raise ValueError('Invalid shape.') eu = np.radians(eu) if degrees else eu if np.any(eu < 0.0) or np.any(eu > 2.0*np.pi) or np.any(eu[...,1] > np.pi): # ToDo: No separate check for PHI @@ -298,6 +302,8 @@ class Rotation: P = -1): ax = np.array(axis_angle,dtype=float) + if ax.shape[:-2:-1] != (4,): + raise ValueError('Invalid shape.') if P > 0: ax[...,0:3] *= -1 # convert from P=1 to P=-1 if degrees: ax[..., 3] = np.radians(ax[...,3]) @@ -315,6 +321,8 @@ class Rotation: reciprocal = False): om = np.array(basis,dtype=float) + if om.shape[:-3:-1] != (3,3): + raise ValueError('Invalid shape.') if reciprocal: om = np.linalg.inv(mechanics.transpose(om)/np.pi) # transform reciprocal basis set @@ -342,6 +350,8 @@ class Rotation: P = -1): ro = np.array(rodrigues,dtype=float) + if ro.shape[:-2:-1] != (4,): + raise ValueError('Invalid shape.') if P > 0: ro[...,0:3] *= -1 # convert from P=1 to P=-1 if normalise: ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1) @@ -357,6 +367,8 @@ class Rotation: P = -1): ho = np.array(homochoric,dtype=float) + if ho.shape[:-2:-1] != (3,): + raise ValueError('Invalid shape.') if P > 0: ho *= -1 # convert from P=1 to P=-1 @@ -370,6 +382,8 @@ class Rotation: P = -1): cu = np.array(cubochoric,dtype=float) + if cu.shape[:-2:-1] != (3,): + raise ValueError('Invalid shape.') if np.abs(np.max(cu))>np.pi**(2./3.) * 0.5+1e-9: raise ValueError('Cubochoric coordinate outside of the cube: {} {} {}.'.format(*cu)) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 8150e35f8..302e895ee 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -157,6 +157,17 @@ class TestRotation: print(m,o,rot.asQuaternion()) assert ok and o.max() < np.pi**(2./3.)*0.5+1.e-9 + @pytest.mark.parametrize('function',[Rotation.from_quaternion, + Rotation.from_Eulers, + Rotation.from_axis_angle, + Rotation.from_matrix, + Rotation.from_Rodrigues, + Rotation.from_homochoric]) + def test_invalid_shape(self,function): + invalid_shape = np.random.random(np.random.randint(8,32,(3))) + with pytest.raises(ValueError): + function(invalid_shape) + @pytest.mark.parametrize('function,invalid',[(Rotation.from_quaternion, np.array([-1,0,0,0])), (Rotation.from_quaternion, np.array([1,1,1,0])), (Rotation.from_Eulers, np.array([1,4,0])), From b26bc78a44f42e9507e017c9f1d8aa7cb5a61c74 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 21 Apr 2020 18:49:50 +0200 Subject: [PATCH 108/186] adopting to new grid layout --- processing/post/DADF5_postResults.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/processing/post/DADF5_postResults.py b/processing/post/DADF5_postResults.py index 70c883aeb..2230ba563 100755 --- a/processing/post/DADF5_postResults.py +++ b/processing/post/DADF5_postResults.py @@ -33,7 +33,7 @@ for filename in options.filenames: results = damask.Result(filename) if not results.structured: continue - coords = damask.grid_filters.cell_coord0(results.grid,results.size,results.origin) + coords = damask.grid_filters.cell_coord0(results.grid,results.size,results.origin).reshape(-1,3,order='F') N_digits = int(np.floor(np.log10(int(results.increments[-1][3:]))))+1 N_digits = 5 # hack to keep test intact From 7452ebc727af4d5e71f46036b4d6166aec034fb2 Mon Sep 17 00:00:00 2001 From: Test User Date: Tue, 21 Apr 2020 19:37:07 +0200 Subject: [PATCH 109/186] [skip ci] updated version information after successful test of v2.0.3-2311-gf1afc159 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7be7a7f6c..7cb1691ed 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2303-g2a6132b7 +v2.0.3-2311-gf1afc159 From a8c6fdd9ba903f62bba60251644849757ea7f426 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 22 Apr 2020 07:40:02 +0200 Subject: [PATCH 110/186] for the sake of completeness --- python/damask/_result.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python/damask/_result.py b/python/damask/_result.py index 0d84847fb..a8181b7a1 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -465,6 +465,14 @@ class Result: with h5py.File(self.fname,'r') as f: return f['geometry/x_c'][()] + def node_coordinates(self): + """Return initial coordinates of the cell centers.""" + if self.structured: + return grid_filters.node_coord0(self.grid,self.size,self.origin).reshape(-1,3,order='F') + else: + with h5py.File(self.fname,'r') as f: + return f['geometry/x_n'][()] + @staticmethod def _add_absolute(x): From 53b8c1c89386040aa6222074ef5fb7aa145f38d5 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 22 Apr 2020 08:58:43 +0200 Subject: [PATCH 111/186] simplified --- python/tests/test_mechanics.py | 141 +++++++++++---------------------- 1 file changed, 45 insertions(+), 96 deletions(-) diff --git a/python/tests/test_mechanics.py b/python/tests/test_mechanics.py index 4248254ab..163cac6ed 100644 --- a/python/tests/test_mechanics.py +++ b/python/tests/test_mechanics.py @@ -1,4 +1,6 @@ +import pytest import numpy as np + from damask import mechanics class TestMechanics: @@ -7,127 +9,78 @@ class TestMechanics: c = np.random.randint(n) - def test_vectorize_Cauchy(self): - P = np.random.random((self.n,3,3)) - F = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.Cauchy(P,F)[self.c], - mechanics.Cauchy(P[self.c],F[self.c])) + @pytest.mark.parametrize('function',[mechanics.deviatoric_part, + mechanics.eigenvalues, + mechanics.eigenvectors, + mechanics.deviatoric_part, + mechanics.left_stretch, + mechanics.maximum_shear, + mechanics.Mises_strain, + mechanics.Mises_stress, + mechanics.right_stretch, + mechanics.rotational_part, + mechanics.spherical_part, + mechanics.symmetric, + mechanics.transpose, + ]) + def test_vectorize_1_arg(self,function): + epsilon = np.random.rand(self.n,3,3) + assert np.allclose(function(epsilon)[self.c],function(epsilon[self.c])) - def test_vectorize_deviatoric_part(self): - x = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.deviatoric_part(x)[self.c], - mechanics.deviatoric_part(x[self.c])) - - def test_vectorize_eigenvalues(self): - x = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.eigenvalues(x)[self.c], - mechanics.eigenvalues(x[self.c])) - - def test_vectorize_eigenvectors(self): - x = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.eigenvectors(x)[self.c], - mechanics.eigenvectors(x[self.c])) - - def test_vectorize_left_stretch(self): - x = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.left_stretch(x)[self.c], - mechanics.left_stretch(x[self.c])) - - def test_vectorize_maximum_shear(self): - x = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.maximum_shear(x)[self.c], - mechanics.maximum_shear(x[self.c])) - - def test_vectorize_Mises_strain(self): - epsilon = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.Mises_strain(epsilon)[self.c], - mechanics.Mises_strain(epsilon[self.c])) - - def test_vectorize_Mises_stress(self): - sigma = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.Mises_stress(sigma)[self.c], - mechanics.Mises_stress(sigma[self.c])) - - def test_vectorize_PK2(self): - F = np.random.random((self.n,3,3)) - P = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.PK2(P,F)[self.c], - mechanics.PK2(P[self.c],F[self.c])) - - def test_vectorize_right_stretch(self): - x = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.right_stretch(x)[self.c], - mechanics.right_stretch(x[self.c])) - - def test_vectorize_rotational_part(self): - x = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.rotational_part(x)[self.c], - mechanics.rotational_part(x[self.c])) - - def test_vectorize_spherical_part(self): - x = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.spherical_part(x,True)[self.c], - mechanics.spherical_part(x[self.c],True)) + @pytest.mark.parametrize('function',[mechanics.Cauchy, + mechanics.PK2, + ]) + def test_vectorize_2_arg(self,function): + P = np.random.rand(self.n,3,3) + F = np.random.rand(self.n,3,3) + assert np.allclose(function(P,F)[self.c],function(P[self.c],F[self.c])) def test_vectorize_strain_tensor(self): - F = np.random.random((self.n,3,3)) + F = np.random.rand(self.n,3,3) t = ['V','U'][np.random.randint(0,2)] m = np.random.random()*10. -5.0 assert np.allclose(mechanics.strain_tensor(F,t,m)[self.c], mechanics.strain_tensor(F[self.c],t,m)) - def test_vectorize_symmetric(self): - x = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.symmetric(x)[self.c], - mechanics.symmetric(x[self.c])) - - def test_vectorize_transpose(self): - x = np.random.random((self.n,3,3)) - assert np.allclose(mechanics.transpose(x)[self.c], - mechanics.transpose(x[self.c])) - def test_Cauchy(self): """Ensure Cauchy stress is symmetrized 1. Piola-Kirchhoff stress for no deformation.""" - P = np.random.random((self.n,3,3)) + P = np.random.rand(self.n,3,3) assert np.allclose(mechanics.Cauchy(P,np.broadcast_to(np.eye(3),(self.n,3,3))), mechanics.symmetric(P)) - def test_polar_decomposition(self): """F = RU = VR.""" - F = np.broadcast_to(np.eye(3),[self.n,3,3])*np.random.random((self.n,3,3)) + F = np.broadcast_to(np.eye(3),[self.n,3,3])*np.random.rand(self.n,3,3) R = mechanics.rotational_part(F) V = mechanics.left_stretch(F) U = mechanics.right_stretch(F) assert np.allclose(np.matmul(R,U), np.matmul(V,R)) - def test_PK2(self): """Ensure 2. Piola-Kirchhoff stress is symmetrized 1. Piola-Kirchhoff stress for no deformation.""" - P = np.random.random((self.n,3,3)) + P = np.random.rand(self.n,3,3) assert np.allclose(mechanics.PK2(P,np.broadcast_to(np.eye(3),(self.n,3,3))), mechanics.symmetric(P)) - def test_strain_tensor_no_rotation(self): """Ensure that left and right stretch give same results for no rotation.""" - F = np.broadcast_to(np.eye(3),[self.n,3,3])*np.random.random((self.n,3,3)) + F = np.broadcast_to(np.eye(3),[self.n,3,3])*np.random.rand(self.n,3,3) m = np.random.random()*20.0-10.0 assert np.allclose(mechanics.strain_tensor(F,'U',m), mechanics.strain_tensor(F,'V',m)) def test_strain_tensor_rotation_equivalence(self): """Ensure that left and right strain differ only by a rotation.""" - F = np.broadcast_to(np.eye(3),[self.n,3,3]) + (np.random.random((self.n,3,3))*0.5 - 0.25) + F = np.broadcast_to(np.eye(3),[self.n,3,3]) + (np.random.rand(self.n,3,3)*0.5 - 0.25) m = np.random.random()*5.0-2.5 assert np.allclose(np.linalg.det(mechanics.strain_tensor(F,'U',m)), np.linalg.det(mechanics.strain_tensor(F,'V',m))) def test_strain_tensor_rotation(self): """Ensure that pure rotation results in no strain.""" - F = mechanics.rotational_part(np.random.random((self.n,3,3))) + F = mechanics.rotational_part(np.random.rand(self.n,3,3)) t = ['V','U'][np.random.randint(0,2)] m = np.random.random()*2.0 - 1.0 assert np.allclose(mechanics.strain_tensor(F,t,m), @@ -139,21 +92,20 @@ class TestMechanics: Should be +1, but random F might contain a reflection. """ - x = np.random.random((self.n,3,3)) + x = np.random.rand(self.n,3,3) assert np.allclose(np.abs(np.linalg.det(mechanics.rotational_part(x))), 1.0) - def test_spherical_deviatoric_part(self): """Ensure that full tensor is sum of spherical and deviatoric part.""" - x = np.random.random((self.n,3,3)) + x = np.random.rand(self.n,3,3) sph = mechanics.spherical_part(x,True) assert np.allclose(sph + mechanics.deviatoric_part(x), x) def test_deviatoric_Mises(self): """Ensure that Mises equivalent stress depends only on deviatoric part.""" - x = np.random.random((self.n,3,3)) + x = np.random.rand(self.n,3,3) full = mechanics.Mises_stress(x) dev = mechanics.Mises_stress(mechanics.deviatoric_part(x)) assert np.allclose(full, @@ -161,7 +113,7 @@ class TestMechanics: def test_spherical_mapping(self): """Ensure that mapping to tensor is correct.""" - x = np.random.random((self.n,3,3)) + x = np.random.rand(self.n,3,3) tensor = mechanics.spherical_part(x,True) scalar = mechanics.spherical_part(x) assert np.allclose(np.linalg.det(tensor), @@ -169,35 +121,32 @@ class TestMechanics: def test_spherical_Mises(self): """Ensure that Mises equivalent strrain of spherical strain is 0.""" - x = np.random.random((self.n,3,3)) + x = np.random.rand(self.n,3,3) sph = mechanics.spherical_part(x,True) assert np.allclose(mechanics.Mises_strain(sph), 0.0) def test_symmetric(self): """Ensure that a symmetric tensor is half of the sum of a tensor and its transpose.""" - x = np.random.random((self.n,3,3)) + x = np.random.rand(self.n,3,3) assert np.allclose(mechanics.symmetric(x)*2.0, mechanics.transpose(x)+x) - def test_transpose(self): """Ensure that a symmetric tensor equals its transpose.""" - x = mechanics.symmetric(np.random.random((self.n,3,3))) + x = mechanics.symmetric(np.random.rand(self.n,3,3)) assert np.allclose(mechanics.transpose(x), x) - def test_Mises(self): """Ensure that equivalent stress is 3/2 of equivalent strain.""" - x = np.random.random((self.n,3,3)) + x = np.random.rand(self.n,3,3) assert np.allclose(mechanics.Mises_stress(x)/mechanics.Mises_strain(x), 1.5) - def test_eigenvalues(self): """Ensure that the characteristic polynomial can be solved.""" - A = mechanics.symmetric(np.random.random((self.n,3,3))) + A = mechanics.symmetric(np.random.rand(self.n,3,3)) lambd = mechanics.eigenvalues(A) s = np.random.randint(self.n) for i in range(3): @@ -205,7 +154,7 @@ class TestMechanics: def test_eigenvalues_and_vectors(self): """Ensure that eigenvalues and -vectors are the solution to the characteristic polynomial.""" - A = mechanics.symmetric(np.random.random((self.n,3,3))) + A = mechanics.symmetric(np.random.rand(self.n,3,3)) lambd = mechanics.eigenvalues(A) x = mechanics.eigenvectors(A) s = np.random.randint(self.n) @@ -214,12 +163,12 @@ class TestMechanics: def test_eigenvectors_RHS(self): """Ensure that RHS coordinate system does only change sign of determinant.""" - A = mechanics.symmetric(np.random.random((self.n,3,3))) + A = mechanics.symmetric(np.random.rand(self.n,3,3)) LRHS = np.linalg.det(mechanics.eigenvectors(A,RHS=False)) RHS = np.linalg.det(mechanics.eigenvectors(A,RHS=True)) assert np.allclose(np.abs(LRHS),RHS) def test_spherical_no_shear(self): """Ensure that sherical stress has max shear of 0.0.""" - A = mechanics.spherical_part(mechanics.symmetric(np.random.random((self.n,3,3))),True) + A = mechanics.spherical_part(mechanics.symmetric(np.random.rand(self.n,3,3)),True) assert np.allclose(mechanics.maximum_shear(A),0.0) From 3621dddd66c7022c4e68ad9f9735e2d7b0e73838 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 22 Apr 2020 09:16:53 +0200 Subject: [PATCH 112/186] test deviatoric part for known analytic solution --- python/tests/test_mechanics.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/tests/test_mechanics.py b/python/tests/test_mechanics.py index 163cac6ed..ac2ac419e 100644 --- a/python/tests/test_mechanics.py +++ b/python/tests/test_mechanics.py @@ -49,6 +49,11 @@ class TestMechanics: assert np.allclose(mechanics.Cauchy(P,np.broadcast_to(np.eye(3),(self.n,3,3))), mechanics.symmetric(P)) + def test_deviatoric_part(self): + I_n = np.broadcast_to(np.eye(3),(self.n,3,3)) + r = np.logical_not(I_n)*np.random.rand(self.n,3,3) + assert np.allclose(mechanics.deviatoric_part(I_n+r),r) + def test_polar_decomposition(self): """F = RU = VR.""" F = np.broadcast_to(np.eye(3),[self.n,3,3])*np.random.rand(self.n,3,3) From e969fefbc6dc252c7773f21093853de2554eddc9 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 22 Apr 2020 09:45:25 +0200 Subject: [PATCH 113/186] can be done in python more easily these shell scripts are just wrappers around tested functionality of the python classes (geom or mechanics). Testing and using them is cumbersome in comparison to using the python functionality directly --- PRIVATE | 2 +- processing/post/addCauchy.py | 49 ---------------------- processing/post/addDeterminant.py | 45 -------------------- processing/post/addDeviator.py | 51 ----------------------- processing/post/addInfo.py | 41 ------------------- processing/post/addMises.py | 56 ------------------------- processing/post/reLabel.py | 50 ---------------------- processing/post/sortTable.py | 50 ---------------------- processing/pre/geom_clean.py | 42 ------------------- processing/pre/geom_fromScratch.py | 66 ------------------------------ processing/pre/geom_mirror.py | 47 --------------------- processing/pre/geom_pack.py | 37 ----------------- processing/pre/geom_rescale.py | 60 --------------------------- processing/pre/geom_toTable.py | 45 -------------------- processing/pre/geom_unpack.py | 37 ----------------- 15 files changed, 1 insertion(+), 677 deletions(-) delete mode 100755 processing/post/addCauchy.py delete mode 100755 processing/post/addDeterminant.py delete mode 100755 processing/post/addDeviator.py delete mode 100755 processing/post/addInfo.py delete mode 100755 processing/post/addMises.py delete mode 100755 processing/post/reLabel.py delete mode 100755 processing/post/sortTable.py delete mode 100755 processing/pre/geom_clean.py delete mode 100755 processing/pre/geom_fromScratch.py delete mode 100755 processing/pre/geom_mirror.py delete mode 100755 processing/pre/geom_pack.py delete mode 100755 processing/pre/geom_rescale.py delete mode 100755 processing/pre/geom_toTable.py delete mode 100755 processing/pre/geom_unpack.py diff --git a/PRIVATE b/PRIVATE index 232a094c7..cc41b4d04 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 232a094c715bcbbd1c6652c4dc4a4a50d402b82f +Subproject commit cc41b4d047032a971430f3aa3aea3f614e6ec5bf diff --git a/processing/post/addCauchy.py b/processing/post/addCauchy.py deleted file mode 100755 index 8bbc7fb0e..000000000 --- a/processing/post/addCauchy.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ -Add column containing Cauchy stress based on deformation gradient and first Piola--Kirchhoff stress. - -""", version = scriptID) - -parser.add_option('-f','--defgrad', - dest = 'defgrad', - type = 'string', metavar = 'string', - help = 'heading of columns containing deformation gradient [%default]') -parser.add_option('-p','--stress', - dest = 'stress', - type = 'string', metavar = 'string', - help = 'heading of columns containing first Piola--Kirchhoff stress [%default]') - -parser.set_defaults(defgrad = 'f', - stress = 'p', - ) - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - table.add('Cauchy', - damask.mechanics.Cauchy(table.get(options.stress ).reshape(-1,3,3), - table.get(options.defgrad).reshape(-1,3,3)).reshape(-1,9), - scriptID+' '+' '.join(sys.argv[1:])) - - table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/addDeterminant.py b/processing/post/addDeterminant.py deleted file mode 100755 index f2368559d..000000000 --- a/processing/post/addDeterminant.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import numpy as np - -import damask - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ -Add column(s) containing determinant of requested tensor column(s). - -""", version = scriptID) - -parser.add_option('-t','--tensor', - dest = 'tensor', - action = 'extend', metavar = '', - help = 'heading of columns containing tensor field values') - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -if options.tensor is None: - parser.error('no data column specified.') - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - for tensor in options.tensor: - table.add('det({})'.format(tensor), - np.linalg.det(table.get(tensor).reshape(-1,3,3)), - scriptID+' '+' '.join(sys.argv[1:])) - - table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/addDeviator.py b/processing/post/addDeviator.py deleted file mode 100755 index 9a532caec..000000000 --- a/processing/post/addDeviator.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(2)]', description = """ -Add column(s) containing deviator of requested tensor column(s). - -""", version = scriptID) - -parser.add_option('-t','--tensor', - dest = 'tensor', - action = 'extend', metavar='', - help = 'heading of columns containing tensor field values') -parser.add_option('-s','--spherical', - dest = 'spherical', - action = 'store_true', - help = 'report spherical part of tensor (hydrostatic component, pressure)') - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -if options.tensor is None: - parser.error('no data column specified...') - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - for tensor in options.tensor: - table.add('dev({})'.format(tensor), - damask.mechanics.deviatoric_part(table.get(tensor).reshape(-1,3,3)).reshape(-1,9), - scriptID+' '+' '.join(sys.argv[1:])) - if options.spherical: - table.add('sph({})'.format(tensor), - damask.mechanics.spherical_part(table.get(tensor).reshape(-1,3,3)), - scriptID+' '+' '.join(sys.argv[1:])) - - table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/addInfo.py b/processing/post/addInfo.py deleted file mode 100755 index 5e32510db..000000000 --- a/processing/post/addInfo.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ -Add info lines to ASCIItable header. - -""", version = scriptID) - -parser.add_option('-i', - '--info', - dest = 'info', action = 'extend', metavar = '', - help = 'items to add') - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -if options.info is None: - parser.error('no info specified.') - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - table.comments += options.info - - table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/addMises.py b/processing/post/addMises.py deleted file mode 100755 index 0c2a6db50..000000000 --- a/processing/post/addMises.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ -Add vonMises equivalent values for symmetric part of requested strains and/or stresses. - -""", version = scriptID) - -parser.add_option('-e','--strain', - dest = 'strain', - action = 'extend', metavar = '', - help = 'heading(s) of columns containing strain tensors') -parser.add_option('-s','--stress', - dest = 'stress', - action = 'extend', metavar = '', - help = 'heading(s) of columns containing stress tensors') - -parser.set_defaults(strain = [], - stress = [], - ) -(options,filenames) = parser.parse_args() - -if options.stress is [] and options.strain is []: - parser.error('no data column specified...') - -if filenames == []: filenames = [None] - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - for strain in options.strain: - table.add('Mises({})'.format(strain), - damask.mechanics.Mises_strain(damask.mechanics.symmetric(table.get(strain).reshape(-1,3,3))), - scriptID+' '+' '.join(sys.argv[1:])) - for stress in options.stress: - table.add('Mises({})'.format(stress), - damask.mechanics.Mises_stress(damask.mechanics.symmetric(table.get(stress).reshape(-1,3,3))), - scriptID+' '+' '.join(sys.argv[1:])) - - table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/reLabel.py b/processing/post/reLabel.py deleted file mode 100755 index da608e994..000000000 --- a/processing/post/reLabel.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ -Rename scalar, vectorial, and/or tensorial data header labels. - -""", version = scriptID) - -parser.add_option('-l','--label', - dest = 'label', - action = 'extend', metavar='', - help = 'column(s) to rename') -parser.add_option('-s','--substitute', - dest = 'substitute', - action = 'extend', metavar='', - help = 'new column label(s)') - -parser.set_defaults(label = [], - substitute = [], - ) - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -if len(options.label) != len(options.substitute): - parser.error('number of column labels and substitutes do not match.') - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - for label,substitute in zip(options.label,options.substitute): - table.rename(label,substitute,scriptID+' '+' '.join(sys.argv[1:])) - - table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/sortTable.py b/processing/post/sortTable.py deleted file mode 100755 index 3a3738d18..000000000 --- a/processing/post/sortTable.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ -Sort rows by given (or all) column label(s). - -Examples: -With coordinates in columns "x", "y", and "z"; sorting with x slowest and z fastest varying index: --label x,y,z. -""", version = scriptID) - - -parser.add_option('-l','--label', - dest = 'labels', - action = 'extend', metavar = '', - help = 'list of column labels (a,b,c,...)') -parser.add_option('-r','--reverse', - dest = 'reverse', - action = 'store_true', - help = 'sort in reverse') - -parser.set_defaults(reverse = False, - ) - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -if options.labels is None: - parser.error('no labels specified.') -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - table.sort_by(options.labels,not options.reverse) - - table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/pre/geom_clean.py b/processing/pre/geom_clean.py deleted file mode 100755 index 8883c1b2a..000000000 --- a/processing/pre/geom_clean.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -#-------------------------------------------------------------------------------------------------- -# MAIN -#-------------------------------------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [geomfile(s)]', description = """ -Smooth microstructure by selecting most frequent index within given stencil at each location. - -""", version=scriptID) - -parser.add_option('-s','--stencil', - dest = 'stencil', - type = 'int', metavar = 'int', - help = 'size of smoothing stencil [%default]') - -parser.set_defaults(stencil = 3) - -(options, filenames) = parser.parse_args() - - -if filenames == []: filenames = [None] - -for name in filenames: - damask.util.report(scriptName,name) - - geom = damask.Geom.from_file(StringIO(''.join(sys.stdin.read())) if name is None else name) - damask.util.croak(geom.clean(options.stencil)) - geom.add_comments(scriptID + ' ' + ' '.join(sys.argv[1:])) - geom.to_file(sys.stdout if name is None else name,pack=False) diff --git a/processing/pre/geom_fromScratch.py b/processing/pre/geom_fromScratch.py deleted file mode 100755 index 89fd27be5..000000000 --- a/processing/pre/geom_fromScratch.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from optparse import OptionParser - -import numpy as np - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [geomfile(s)]', description = """ -Generate homogeneous geometry. - -""", version = scriptID) - -parser.add_option('-g','--grid', - dest = 'grid', - type = 'int', nargs = 3, metavar = ' '.join(['int']*3), - help = 'a,b,c grid of hexahedral box %default') -parser.add_option('-s', '--size', - dest = 'size', - type = 'float', nargs = 3, metavar = ' '.join(['float']*3), - help = 'x,y,z of geometry size') -parser.add_option('-o','--origin', - dest = 'origin', - type = 'float', nargs = 3, metavar = ' '.join(['float']*3), - help = 'x,y,z of geometry origin %default') -parser.add_option('--homogenization', - dest = 'homogenization', - type = 'int', metavar = 'int', - help = 'homogenization index [%default]') -parser.add_option('-f','--fill', - dest = 'fill', - type = 'float', metavar = 'int', - help = 'microstructure index [%default]') - -parser.set_defaults(grid = (16,16,16), - origin = (0.,0.,0.), - homogenization = 1, - fill = 1, - ) - -(options, filename) = parser.parse_args() - - -name = None if filename == [] else filename[0] -damask.util.report(scriptName,name) - -dtype = float if np.isnan(options.fill) or int(options.fill) != options.fill else int -geom = damask.Geom(microstructure=np.full(options.grid,options.fill,dtype=dtype), - size=options.size, - origin=options.origin, - homogenization=options.homogenization, - comments=scriptID + ' ' + ' '.join(sys.argv[1:])) -damask.util.croak(geom) - -geom.to_file(sys.stdout if name is None else name,pack=False) diff --git a/processing/pre/geom_mirror.py b/processing/pre/geom_mirror.py deleted file mode 100755 index cca0a4e10..000000000 --- a/processing/pre/geom_mirror.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -#-------------------------------------------------------------------------------------------------- -# MAIN -#-------------------------------------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [geomfile(s)]', description = """ -Mirror along given directions. - -""", version=scriptID) - -validDirections = ['x','y','z'] - -parser.add_option('-d','--direction', - dest = 'directions', - action = 'extend', metavar = '', - help = "directions in which to mirror {{{}}}".format(','.join(validDirections))) -parser.add_option( '--reflect', - dest = 'reflect', - action = 'store_true', - help = 'reflect (include) outermost layers') - -parser.set_defaults(reflect = False) - -(options, filenames) = parser.parse_args() - -if filenames == []: filenames = [None] - -for name in filenames: - damask.util.report(scriptName,name) - - geom = damask.Geom.from_file(StringIO(''.join(sys.stdin.read())) if name is None else name) - damask.util.croak(geom.mirror(options.directions,options.reflect)) - geom.add_comments(scriptID + ' ' + ' '.join(sys.argv[1:])) - geom.to_file(sys.stdout if name is None else name,pack=False) diff --git a/processing/pre/geom_pack.py b/processing/pre/geom_pack.py deleted file mode 100755 index e927c006f..000000000 --- a/processing/pre/geom_pack.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -#-------------------------------------------------------------------------------------------------- -# MAIN -#-------------------------------------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog [geomfile(s)]', description = """ -Pack ranges to "a to b" and/or multiples to "n of x". - -""", version = scriptID) - -(options, filenames) = parser.parse_args() - - -if filenames == []: filenames = [None] - -for name in filenames: - damask.util.report(scriptName,name) - - geom = damask.Geom.from_file(StringIO(''.join(sys.stdin.read())) if name is None else name) - - damask.util.croak(geom) - geom.add_comments(scriptID + ' ' + ' '.join(sys.argv[1:])) - - geom.to_file(sys.stdout if name is None else name,pack=True) diff --git a/processing/pre/geom_rescale.py b/processing/pre/geom_rescale.py deleted file mode 100755 index b1a15593c..000000000 --- a/processing/pre/geom_rescale.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import numpy as np - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -#-------------------------------------------------------------------------------------------------- -# MAIN -#-------------------------------------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [geomfile(s)]', description = """ -Scales independently in x, y, and z direction in terms of grid and/or size. -Either absolute values or relative factors (like "0.25x") can be used. - -""", version = scriptID) - -parser.add_option('-g', '--grid', - dest = 'grid', - type = 'string', nargs = 3, metavar = 'string string string', - help = 'a,b,c grid of hexahedral box') -parser.add_option('-s', '--size', - dest = 'size', - type = 'string', nargs = 3, metavar = 'string string string', - help = 'x,y,z size of hexahedral box') - -(options, filenames) = parser.parse_args() - - -if filenames == []: filenames = [None] - -for name in filenames: - damask.util.report(scriptName,name) - - geom = damask.Geom.from_file(StringIO(''.join(sys.stdin.read())) if name is None else name) - - grid = geom.get_grid() - size = geom.get_size() - - new_grid = grid if options.grid is None else \ - np.array([int(o*float(n.lower().replace('x',''))) if n.lower().endswith('x') \ - else int(n) for o,n in zip(grid,options.grid)],dtype=int) - - new_size = size if options.size is None else \ - np.array([o*float(n.lower().replace('x','')) if n.lower().endswith('x') \ - else float(n) for o,n in zip(size,options.size)],dtype=float) - - geom.scale(new_grid) - damask.util.croak(geom.update(microstructure = None,size = new_size)) - geom.add_comments(scriptID + ' ' + ' '.join(sys.argv[1:])) - geom.to_file(sys.stdout if name is None else name,pack=False) diff --git a/processing/pre/geom_toTable.py b/processing/pre/geom_toTable.py deleted file mode 100755 index f1b5b9555..000000000 --- a/processing/pre/geom_toTable.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -#-------------------------------------------------------------------------------------------------- -# MAIN -#-------------------------------------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog [geomfile(s)]', description = """ -Translate geom description into ASCIItable containing position and microstructure. - -""", version = scriptID) - -(options, filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -for name in filenames: - damask.util.report(scriptName,name) - - geom = damask.Geom.from_file(StringIO(''.join(sys.stdin.read())) if name is None else name) - damask.util.croak(geom) - - coord0 = damask.grid_filters.cell_coord0(geom.grid,geom.size,geom.origin).reshape(-1,3) - - comments = geom.comments \ - + [scriptID + ' ' + ' '.join(sys.argv[1:]), - 'grid\ta {}\tb {}\tc {}'.format(*geom.grid), - 'size\tx {}\ty {}\tz {}'.format(*geom.size), - 'origin\tx {}\ty {}\tz {}'.format(*geom.origin), - 'homogenization\t{}'.format(geom.homogenization)] - - table = damask.Table(coord0,{'pos':(3,)},comments) - table.add('microstructure',geom.microstructure.reshape((-1,1),order='F')) - - table.to_ASCII(sys.stdout if name is None else os.path.splitext(name)[0]+'.txt') diff --git a/processing/pre/geom_unpack.py b/processing/pre/geom_unpack.py deleted file mode 100755 index 58bd5de87..000000000 --- a/processing/pre/geom_unpack.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from optparse import OptionParser -from io import StringIO - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -#-------------------------------------------------------------------------------------------------- -# MAIN -#-------------------------------------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog [geomfile(s)]', description = """ -Unpack ranges "a to b" and/or "n of x" multiples (exclusively in one line). - -""", version = scriptID) - -(options, filenames) = parser.parse_args() - - -if filenames == []: filenames = [None] - -for name in filenames: - damask.util.report(scriptName,name) - - geom = damask.Geom.from_file(StringIO(''.join(sys.stdin.read())) if name is None else name) - - damask.util.croak(geom) - geom.add_comments(scriptID + ' ' + ' '.join(sys.argv[1:])) - - geom.to_file(sys.stdout if name is None else name,pack=False) From 64b30ade6b83d6624cd211a0ea95e431efa8035c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 22 Apr 2020 10:48:09 +0200 Subject: [PATCH 114/186] don't make things complex by wrapping them into shell scripts --- PRIVATE | 2 +- processing/post/addTable.py | 44 -------------------------------- processing/post/growTable.py | 43 ------------------------------- processing/post/scaleData.py | 49 ------------------------------------ processing/post/shiftData.py | 49 ------------------------------------ 5 files changed, 1 insertion(+), 186 deletions(-) delete mode 100755 processing/post/addTable.py delete mode 100755 processing/post/growTable.py delete mode 100755 processing/post/scaleData.py delete mode 100755 processing/post/shiftData.py diff --git a/PRIVATE b/PRIVATE index cc41b4d04..3c52c31ca 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit cc41b4d047032a971430f3aa3aea3f614e6ec5bf +Subproject commit 3c52c31ca3272e0afe7967d2e59e0819f92e85c9 diff --git a/processing/post/addTable.py b/processing/post/addTable.py deleted file mode 100755 index 944214e69..000000000 --- a/processing/post/addTable.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ -Append data of ASCIItable(s) column-wise. - -""", version = scriptID) - -parser.add_option('-a', '--add','--table', - dest = 'table', - action = 'extend', metavar = '', - help = 'tables to add') - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -if options.table is None: - parser.error('no table specified.') - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - - for addTable in options.table: - table2 = damask.Table.from_ASCII(addTable) - table2.data = table2.data[:table.data.shape[0]] - table.join(table2) - - table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/growTable.py b/processing/post/growTable.py deleted file mode 100755 index 1dbfa8423..000000000 --- a/processing/post/growTable.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ -Append data of ASCIItable(s) row-wise. - -""", version = scriptID) - -parser.add_option('-a', '--add','--table', - dest = 'table', - action = 'extend', metavar = '', - help = 'tables to add') - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -if options.table is None: - parser.error('no table specified.') - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - - for growTable in options.table: - table2 = damask.Table.from_ASCII(growTable) - table.append(table2) - - table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/scaleData.py b/processing/post/scaleData.py deleted file mode 100755 index c6ce0a64e..000000000 --- a/processing/post/scaleData.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ -Uniformly scale column values by given factor. - -""", version = scriptID) - -parser.add_option('-l','--label', - dest = 'labels', - action = 'extend', metavar = '', - help ='column(s) to scale') -parser.add_option('-f','--factor', - dest = 'factor', - action = 'extend', metavar='', - help = 'factor(s) per column') - -parser.set_defaults(label = [], - factor = []) - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -if len(options.labels) != len(options.factor): - parser.error('number of column labels and factors do not match.') - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - for label,factor in zip(options.labels,options.factor): - table.set(label,table.get(label)*float(factor),scriptID+' '+' '.join(sys.argv[1:])) - - table.to_ASCII(sys.stdout if name is None else name) diff --git a/processing/post/shiftData.py b/processing/post/shiftData.py deleted file mode 100755 index 341a78c7e..000000000 --- a/processing/post/shiftData.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ -Uniformly shift column values by given offset. - -""", version = scriptID) - -parser.add_option('-l','--label', - dest = 'labels', - action = 'extend', metavar = '', - help ='column(s) to shift') -parser.add_option('-o','--offset', - dest = 'offset', - action = 'extend', metavar='', - help = 'offset(s) per column') - -parser.set_defaults(label = [], - offset = []) - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -if len(options.labels) != len(options.offset): - parser.error('number of column labels and offsets do not match.') - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - for label,offset in zip(options.labels,options.offset): - table.set(label,table.get(label)+float(offset),scriptID+' '+' '.join(sys.argv[1:])) - - table.to_ASCII(sys.stdout if name is None else name) From b9fec2a4cff7119977d034ae1cb02c084fa12391 Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Wed, 22 Apr 2020 12:23:09 +0200 Subject: [PATCH 115/186] Public functions required --- src/IO.f90 | 108 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 23 deletions(-) diff --git a/src/IO.f90 b/src/IO.f90 index 6e467cb89..11ce664f8 100644 --- a/src/IO.f90 +++ b/src/IO.f90 @@ -31,6 +31,10 @@ module IO IO_stringValue, & IO_floatValue, & IO_intValue, & + IO_stringAsInt, & + IO_stringAsFloat, & + IO_stringAsBool, & + IO_rmComment, & IO_lc, & IO_error, & IO_warning @@ -250,7 +254,7 @@ integer function IO_intValue(string,chunkPos,myChunk) integer, dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string integer, intent(in) :: myChunk !< position number of desired chunk - IO_intValue = verifyIntValue(IO_stringValue(string,chunkPos,myChunk)) + IO_intValue = IO_stringAsInt(IO_stringValue(string,chunkPos,myChunk)) end function IO_intValue @@ -264,7 +268,7 @@ real(pReal) function IO_floatValue(string,chunkPos,myChunk) integer, dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string integer, intent(in) :: myChunk !< position number of desired chunk - IO_floatValue = verifyFloatValue(IO_stringValue(string,chunkPos,myChunk)) + IO_floatValue = IO_stringAsFloat(IO_stringValue(string,chunkPos,myChunk)) end function IO_floatValue @@ -335,7 +339,8 @@ subroutine IO_error(error_ID,el,ip,g,instance,ext_msg) msg = 'invalid character for int:' case (112) msg = 'invalid character for float:' - + case (113) + msg = 'invalid character for logical:' !-------------------------------------------------------------------------------------------------- ! lattice error messages case (130) @@ -607,12 +612,9 @@ end subroutine IO_warning !-------------------------------------------------------------------------------------------------- -! internal helper functions - +!> @brief return verified integer value in given string !-------------------------------------------------------------------------------------------------- -!> @brief returns verified integer value in given string -!-------------------------------------------------------------------------------------------------- -integer function verifyIntValue(string) +integer function IO_stringAsInt(string) character(len=*), intent(in) :: string !< string for conversion to int value @@ -620,20 +622,20 @@ integer function verifyIntValue(string) character(len=*), parameter :: VALIDCHARS = '0123456789+- ' valid: if (verify(string,VALIDCHARS) == 0) then - read(string,*,iostat=readStatus) verifyIntValue + read(string,*,iostat=readStatus) IO_stringAsInt if (readStatus /= 0) call IO_error(111,ext_msg=string) else valid - verifyIntValue = 0 + IO_stringAsInt = 0 call IO_error(111,ext_msg=string) endif valid -end function verifyIntValue +end function IO_stringAsInt !-------------------------------------------------------------------------------------------------- -!> @brief returns verified float value in given string +!> @brief return verified float value in given string !-------------------------------------------------------------------------------------------------- -real(pReal) function verifyFloatValue(string) +real(pReal) function IO_stringAsFloat(string) character(len=*), intent(in) :: string !< string for conversion to float value @@ -641,14 +643,54 @@ real(pReal) function verifyFloatValue(string) character(len=*), parameter :: VALIDCHARS = '0123456789eE.+- ' valid: if (verify(string,VALIDCHARS) == 0) then - read(string,*,iostat=readStatus) verifyFloatValue + read(string,*,iostat=readStatus) IO_stringAsFloat if (readStatus /= 0) call IO_error(112,ext_msg=string) else valid - verifyFloatValue = 0.0_pReal + IO_stringAsFloat = 0.0_pReal call IO_error(112,ext_msg=string) endif valid -end function verifyFloatValue +end function IO_stringAsFloat + + +!-------------------------------------------------------------------------------------------------- +!> @brief return verified logical value in given string +!-------------------------------------------------------------------------------------------------- +logical function IO_stringAsBool(string) + + character(len=*), intent(in) :: string !< string for conversion to int value + + if (trim(adjustl(string)) == 'True') then + IO_stringAsBool = .true. + elseif (trim(adjustl(string)) == 'False') then + IO_stringAsBool = .false. + else + IO_stringAsBool = .false. + call IO_error(113,ext_msg=string) + endif + +end function IO_stringAsBool + + +!-------------------------------------------------------------------------------------------------- +! @brief Remove comments (characters beyond '#') and trailing space +! ToDo: Discuss name (the trim aspect is not clear) +!-------------------------------------------------------------------------------------------------- +function IO_rmComment(line) + + character(len=*), intent(in) :: line + character(len=:), allocatable :: IO_rmComment + integer :: split + + split = index(line,IO_COMMENT) + + if (split == 0) then + IO_rmComment = trim(line) + else + IO_rmComment = trim(line(:split-1)) + endif + +end function IO_rmComment !-------------------------------------------------------------------------------------------------- @@ -659,14 +701,19 @@ subroutine unitTest integer, dimension(:), allocatable :: chunkPos character(len=:), allocatable :: str - if(dNeq(1.0_pReal, verifyFloatValue('1.0'))) call IO_error(0,ext_msg='verifyFloatValue') - if(dNeq(1.0_pReal, verifyFloatValue('1e0'))) call IO_error(0,ext_msg='verifyFloatValue') - if(dNeq(0.1_pReal, verifyFloatValue('1e-1'))) call IO_error(0,ext_msg='verifyFloatValue') + if(dNeq(1.0_pReal, IO_stringAsFloat('1.0'))) call IO_error(0,ext_msg='IO_stringAsFloat') + if(dNeq(1.0_pReal, IO_stringAsFloat('1e0'))) call IO_error(0,ext_msg='IO_stringAsFloat') + if(dNeq(0.1_pReal, IO_stringAsFloat('1e-1'))) call IO_error(0,ext_msg='IO_stringAsFloat') - if(3112019 /= verifyIntValue( '3112019')) call IO_error(0,ext_msg='verifyIntValue') - if(3112019 /= verifyIntValue(' 3112019')) call IO_error(0,ext_msg='verifyIntValue') - if(-3112019 /= verifyIntValue('-3112019')) call IO_error(0,ext_msg='verifyIntValue') - if(3112019 /= verifyIntValue('+3112019 ')) call IO_error(0,ext_msg='verifyIntValue') + if(3112019 /= IO_stringAsInt( '3112019')) call IO_error(0,ext_msg='IO_stringAsInt') + if(3112019 /= IO_stringAsInt(' 3112019')) call IO_error(0,ext_msg='IO_stringAsInt') + if(-3112019 /= IO_stringAsInt('-3112019')) call IO_error(0,ext_msg='IO_stringAsInt') + if(3112019 /= IO_stringAsInt('+3112019 ')) call IO_error(0,ext_msg='IO_stringAsInt') + + if(.not. IO_stringAsBool(' True')) call IO_error(0,ext_msg='IO_stringAsBool') + if(.not. IO_stringAsBool(' True ')) call IO_error(0,ext_msg='IO_stringAsBool') + if( IO_stringAsBool(' False')) call IO_error(0,ext_msg='IO_stringAsBool') + if( IO_stringAsBool('False')) call IO_error(0,ext_msg='IO_stringAsBool') if(any([1,1,1] /= IO_stringPos('a'))) call IO_error(0,ext_msg='IO_stringPos') if(any([2,2,3,5,5] /= IO_stringPos(' aa b'))) call IO_error(0,ext_msg='IO_stringPos') @@ -683,6 +730,21 @@ subroutine unitTest if(.not. IO_isBlank(' #isBlank')) call IO_error(0,ext_msg='IO_isBlank/2') if( IO_isBlank(' i#s')) call IO_error(0,ext_msg='IO_isBlank/3') + str = IO_rmComment('#') + if (str /= '' .or. len(str) /= 0) call IO_error(0,ext_msg='IO_rmComment/1') + str = IO_rmComment(' #') + if (str /= '' .or. len(str) /= 0) call IO_error(0,ext_msg='IO_rmComment/2') + str = IO_rmComment(' # ') + if (str /= '' .or. len(str) /= 0) call IO_error(0,ext_msg='IO_rmComment/3') + str = IO_rmComment(' # a') + if (str /= '' .or. len(str) /= 0) call IO_error(0,ext_msg='IO_rmComment/4') + str = IO_rmComment(' # a') + if (str /= '' .or. len(str) /= 0) call IO_error(0,ext_msg='IO_rmComment/5') + str = IO_rmComment(' a#') + if (str /= ' a' .or. len(str) /= 2) call IO_error(0,ext_msg='IO_rmComment/6') + str = IO_rmComment(' ab #') + if (str /= ' ab'.or. len(str) /= 3) call IO_error(0,ext_msg='IO_rmComment/7') + end subroutine unitTest end module IO From a39e6b7af97b6760df7db973e3c2e52d5aebf114 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 22 Apr 2020 13:12:30 +0200 Subject: [PATCH 116/186] hide internal variables --- PRIVATE | 2 +- python/damask/_Lambert.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/PRIVATE b/PRIVATE index 232a094c7..3c52c31ca 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 232a094c715bcbbd1c6652c4dc4a4a50d402b82f +Subproject commit 3c52c31ca3272e0afe7967d2e59e0819f92e85c9 diff --git a/python/damask/_Lambert.py b/python/damask/_Lambert.py index a823764e9..8a0f043f3 100644 --- a/python/damask/_Lambert.py +++ b/python/damask/_Lambert.py @@ -32,9 +32,9 @@ import numpy as np -sc = np.pi**(1./6.)/6.**(1./6.) -beta = np.pi**(5./6.)/6.**(1./6.)/2. -R1 = (3.*np.pi/4.)**(1./3.) +_sc = np.pi**(1./6.)/6.**(1./6.) +_beta = np.pi**(5./6.)/6.**(1./6.)/2. +_R1 = (3.*np.pi/4.)**(1./3.) def cube_to_ball(cube): """ @@ -59,7 +59,7 @@ def cube_to_ball(cube): else: # get pyramide and scale by grid parameter ratio p = _get_order(cube_) - XYZ = cube_[p[0]] * sc + XYZ = cube_[p[0]] * _sc # intercept all the points along the z-axis if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-16): @@ -69,7 +69,7 @@ def cube_to_ball(cube): q = np.pi/12.0 * XYZ[order[0]]/XYZ[order[1]] c = np.cos(q) s = np.sin(q) - q = R1*2.0**0.25/beta * XYZ[order[1]] / np.sqrt(np.sqrt(2.0)-c) + q = _R1*2.0**0.25/_beta * XYZ[order[1]] / np.sqrt(np.sqrt(2.0)-c) T = np.array([ (np.sqrt(2.0)*c - 1.0), np.sqrt(2.0) * s]) * q # transform to sphere grid (inverse Lambert) @@ -101,7 +101,7 @@ def ball_to_cube(ball): https://doi.org/10.1088/0965-0393/22/7/075013 """ - ball_ = ball/np.linalg.norm(ball)*R1 if np.isclose(np.linalg.norm(ball),R1,atol=1e-6) else ball + ball_ = ball/np.linalg.norm(ball)*_R1 if np.isclose(np.linalg.norm(ball),_R1,atol=1e-6) else ball rs = np.linalg.norm(ball_) if np.allclose(ball_,0.0,rtol=0.0,atol=1.0e-16): @@ -121,14 +121,14 @@ def ball_to_cube(ball): else: q2 = qxy + np.max(np.abs(xyz2))**2 sq2 = np.sqrt(q2) - q = (beta/np.sqrt(2.0)/R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2))*sq2)) + q = (_beta/np.sqrt(2.0)/_R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2))*sq2)) tt = np.clip((np.min(np.abs(xyz2))**2+np.max(np.abs(xyz2))*sq2)/np.sqrt(2.0)/qxy,-1.0,1.0) Tinv = np.array([1.0,np.arccos(tt)/np.pi*12.0]) if np.abs(xyz2[1]) <= np.abs(xyz2[0]) else \ np.array([np.arccos(tt)/np.pi*12.0,1.0]) Tinv = q * np.where(xyz2<0.0,-Tinv,Tinv) # inverse M_1 - cube = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /sc + cube = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /_sc # reverse the coordinates back to the regular order according to the original pyramid number cube = cube[p[1]] From 8ba547a1b5caec6fa9656c7e14041fed24678008 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 22 Apr 2020 13:23:33 +0200 Subject: [PATCH 117/186] no need for an extra file --- python/damask/_Lambert.py | 164 ------------------------------------- python/damask/_rotation.py | 125 ++++++++++++++++++++++++++-- 2 files changed, 120 insertions(+), 169 deletions(-) delete mode 100644 python/damask/_Lambert.py diff --git a/python/damask/_Lambert.py b/python/damask/_Lambert.py deleted file mode 100644 index 8a0f043f3..000000000 --- a/python/damask/_Lambert.py +++ /dev/null @@ -1,164 +0,0 @@ -#################################################################################################### -# Code below available according to the following conditions on -# https://github.com/MarDiehl/3Drotations -#################################################################################################### -# Copyright (c) 2017-2019, Martin Diehl/Max-Planck-Institut für Eisenforschung GmbH -# Copyright (c) 2013-2014, Marc De Graef/Carnegie Mellon University -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, are -# permitted provided that the following conditions are met: -# -# - Redistributions of source code must retain the above copyright notice, this list -# of conditions and the following disclaimer. -# - Redistributions in binary form must reproduce the above copyright notice, this -# list of conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. -# - Neither the names of Marc De Graef, Carnegie Mellon University nor the names -# of its contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#################################################################################################### - -import numpy as np - -_sc = np.pi**(1./6.)/6.**(1./6.) -_beta = np.pi**(5./6.)/6.**(1./6.)/2. -_R1 = (3.*np.pi/4.)**(1./3.) - -def cube_to_ball(cube): - """ - Map a point in a uniform refinable cubical grid to a point on a uniform refinable grid on a ball. - - Parameters - ---------- - cube : numpy.ndarray - coordinates of a point in a uniform refinable cubical grid. - - References - ---------- - D. Roşca et al., Modelling and Simulation in Materials Science and Engineering 22:075013, 2014 - https://doi.org/10.1088/0965-0393/22/7/075013 - - """ - cube_ = np.clip(cube,None,np.pi**(2./3.) * 0.5) if np.isclose(np.abs(np.max(cube)),np.pi**(2./3.) * 0.5,atol=1e-6) else cube - - # transform to the sphere grid via the curved square, and intercept the zero point - if np.allclose(cube_,0.0,rtol=0.0,atol=1.0e-16): - ball = np.zeros(3) - else: - # get pyramide and scale by grid parameter ratio - p = _get_order(cube_) - XYZ = cube_[p[0]] * _sc - - # intercept all the points along the z-axis - if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-16): - ball = np.array([0.0, 0.0, np.sqrt(6.0/np.pi) * XYZ[2]]) - else: - order = [1,0] if np.abs(XYZ[1]) <= np.abs(XYZ[0]) else [0,1] - q = np.pi/12.0 * XYZ[order[0]]/XYZ[order[1]] - c = np.cos(q) - s = np.sin(q) - q = _R1*2.0**0.25/_beta * XYZ[order[1]] / np.sqrt(np.sqrt(2.0)-c) - T = np.array([ (np.sqrt(2.0)*c - 1.0), np.sqrt(2.0) * s]) * q - - # transform to sphere grid (inverse Lambert) - # note that there is no need to worry about dividing by zero, since XYZ[2] can not become zero - c = np.sum(T**2) - s = c * np.pi/24.0 /XYZ[2]**2 - c = c * np.sqrt(np.pi/24.0)/XYZ[2] - q = np.sqrt( 1.0 - s ) - ball = np.array([ T[order[1]] * q, T[order[0]] * q, np.sqrt(6.0/np.pi) * XYZ[2] - c ]) - - # reverse the coordinates back to the regular order according to the original pyramid number - ball = ball[p[1]] - - return ball - - -def ball_to_cube(ball): - """ - Map a point on a uniform refinable grid on a ball to a point in a uniform refinable cubical grid. - - Parameters - ---------- - ball : numpy.ndarray - coordinates of a point on a uniform refinable grid on a ball. - - References - ---------- - D. Roşca et al., Modelling and Simulation in Materials Science and Engineering 22:075013, 2014 - https://doi.org/10.1088/0965-0393/22/7/075013 - - """ - ball_ = ball/np.linalg.norm(ball)*_R1 if np.isclose(np.linalg.norm(ball),_R1,atol=1e-6) else ball - rs = np.linalg.norm(ball_) - - if np.allclose(ball_,0.0,rtol=0.0,atol=1.0e-16): - cube = np.zeros(3) - else: - p = _get_order(ball_) - xyz3 = ball_[p[0]] - - # inverse M_3 - xyz2 = xyz3[0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[2])) ) - - # inverse M_2 - qxy = np.sum(xyz2**2) - - if np.isclose(qxy,0.0,rtol=0.0,atol=1.0e-16): - Tinv = np.zeros(2) - else: - q2 = qxy + np.max(np.abs(xyz2))**2 - sq2 = np.sqrt(q2) - q = (_beta/np.sqrt(2.0)/_R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2))*sq2)) - tt = np.clip((np.min(np.abs(xyz2))**2+np.max(np.abs(xyz2))*sq2)/np.sqrt(2.0)/qxy,-1.0,1.0) - Tinv = np.array([1.0,np.arccos(tt)/np.pi*12.0]) if np.abs(xyz2[1]) <= np.abs(xyz2[0]) else \ - np.array([np.arccos(tt)/np.pi*12.0,1.0]) - Tinv = q * np.where(xyz2<0.0,-Tinv,Tinv) - - # inverse M_1 - cube = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /_sc - # reverse the coordinates back to the regular order according to the original pyramid number - cube = cube[p[1]] - - return cube - - -def _get_order(xyz): - """ - Get order of the coordinates. - - Depending on the pyramid in which the point is located, the order need to be adjusted. - - Parameters - ---------- - xyz : numpy.ndarray - coordinates of a point on a uniform refinable grid on a ball or - in a uniform refinable cubical grid. - - References - ---------- - D. Roşca et al., Modelling and Simulation in Materials Science and Engineering 22:075013, 2014 - https://doi.org/10.1088/0965-0393/22/7/075013 - - """ - if (abs(xyz[0])<= xyz[2]) and (abs(xyz[1])<= xyz[2]) or \ - (abs(xyz[0])<=-xyz[2]) and (abs(xyz[1])<=-xyz[2]): - return [[0,1,2],[0,1,2]] - elif (abs(xyz[2])<= xyz[0]) and (abs(xyz[1])<= xyz[0]) or \ - (abs(xyz[2])<=-xyz[0]) and (abs(xyz[1])<=-xyz[0]): - return [[1,2,0],[2,0,1]] - elif (abs(xyz[0])<= xyz[1]) and (abs(xyz[2])<= xyz[1]) or \ - (abs(xyz[0])<=-xyz[1]) and (abs(xyz[2])<=-xyz[1]): - return [[2,0,1],[1,2,0]] diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 6076b4add..723664e18 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -1,10 +1,14 @@ import numpy as np -from ._Lambert import ball_to_cube, cube_to_ball from . import mechanics _P = -1 +# parameters for conversion from/to cubochoric +_sc = np.pi**(1./6.)/6.**(1./6.) +_beta = np.pi**(5./6.)/6.**(1./6.)/2. +_R1 = (3.*np.pi/4.)**(1./3.) + def iszero(a): return np.isclose(a,0.0,atol=1.0e-12,rtol=0.0) @@ -1043,9 +1047,49 @@ class Rotation: @staticmethod def ho2cu(ho): - """Homochoric vector to cubochoric vector.""" + """ + Homochoric vector to cubochoric vector. + + References + ---------- + D. Roşca et al., Modelling and Simulation in Materials Science and Engineering 22:075013, 2014 + https://doi.org/10.1088/0965-0393/22/7/075013 + + """ if len(ho.shape) == 1: - return ball_to_cube(ho) + ball_ = ho/np.linalg.norm(ho)*_R1 if np.isclose(np.linalg.norm(ho),_R1,atol=1e-6) \ + else ho + rs = np.linalg.norm(ball_) + + if np.allclose(ball_,0.0,rtol=0.0,atol=1.0e-16): + cube = np.zeros(3) + else: + p = _get_order(ball_) + xyz3 = ball_[p[0]] + + # inverse M_3 + xyz2 = xyz3[0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[2])) ) + + # inverse M_2 + qxy = np.sum(xyz2**2) + + if np.isclose(qxy,0.0,rtol=0.0,atol=1.0e-16): + Tinv = np.zeros(2) + else: + q2 = qxy + np.max(np.abs(xyz2))**2 + sq2 = np.sqrt(q2) + q = (_beta/np.sqrt(2.0)/_R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2))*sq2)) + tt = np.clip((np.min(np.abs(xyz2))**2+np.max(np.abs(xyz2))*sq2)/np.sqrt(2.0)/qxy,-1.0,1.0) + Tinv = np.array([1.0,np.arccos(tt)/np.pi*12.0]) if np.abs(xyz2[1]) <= np.abs(xyz2[0]) else \ + np.array([np.arccos(tt)/np.pi*12.0,1.0]) + Tinv = q * np.where(xyz2<0.0,-Tinv,Tinv) + + # inverse M_1 + cube = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /_sc + # reverse the coordinates back to the regular order according to the original pyramid number + cube = cube[p[1]] + + return cube else: raise NotImplementedError @@ -1078,8 +1122,79 @@ class Rotation: @staticmethod def cu2ho(cu): - """Cubochoric vector to homochoric vector.""" + """ + Cubochoric vector to homochoric vector. + + References + ---------- + D. Roşca et al., Modelling and Simulation in Materials Science and Engineering 22:075013, 2014 + https://doi.org/10.1088/0965-0393/22/7/075013 + + """ if len(cu.shape) == 1: - return cube_to_ball(cu) + + cube_ = np.clip(cu,None,np.pi**(2./3.) * 0.5) if np.isclose(np.abs(np.max(cu)),np.pi**(2./3.) * 0.5,atol=1e-6) \ + else cu + + # transform to the sphere grid via the curved square, and intercept the zero point + if np.allclose(cube_,0.0,rtol=0.0,atol=1.0e-16): + ball = np.zeros(3) + else: + # get pyramide and scale by grid parameter ratio + p = _get_order(cube_) + XYZ = cube_[p[0]] * _sc + + # intercept all the points along the z-axis + if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-16): + ball = np.array([0.0, 0.0, np.sqrt(6.0/np.pi) * XYZ[2]]) + else: + order = [1,0] if np.abs(XYZ[1]) <= np.abs(XYZ[0]) else [0,1] + q = np.pi/12.0 * XYZ[order[0]]/XYZ[order[1]] + c = np.cos(q) + s = np.sin(q) + q = _R1*2.0**0.25/_beta * XYZ[order[1]] / np.sqrt(np.sqrt(2.0)-c) + T = np.array([ (np.sqrt(2.0)*c - 1.0), np.sqrt(2.0) * s]) * q + + # transform to sphere grid (inverse Lambert) + # note that there is no need to worry about dividing by zero, since XYZ[2] can not become zero + c = np.sum(T**2) + s = c * np.pi/24.0 /XYZ[2]**2 + c = c * np.sqrt(np.pi/24.0)/XYZ[2] + q = np.sqrt( 1.0 - s ) + ball = np.array([ T[order[1]] * q, T[order[0]] * q, np.sqrt(6.0/np.pi) * XYZ[2] - c ]) + + # reverse the coordinates back to the regular order according to the original pyramid number + ball = ball[p[1]] + + return ball else: raise NotImplementedError + + +def _get_order(xyz): + """ + Get order of the coordinates. + + Depending on the pyramid in which the point is located, the order need to be adjusted. + + Parameters + ---------- + xyz : numpy.ndarray + coordinates of a point on a uniform refinable grid on a ball or + in a uniform refinable cubical grid. + + References + ---------- + D. Roşca et al., Modelling and Simulation in Materials Science and Engineering 22:075013, 2014 + https://doi.org/10.1088/0965-0393/22/7/075013 + + """ + if (abs(xyz[0])<= xyz[2]) and (abs(xyz[1])<= xyz[2]) or \ + (abs(xyz[0])<=-xyz[2]) and (abs(xyz[1])<=-xyz[2]): + return [[0,1,2],[0,1,2]] + elif (abs(xyz[2])<= xyz[0]) and (abs(xyz[1])<= xyz[0]) or \ + (abs(xyz[2])<=-xyz[0]) and (abs(xyz[1])<=-xyz[0]): + return [[1,2,0],[2,0,1]] + elif (abs(xyz[0])<= xyz[1]) and (abs(xyz[2])<= xyz[1]) or \ + (abs(xyz[0])<=-xyz[1]) and (abs(xyz[2])<=-xyz[1]): + return [[2,0,1],[1,2,0]] From c4bcd3b430268516fa788fa7257fe489628a4be8 Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Wed, 22 Apr 2020 12:52:47 +0200 Subject: [PATCH 118/186] Functions needed to store and read yaml data --- src/CPFEM.f90 | 2 + src/CPFEM2.f90 | 2 + src/YAML_types.f90 | 977 +++++++++++++++++++++++++++++++++ src/commercialFEM_fileList.f90 | 1 + 4 files changed, 982 insertions(+) create mode 100644 src/YAML_types.f90 diff --git a/src/CPFEM.f90 b/src/CPFEM.f90 index c590a86b5..f26d4d064 100644 --- a/src/CPFEM.f90 +++ b/src/CPFEM.f90 @@ -10,6 +10,7 @@ module CPFEM use FEsolving use math use rotations + use types use discretization_marc use material use config @@ -83,6 +84,7 @@ subroutine CPFEM_initAll(el,ip) call config_init call math_init call rotations_init + call types_init call HDF5_utilities_init call results_init call discretization_marc_init(ip, el) diff --git a/src/CPFEM2.f90 b/src/CPFEM2.f90 index 357bcce9f..2893b4759 100644 --- a/src/CPFEM2.f90 +++ b/src/CPFEM2.f90 @@ -11,6 +11,7 @@ module CPFEM2 use FEsolving use math use rotations + use types use material use lattice use IO @@ -50,6 +51,7 @@ subroutine CPFEM_initAll call config_init call math_init call rotations_init + call types_init call lattice_init call HDF5_utilities_init call results_init diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 new file mode 100644 index 000000000..165a34033 --- /dev/null +++ b/src/YAML_types.f90 @@ -0,0 +1,977 @@ +!-------------------------------------------------------------------------------------------------- +!> @brief yaml_types +!> @details module describes the various functions to store and get the yaml data. +!! tNode is the fundamental derived data type. It can be of tScalar, & +!! tList or tDict. +!! Every 'value' in a key: value pair is of tNode and is a pointer. +!! If 'value' is of tScalar, it can either be a string, real, integer or logical, & +!! functions exist to convert this scalar type to its respective primitive data type. +!-------------------------------------------------------------------------------------------------- + +module types + + use IO + use prec + + implicit none + + private + + public tNode + public tScalar + public tDict + public tList + public types_init + + type, abstract :: tNode + integer :: length = 0 + contains + procedure(asFormattedString), deferred :: asFormattedString + procedure :: & + asScalar => tNode_asScalar + procedure :: & + asList => tNode_asList + procedure :: & + asDict => tNode_asDict + procedure :: & + tNode_get_byIndex, & + tNode_get_byIndex_asFloat, & + tNode_get_byIndex_asFloats, & + tNode_get_byIndex_asInt, & + tNode_get_byIndex_asInts, & + tNode_get_byIndex_asBool, & + tNode_get_byIndex_asBools, & + tNode_get_byIndex_asString, & + tNode_get_byIndex_asStrings, & + tNode_get_byKey, & + tNode_get_byKey_asFloat, & + tNode_get_byKey_asFloats, & + tNode_get_byKey_asInt, & + tNode_get_byKey_asInts, & + tNode_get_byKey_asBool, & + tNode_get_byKey_asBools, & + tNode_get_byKey_asString, & + tNode_get_byKey_asStrings + generic :: & + get => tNode_get_byIndex, & + tNode_get_byKey + generic :: & + get_asFloat => tNode_get_byIndex_asFloat, & + tNode_get_byKey_asFloat + generic :: & + get_asFloats => tNode_get_byIndex_asFloats, & + tNode_get_byKey_asFloats + generic :: & + get_asInt => tNode_get_byIndex_asInt, & + tNode_get_byKey_asInt + generic :: & + get_asInts => tNode_get_byIndex_asInts, & + tNode_get_byKey_asInts + generic :: & + get_asBool => tNode_get_byIndex_asBool, & + tNode_get_byKey_asBool + generic :: & + get_asBools => tNode_get_byIndex_asBools, & + tNode_get_byKey_asBools + generic :: & + get_asString => tNode_get_byIndex_asString, & + tNode_get_byKey_asString + generic :: & + get_asStrings => tNode_get_byIndex_asStrings, & + tNode_get_byKey_asStrings + end type tNode + + + type, extends(tNode) :: tScalar + + character(len=:), allocatable, private :: value + + contains + procedure :: asFormattedString => tScalar_asFormattedString + procedure :: & + asFloat => tScalar_asFloat + procedure :: & + asInt => tScalar_asInt + procedure :: & + asBool => tScalar_asBool + procedure :: & + asString => tScalar_asString + end type tScalar + + type, extends(tNode) :: tList + + class(tItem), pointer :: first => null() + + contains + procedure :: asFormattedString => tList_asFormattedString + procedure :: append => tList_append + procedure :: & + asFloats => tList_asFloats + procedure :: & + asInts => tList_asInts + procedure :: & + asBools => tList_asBools + procedure :: & + asStrings => tList_asStrings + final :: tList_finalize + end type tList + + type, extends(tList) :: tDict + contains + procedure :: asFormattedString => tDict_asFormattedString + procedure :: set => tDict_set + final :: tDict_finalize + end type tDict + + + type :: tItem + character(len=:), allocatable :: key + class(tNode), allocatable :: node + class(tItem), pointer :: next => null() + end type tItem + + abstract interface + + recursive function asFormattedString(self,indent) + import tNode + character(len=:), allocatable :: asFormattedString + class(tNode), intent(in), target :: self + integer, intent(in), optional :: indent + end function asFormattedString + + end interface + + interface tScalar + module procedure tScalar_init__ + end interface tScalar + + interface assignment (=) + module procedure tScalar_assign__ + end interface assignment (=) + +contains + +subroutine types_init + call unitTest +end subroutine types_init + + +subroutine unitTest + + type(tScalar),target :: s1,s2 + + s1 = '1' + if(s1%asInt() /= 1) call IO_error(0,ext_msg='tScalar_asInt') + if(dNeq(s1%asFloat(),1.0_pReal)) call IO_error(0,ext_msg='tScalar_asFloat') + s1 = 'True' + if(.not. s1%asBool()) call IO_error(0,ext_msg='tScalar_asBool') + if(s1%asString() /= 'True') call IO_error(0,ext_msg='tScalar_asString') + + + block + type(tList), target :: l1, l2 + class(tNode), pointer :: n + + s1 = '2' + s2 = '3' + call l1%append(s1) + call l1%append(s2) + call l2%append(l1) + n => l1 + + if(any(l1%asInts() /= [2,3])) call IO_error(0,ext_msg='tList_asInts') + if(any(dNeq(l1%asFloats(),[2.0_pReal,3.0_pReal]))) call IO_error(0,ext_msg='tList_asFloats') + if(n%get_asInt(1) /= 2) call IO_error(0,ext_msg='byIndex_asInt') + if(dNeq(n%get_asFloat(2),3.0_pReal)) call IO_error(0,ext_msg='byIndex_asFloat') + if(any(l2%get_asInts(1) /= [2,3])) call IO_error(0,ext_msg='byIndex_asInts') + if(any(dNeq(l2%get_asFloats(1),[2.0_pReal,3.0_pReal]))) call IO_error(0,ext_msg='byIndex_asFloats') + end block + + block + type(tList), target :: l1, l2 + class(tNode), pointer :: n + s1 = 'True' + s2 = 'False' + call l1%append(s1) + call l1%append(s2) + call l2%append(l1) + n=> l1 + + if(any(l1%asBools() .neqv. [.true., .false.])) call IO_error(0,ext_msg='tList_asBools') + if(any(l1%asStrings() /= ['True ','False'])) call IO_error(0,ext_msg='tList_asStrings') + if(n%get_asBool(2)) call IO_error(0,ext_msg='byIndex_asBool') + if(n%get_asString(1) /= 'True') call IO_error(0,ext_msg='byIndex_asString') + if(any(l2%get_asBools(1) .neqv. [.true., .false.])) call IO_error(0,ext_msg='byIndex_asBools') + if(any(l2%get_asStrings(1) /= ['True ','False'])) call IO_error(0,ext_msg='byIndex_asStrings') + end block + +end subroutine unitTest + + +!--------------------------------------------------------------------------------------------------- +!> @brief init from string +!--------------------------------------------------------------------------------------------------- +type(tScalar) pure function tScalar_init__(value) + + character(len=*), intent(in) :: value + + tScalar_init__%value =value + +end function tScalar_init__ + + +!--------------------------------------------------------------------------------------------------- +!> @brief set value from string +!--------------------------------------------------------------------------------------------------- +elemental pure subroutine tScalar_assign__(self,value) + + type(tScalar), intent(out) :: self + character(len=*), intent(in) :: value + + self%value = value + +end subroutine tScalar_assign__ + + +!-------------------------------------------------------------------------------------------------- +!> @brief Type guard, guarantee scalar +!-------------------------------------------------------------------------------------------------- +function tNode_asScalar(self) result(scalar) + + class(tNode), intent(in), target :: self + class(tScalar), pointer :: scalar + + select type(self) + class is(tScalar) + scalar => self + class default + call IO_error(0) + end select + +end function tNode_asScalar + + +!-------------------------------------------------------------------------------------------------- +!> @brief Type guard, guarantee list +!-------------------------------------------------------------------------------------------------- +function tNode_asList(self) result(list) + + class(tNode), intent(in), target :: self + class(tList), pointer :: list + + select type(self) + class is(tList) + list => self + class default + call IO_error(0) + end select + +end function tNode_asList + + +!-------------------------------------------------------------------------------------------------- +!> @brief Type guard, guarantee dict +!-------------------------------------------------------------------------------------------------- +function tNode_asDict(self) result(dict) + + class(tNode), intent(in), target :: self + class(tDict), pointer :: dict + + select type(self) + class is(tDict) + dict => self + class default + call IO_error(0) + end select + +end function tNode_asDict + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by index +!-------------------------------------------------------------------------------------------------- +function tNode_get_byIndex(self,i) result(node) + + class(tNode), intent(in), target :: self + integer, intent(in) :: i + class(tNode), pointer :: node + + class(tList), pointer :: self_ + class(tItem), pointer :: item + integer :: j + + self_ => self%asList() + if(i < 1 .or. i > self_%length) call IO_error(0) + + j = 1 + item => self_%first + do while(j item%next + j = j + 1 + enddo + node => item%node + +end function tNode_get_byIndex + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by index and convert to float +!-------------------------------------------------------------------------------------------------- +function tNode_get_byIndex_asFloat(self,i) result(nodeAsFloat) + + class(tNode), intent(in), target :: self + integer, intent(in) :: i + real(pReal) :: nodeAsFloat + + class(tNode), pointer :: node + type(tScalar), pointer :: scalar + + node => self%get(i) + scalar => node%asScalar() + nodeAsFloat = scalar%asFloat() + +end function tNode_get_byIndex_asFloat + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by index and convert to int +!-------------------------------------------------------------------------------------------------- +function tNode_get_byIndex_asInt(self,i) result(nodeAsInt) + + class(tNode), intent(in), target :: self + integer, intent(in) :: i + integer :: nodeAsInt + + class(tNode), pointer :: node + type(tScalar), pointer :: scalar + + node => self%get(i) + scalar => node%asScalar() + nodeAsInt = scalar%asInt() + +end function tNode_get_byIndex_asInt + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by index and convert to bool +!-------------------------------------------------------------------------------------------------- +function tNode_get_byIndex_asBool(self,i) result(nodeAsBool) + + class(tNode), intent(in), target :: self + integer, intent(in) :: i + logical :: nodeAsBool + + class(tNode), pointer :: node + type(tScalar), pointer :: scalar + + node => self%get(i) + scalar => node%asScalar() + nodeAsBool = scalar%asBool() + +end function tNode_get_byIndex_asBool + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by index and convert to string +!-------------------------------------------------------------------------------------------------- +function tNode_get_byIndex_asString(self,i) result(nodeAsString) + + class(tNode), intent(in), target :: self + integer, intent(in) :: i + character(len=:), allocatable :: nodeAsString + + class(tNode), pointer :: node + type(tScalar), pointer :: scalar + + node => self%get(i) + scalar => node%asScalar() + nodeAsString = scalar%asString() + +end function tNode_get_byIndex_asString + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by index and convert to float array +!-------------------------------------------------------------------------------------------------- +function tNode_get_byIndex_asFloats(self,i) result(nodeAsFloats) + + class(tNode), intent(in), target :: self + integer, intent(in) :: i + real(pReal), dimension(:), allocatable :: nodeAsFloats + + class(tNode), pointer :: node + class(tList), pointer :: list + + node => self%get(i) + list => node%asList() + nodeAsFloats = list%asFloats() + +end function tNode_get_byIndex_asFloats + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by index and convert to int array +!-------------------------------------------------------------------------------------------------- +function tNode_get_byIndex_asInts(self,i) result(nodeAsInts) + + class(tNode), intent(in), target :: self + integer, intent(in) :: i + integer, dimension(:), allocatable :: nodeAsInts + + class(tNode), pointer :: node + class(tList), pointer :: list + + node => self%get(i) + list => node%asList() + nodeAsInts = list%asInts() + +end function tNode_get_byIndex_asInts + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by index and convert to bool array +!-------------------------------------------------------------------------------------------------- +function tNode_get_byIndex_asBools(self,i) result(nodeAsBools) + + class(tNode), intent(in), target :: self + integer, intent(in) :: i + logical, dimension(:), allocatable :: nodeAsBools + + class(tNode), pointer :: node + class(tList), pointer :: list + + node => self%get(i) + list => node%asList() + nodeAsBools = list%asBools() + +end function tNode_get_byIndex_asBools + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by index and convert to string array +!-------------------------------------------------------------------------------------------------- +function tNode_get_byIndex_asStrings(self,i) result(nodeAsStrings) + + class(tNode), intent(in), target :: self + integer, intent(in) :: i + character(len=:), allocatable, dimension(:) :: nodeAsStrings + + class(tNode), pointer :: node + type(tList), pointer :: list + + node => self%get(i) + list => node%asList() + nodeAsStrings = list%asStrings() + +end function tNode_get_byIndex_asStrings + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by index +!-------------------------------------------------------------------------------------------------- +function tNode_get_byKey(self,k) result(node) + + class(tNode), intent(in), target :: self + character(len=*), intent(in) :: k + class(tNode), pointer :: node + + type(tDict), pointer :: self_ + type(tItem), pointer :: item + integer :: j + + self_ => self%asDict() + + j = 1 + item => self_%first + do while(j <= self_%length) + if (item%key == k) exit + item => item%next + j = j + 1 + enddo + if (.not. item%key == k) call IO_error(0) + node => item%node + +end function tNode_get_byKey + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by key and convert to float +!-------------------------------------------------------------------------------------------------- +function tNode_get_byKey_asFloat(self,k) result(nodeAsFloat) + + class(tNode), intent(in), target :: self + character(len=*), intent(in) :: k + real(pReal) :: nodeAsFloat + + class(tNode), pointer :: node + type(tScalar), pointer :: scalar + + node => self%get(k) + scalar => node%asScalar() + nodeAsFloat = scalar%asFloat() + +end function tNode_get_byKey_asFloat + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by key and convert to int +!-------------------------------------------------------------------------------------------------- +function tNode_get_byKey_asInt(self,k) result(nodeAsInt) + + class(tNode), intent(in), target :: self + character(len=*), intent(in) :: k + integer :: nodeAsInt + + class(tNode), pointer :: node + type(tScalar), pointer :: scalar + + node => self%get(k) + scalar => node%asScalar() + nodeAsInt = scalar%asInt() + +end function tNode_get_byKey_asInt + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by key and convert to bool +!-------------------------------------------------------------------------------------------------- +function tNode_get_byKey_asBool(self,k) result(nodeAsBool) + + class(tNode), intent(in), target :: self + character(len=*), intent(in) :: k + logical :: nodeAsBool + + class(tNode), pointer :: node + type(tScalar), pointer :: scalar + + node => self%get(k) + scalar => node%asScalar() + nodeAsBool = scalar%asBool() + +end function tNode_get_byKey_asBool + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by key and convert to string +!-------------------------------------------------------------------------------------------------- +function tNode_get_byKey_asString(self,k) result(nodeAsString) + + class(tNode), intent(in), target :: self + character(len=*), intent(in) :: k + character(len=:), allocatable :: nodeAsString + + class(tNode), pointer :: node + type(tScalar), pointer :: scalar + + node => self%get(k) + scalar => node%asScalar() + nodeAsString = scalar%asString() + +end function tNode_get_byKey_asString + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by key and convert to float array +!-------------------------------------------------------------------------------------------------- +function tNode_get_byKey_asFloats(self,k) result(nodeAsFloats) + + class(tNode), intent(in), target :: self + character(len=*), intent(in) :: k + real(pReal), dimension(:), allocatable :: nodeAsFloats + + class(tNode), pointer :: node + type(tList), pointer :: list + + node => self%get(k) + list => node%asList() + nodeAsFloats = list%asFloats() + +end function tNode_get_byKey_asFloats + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by key and convert to int array +!-------------------------------------------------------------------------------------------------- +function tNode_get_byKey_asInts(self,k) result(nodeAsInts) + + class(tNode), intent(in), target :: self + character(len=*), intent(in) :: k + integer, dimension(:), allocatable :: nodeAsInts + + class(tNode), pointer :: node + type(tList), pointer :: list + + node => self%get(k) + list => node%asList() + nodeAsInts = list%asInts() + +end function tNode_get_byKey_asInts + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by key and convert to bool array +!-------------------------------------------------------------------------------------------------- +function tNode_get_byKey_asBools(self,k) result(nodeAsBools) + + class(tNode), intent(in), target :: self + character(len=*), intent(in) :: k + logical, dimension(:), allocatable :: nodeAsBools + + class(tNode), pointer :: node + type(tList), pointer :: list + + node => self%get(k) + list => node%asList() + nodeAsBools = list%asBools() + +end function tNode_get_byKey_asBools + + +!-------------------------------------------------------------------------------------------------- +!> @brief Access by key and convert to string array +!-------------------------------------------------------------------------------------------------- +function tNode_get_byKey_asStrings(self,k) result(nodeAsStrings) + + class(tNode), intent(in), target :: self + character(len=*), intent(in) :: k + character(len=:), allocatable, dimension(:) :: nodeAsStrings + + class(tNode), pointer :: node + type(tList), pointer :: list + + node => self%get(k) + list => node%asList() + nodeAsStrings = list%asStrings() + +end function tNode_get_byKey_asStrings + + +!-------------------------------------------------------------------------------------------------- +!> @brief Return scalar as string +!-------------------------------------------------------------------------------------------------- +recursive function tScalar_asFormattedString(self,indent) + + character(len=:), allocatable :: tScalar_asFormattedString + class(tScalar), intent(in), target :: self + integer, intent(in), optional :: indent + + integer :: indent_ + + if(present(indent)) then + indent_ = indent + else + indent_ = 0 + endif + + tScalar_asFormattedString = repeat(' ',indent_)//trim(self%value)//IO_EOL + +end function tScalar_asFormattedString + + +!-------------------------------------------------------------------------------------------------- +!> @brief Return list as string (YAML block style) +!-------------------------------------------------------------------------------------------------- +recursive function tList_asFormattedString(self,indent) result(str) + + class(tList), intent(in), target :: self + integer, intent(in), optional :: indent + + class(tItem), pointer :: item + character(len=:), allocatable :: str + integer :: i,indent_ + + if(present(indent)) then + indent_ = indent + else + indent_ = 0 + endif + + item => self%first + do i = 1, self%length + str = str//repeat(' ',indent_)//'-'//IO_EOL//item%node%asFormattedString(indent_+2) + item => item%next + enddo + +end function tList_asFormattedString + + +!-------------------------------------------------------------------------------------------------- +!> @brief Return dictionary as string (YAML block style) +!-------------------------------------------------------------------------------------------------- +recursive function tDict_asFormattedString(self,indent) result(str) + + class(tDict), intent(in), target :: self + integer, intent(in), optional :: indent + + class(tItem), pointer :: item + character(len=:), allocatable :: str + integer :: i,indent_ + + if(present(indent)) then + indent_ = indent + else + indent_ = 0 + endif + + item => self%first + do i = 1, self%length + str = str//repeat(' ',indent_)//item%key//':'//IO_EOL//item%node%asFormattedString(indent_+2) + item => item%next + enddo + +end function tDict_asFormattedString + + +!-------------------------------------------------------------------------------------------------- +!> @brief Convert to float +!-------------------------------------------------------------------------------------------------- +function tScalar_asFloat(self) + + class(tScalar), intent(in), target :: self + real(pReal) :: tScalar_asFloat + + tScalar_asFloat = IO_stringAsFloat(self%value) + +end function tScalar_asFloat + + +!-------------------------------------------------------------------------------------------------- +!> @brief Convert to int +!-------------------------------------------------------------------------------------------------- +function tScalar_asInt(self) + + class(tScalar), intent(in), target :: self + integer :: tScalar_asInt + + tScalar_asInt = IO_stringAsInt(self%value) + +end function tScalar_asInt + + +!-------------------------------------------------------------------------------------------------- +!> @brief Convert to bool +!-------------------------------------------------------------------------------------------------- +function tScalar_asBool(self) + + class(tScalar), intent(in), target :: self + logical :: tScalar_asBool + + tScalar_asBool = IO_stringAsBool(self%value) + +end function tScalar_asBool + + +!-------------------------------------------------------------------------------------------------- +!> @brief Convert to string +!-------------------------------------------------------------------------------------------------- +function tScalar_asString(self) + + class(tScalar), intent(in), target :: self + character(len=:), allocatable :: tScalar_asString + + tScalar_asString = self%value + +end function tScalar_asString + + +!-------------------------------------------------------------------------------------------------- +!> @brief Convert to float array +!-------------------------------------------------------------------------------------------------- +function tList_asFloats(self) + + class(tList), intent(in), target :: self + real(pReal), dimension(:), allocatable :: tList_asFloats + + integer :: i + type(tItem), pointer :: item + type(tScalar), pointer :: scalar + + allocate(tList_asFloats(self%length)) + item => self%first + do i = 1, self%length + scalar => item%node%asScalar() + tList_asFloats(i) = scalar%asFloat() + item => item%next + enddo + +end function tList_asFloats + + +!-------------------------------------------------------------------------------------------------- +!> @brief Convert to int array +!-------------------------------------------------------------------------------------------------- +function tList_asInts(self) + + class(tList), intent(in), target :: self + integer, dimension(:), allocatable :: tList_asInts + + integer :: i + type(tItem), pointer :: item + type(tScalar), pointer :: scalar + + allocate(tList_asInts(self%length)) + item => self%first + do i = 1, self%length + scalar => item%node%asScalar() + tList_asInts(i) = scalar%asInt() + item => item%next + enddo + +end function tList_asInts + + +!-------------------------------------------------------------------------------------------------- +!> @brief Convert to bool array +!-------------------------------------------------------------------------------------------------- +function tList_asBools(self) + + class(tList), intent(in), target :: self + logical, dimension(:), allocatable :: tList_asBools + + integer :: i + type(tItem), pointer :: item + type(tScalar), pointer :: scalar + + allocate(tList_asBools(self%length)) + item => self%first + do i = 1, self%length + scalar => item%node%asScalar() + tList_asBools(i) = scalar%asBool() + item => item%next + enddo + +end function tList_asBools + + +!-------------------------------------------------------------------------------------------------- +!> @brief Convert to string array +!-------------------------------------------------------------------------------------------------- +function tList_asStrings(self) + + class(tList), intent(in), target :: self + character(len=:), allocatable, dimension(:) :: tList_asStrings + + integer :: i,len_max + type(tItem), pointer :: item + type(tScalar), pointer :: scalar + + len_max = 0 + allocate(character(len=pStringLen) :: tList_asStrings(self%length)) + item => self%first + do i = 1, self%length + scalar => item%node%asScalar() + tList_asStrings(i) = scalar%asString() + len_max = max(len_max, len_trim(tList_asStrings(i))) + item => item%next + enddo + + !ToDo: trim to len_max + +end function tList_asStrings + + +!-------------------------------------------------------------------------------------------------- +!> @brief Append element +!-------------------------------------------------------------------------------------------------- +subroutine tList_append(self,node) + + class(tList), intent(inout) :: self + class(tNode), intent(in) :: node + + type(tItem), pointer :: item + + if (.not. associated(self%first)) then + allocate(self%first) + item => self%first + else + item => self%first + do while (associated(item%next)) + item => item%next + end do + allocate(item%next) + item => item%next + end if + + allocate(item%node,source=node) ! ToDo: Discuss ownership (copy vs referencing) + self%length = self%length + 1 + +end subroutine tList_append + + +!-------------------------------------------------------------------------------------------------- +!> @brief Set the value of a key (either replace or add new) +!-------------------------------------------------------------------------------------------------- +subroutine tDict_set(self,key,node) + + class (tDict), intent(inout) :: self + character(len=*), intent(in) :: key + class(tNode), intent(in) :: node + + type(tItem), pointer :: item + + if (.not.associated(self%first)) then + allocate(self%first) + item => self%first + self%length = 1 + else + item => self%first + searchExisting: do while (associated(item%next)) + if (item%key == key) exit + item => item%next + end do searchExisting + if (.not. item%key == key) then + allocate(item%next) + item => item%next + self%length = self%length + 1 + end if + end if + + item%key = key + allocate(item%node,source=node) ! ToDo: Discuss ownership (copy vs referencing) + +end subroutine tDict_set + + +!-------------------------------------------------------------------------------------------------- +!> @brief empties dictionary and frees associated memory +!> @details called when variable goes out of scope. Triggers a chain reaction +!-------------------------------------------------------------------------------------------------- +recursive subroutine tDict_finalize(self) + + type (tDict),intent(inout) :: self + + type (tItem),pointer :: current, & + next + current => self%first + do while (associated(current)) + next => current%next + deallocate(current%node) + current => next + end do + nullify(self%first) + +end subroutine tDict_finalize + + +!-------------------------------------------------------------------------------------------------- +!> @brief empties lists and free associated memory +!> @details called when variable goes out of scope. +!-------------------------------------------------------------------------------------------------- +recursive subroutine tList_finalize(self) + + type (tList),intent(inout) :: self + + type (tItem),pointer :: current, & + next + current => self%first + do while (associated(current)) + next => current%next + deallocate(current%node) + current => next + end do + nullify(self%first) + +end subroutine tList_finalize + + +end module types diff --git a/src/commercialFEM_fileList.f90 b/src/commercialFEM_fileList.f90 index 64ad3e1d7..f13778f01 100644 --- a/src/commercialFEM_fileList.f90 +++ b/src/commercialFEM_fileList.f90 @@ -7,6 +7,7 @@ #include "numerics.f90" #include "debug.f90" #include "list.f90" +#include "YAML_types.f90" #include "future.f90" #include "config.f90" #include "LAPACK_interface.f90" From d61f302305782b208e3dca54859cba985a3c76bb Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 22 Apr 2020 15:26:29 +0200 Subject: [PATCH 119/186] no need for separate file --- src/Lambert.f90 | 201 ------------------ src/commercialFEM_fileList.f90 | 1 - src/rotations.f90 | 370 +++++++++++++++++++++++---------- 3 files changed, 258 insertions(+), 314 deletions(-) delete mode 100644 src/Lambert.f90 diff --git a/src/Lambert.f90 b/src/Lambert.f90 deleted file mode 100644 index 932fe221b..000000000 --- a/src/Lambert.f90 +++ /dev/null @@ -1,201 +0,0 @@ -! ################################################################### -! Copyright (c) 2013-2015, Marc De Graef/Carnegie Mellon University -! Modified 2017-2019, Martin Diehl/Max-Planck-Institut für Eisenforschung GmbH -! All rights reserved. -! -! Redistribution and use in source and binary forms, with or without modification, are -! permitted provided that the following conditions are met: -! -! - Redistributions of source code must retain the above copyright notice, this list -! of conditions and the following disclaimer. -! - Redistributions in binary form must reproduce the above copyright notice, this -! list of conditions and the following disclaimer in the documentation and/or -! other materials provided with the distribution. -! - Neither the names of Marc De Graef, Carnegie Mellon University nor the names -! of its contributors may be used to endorse or promote products derived from -! this software without specific prior written permission. -! -! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -! USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -! ################################################################### - -!-------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Mapping homochoric <-> cubochoric -! -!> @details -!> D. Rosca, A. Morawiec, and M. De Graef. “A new method of constructing a grid -!> in the space of 3D rotations and its applications to texture analysis”. -!> Modeling and Simulations in Materials Science and Engineering 22, 075013 (2014). -!-------------------------------------------------------------------------- -module Lambert - use prec - use math - - implicit none - private - - real(pReal), parameter :: & - SPI = sqrt(PI), & - PREF = sqrt(6.0_pReal/PI), & - A = PI**(5.0_pReal/6.0_pReal)/6.0_pReal**(1.0_pReal/6.0_pReal), & - AP = PI**(2.0_pReal/3.0_pReal), & - SC = A/AP, & - BETA = A/2.0_pReal, & - R1 = (3.0_pReal*PI/4.0_pReal)**(1.0_pReal/3.0_pReal), & - R2 = sqrt(2.0_pReal), & - PI12 = PI/12.0_pReal, & - PREK = R1 * 2.0_pReal**(1.0_pReal/4.0_pReal)/BETA - - public :: & - Lambert_CubeToBall, & - Lambert_BallToCube - -contains - - -!-------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief map from 3D cubic grid to 3D ball -!-------------------------------------------------------------------------- -pure function Lambert_CubeToBall(cube) result(ball) - - real(pReal), intent(in), dimension(3) :: cube - real(pReal), dimension(3) :: ball, LamXYZ, XYZ - real(pReal), dimension(2) :: T - real(pReal) :: c, s, q - real(pReal), parameter :: eps = 1.0e-8_pReal - integer, dimension(3,2) :: p - integer, dimension(2) :: order - - if (maxval(abs(cube)) > AP/2.0+eps) then - ball = IEEE_value(cube,IEEE_positive_inf) - return - end if - - ! transform to the sphere grid via the curved square, and intercept the zero point - center: if (all(dEq0(cube))) then - ball = 0.0_pReal - else center - ! get pyramide and scale by grid parameter ratio - p = GetPyramidOrder(cube) - XYZ = cube(p(:,1)) * sc - - ! intercept all the points along the z-axis - special: if (all(dEq0(XYZ(1:2)))) then - LamXYZ = [ 0.0_pReal, 0.0_pReal, pref * XYZ(3) ] - else special - order = merge( [2,1], [1,2], abs(XYZ(2)) <= abs(XYZ(1))) ! order of absolute values of XYZ - q = PI12 * XYZ(order(1))/XYZ(order(2)) ! smaller by larger - c = cos(q) - s = sin(q) - q = prek * XYZ(order(2))/ sqrt(R2-c) - T = [ (R2*c - 1.0), R2 * s] * q - - ! transform to sphere grid (inverse Lambert) - ! [note that there is no need to worry about dividing by zero, since XYZ(3) can not become zero] - c = sum(T**2) - s = Pi * c/(24.0*XYZ(3)**2) - c = sPi * c / sqrt(24.0_pReal) / XYZ(3) - q = sqrt( 1.0 - s ) - LamXYZ = [ T(order(2)) * q, T(order(1)) * q, pref * XYZ(3) - c ] - endif special - - ! reverse the coordinates back to order according to the original pyramid number - ball = LamXYZ(p(:,2)) - - endif center - -end function Lambert_CubeToBall - - -!-------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief map from 3D ball to 3D cubic grid -!-------------------------------------------------------------------------- -pure function Lambert_BallToCube(xyz) result(cube) - - real(pReal), intent(in), dimension(3) :: xyz - real(pReal), dimension(3) :: cube, xyz1, xyz3 - real(pReal), dimension(2) :: Tinv, xyz2 - real(pReal) :: rs, qxy, q2, sq2, q, tt - integer, dimension(3,2) :: p - - rs = norm2(xyz) - if (rs > R1) then - cube = IEEE_value(cube,IEEE_positive_inf) - return - endif - - center: if (all(dEq0(xyz))) then - cube = 0.0_pReal - else center - p = GetPyramidOrder(xyz) - xyz3 = xyz(p(:,1)) - - ! inverse M_3 - xyz2 = xyz3(1:2) * sqrt( 2.0*rs/(rs+abs(xyz3(3))) ) - - ! inverse M_2 - qxy = sum(xyz2**2) - - special: if (dEq0(qxy)) then - Tinv = 0.0_pReal - else special - q2 = qxy + maxval(abs(xyz2))**2 - sq2 = sqrt(q2) - q = (beta/R2/R1) * sqrt(q2*qxy/(q2-maxval(abs(xyz2))*sq2)) - tt = (minval(abs(xyz2))**2+maxval(abs(xyz2))*sq2)/R2/qxy - Tinv = q * sign(1.0_pReal,xyz2) * merge([ 1.0_pReal, acos(math_clip(tt,-1.0_pReal,1.0_pReal))/PI12], & - [ acos(math_clip(tt,-1.0_pReal,1.0_pReal))/PI12, 1.0_pReal], & - abs(xyz2(2)) <= abs(xyz2(1))) - endif special - - ! inverse M_1 - xyz1 = [ Tinv(1), Tinv(2), sign(1.0_pReal,xyz3(3)) * rs / pref ] /sc - - ! reverse the coordinates back to order according to the original pyramid number - cube = xyz1(p(:,2)) - - endif center - -end function Lambert_BallToCube - - -!-------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief determine to which pyramid a point in a cubic grid belongs -!-------------------------------------------------------------------------- -pure function GetPyramidOrder(xyz) - - real(pReal),intent(in),dimension(3) :: xyz - integer, dimension(3,2) :: GetPyramidOrder - - if (((abs(xyz(1)) <= xyz(3)).and.(abs(xyz(2)) <= xyz(3))) .or. & - ((abs(xyz(1)) <= -xyz(3)).and.(abs(xyz(2)) <= -xyz(3)))) then - GetPyramidOrder = reshape([[1,2,3],[1,2,3]],[3,2]) - else if (((abs(xyz(3)) <= xyz(1)).and.(abs(xyz(2)) <= xyz(1))) .or. & - ((abs(xyz(3)) <= -xyz(1)).and.(abs(xyz(2)) <= -xyz(1)))) then - GetPyramidOrder = reshape([[2,3,1],[3,1,2]],[3,2]) - else if (((abs(xyz(1)) <= xyz(2)).and.(abs(xyz(3)) <= xyz(2))) .or. & - ((abs(xyz(1)) <= -xyz(2)).and.(abs(xyz(3)) <= -xyz(2)))) then - GetPyramidOrder = reshape([[3,1,2],[2,3,1]],[3,2]) - else - GetPyramidOrder = -1 ! should be impossible, but might simplify debugging - end if - -end function GetPyramidOrder - -end module Lambert diff --git a/src/commercialFEM_fileList.f90 b/src/commercialFEM_fileList.f90 index 64ad3e1d7..ba614e253 100644 --- a/src/commercialFEM_fileList.f90 +++ b/src/commercialFEM_fileList.f90 @@ -12,7 +12,6 @@ #include "LAPACK_interface.f90" #include "math.f90" #include "quaternions.f90" -#include "Lambert.f90" #include "rotations.f90" #include "FEsolving.f90" #include "element.f90" diff --git a/src/rotations.f90 b/src/rotations.f90 index c20b9e905..98c529933 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -3,27 +3,27 @@ ! Modified 2017-2020, Martin Diehl/Max-Planck-Institut für Eisenforschung GmbH ! All rights reserved. ! -! Redistribution and use in source and binary forms, with or without modification, are +! Redistribution and use in source and binary forms, with or without modification, are ! permitted provided that the following conditions are met: ! -! - Redistributions of source code must retain the above copyright notice, this list +! - Redistributions of source code must retain the above copyright notice, this list ! of conditions and the following disclaimer. -! - Redistributions in binary form must reproduce the above copyright notice, this -! list of conditions and the following disclaimer in the documentation and/or +! - Redistributions in binary form must reproduce the above copyright notice, this +! list of conditions and the following disclaimer in the documentation and/or ! other materials provided with the distribution. -! - Neither the names of Marc De Graef, Carnegie Mellon University nor the names -! of its contributors may be used to endorse or promote products derived from +! - Neither the names of Marc De Graef, Carnegie Mellon University nor the names +! of its contributors may be used to endorse or promote products derived from ! this software without specific prior written permission. ! -! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ! USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ################################################################### @@ -31,7 +31,7 @@ !> @author Marc De Graef, Carnegie Mellon University !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH !> @brief rotation storage and conversion -!> @details: rotation is internally stored as quaternion. It can be inialized from different +!> @details: rotation is internally stored as quaternion. It can be inialized from different !> representations and also returns itself in different representations. ! ! All methods and naming conventions based on Rowenhorst_etal2015 @@ -50,9 +50,8 @@ module rotations use prec use IO use math - use Lambert use quaternions - + implicit none private @@ -80,7 +79,19 @@ module rotations procedure, public :: misorientation procedure, public :: standardize end type rotation - + + real(pReal), parameter :: & + SPI = sqrt(PI), & + PREF = sqrt(6.0_pReal/PI), & + A = PI**(5.0_pReal/6.0_pReal)/6.0_pReal**(1.0_pReal/6.0_pReal), & + AP = PI**(2.0_pReal/3.0_pReal), & + SC = A/AP, & + BETA = A/2.0_pReal, & + R1 = (3.0_pReal*PI/4.0_pReal)**(1.0_pReal/3.0_pReal), & + R2 = sqrt(2.0_pReal), & + PI12 = PI/12.0_pReal, & + PREK = R1 * 2.0_pReal**(1.0_pReal/4.0_pReal)/BETA + public :: & rotations_init, & eu2om @@ -106,16 +117,16 @@ pure function asQuaternion(self) class(rotation), intent(in) :: self real(pReal), dimension(4) :: asQuaternion - + asQuaternion = self%q%asArray() end function asQuaternion !--------------------------------------------------------------------------------------------------- pure function asEulers(self) - + class(rotation), intent(in) :: self real(pReal), dimension(3) :: asEulers - + asEulers = qu2eu(self%q%asArray()) end function asEulers @@ -124,16 +135,16 @@ pure function asAxisAngle(self) class(rotation), intent(in) :: self real(pReal), dimension(4) :: asAxisAngle - + asAxisAngle = qu2ax(self%q%asArray()) end function asAxisAngle !--------------------------------------------------------------------------------------------------- pure function asMatrix(self) - + class(rotation), intent(in) :: self real(pReal), dimension(3,3) :: asMatrix - + asMatrix = qu2om(self%q%asArray()) end function asMatrix @@ -142,20 +153,20 @@ pure function asRodrigues(self) class(rotation), intent(in) :: self real(pReal), dimension(4) :: asRodrigues - + asRodrigues = qu2ro(self%q%asArray()) - + end function asRodrigues !--------------------------------------------------------------------------------------------------- pure function asHomochoric(self) class(rotation), intent(in) :: self real(pReal), dimension(3) :: asHomochoric - + asHomochoric = qu2ho(self%q%asArray()) end function asHomochoric - + !--------------------------------------------------------------------------------------------------- ! Initialize rotation from different representations !--------------------------------------------------------------------------------------------------- @@ -207,7 +218,7 @@ subroutine fromAxisAngle(self,ax,degrees,P) else angle = merge(ax(4)*INRAD,ax(4),degrees) endif - + if (.not. present(P)) then axis = ax(1:3) else @@ -217,7 +228,7 @@ subroutine fromAxisAngle(self,ax,degrees,P) if(dNeq(norm2(axis),1.0_pReal) .or. angle < 0.0_pReal .or. angle > PI) & call IO_error(402,ext_msg='fromAxisAngle') - + self%q = ax2qu([axis,angle]) end subroutine fromAxisAngle @@ -240,10 +251,10 @@ end subroutine fromMatrix !> @brief: Rotate a rotation !--------------------------------------------------------------------------------------------------- pure elemental function rotRot__(self,R) result(rRot) - + type(rotation) :: rRot class(rotation), intent(in) :: self,R - + rRot = rotation(self%q*R%q) call rRot%standardize() @@ -251,12 +262,12 @@ end function rotRot__ !--------------------------------------------------------------------------------------------------- -!> @brief quaternion representation with positive q +!> @brief quaternion representation with positive q !--------------------------------------------------------------------------------------------------- pure elemental subroutine standardize(self) class(rotation), intent(inout) :: self - + if (real(self%q) < 0.0_pReal) self%q = self%q%homomorphed() end subroutine standardize @@ -267,22 +278,22 @@ end subroutine standardize !> @brief rotate a vector passively (default) or actively !--------------------------------------------------------------------------------------------------- pure function rotVector(self,v,active) result(vRot) - + real(pReal), dimension(3) :: vRot class(rotation), intent(in) :: self real(pReal), intent(in), dimension(3) :: v logical, intent(in), optional :: active - + real(pReal), dimension(3) :: v_normed type(quaternion) :: q logical :: passive - + if (present(active)) then passive = .not. active else passive = .true. endif - + if (dEq0(norm2(v))) then vRot = v else @@ -304,12 +315,12 @@ end function rotVector !> @details: rotation is based on rotation matrix !--------------------------------------------------------------------------------------------------- pure function rotTensor2(self,T,active) result(tRot) - + real(pReal), dimension(3,3) :: tRot class(rotation), intent(in) :: self real(pReal), intent(in), dimension(3,3) :: T logical, intent(in), optional :: active - + logical :: passive if (present(active)) then @@ -317,7 +328,7 @@ pure function rotTensor2(self,T,active) result(tRot) else passive = .true. endif - + if (passive) then tRot = matmul(matmul(self%asMatrix(),T),transpose(self%asMatrix())) else @@ -339,7 +350,7 @@ pure function rotTensor4(self,T,active) result(tRot) class(rotation), intent(in) :: self real(pReal), intent(in), dimension(3,3,3,3) :: T logical, intent(in), optional :: active - + real(pReal), dimension(3,3) :: R integer :: i,j,k,l,m,n,o,p @@ -370,7 +381,7 @@ pure function rotTensor4sym(self,T,active) result(tRot) class(rotation), intent(in) :: self real(pReal), intent(in), dimension(6,6) :: T logical, intent(in), optional :: active - + if (present(active)) then tRot = math_sym3333to66(rotTensor4(self,math_66toSym3333(T),active)) else @@ -384,10 +395,10 @@ end function rotTensor4sym !> @brief misorientation !--------------------------------------------------------------------------------------------------- pure elemental function misorientation(self,other) - + type(rotation) :: misorientation class(rotation), intent(in) :: self, other - + misorientation%q = other%q * conjg(self%q) end function misorientation @@ -401,7 +412,7 @@ pure function qu2om(qu) result(om) real(pReal), intent(in), dimension(4) :: qu real(pReal), dimension(3,3) :: om - + real(pReal) :: qq qq = qu(1)**2-sum(qu(2:4)**2) @@ -431,13 +442,13 @@ pure function qu2eu(qu) result(eu) real(pReal), intent(in), dimension(4) :: qu real(pReal), dimension(3) :: eu - + real(pReal) :: q12, q03, chi - + q03 = qu(1)**2+qu(4)**2 q12 = qu(2)**2+qu(3)**2 chi = sqrt(q03*q12) - + degenerated: if (dEq0(q12)) then eu = [atan2(-P*2.0_pReal*qu(1)*qu(4),qu(1)**2-qu(4)**2), 0.0_pReal, 0.0_pReal] elseif (dEq0(q03)) then @@ -460,7 +471,7 @@ pure function qu2ax(qu) result(ax) real(pReal), intent(in), dimension(4) :: qu real(pReal), dimension(4) :: ax - + real(pReal) :: omega, s if (dEq0(sum(qu(2:4)**2))) then @@ -481,13 +492,13 @@ end function qu2ax !> @brief convert unit quaternion to Rodrigues vector !--------------------------------------------------------------------------------------------------- pure function qu2ro(qu) result(ro) - + real(pReal), intent(in), dimension(4) :: qu real(pReal), dimension(4) :: ro - + real(pReal) :: s real(pReal), parameter :: thr = 1.0e-8_pReal - + if (abs(qu(1)) < thr) then ro = [qu(2), qu(3), qu(4), IEEE_value(1.0_pReal,IEEE_positive_inf)] else @@ -497,7 +508,7 @@ pure function qu2ro(qu) result(ro) else ro = [qu(2)/s,qu(3)/s,qu(4)/s, tan(acos(math_clip(qu(1),-1.0_pReal,1.0_pReal)))] endif - + end if end function qu2ro @@ -511,11 +522,11 @@ pure function qu2ho(qu) result(ho) real(pReal), intent(in), dimension(4) :: qu real(pReal), dimension(3) :: ho - + real(pReal) :: omega, f omega = 2.0 * acos(math_clip(qu(1),-1.0_pReal,1.0_pReal)) - + if (dEq0(omega)) then ho = [ 0.0_pReal, 0.0_pReal, 0.0_pReal ] else @@ -532,7 +543,7 @@ end function qu2ho !> @brief convert unit quaternion to cubochoric !--------------------------------------------------------------------------------------------------- pure function qu2cu(qu) result(cu) - + real(pReal), intent(in), dimension(4) :: qu real(pReal), dimension(3) :: cu @@ -565,18 +576,18 @@ pure function om2eu(om) result(eu) real(pReal), intent(in), dimension(3,3) :: om real(pReal), dimension(3) :: eu real(pReal) :: zeta - + if (abs(om(3,3)) < 1.0_pReal) then zeta = 1.0_pReal/sqrt(1.0_pReal-om(3,3)**2.0_pReal) eu = [atan2(om(3,1)*zeta,-om(3,2)*zeta), & acos(om(3,3)), & atan2(om(1,3)*zeta, om(2,3)*zeta)] - else + else eu = [atan2(om(1,2),om(1,1)), 0.5_pReal*PI*(1.0_pReal-om(3,3)),0.0_pReal ] end if where(eu<0.0_pReal) eu = mod(eu+2.0_pReal*PI,[2.0_pReal*PI,PI,2.0_pReal*PI]) - + end function om2eu @@ -588,19 +599,19 @@ function om2ax(om) result(ax) real(pReal), intent(in), dimension(3,3) :: om real(pReal), dimension(4) :: ax - + real(pReal) :: t real(pReal), dimension(3) :: Wr, Wi real(pReal), dimension((64+2)*3) :: work real(pReal), dimension(3,3) :: VR, devNull, om_ integer :: ierr, i - + om_ = om - + ! first get the rotation angle t = 0.5_pReal * (math_trace33(om) - 1.0_pReal) ax(4) = acos(math_clip(t,-1.0_pReal,1.0_pReal)) - + if (dEq0(ax(4))) then ax(1:3) = [ 0.0_pReal, 0.0_pReal, 1.0_pReal ] else @@ -674,7 +685,7 @@ pure function eu2qu(eu) result(qu) real(pReal) :: cPhi, sPhi ee = 0.5_pReal*eu - + cPhi = cos(ee(2)) sPhi = sin(ee(2)) @@ -692,15 +703,15 @@ end function eu2qu !> @brief Euler angles to orientation matrix !--------------------------------------------------------------------------------------------------- pure function eu2om(eu) result(om) - + real(pReal), intent(in), dimension(3) :: eu real(pReal), dimension(3,3) :: om - - real(pReal), dimension(3) :: c, s - + + real(pReal), dimension(3) :: c, s + c = cos(eu) s = sin(eu) - + om(1,1) = c(1)*c(3)-s(1)*s(3)*c(2) om(1,2) = s(1)*c(3)+c(1)*s(3)*c(2) om(1,3) = s(3)*s(2) @@ -710,7 +721,7 @@ pure function eu2om(eu) result(om) om(3,1) = s(1)*s(2) om(3,2) = -c(1)*s(2) om(3,3) = c(2) - + where(dEq0(om)) om = 0.0_pReal end function eu2om @@ -721,19 +732,19 @@ end function eu2om !> @brief convert euler to axis angle !--------------------------------------------------------------------------------------------------- pure function eu2ax(eu) result(ax) - + real(pReal), intent(in), dimension(3) :: eu real(pReal), dimension(4) :: ax - + real(pReal) :: t, delta, tau, alpha, sigma - + t = tan(eu(2)*0.5_pReal) sigma = 0.5_pReal*(eu(1)+eu(3)) delta = 0.5_pReal*(eu(1)-eu(3)) tau = sqrt(t**2+sin(sigma)**2) - + alpha = merge(PI, 2.0_pReal*atan(tau/cos(sigma)), dEq(sigma,PI*0.5_pReal,tol=1.0e-15_pReal)) - + if (dEq0(alpha)) then ! return a default identity axis-angle pair ax = [ 0.0_pReal, 0.0_pReal, 1.0_pReal, 0.0_pReal ] else @@ -741,7 +752,7 @@ pure function eu2ax(eu) result(ax) ax(4) = alpha if (alpha < 0.0_pReal) ax = -ax ! ensure alpha is positive end if - + end function eu2ax @@ -753,7 +764,7 @@ pure function eu2ro(eu) result(ro) real(pReal), intent(in), dimension(3) :: eu real(pReal), dimension(4) :: ro - + ro = eu2ax(eu) if (ro(4) >= PI) then ro(4) = IEEE_value(ro(4),IEEE_positive_inf) @@ -762,7 +773,7 @@ pure function eu2ro(eu) result(ro) else ro(4) = tan(ro(4)*0.5_pReal) end if - + end function eu2ro @@ -799,7 +810,7 @@ end function eu2cu !> @brief convert axis angle pair to quaternion !--------------------------------------------------------------------------------------------------- pure function ax2qu(ax) result(qu) - + real(pReal), intent(in), dimension(4) :: ax real(pReal), dimension(4) :: qu @@ -825,7 +836,7 @@ pure function ax2om(ax) result(om) real(pReal), intent(in), dimension(4) :: ax real(pReal), dimension(3,3) :: om - + real(pReal) :: q, c, s, omc c = cos(ax(4)) @@ -839,11 +850,11 @@ pure function ax2om(ax) result(om) q = omc*ax(1)*ax(2) om(1,2) = q + s*ax(3) om(2,1) = q - s*ax(3) - + q = omc*ax(2)*ax(3) om(2,3) = q + s*ax(1) om(3,2) = q - s*ax(1) - + q = omc*ax(3)*ax(1) om(3,1) = q + s*ax(2) om(1,3) = q - s*ax(2) @@ -875,12 +886,12 @@ pure function ax2ro(ax) result(ro) real(pReal), intent(in), dimension(4) :: ax real(pReal), dimension(4) :: ro - + real(pReal), parameter :: thr = 1.0e-7_pReal - + if (dEq0(ax(4))) then ro = [ 0.0_pReal, 0.0_pReal, P, 0.0_pReal ] - else + else ro(1:3) = ax(1:3) ! we need to deal with the 180 degree case ro(4) = merge(IEEE_value(ro(4),IEEE_positive_inf),tan(ax(4)*0.5_pReal),abs(ax(4)-PI) < thr) @@ -897,9 +908,9 @@ pure function ax2ho(ax) result(ho) real(pReal), intent(in), dimension(4) :: ax real(pReal), dimension(3) :: ho - + real(pReal) :: f - + f = 0.75_pReal * ( ax(4) - sin(ax(4)) ) f = f**(1.0_pReal/3.0_pReal) ho = ax(1:3) * f @@ -929,7 +940,7 @@ pure function ro2qu(ro) result(qu) real(pReal), intent(in), dimension(4) :: ro real(pReal), dimension(4) :: qu - + qu = ax2qu(ro2ax(ro)) end function ro2qu @@ -957,7 +968,7 @@ pure function ro2eu(ro) result(eu) real(pReal), intent(in), dimension(4) :: ro real(pReal), dimension(3) :: eu - + eu = om2eu(ro2om(ro)) end function ro2eu @@ -971,14 +982,14 @@ pure function ro2ax(ro) result(ax) real(pReal), intent(in), dimension(4) :: ro real(pReal), dimension(4) :: ax - + real(pReal) :: ta, angle - + ta = ro(4) - + if (.not. IEEE_is_finite(ta)) then ax = [ ro(1), ro(2), ro(3), PI ] - elseif (dEq0(ta)) then + elseif (dEq0(ta)) then ax = [ 0.0_pReal, 0.0_pReal, 1.0_pReal, 0.0_pReal ] else angle = 2.0_pReal*atan(ta) @@ -997,9 +1008,9 @@ pure function ro2ho(ro) result(ho) real(pReal), intent(in), dimension(4) :: ro real(pReal), dimension(3) :: ho - + real(pReal) :: f - + if (dEq0(norm2(ro(1:3)))) then ho = [ 0.0_pReal, 0.0_pReal, 0.0_pReal ] else @@ -1074,26 +1085,26 @@ pure function ho2ax(ho) result(ax) real(pReal), intent(in), dimension(3) :: ho real(pReal), dimension(4) :: ax - + integer :: i real(pReal) :: hmag_squared, s, hm real(pReal), parameter, dimension(16) :: & - tfit = [ 1.0000000000018852_pReal, -0.5000000002194847_pReal, & - -0.024999992127593126_pReal, -0.003928701544781374_pReal, & - -0.0008152701535450438_pReal, -0.0002009500426119712_pReal, & - -0.00002397986776071756_pReal, -0.00008202868926605841_pReal, & - +0.00012448715042090092_pReal, -0.0001749114214822577_pReal, & - +0.0001703481934140054_pReal, -0.00012062065004116828_pReal, & - +0.000059719705868660826_pReal, -0.00001980756723965647_pReal, & + tfit = [ 1.0000000000018852_pReal, -0.5000000002194847_pReal, & + -0.024999992127593126_pReal, -0.003928701544781374_pReal, & + -0.0008152701535450438_pReal, -0.0002009500426119712_pReal, & + -0.00002397986776071756_pReal, -0.00008202868926605841_pReal, & + +0.00012448715042090092_pReal, -0.0001749114214822577_pReal, & + +0.0001703481934140054_pReal, -0.00012062065004116828_pReal, & + +0.000059719705868660826_pReal, -0.00001980756723965647_pReal, & +0.000003953714684212874_pReal, -0.00000036555001439719544_pReal ] - + ! normalize h and store the magnitude hmag_squared = sum(ho**2.0_pReal) if (dEq0(hmag_squared)) then ax = [ 0.0_pReal, 0.0_pReal, 1.0_pReal, 0.0_pReal ] else hm = hmag_squared - + ! convert the magnitude to the rotation angle s = tfit(1) + tfit(2) * hmag_squared do i=3,16 @@ -1217,12 +1228,147 @@ pure function cu2ho(cu) result(ho) end function cu2ho +!-------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief map from 3D cubic grid to 3D ball +!-------------------------------------------------------------------------- +pure function Lambert_CubeToBall(cube) result(ball) + + real(pReal), intent(in), dimension(3) :: cube + real(pReal), dimension(3) :: ball, LamXYZ, XYZ + real(pReal), dimension(2) :: T + real(pReal) :: c, s, q + real(pReal), parameter :: eps = 1.0e-8_pReal + integer, dimension(3,2) :: p + integer, dimension(2) :: order + + if (maxval(abs(cube)) > AP/2.0+eps) then + ball = IEEE_value(cube,IEEE_positive_inf) + return + end if + + ! transform to the sphere grid via the curved square, and intercept the zero point + center: if (all(dEq0(cube))) then + ball = 0.0_pReal + else center + ! get pyramide and scale by grid parameter ratio + p = GetPyramidOrder(cube) + XYZ = cube(p(:,1)) * sc + + ! intercept all the points along the z-axis + special: if (all(dEq0(XYZ(1:2)))) then + LamXYZ = [ 0.0_pReal, 0.0_pReal, pref * XYZ(3) ] + else special + order = merge( [2,1], [1,2], abs(XYZ(2)) <= abs(XYZ(1))) ! order of absolute values of XYZ + q = PI12 * XYZ(order(1))/XYZ(order(2)) ! smaller by larger + c = cos(q) + s = sin(q) + q = prek * XYZ(order(2))/ sqrt(R2-c) + T = [ (R2*c - 1.0), R2 * s] * q + + ! transform to sphere grid (inverse Lambert) + ! [note that there is no need to worry about dividing by zero, since XYZ(3) can not become zero] + c = sum(T**2) + s = Pi * c/(24.0*XYZ(3)**2) + c = sPi * c / sqrt(24.0_pReal) / XYZ(3) + q = sqrt( 1.0 - s ) + LamXYZ = [ T(order(2)) * q, T(order(1)) * q, pref * XYZ(3) - c ] + endif special + + ! reverse the coordinates back to order according to the original pyramid number + ball = LamXYZ(p(:,2)) + + endif center + +end function Lambert_CubeToBall + + +!-------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief map from 3D ball to 3D cubic grid +!-------------------------------------------------------------------------- +pure function Lambert_BallToCube(xyz) result(cube) + + real(pReal), intent(in), dimension(3) :: xyz + real(pReal), dimension(3) :: cube, xyz1, xyz3 + real(pReal), dimension(2) :: Tinv, xyz2 + real(pReal) :: rs, qxy, q2, sq2, q, tt + integer, dimension(3,2) :: p + + rs = norm2(xyz) + if (rs > R1) then + cube = IEEE_value(cube,IEEE_positive_inf) + return + endif + + center: if (all(dEq0(xyz))) then + cube = 0.0_pReal + else center + p = GetPyramidOrder(xyz) + xyz3 = xyz(p(:,1)) + + ! inverse M_3 + xyz2 = xyz3(1:2) * sqrt( 2.0*rs/(rs+abs(xyz3(3))) ) + + ! inverse M_2 + qxy = sum(xyz2**2) + + special: if (dEq0(qxy)) then + Tinv = 0.0_pReal + else special + q2 = qxy + maxval(abs(xyz2))**2 + sq2 = sqrt(q2) + q = (beta/R2/R1) * sqrt(q2*qxy/(q2-maxval(abs(xyz2))*sq2)) + tt = (minval(abs(xyz2))**2+maxval(abs(xyz2))*sq2)/R2/qxy + Tinv = q * sign(1.0_pReal,xyz2) * merge([ 1.0_pReal, acos(math_clip(tt,-1.0_pReal,1.0_pReal))/PI12], & + [ acos(math_clip(tt,-1.0_pReal,1.0_pReal))/PI12, 1.0_pReal], & + abs(xyz2(2)) <= abs(xyz2(1))) + endif special + + ! inverse M_1 + xyz1 = [ Tinv(1), Tinv(2), sign(1.0_pReal,xyz3(3)) * rs / pref ] /sc + + ! reverse the coordinates back to order according to the original pyramid number + cube = xyz1(p(:,2)) + + endif center + +end function Lambert_BallToCube + + +!-------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief determine to which pyramid a point in a cubic grid belongs +!-------------------------------------------------------------------------- +pure function GetPyramidOrder(xyz) + + real(pReal),intent(in),dimension(3) :: xyz + integer, dimension(3,2) :: GetPyramidOrder + + if (((abs(xyz(1)) <= xyz(3)).and.(abs(xyz(2)) <= xyz(3))) .or. & + ((abs(xyz(1)) <= -xyz(3)).and.(abs(xyz(2)) <= -xyz(3)))) then + GetPyramidOrder = reshape([[1,2,3],[1,2,3]],[3,2]) + else if (((abs(xyz(3)) <= xyz(1)).and.(abs(xyz(2)) <= xyz(1))) .or. & + ((abs(xyz(3)) <= -xyz(1)).and.(abs(xyz(2)) <= -xyz(1)))) then + GetPyramidOrder = reshape([[2,3,1],[3,1,2]],[3,2]) + else if (((abs(xyz(1)) <= xyz(2)).and.(abs(xyz(3)) <= xyz(2))) .or. & + ((abs(xyz(1)) <= -xyz(2)).and.(abs(xyz(3)) <= -xyz(2)))) then + GetPyramidOrder = reshape([[3,1,2],[2,3,1]],[3,2]) + else + GetPyramidOrder = -1 ! should be impossible, but might simplify debugging + end if + +end function GetPyramidOrder + !-------------------------------------------------------------------------------------------------- !> @brief check correctness of some rotations functions !-------------------------------------------------------------------------------------------------- subroutine unitTest - + type(rotation) :: R real(pReal), dimension(4) :: qu, ax, ro real(pReal), dimension(3) :: x, eu, ho, v3 @@ -1233,7 +1379,7 @@ subroutine unitTest integer :: i do i=1,10 - + msg = '' #if defined(__GFORTRAN__) && __GNUC__<9 @@ -1307,15 +1453,15 @@ subroutine unitTest #endif call R%fromMatrix(om) - + call random_number(v3) if(all(dNeq(R%rotVector(R%rotVector(v3),active=.true.),v3,1.0e-12_pReal))) & msg = trim(msg)//'rotVector,' - + call random_number(t33) if(all(dNeq(R%rotTensor2(R%rotTensor2(t33),active=.true.),t33,1.0e-12_pReal))) & msg = trim(msg)//'rotTensor2,' - + call random_number(t3333) if(all(dNeq(R%rotTensor4(R%rotTensor4(t3333),active=.true.),t3333,1.0e-12_pReal))) & msg = trim(msg)//'rotTensor4,' From 6a0a8f1d275e88a5788045b85600f74f06f96794 Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Wed, 22 Apr 2020 15:51:05 +0200 Subject: [PATCH 120/186] Fortran syntax check showed an error --- src/YAML_types.f90 | 54 ++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index 165a34033..049029203 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -33,25 +33,43 @@ module types asList => tNode_asList procedure :: & asDict => tNode_asDict + procedure :: & + tNode_get_byIndex => tNode_get_byIndex procedure :: & - tNode_get_byIndex, & - tNode_get_byIndex_asFloat, & - tNode_get_byIndex_asFloats, & - tNode_get_byIndex_asInt, & - tNode_get_byIndex_asInts, & - tNode_get_byIndex_asBool, & - tNode_get_byIndex_asBools, & - tNode_get_byIndex_asString, & - tNode_get_byIndex_asStrings, & - tNode_get_byKey, & - tNode_get_byKey_asFloat, & - tNode_get_byKey_asFloats, & - tNode_get_byKey_asInt, & - tNode_get_byKey_asInts, & - tNode_get_byKey_asBool, & - tNode_get_byKey_asBools, & - tNode_get_byKey_asString, & - tNode_get_byKey_asStrings + tNode_get_byIndex_asFloat => tNode_get_byIndex_asFloat + procedure :: & + tNode_get_byIndex_asFloats => tNode_get_byIndex_asFloats + procedure :: & + tNode_get_byIndex_asInt => tNode_get_byIndex_asInt + procedure :: & + tNode_get_byIndex_asInts => tNode_get_byIndex_asInts + procedure :: & + tNode_get_byIndex_asBool => tNode_get_byIndex_asBool + procedure :: & + tNode_get_byIndex_asBools => tNode_get_byIndex_asBools + procedure :: & + tNode_get_byIndex_asString => tNode_get_byIndex_asString + procedure :: & + tNode_get_byIndex_asStrings => tNode_get_byIndex_asStrings + procedure :: & + tNode_get_byKey => tNode_get_byKey + procedure :: & + tNode_get_byKey_asFloat => tNode_get_byKey_asFloat + procedure :: & + tNode_get_byKey_asFloats => tNode_get_byKey_asFloats + procedure :: & + tNode_get_byKey_asInt => tNode_get_byKey_asInt + procedure :: & + tNode_get_byKey_asInts => tNode_get_byKey_asInts + procedure :: & + tNode_get_byKey_asBool => tNode_get_byKey_asBool + procedure :: & + tNode_get_byKey_asBools => tNode_get_byKey_asBools + procedure :: & + tNode_get_byKey_asString => tNode_get_byKey_asString + procedure :: & + tNode_get_byKey_asStrings => tNode_get_byKey_asStrings + generic :: & get => tNode_get_byIndex, & tNode_get_byKey From 11c4ff7787f2d980fd527f3d8f804a8df27e3ddc Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Wed, 22 Apr 2020 16:49:31 +0200 Subject: [PATCH 121/186] finalization error --- src/YAML_types.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index 049029203..2edff3a58 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -984,7 +984,7 @@ recursive subroutine tList_finalize(self) current => self%first do while (associated(current)) next => current%next - deallocate(current%node) + if(allocated(current%node)) deallocate(current%node) current => next end do nullify(self%first) From 936ce6a160020e2b038805e8091757665362ce8e Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 22 Apr 2020 18:26:10 +0200 Subject: [PATCH 122/186] reshape for scalar/vector not needed --- processing/post/addGradient.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/processing/post/addGradient.py b/processing/post/addGradient.py index c6df0eacf..f63f24789 100755 --- a/processing/post/addGradient.py +++ b/processing/post/addGradient.py @@ -49,7 +49,7 @@ for name in filenames: for label in options.labels: field = table.get(label) shape = (1,) if np.prod(field.shape)//np.prod(grid) == 1 else (3,) # scalar or vector - field = field.reshape(tuple(grid)+(-1,),order='F').reshape(tuple(grid)+shape) + field = field.reshape(tuple(grid)+(-1,),order='F') grad = damask.grid_filters.gradient(size,field) table.add('gradFFT({})'.format(label), grad.reshape(tuple(grid)+(-1,)).reshape(-1,np.prod(shape)*3,order='F'), From 12d7fa7fda5f24d7725ad41205ef10235c3d2e97 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 23 Apr 2020 09:59:31 +0200 Subject: [PATCH 123/186] migrated to new class --- processing/post/permuteData.py | 77 +++++++--------------------------- 1 file changed, 14 insertions(+), 63 deletions(-) diff --git a/processing/post/permuteData.py b/processing/post/permuteData.py index 81af71adb..c271227d5 100755 --- a/processing/post/permuteData.py +++ b/processing/post/permuteData.py @@ -2,6 +2,7 @@ import os import sys +from io import StringIO from optparse import OptionParser import numpy as np @@ -41,73 +42,23 @@ parser.set_defaults(label = [], ) (options,filenames) = parser.parse_args() - -if len(options.label) == 0: - parser.error('no labels specified.') - -# --- loop over input files ------------------------------------------------------------------------- - if filenames == []: filenames = [None] for name in filenames: - try: - table = damask.ASCIItable(name = name) - except IOError: - continue - damask.util.report(scriptName,name) + damask.util.report(scriptName,name) -# ------------------------------------------ read header ------------------------------------------ + table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - table.head_read() + randomSeed = int(os.urandom(4).hex(), 16) if options.randomSeed is None else options.randomSeed # random seed per file + np.random.seed(randomSeed) -# ------------------------------------------ process labels --------------------------------------- + for label in options.label: + data = table.get(label) + if options.unique: + uniques,inverse = np.unique(data,return_inverse=True,axis=0) + np.random.shuffle(uniques) + table.set(label,uniques[inverse], scriptID+' '+' '.join(sys.argv[1:])) + else: + table.set(label,np.random.permutation(data), scriptID+' '+' '.join(sys.argv[1:])) - errors = [] - remarks = [] - columns = [] - dims = [] - - indices = table.label_index (options.label) - dimensions = table.label_dimension(options.label) - for i,index in enumerate(indices): - if index == -1: remarks.append('label "{}" not present...'.format(options.label[i])) - else: - columns.append(index) - dims.append(dimensions[i]) - - if remarks != []: damask.util.croak(remarks) - if errors != []: - damask.util.croak(errors) - table.close(dismiss = True) - continue - -# ------------------------------------------ assemble header --------------------------------------- - - randomSeed = int(os.urandom(4).hex(), 16) if options.randomSeed is None else options.randomSeed # random seed per file - np.random.seed(randomSeed) - - table.info_append([scriptID + '\t' + ' '.join(sys.argv[1:]), - 'random seed {}'.format(randomSeed), - ]) - table.head_write() - -# ------------------------------------------ process data ------------------------------------------ - - table.data_readArray() # read all data at once - for col,dim in zip(columns,dims): - if options.unique: - s = set(map(tuple,table.data[:,col:col+dim])) # generate set of (unique) values - uniques = np.array(map(np.array,s)) # translate set to np.array - shuffler = dict(zip(s,np.random.permutation(len(s)))) # random permutation - table.data[:,col:col+dim] = uniques[np.array(map(lambda x: shuffler[tuple(x)], - table.data[:,col:col+dim]))] # fill table with mapped uniques - else: - np.random.shuffle(table.data[:,col:col+dim]) # independently shuffle every row - -# ------------------------------------------ output result ----------------------------------------- - - table.data_writeArray() - -# ------------------------------------------ output finalization ----------------------------------- - - table.close() # close ASCII tables + table.to_ASCII(sys.stdout if name is None else name) From a3d54c5621878b012685d1dc5898b2486815ed3e Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 23 Apr 2020 10:08:29 +0200 Subject: [PATCH 124/186] just boilerplate code --- processing/misc/ang_toTable.py | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100755 processing/misc/ang_toTable.py diff --git a/processing/misc/ang_toTable.py b/processing/misc/ang_toTable.py deleted file mode 100755 index 5579f2466..000000000 --- a/processing/misc/ang_toTable.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -import damask - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -#-------------------------------------------------------------------------------------------------- -# MAIN -#-------------------------------------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog [angfile[s]]', description = """ -Convert TSL/EDAX *.ang file to ASCIItable - -""", version = scriptID) - -(options, filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.from_ang(StringIO(''.join(sys.stdin.read())) if name is None else name) - table.to_ASCII(sys.stdout if name is None else os.path.splitext(name)[0]+'.txt') From 7fe2a52b65eb8e22aeadb731a95818504e6c1f9d Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Thu, 23 Apr 2020 17:10:33 +0200 Subject: [PATCH 125/186] better logic for finalization --- src/YAML_types.f90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index 2edff3a58..e951c2c83 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -214,7 +214,7 @@ subroutine unitTest call l1%append(s2) call l2%append(l1) n=> l1 - + if(any(l1%asBools() .neqv. [.true., .false.])) call IO_error(0,ext_msg='tList_asBools') if(any(l1%asStrings() /= ['True ','False'])) call IO_error(0,ext_msg='tList_asStrings') if(n%get_asBool(2)) call IO_error(0,ext_msg='byIndex_asBool') @@ -960,13 +960,13 @@ recursive subroutine tDict_finalize(self) type (tItem),pointer :: current, & next + current => self%first do while (associated(current)) next => current%next - deallocate(current%node) + deallocate(current) current => next end do - nullify(self%first) end subroutine tDict_finalize @@ -981,13 +981,13 @@ recursive subroutine tList_finalize(self) type (tItem),pointer :: current, & next + current => self%first do while (associated(current)) next => current%next - if(allocated(current%node)) deallocate(current%node) + deallocate(current) current => next end do - nullify(self%first) end subroutine tList_finalize From f0e2437d751b23f98f7cfa8cceb8805c7cf5b2e0 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Wed, 22 Apr 2020 21:36:05 -0400 Subject: [PATCH 126/186] [skip ci] added "list(map..." required since Python3 --- processing/post/permuteData.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/processing/post/permuteData.py b/processing/post/permuteData.py index 81af71adb..72759f2ce 100755 --- a/processing/post/permuteData.py +++ b/processing/post/permuteData.py @@ -60,7 +60,7 @@ for name in filenames: table.head_read() -# ------------------------------------------ process labels --------------------------------------- +# ------------------------------------------ process labels --------------------------------------- errors = [] remarks = [] @@ -80,7 +80,7 @@ for name in filenames: damask.util.croak(errors) table.close(dismiss = True) continue - + # ------------------------------------------ assemble header --------------------------------------- randomSeed = int(os.urandom(4).hex(), 16) if options.randomSeed is None else options.randomSeed # random seed per file @@ -97,17 +97,17 @@ for name in filenames: for col,dim in zip(columns,dims): if options.unique: s = set(map(tuple,table.data[:,col:col+dim])) # generate set of (unique) values - uniques = np.array(map(np.array,s)) # translate set to np.array + uniques = np.array(list(map(np.array,s))) # translate set to np.array shuffler = dict(zip(s,np.random.permutation(len(s)))) # random permutation - table.data[:,col:col+dim] = uniques[np.array(map(lambda x: shuffler[tuple(x)], - table.data[:,col:col+dim]))] # fill table with mapped uniques + table.data[:,col:col+dim] = uniques[np.array(list(map(lambda x: shuffler[tuple(x)], + table.data[:,col:col+dim])))] # fill table with mapped uniques else: np.random.shuffle(table.data[:,col:col+dim]) # independently shuffle every row -# ------------------------------------------ output result ----------------------------------------- +# ------------------------------------------ output result ----------------------------------------- table.data_writeArray() -# ------------------------------------------ output finalization ----------------------------------- +# ------------------------------------------ output finalization ----------------------------------- table.close() # close ASCII tables From b2f8e8847fc6395e03fab058a6be6ad7f530b44e Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 23 Apr 2020 21:34:11 +0200 Subject: [PATCH 127/186] [skip ci] updated version information after successful test of v2.0.3-2339-g28980887 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7cb1691ed..10a6e2bdb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2311-gf1afc159 +v2.0.3-2339-g28980887 From 62f7363a29cac549a5853185ede1dfd78c27cf45 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 23 Apr 2020 22:11:57 +0200 Subject: [PATCH 128/186] orientation conversion test in PRIVATE has the tendency to fail new tolerances lead more often to a transfer from phi_2 to phi_1 for PHI=180 or PHI=0. The pytest takes care of that, the deprecated test in PRIVATE not --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dd20c8baa..501b9e193 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -203,7 +203,6 @@ Post_OrientationConversion: stage: postprocessing script: - OrientationConversion/test.py - - OrientationConversion/test2.py except: - master - release From 05fd943cf480868d6a1d486281808185ed012bba Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 24 Apr 2020 00:45:37 +0200 Subject: [PATCH 129/186] [skip ci] updated version information after successful test of v2.0.3-2364-g62f7363a --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 10a6e2bdb..6e24519bd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2339-g28980887 +v2.0.3-2364-g62f7363a From 707324887f562c4449ff2091082abdcb1246a71c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 24 Apr 2020 06:52:09 +0200 Subject: [PATCH 130/186] inform the user about planned functionality --- python/damask/_orientation.py | 3 +++ python/damask/_rotation.py | 14 +++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/python/damask/_orientation.py b/python/damask/_orientation.py index 76475e057..e6c732007 100644 --- a/python/damask/_orientation.py +++ b/python/damask/_orientation.py @@ -38,6 +38,9 @@ class Orientation: else: self.rotation = Rotation.fromQuaternion(rotation) # assume quaternion + if self.rotation.quaternion.shape != (4,): + raise NotImplementedError('Support for multiple rotations missing') + def disorientation(self, other, SST = True, diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 6076b4add..716977a79 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -63,7 +63,7 @@ class Rotation: def __repr__(self): """Orientation displayed as unit quaternion, rotation matrix, and Bunge-Euler angles.""" if self.quaternion.shape != (4,): - raise NotImplementedError + raise NotImplementedError('Support for multiple rotations missing') return '\n'.join([ 'Quaternion: (real={:.3f}, imag=<{:+.3f}, {:+.3f}, {:+.3f}>)'.format(*(self.quaternion)), 'Matrix:\n{}'.format(self.asMatrix()), @@ -86,6 +86,8 @@ class Rotation: considere rotation of (3,3,3,3)-matrix """ + if self.quaternion.shape != (4,): + raise NotImplementedError('Support for multiple rotations missing') if isinstance(other, Rotation): # rotate a rotation self_q = self.quaternion[0] self_p = self.quaternion[1:] @@ -110,7 +112,7 @@ class Rotation: elif other.shape == (3,3,): # rotate a single (3x3)-matrix return np.dot(self.asMatrix(),np.dot(other,self.asMatrix().T)) elif other.shape == (3,3,3,3,): - raise NotImplementedError + raise NotImplementedError('Support for rotation of 4th order tensors missing') else: return NotImplemented else: @@ -133,7 +135,7 @@ class Rotation: return self def standardized(self): - """Quaternion representation with positive real.""" + """Quaternion representation with positive real part.""" return self.copy().standardize() @@ -160,6 +162,8 @@ class Rotation: Rotation from which the average is rotated. """ + if self.quaternion.shape != (4,) or other.quaternion.shape != (4,): + raise NotImplementedError('Support for multiple rotations missing') return Rotation.fromAverage([self,other]) @@ -1047,7 +1051,7 @@ class Rotation: if len(ho.shape) == 1: return ball_to_cube(ho) else: - raise NotImplementedError + raise NotImplementedError('Support for multiple rotations missing') #---------- Cubochoric ---------- @@ -1082,4 +1086,4 @@ class Rotation: if len(cu.shape) == 1: return cube_to_ball(cu) else: - raise NotImplementedError + raise NotImplementedError('Support for multiple rotations missing') From 97438713ccbed90d2da6ceedfcb3a80f082b8333 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 24 Apr 2020 12:55:59 +0200 Subject: [PATCH 131/186] require numpy array --- processing/post/addSchmidfactors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/processing/post/addSchmidfactors.py b/processing/post/addSchmidfactors.py index 94c062766..b3c4c7500 100755 --- a/processing/post/addSchmidfactors.py +++ b/processing/post/addSchmidfactors.py @@ -214,7 +214,7 @@ for name in filenames: outputAlive = True while outputAlive and table.data_read(): # read next data line of ASCII table - o = damask.Rotation(list(map(float,table.data[column:column+4]))) + o = damask.Rotation(np.array(list(map(float,table.data[column:column+4])))) table.data_append( np.abs( np.sum(slip_direction * (o * force) ,axis=1) \ * np.sum(slip_normal * (o * normal),axis=1))) From ca6aa4bcd1ba6036aa0ac7d40c481085fe8c0046 Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Fri, 24 Apr 2020 16:50:42 +0200 Subject: [PATCH 132/186] child type would inherit procedures from parent type --- src/YAML_types.f90 | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index e951c2c83..9dba4fd37 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -138,7 +138,6 @@ module types contains procedure :: asFormattedString => tDict_asFormattedString procedure :: set => tDict_set - final :: tDict_finalize end type tDict @@ -951,28 +950,7 @@ end subroutine tDict_set !-------------------------------------------------------------------------------------------------- -!> @brief empties dictionary and frees associated memory -!> @details called when variable goes out of scope. Triggers a chain reaction -!-------------------------------------------------------------------------------------------------- -recursive subroutine tDict_finalize(self) - - type (tDict),intent(inout) :: self - - type (tItem),pointer :: current, & - next - - current => self%first - do while (associated(current)) - next => current%next - deallocate(current) - current => next - end do - -end subroutine tDict_finalize - - -!-------------------------------------------------------------------------------------------------- -!> @brief empties lists and free associated memory +!> @brief empties lists and dicts and free associated memory !> @details called when variable goes out of scope. !-------------------------------------------------------------------------------------------------- recursive subroutine tList_finalize(self) From d37c43d30d4bad6402f4f528e5cfdeb4d15c4638 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 24 Apr 2020 19:02:58 +0200 Subject: [PATCH 133/186] [skip ci] updated version information after successful test of v2.0.3-2375-gc6d58954 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6e24519bd..bc189726d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2364-g62f7363a +v2.0.3-2375-gc6d58954 From 9671a632b55110992eb6878a61c2488b05abce15 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 26 Apr 2020 14:58:07 +0200 Subject: [PATCH 134/186] compare floats with tolerances --- src/rotations.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rotations.f90 b/src/rotations.f90 index 98c529933..8ff5aca4e 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -527,7 +527,7 @@ pure function qu2ho(qu) result(ho) omega = 2.0 * acos(math_clip(qu(1),-1.0_pReal,1.0_pReal)) - if (dEq0(omega)) then + if (dEq0(omega,tol=1.e-5_pReal)) then ho = [ 0.0_pReal, 0.0_pReal, 0.0_pReal ] else ho = qu(2:4) @@ -1298,7 +1298,7 @@ pure function Lambert_BallToCube(xyz) result(cube) integer, dimension(3,2) :: p rs = norm2(xyz) - if (rs > R1) then + if (rs > R1+1.e-6_pReal) then cube = IEEE_value(cube,IEEE_positive_inf) return endif From 2d14790863bb3ebbef8aee5ebd17cbf656543642 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 27 Apr 2020 05:08:47 +0200 Subject: [PATCH 135/186] the result of a differential operator operating on a constant field is 0 --- python/tests/test_grid_filters.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index eb359006a..35f28bb0d 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -101,6 +101,7 @@ class TestGridFilters: with pytest.raises(ValueError): function(uneven) + @pytest.mark.parametrize('mode',[True,False]) @pytest.mark.parametrize('function',[grid_filters.node_coord0_gridSizeOrigin, grid_filters.cell_coord0_gridSizeOrigin]) @@ -120,3 +121,20 @@ class TestGridFilters: grid = np.random.randint(8,32,(3)) F = np.broadcast_to(np.eye(3), tuple(grid)+(3,3)) assert all(grid_filters.regrid(size,F,grid) == np.arange(grid.prod())) + + + @pytest.mark.parametrize('differential_operator',[grid_filters.curl, + grid_filters.divergence, + grid_filters.gradient]) + def test_differential_operator_constant(self,differential_operator): + size = np.random.random(3)+1.0 + grid = np.random.randint(8,32,(3)) + shapes = { + grid_filters.curl: [(3,),(3,3)], + grid_filters.divergence:[(3,),(3,3)], + grid_filters.gradient: [(1,),(3,)] + } + for shape in shapes[differential_operator]: + field = np.ones(tuple(grid)+shape)*np.random.random()*1.0e5 + assert np.allclose(differential_operator(size,field),0.0) + From 40fd0040a9dc11991b00227fb50701a58395a073 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 27 Apr 2020 08:17:07 +0200 Subject: [PATCH 136/186] use current status of release for Ubuntu --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 232a094c7..1741c5b2f 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 232a094c715bcbbd1c6652c4dc4a4a50d402b82f +Subproject commit 1741c5b2f39e36599a1f7530365e4452e12b6d97 From 9750f267c8c4232dc2e1b28bbc546e3c25acc0a1 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 27 Apr 2020 13:39:32 +0200 Subject: [PATCH 137/186] missing initialization can lead to infinite loops for no 'ping pong' (MSC.Marc) --- src/crystallite.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 7a13d228e..929fec862 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -303,6 +303,7 @@ function crystallite_stress(dummyArgumentToPreventInternalCompilerErrorWithGCC) s logical, dimension(homogenization_maxNgrains,discretization_nIP,discretization_nElem) :: todo !ToDo: need to set some values to false for different Ngrains + todo = .false. #ifdef DEBUG if (iand(debug_level(debug_crystallite),debug_levelSelective) /= 0 & .and. FEsolving_execElem(1) <= debug_e & From f2164a5bd3cb8c89c09056024b069daaf433d00d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 27 Apr 2020 13:40:22 +0200 Subject: [PATCH 138/186] simplified openMP is not used here ... --- src/CPFEM.f90 | 40 ++++++++++++++++++---------------------- src/DAMASK_marc.f90 | 3 +-- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/CPFEM.f90 b/src/CPFEM.f90 index c590a86b5..5394fc90c 100644 --- a/src/CPFEM.f90 +++ b/src/CPFEM.f90 @@ -73,28 +73,24 @@ subroutine CPFEM_initAll(el,ip) integer(pInt), intent(in) :: el, & !< FE el number ip !< FE integration point number - !$OMP CRITICAL(init) - if (.not. CPFEM_init_done) then - call DAMASK_interface_init - call prec_init - call IO_init - call numerics_init - call debug_init - call config_init - call math_init - call rotations_init - call HDF5_utilities_init - call results_init - call discretization_marc_init(ip, el) - call lattice_init - call material_init - call constitutive_init - call crystallite_init - call homogenization_init - call CPFEM_init - CPFEM_init_done = .true. - endif - !$OMP END CRITICAL(init) + CPFEM_init_done = .true. + call DAMASK_interface_init + call prec_init + call IO_init + call numerics_init + call debug_init + call config_init + call math_init + call rotations_init + call HDF5_utilities_init + call results_init + call discretization_marc_init(ip, el) + call lattice_init + call material_init + call constitutive_init + call crystallite_init + call homogenization_init + call CPFEM_init end subroutine CPFEM_initAll diff --git a/src/DAMASK_marc.f90 b/src/DAMASK_marc.f90 index 9fd41459b..fa0711b02 100644 --- a/src/DAMASK_marc.f90 +++ b/src/DAMASK_marc.f90 @@ -261,11 +261,10 @@ subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, & endif !$ defaultNumThreadsInt = omp_get_num_threads() ! remember number of threads set by Marc + !$ call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution set by DAMASK_NUM_THREADS if (.not. CPFEM_init_done) call CPFEM_initAll(m(1),nn) - !$ call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution set by DAMASK_NUM_THREADS - computationMode = 0 ! save initialization value, since it does not result in any calculation if (lovl == 4 ) then ! jacobian requested by marc if (timinc < theDelta .and. theInc == inc .and. lastLovl /= lovl) & ! first after cutback From 9273c887824fa940f3be541958e7f933247b9a26 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 27 Apr 2020 06:10:48 +0200 Subject: [PATCH 139/186] [skip ci] WIP: migrating from PRIVATE repo --- python/tests/test_grid_filters.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index 35f28bb0d..84d2ef771 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -138,3 +138,33 @@ class TestGridFilters: field = np.ones(tuple(grid)+shape)*np.random.random()*1.0e5 assert np.allclose(differential_operator(size,field),0.0) + + @pytest.mark.parametrize('field_def,curl_def', + [(['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0' ], + ['0.0' , '0.0', '0.0', + 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0', '0.0', + '0.0', '0.0', '0.0'] + ), + (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', + '0.0', '0.0', '0.0', + 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + 'np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0'] + ) + ]) + def test_curl(self,field_def,curl_def): + size = np.random.random(3)+1.0 + grid = np.random.randint(8,32,(3)) + + nodes = grid_filters.cell_coord0(grid,size) + my_locals = locals() # needed for list comprehension + + field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) + field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) + curl = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in curl_def], axis=-1) + curl = curl.reshape(tuple(grid) + ((3,3) if len(curl_def)==9 else (3,))) + + assert np.allclose(curl,grid_filters.curl(size,field)) From f3be26ffa251330d2dbd10aa2f54d7ff6b1dd247 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 28 Apr 2020 10:05:36 +0200 Subject: [PATCH 140/186] long error and warning functions at the end of public methods --- src/IO.f90 | 170 ++++++++++++++++++++++++++--------------------------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/src/IO.f90 b/src/IO.f90 index 11ce664f8..1bd2df833 100644 --- a/src/IO.f90 +++ b/src/IO.f90 @@ -29,13 +29,13 @@ module IO IO_getTag, & IO_stringPos, & IO_stringValue, & - IO_floatValue, & IO_intValue, & + IO_floatValue, & + IO_lc, & + IO_rmComment, & IO_stringAsInt, & IO_stringAsFloat, & IO_stringAsBool, & - IO_rmComment, & - IO_lc, & IO_error, & IO_warning @@ -298,6 +298,88 @@ pure function IO_lc(string) end function IO_lc +!-------------------------------------------------------------------------------------------------- +! @brief Remove comments (characters beyond '#') and trailing space +! ToDo: Discuss name (the trim aspect is not clear) +!-------------------------------------------------------------------------------------------------- +function IO_rmComment(line) + + character(len=*), intent(in) :: line + character(len=:), allocatable :: IO_rmComment + integer :: split + + split = index(line,IO_COMMENT) + + if (split == 0) then + IO_rmComment = trim(line) + else + IO_rmComment = trim(line(:split-1)) + endif + +end function IO_rmComment + + +!-------------------------------------------------------------------------------------------------- +!> @brief return verified integer value in given string +!-------------------------------------------------------------------------------------------------- +integer function IO_stringAsInt(string) + + character(len=*), intent(in) :: string !< string for conversion to int value + + integer :: readStatus + character(len=*), parameter :: VALIDCHARS = '0123456789+- ' + + valid: if (verify(string,VALIDCHARS) == 0) then + read(string,*,iostat=readStatus) IO_stringAsInt + if (readStatus /= 0) call IO_error(111,ext_msg=string) + else valid + IO_stringAsInt = 0 + call IO_error(111,ext_msg=string) + endif valid + +end function IO_stringAsInt + + +!-------------------------------------------------------------------------------------------------- +!> @brief return verified float value in given string +!-------------------------------------------------------------------------------------------------- +real(pReal) function IO_stringAsFloat(string) + + character(len=*), intent(in) :: string !< string for conversion to float value + + integer :: readStatus + character(len=*), parameter :: VALIDCHARS = '0123456789eE.+- ' + + valid: if (verify(string,VALIDCHARS) == 0) then + read(string,*,iostat=readStatus) IO_stringAsFloat + if (readStatus /= 0) call IO_error(112,ext_msg=string) + else valid + IO_stringAsFloat = 0.0_pReal + call IO_error(112,ext_msg=string) + endif valid + +end function IO_stringAsFloat + + +!-------------------------------------------------------------------------------------------------- +!> @brief return verified logical value in given string +!-------------------------------------------------------------------------------------------------- +logical function IO_stringAsBool(string) + + character(len=*), intent(in) :: string !< string for conversion to int value + + if (trim(adjustl(string)) == 'True') then + IO_stringAsBool = .true. + elseif (trim(adjustl(string)) == 'False') then + IO_stringAsBool = .false. + else + IO_stringAsBool = .false. + call IO_error(113,ext_msg=string) + endif + +end function IO_stringAsBool + + !-------------------------------------------------------------------------------------------------- !> @brief write error statements to standard out and terminate the Marc/spectral run with exit #9xxx !-------------------------------------------------------------------------------------------------- @@ -611,88 +693,6 @@ subroutine IO_warning(warning_ID,el,ip,g,ext_msg) end subroutine IO_warning -!-------------------------------------------------------------------------------------------------- -!> @brief return verified integer value in given string -!-------------------------------------------------------------------------------------------------- -integer function IO_stringAsInt(string) - - character(len=*), intent(in) :: string !< string for conversion to int value - - integer :: readStatus - character(len=*), parameter :: VALIDCHARS = '0123456789+- ' - - valid: if (verify(string,VALIDCHARS) == 0) then - read(string,*,iostat=readStatus) IO_stringAsInt - if (readStatus /= 0) call IO_error(111,ext_msg=string) - else valid - IO_stringAsInt = 0 - call IO_error(111,ext_msg=string) - endif valid - -end function IO_stringAsInt - - -!-------------------------------------------------------------------------------------------------- -!> @brief return verified float value in given string -!-------------------------------------------------------------------------------------------------- -real(pReal) function IO_stringAsFloat(string) - - character(len=*), intent(in) :: string !< string for conversion to float value - - integer :: readStatus - character(len=*), parameter :: VALIDCHARS = '0123456789eE.+- ' - - valid: if (verify(string,VALIDCHARS) == 0) then - read(string,*,iostat=readStatus) IO_stringAsFloat - if (readStatus /= 0) call IO_error(112,ext_msg=string) - else valid - IO_stringAsFloat = 0.0_pReal - call IO_error(112,ext_msg=string) - endif valid - -end function IO_stringAsFloat - - -!-------------------------------------------------------------------------------------------------- -!> @brief return verified logical value in given string -!-------------------------------------------------------------------------------------------------- -logical function IO_stringAsBool(string) - - character(len=*), intent(in) :: string !< string for conversion to int value - - if (trim(adjustl(string)) == 'True') then - IO_stringAsBool = .true. - elseif (trim(adjustl(string)) == 'False') then - IO_stringAsBool = .false. - else - IO_stringAsBool = .false. - call IO_error(113,ext_msg=string) - endif - -end function IO_stringAsBool - - -!-------------------------------------------------------------------------------------------------- -! @brief Remove comments (characters beyond '#') and trailing space -! ToDo: Discuss name (the trim aspect is not clear) -!-------------------------------------------------------------------------------------------------- -function IO_rmComment(line) - - character(len=*), intent(in) :: line - character(len=:), allocatable :: IO_rmComment - integer :: split - - split = index(line,IO_COMMENT) - - if (split == 0) then - IO_rmComment = trim(line) - else - IO_rmComment = trim(line(:split-1)) - endif - -end function IO_rmComment - - !-------------------------------------------------------------------------------------------------- !> @brief check correctness of some IO functions !-------------------------------------------------------------------------------------------------- From 20b604a334fee662a5905927440adaa7551f39af Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 28 Apr 2020 10:29:13 +0200 Subject: [PATCH 141/186] finalize does not work for gfortran --- src/CPFEM.f90 | 4 ++-- src/CPFEM2.f90 | 4 ++-- src/YAML_types.f90 | 49 +++++++++++++++++++++++++++++----------------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/CPFEM.f90 b/src/CPFEM.f90 index f26d4d064..83ecf65a4 100644 --- a/src/CPFEM.f90 +++ b/src/CPFEM.f90 @@ -10,7 +10,7 @@ module CPFEM use FEsolving use math use rotations - use types + use YAML_types use discretization_marc use material use config @@ -84,7 +84,7 @@ subroutine CPFEM_initAll(el,ip) call config_init call math_init call rotations_init - call types_init + call YAML_types_init call HDF5_utilities_init call results_init call discretization_marc_init(ip, el) diff --git a/src/CPFEM2.f90 b/src/CPFEM2.f90 index 2893b4759..9f61e4ebd 100644 --- a/src/CPFEM2.f90 +++ b/src/CPFEM2.f90 @@ -11,7 +11,7 @@ module CPFEM2 use FEsolving use math use rotations - use types + use YAML_types use material use lattice use IO @@ -51,7 +51,7 @@ subroutine CPFEM_initAll call config_init call math_init call rotations_init - call types_init + call YAML_types_init call lattice_init call HDF5_utilities_init call results_init diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index 9dba4fd37..26f17430a 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -8,7 +8,7 @@ !! functions exist to convert this scalar type to its respective primitive data type. !-------------------------------------------------------------------------------------------------- -module types +module YAML_types use IO use prec @@ -17,11 +17,12 @@ module types private - public tNode - public tScalar - public tDict - public tList - public types_init + public :: & + tNode, & + tScalar, & + tDict, & + tList, & + YAML_types_init type, abstract :: tNode integer :: length = 0 @@ -69,7 +70,7 @@ module types tNode_get_byKey_asString => tNode_get_byKey_asString procedure :: & tNode_get_byKey_asStrings => tNode_get_byKey_asStrings - + generic :: & get => tNode_get_byIndex, & tNode_get_byKey @@ -102,7 +103,7 @@ module types type, extends(tNode) :: tScalar - character(len=:), allocatable, private :: value + character(len=:), allocatable, private :: value contains procedure :: asFormattedString => tScalar_asFormattedString @@ -117,7 +118,7 @@ module types end type tScalar type, extends(tNode) :: tList - + class(tItem), pointer :: first => null() contains @@ -131,7 +132,9 @@ module types asBools => tList_asBools procedure :: & asStrings => tList_asStrings +#ifndef __GFORTRAN__ final :: tList_finalize +#endif end type tList type, extends(tList) :: tDict @@ -168,14 +171,24 @@ module types contains -subroutine types_init +!-------------------------------------------------------------------------------------------------- +!> @brief do sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine YAML_types_init + + write(6,'(/,a)') ' <<<+- YAML_types init -+>>>' + call unitTest -end subroutine types_init + +end subroutine YAML_types_init +!-------------------------------------------------------------------------------------------------- +!> @brief check correctness of some type bound procedures +!-------------------------------------------------------------------------------------------------- subroutine unitTest - type(tScalar),target :: s1,s2 + type(tScalar),target :: s1,s2 s1 = '1' if(s1%asInt() /= 1) call IO_error(0,ext_msg='tScalar_asInt') @@ -213,7 +226,7 @@ subroutine unitTest call l1%append(s2) call l2%append(l1) n=> l1 - + if(any(l1%asBools() .neqv. [.true., .false.])) call IO_error(0,ext_msg='tList_asBools') if(any(l1%asStrings() /= ['True ','False'])) call IO_error(0,ext_msg='tList_asStrings') if(n%get_asBool(2)) call IO_error(0,ext_msg='byIndex_asBool') @@ -598,7 +611,7 @@ function tNode_get_byKey_asFloats(self,k) result(nodeAsFloats) class(tNode), pointer :: node type(tList), pointer :: list - + node => self%get(k) list => node%asList() nodeAsFloats = list%asFloats() @@ -926,7 +939,7 @@ subroutine tDict_set(self,key,node) type(tItem), pointer :: item - if (.not.associated(self%first)) then + if (.not. associated(self%first)) then allocate(self%first) item => self%first self%length = 1 @@ -944,7 +957,7 @@ subroutine tDict_set(self,key,node) end if item%key = key - allocate(item%node,source=node) ! ToDo: Discuss ownership (copy vs referencing) + allocate(item%node,source=node) end subroutine tDict_set @@ -959,7 +972,7 @@ recursive subroutine tList_finalize(self) type (tItem),pointer :: current, & next - + current => self%first do while (associated(current)) next => current%next @@ -970,4 +983,4 @@ recursive subroutine tList_finalize(self) end subroutine tList_finalize -end module types +end module YAML_types From 04aea37d3f9924d2c29c6668e97021db7e75b176 Mon Sep 17 00:00:00 2001 From: Test User Date: Tue, 28 Apr 2020 20:36:31 +0200 Subject: [PATCH 142/186] [skip ci] updated version information after successful test of v2.0.3-2390-g524706d3 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index bc189726d..3cd762d43 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2375-gc6d58954 +v2.0.3-2390-g524706d3 From 763ccc077b333b794bff53ea77bfa043429cc630 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 28 Apr 2020 22:19:09 +0200 Subject: [PATCH 143/186] Philip's corrections --- PRIVATE | 2 +- processing/post/permuteData.py | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/PRIVATE b/PRIVATE index 3c52c31ca..c595994cd 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 3c52c31ca3272e0afe7967d2e59e0819f92e85c9 +Subproject commit c595994cd8880acadf50b5dedb79156d04d35b91 diff --git a/processing/post/permuteData.py b/processing/post/permuteData.py index c271227d5..1f4b80532 100755 --- a/processing/post/permuteData.py +++ b/processing/post/permuteData.py @@ -50,15 +50,12 @@ for name in filenames: table = damask.Table.from_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) randomSeed = int(os.urandom(4).hex(), 16) if options.randomSeed is None else options.randomSeed # random seed per file - np.random.seed(randomSeed) + rng = np.random.default_rng(randomSeed) for label in options.label: data = table.get(label) - if options.unique: - uniques,inverse = np.unique(data,return_inverse=True,axis=0) - np.random.shuffle(uniques) - table.set(label,uniques[inverse], scriptID+' '+' '.join(sys.argv[1:])) - else: - table.set(label,np.random.permutation(data), scriptID+' '+' '.join(sys.argv[1:])) + uniques,inverse = np.unique(data,return_inverse=True,axis=0) if options.unique else (data,np.arange(len(data))) + rng.shuffle(uniques) + table.set(label,uniques[inverse], scriptID+' '+' '.join(sys.argv[1:])) table.to_ASCII(sys.stdout if name is None else name) From 6147b5ef2269005267ed2efcec893d202a62dd63 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 28 Apr 2020 22:28:22 +0200 Subject: [PATCH 144/186] cleaning --- installation/symlink_Processing.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/installation/symlink_Processing.py b/installation/symlink_Processing.py index 2f4c99d34..5972a7f6a 100755 --- a/installation/symlink_Processing.py +++ b/installation/symlink_Processing.py @@ -16,10 +16,6 @@ if not os.path.isdir(binDir): #define ToDo list processing_subDirs = ['pre', 'post', - 'misc', - ] -processing_extensions = ['.py', - '.sh', ] sys.stdout.write('\nsymbolic linking...\n') @@ -31,7 +27,7 @@ for subDir in processing_subDirs: for theFile in os.listdir(theDir): theName,theExt = os.path.splitext(theFile) - if theExt in processing_extensions: # only consider files with proper extensions + if theExt in ['.py']: src = os.path.abspath(os.path.join(theDir,theFile)) sym_link = os.path.abspath(os.path.join(binDir,theName)) From ce9bdc50a4842edc4b1b76f6377f053e90c0cc9f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 29 Apr 2020 14:42:21 +0200 Subject: [PATCH 145/186] common variable names --- python/damask/_rotation.py | 36 +++++++++++++++++----------------- src/rotations.f90 | 40 +++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 723664e18..42b32552b 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -1057,15 +1057,15 @@ class Rotation: """ if len(ho.shape) == 1: - ball_ = ho/np.linalg.norm(ho)*_R1 if np.isclose(np.linalg.norm(ho),_R1,atol=1e-6) \ + ho_ = ho/np.linalg.norm(ho)*_R1 if np.isclose(np.linalg.norm(ho),_R1,atol=1e-6) \ else ho - rs = np.linalg.norm(ball_) + rs = np.linalg.norm(ho_) - if np.allclose(ball_,0.0,rtol=0.0,atol=1.0e-16): - cube = np.zeros(3) + if np.allclose(ho_,0.0,rtol=0.0,atol=1.0e-16): + cu = np.zeros(3) else: - p = _get_order(ball_) - xyz3 = ball_[p[0]] + p = _get_order(ho_) + xyz3 = ho_[p[0]] # inverse M_3 xyz2 = xyz3[0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[2])) ) @@ -1085,11 +1085,11 @@ class Rotation: Tinv = q * np.where(xyz2<0.0,-Tinv,Tinv) # inverse M_1 - cube = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /_sc + cu = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /_sc # reverse the coordinates back to the regular order according to the original pyramid number - cube = cube[p[1]] + cu = cu[p[1]] - return cube + return cu else: raise NotImplementedError @@ -1133,20 +1133,20 @@ class Rotation: """ if len(cu.shape) == 1: - cube_ = np.clip(cu,None,np.pi**(2./3.) * 0.5) if np.isclose(np.abs(np.max(cu)),np.pi**(2./3.) * 0.5,atol=1e-6) \ + cu_ = np.clip(cu,None,np.pi**(2./3.) * 0.5) if np.isclose(np.abs(np.max(cu)),np.pi**(2./3.) * 0.5,atol=1e-6) \ else cu # transform to the sphere grid via the curved square, and intercept the zero point - if np.allclose(cube_,0.0,rtol=0.0,atol=1.0e-16): - ball = np.zeros(3) + if np.allclose(cu_,0.0,rtol=0.0,atol=1.0e-16): + ho = np.zeros(3) else: # get pyramide and scale by grid parameter ratio - p = _get_order(cube_) - XYZ = cube_[p[0]] * _sc + p = _get_order(cu_) + XYZ = cu_[p[0]] * _sc # intercept all the points along the z-axis if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-16): - ball = np.array([0.0, 0.0, np.sqrt(6.0/np.pi) * XYZ[2]]) + ho = np.array([0.0, 0.0, np.sqrt(6.0/np.pi) * XYZ[2]]) else: order = [1,0] if np.abs(XYZ[1]) <= np.abs(XYZ[0]) else [0,1] q = np.pi/12.0 * XYZ[order[0]]/XYZ[order[1]] @@ -1161,12 +1161,12 @@ class Rotation: s = c * np.pi/24.0 /XYZ[2]**2 c = c * np.sqrt(np.pi/24.0)/XYZ[2] q = np.sqrt( 1.0 - s ) - ball = np.array([ T[order[1]] * q, T[order[0]] * q, np.sqrt(6.0/np.pi) * XYZ[2] - c ]) + ho = np.array([ T[order[1]] * q, T[order[0]] * q, np.sqrt(6.0/np.pi) * XYZ[2] - c ]) # reverse the coordinates back to the regular order according to the original pyramid number - ball = ball[p[1]] + ho = ho[p[1]] - return ball + return ho else: raise NotImplementedError diff --git a/src/rotations.f90 b/src/rotations.f90 index 8ff5aca4e..f3110b7d4 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -1233,28 +1233,28 @@ end function cu2ho !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH !> @brief map from 3D cubic grid to 3D ball !-------------------------------------------------------------------------- -pure function Lambert_CubeToBall(cube) result(ball) +pure function Lambert_CubeToBall(cu) result(ho) - real(pReal), intent(in), dimension(3) :: cube - real(pReal), dimension(3) :: ball, LamXYZ, XYZ + real(pReal), intent(in), dimension(3) :: cu + real(pReal), dimension(3) :: ho, LamXYZ, XYZ real(pReal), dimension(2) :: T real(pReal) :: c, s, q real(pReal), parameter :: eps = 1.0e-8_pReal integer, dimension(3,2) :: p integer, dimension(2) :: order - if (maxval(abs(cube)) > AP/2.0+eps) then - ball = IEEE_value(cube,IEEE_positive_inf) + if (maxval(abs(cu)) > AP/2.0+eps) then + ho = IEEE_value(cu,IEEE_positive_inf) return end if ! transform to the sphere grid via the curved square, and intercept the zero point - center: if (all(dEq0(cube))) then - ball = 0.0_pReal + center: if (all(dEq0(cu))) then + ho = 0.0_pReal else center ! get pyramide and scale by grid parameter ratio - p = GetPyramidOrder(cube) - XYZ = cube(p(:,1)) * sc + p = GetPyramidOrder(cu) + XYZ = cu(p(:,1)) * sc ! intercept all the points along the z-axis special: if (all(dEq0(XYZ(1:2)))) then @@ -1277,7 +1277,7 @@ pure function Lambert_CubeToBall(cube) result(ball) endif special ! reverse the coordinates back to order according to the original pyramid number - ball = LamXYZ(p(:,2)) + ho = LamXYZ(p(:,2)) endif center @@ -1289,25 +1289,25 @@ end function Lambert_CubeToBall !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH !> @brief map from 3D ball to 3D cubic grid !-------------------------------------------------------------------------- -pure function Lambert_BallToCube(xyz) result(cube) +pure function Lambert_BallToCube(ho) result(cu) - real(pReal), intent(in), dimension(3) :: xyz - real(pReal), dimension(3) :: cube, xyz1, xyz3 + real(pReal), intent(in), dimension(3) :: ho + real(pReal), dimension(3) :: cu, xyz1, xyz3 real(pReal), dimension(2) :: Tinv, xyz2 real(pReal) :: rs, qxy, q2, sq2, q, tt integer, dimension(3,2) :: p - rs = norm2(xyz) + rs = norm2(ho) if (rs > R1+1.e-6_pReal) then - cube = IEEE_value(cube,IEEE_positive_inf) + cu = IEEE_value(cu,IEEE_positive_inf) return endif - center: if (all(dEq0(xyz))) then - cube = 0.0_pReal + center: if (all(dEq0(ho))) then + cu = 0.0_pReal else center - p = GetPyramidOrder(xyz) - xyz3 = xyz(p(:,1)) + p = GetPyramidOrder(ho) + xyz3 = ho(p(:,1)) ! inverse M_3 xyz2 = xyz3(1:2) * sqrt( 2.0*rs/(rs+abs(xyz3(3))) ) @@ -1331,7 +1331,7 @@ pure function Lambert_BallToCube(xyz) result(cube) xyz1 = [ Tinv(1), Tinv(2), sign(1.0_pReal,xyz3(3)) * rs / pref ] /sc ! reverse the coordinates back to order according to the original pyramid number - cube = xyz1(p(:,2)) + cu = xyz1(p(:,2)) endif center From d0dcfedb47d97ef785f8c3ebf38955757d616976 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 29 Apr 2020 14:52:18 +0200 Subject: [PATCH 146/186] no extra function needed --- src/rotations.f90 | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/src/rotations.f90 b/src/rotations.f90 index f3110b7d4..feb7e54db 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -927,7 +927,7 @@ function ax2cu(ax) result(cu) real(pReal), intent(in), dimension(4) :: ax real(pReal), dimension(3) :: cu - cu = ho2cu(ax2ho(ax)) + cu = ho2cu(ax2ho(ax)) end function ax2cu @@ -1131,20 +1131,6 @@ pure function ho2ro(ho) result(ro) end function ho2ro -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert homochoric to cubochoric -!--------------------------------------------------------------------------------------------------- -pure function ho2cu(ho) result(cu) - - real(pReal), intent(in), dimension(3) :: ho - real(pReal), dimension(3) :: cu - - cu = Lambert_BallToCube(ho) - -end function ho2cu - - !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University !> @brief convert cubochoric to unit quaternion @@ -1215,25 +1201,12 @@ pure function cu2ro(cu) result(ro) end function cu2ro -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert cubochoric to homochoric -!--------------------------------------------------------------------------------------------------- -pure function cu2ho(cu) result(ho) - - real(pReal), intent(in), dimension(3) :: cu - real(pReal), dimension(3) :: ho - - ho = Lambert_CubeToBall(cu) - -end function cu2ho - !-------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH !> @brief map from 3D cubic grid to 3D ball !-------------------------------------------------------------------------- -pure function Lambert_CubeToBall(cu) result(ho) +pure function cu2ho(cu) result(ho) real(pReal), intent(in), dimension(3) :: cu real(pReal), dimension(3) :: ho, LamXYZ, XYZ @@ -1281,15 +1254,15 @@ pure function Lambert_CubeToBall(cu) result(ho) endif center -end function Lambert_CubeToBall +end function cu2ho !-------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief map from 3D ball to 3D cubic grid +!> @brief convert homochoric to cubochoric !-------------------------------------------------------------------------- -pure function Lambert_BallToCube(ho) result(cu) +pure function ho2cu(ho) result(cu) real(pReal), intent(in), dimension(3) :: ho real(pReal), dimension(3) :: cu, xyz1, xyz3 @@ -1335,7 +1308,7 @@ pure function Lambert_BallToCube(ho) result(cu) endif center -end function Lambert_BallToCube +end function ho2cu !-------------------------------------------------------------------------- From ad312201ddf5cefcd4367261561621febfee5946 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 29 Apr 2020 14:53:27 +0200 Subject: [PATCH 147/186] keep order --- src/rotations.f90 | 108 +++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/rotations.f90 b/src/rotations.f90 index feb7e54db..fea642170 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -1131,6 +1131,60 @@ pure function ho2ro(ho) result(ro) end function ho2ro +!-------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief convert homochoric to cubochoric +!-------------------------------------------------------------------------- +pure function ho2cu(ho) result(cu) + + real(pReal), intent(in), dimension(3) :: ho + real(pReal), dimension(3) :: cu, xyz1, xyz3 + real(pReal), dimension(2) :: Tinv, xyz2 + real(pReal) :: rs, qxy, q2, sq2, q, tt + integer, dimension(3,2) :: p + + rs = norm2(ho) + if (rs > R1+1.e-6_pReal) then + cu = IEEE_value(cu,IEEE_positive_inf) + return + endif + + center: if (all(dEq0(ho))) then + cu = 0.0_pReal + else center + p = GetPyramidOrder(ho) + xyz3 = ho(p(:,1)) + + ! inverse M_3 + xyz2 = xyz3(1:2) * sqrt( 2.0*rs/(rs+abs(xyz3(3))) ) + + ! inverse M_2 + qxy = sum(xyz2**2) + + special: if (dEq0(qxy)) then + Tinv = 0.0_pReal + else special + q2 = qxy + maxval(abs(xyz2))**2 + sq2 = sqrt(q2) + q = (beta/R2/R1) * sqrt(q2*qxy/(q2-maxval(abs(xyz2))*sq2)) + tt = (minval(abs(xyz2))**2+maxval(abs(xyz2))*sq2)/R2/qxy + Tinv = q * sign(1.0_pReal,xyz2) * merge([ 1.0_pReal, acos(math_clip(tt,-1.0_pReal,1.0_pReal))/PI12], & + [ acos(math_clip(tt,-1.0_pReal,1.0_pReal))/PI12, 1.0_pReal], & + abs(xyz2(2)) <= abs(xyz2(1))) + endif special + + ! inverse M_1 + xyz1 = [ Tinv(1), Tinv(2), sign(1.0_pReal,xyz3(3)) * rs / pref ] /sc + + ! reverse the coordinates back to order according to the original pyramid number + cu = xyz1(p(:,2)) + + endif center + +end function ho2cu + + !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University !> @brief convert cubochoric to unit quaternion @@ -1257,60 +1311,6 @@ pure function cu2ho(cu) result(ho) end function cu2ho -!-------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief convert homochoric to cubochoric -!-------------------------------------------------------------------------- -pure function ho2cu(ho) result(cu) - - real(pReal), intent(in), dimension(3) :: ho - real(pReal), dimension(3) :: cu, xyz1, xyz3 - real(pReal), dimension(2) :: Tinv, xyz2 - real(pReal) :: rs, qxy, q2, sq2, q, tt - integer, dimension(3,2) :: p - - rs = norm2(ho) - if (rs > R1+1.e-6_pReal) then - cu = IEEE_value(cu,IEEE_positive_inf) - return - endif - - center: if (all(dEq0(ho))) then - cu = 0.0_pReal - else center - p = GetPyramidOrder(ho) - xyz3 = ho(p(:,1)) - - ! inverse M_3 - xyz2 = xyz3(1:2) * sqrt( 2.0*rs/(rs+abs(xyz3(3))) ) - - ! inverse M_2 - qxy = sum(xyz2**2) - - special: if (dEq0(qxy)) then - Tinv = 0.0_pReal - else special - q2 = qxy + maxval(abs(xyz2))**2 - sq2 = sqrt(q2) - q = (beta/R2/R1) * sqrt(q2*qxy/(q2-maxval(abs(xyz2))*sq2)) - tt = (minval(abs(xyz2))**2+maxval(abs(xyz2))*sq2)/R2/qxy - Tinv = q * sign(1.0_pReal,xyz2) * merge([ 1.0_pReal, acos(math_clip(tt,-1.0_pReal,1.0_pReal))/PI12], & - [ acos(math_clip(tt,-1.0_pReal,1.0_pReal))/PI12, 1.0_pReal], & - abs(xyz2(2)) <= abs(xyz2(1))) - endif special - - ! inverse M_1 - xyz1 = [ Tinv(1), Tinv(2), sign(1.0_pReal,xyz3(3)) * rs / pref ] /sc - - ! reverse the coordinates back to order according to the original pyramid number - cu = xyz1(p(:,2)) - - endif center - -end function ho2cu - - !-------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH From 10710bc4460fe4286594c364d72adbac6375830f Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Thu, 30 Apr 2020 21:29:59 +0200 Subject: [PATCH 148/186] using pointers makes finalize general for GNU and Intel --- src/YAML_types.f90 | 253 ++++++++++++++++++++++++++++----------------- 1 file changed, 159 insertions(+), 94 deletions(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index 26f17430a..7a53bdbd3 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -70,6 +70,8 @@ module YAML_types tNode_get_byKey_asString => tNode_get_byKey_asString procedure :: & tNode_get_byKey_asStrings => tNode_get_byKey_asStrings + procedure :: & + getIndex => tNode_get_byKey_asIndex generic :: & get => tNode_get_byIndex, & @@ -132,9 +134,7 @@ module YAML_types asBools => tList_asBools procedure :: & asStrings => tList_asStrings -#ifndef __GFORTRAN__ final :: tList_finalize -#endif end type tList type, extends(tList) :: tDict @@ -146,18 +146,20 @@ module YAML_types type :: tItem character(len=:), allocatable :: key - class(tNode), allocatable :: node + class(tNode), pointer :: node => null() class(tItem), pointer :: next => null() + + contains + final :: tItem_finalize end type tItem abstract interface - recursive function asFormattedString(self,indent) + recursive subroutine asFormattedString(self,indent) import tNode - character(len=:), allocatable :: asFormattedString class(tNode), intent(in), target :: self integer, intent(in), optional :: indent - end function asFormattedString + end subroutine asFormattedString end interface @@ -188,52 +190,76 @@ end subroutine YAML_types_init !-------------------------------------------------------------------------------------------------- subroutine unitTest - type(tScalar),target :: s1,s2 - - s1 = '1' - if(s1%asInt() /= 1) call IO_error(0,ext_msg='tScalar_asInt') - if(dNeq(s1%asFloat(),1.0_pReal)) call IO_error(0,ext_msg='tScalar_asFloat') - s1 = 'True' - if(.not. s1%asBool()) call IO_error(0,ext_msg='tScalar_asBool') - if(s1%asString() /= 'True') call IO_error(0,ext_msg='tScalar_asString') - + class(tNode), pointer :: s1,s2 + allocate(tScalar::s1) + allocate(tScalar::s2) + select type(s1) + class is(tScalar) + s1 = '1' + if(s1%asInt() /= 1) call IO_error(0,ext_msg='tScalar_asInt') + if(dNeq(s1%asFloat(),1.0_pReal)) call IO_error(0,ext_msg='tScalar_asFloat') + s1 = 'True' + if(.not. s1%asBool()) call IO_error(0,ext_msg='tScalar_asBool') + if(s1%asString() /= 'True') call IO_error(0,ext_msg='tScalar_asString') + end select block - type(tList), target :: l1, l2 - class(tNode), pointer :: n + class(tNode), pointer :: l1, l2, n + character(len=1) :: test = '2' + select type(s1) + class is(tScalar) + s1 = test + endselect + + select type(s2) + class is(tScalar) + s2 = '3' + endselect - s1 = '2' - s2 = '3' - call l1%append(s1) - call l1%append(s2) - call l2%append(l1) - n => l1 + allocate(tList::l1) + select type(l1) + class is(tList) + call l1%append(s1) + call l1%append(s2) + n => l1 + if(any(l1%asInts() /= [2,3])) call IO_error(0,ext_msg='tList_asInts') + if(any(dNeq(l1%asFloats(),[2.0_pReal,3.0_pReal]))) call IO_error(0,ext_msg='tList_asFloats') + if(n%get_asInt(1) /= 2) call IO_error(0,ext_msg='byIndex_asInt') + if(dNeq(n%get_asFloat(2),3.0_pReal)) call IO_error(0,ext_msg='byIndex_asFloat') + endselect + + allocate(tList::l2) + select type(l2) + class is(tList) + call l2%append(l1) + if(any(l2%get_asInts(1) /= [2,3])) call IO_error(0,ext_msg='byIndex_asInts') + if(any(dNeq(l2%get_asFloats(1),[2.0_pReal,3.0_pReal]))) call IO_error(0,ext_msg='byIndex_asFloats') + n => l2 + end select + deallocate(n) + end block - if(any(l1%asInts() /= [2,3])) call IO_error(0,ext_msg='tList_asInts') - if(any(dNeq(l1%asFloats(),[2.0_pReal,3.0_pReal]))) call IO_error(0,ext_msg='tList_asFloats') - if(n%get_asInt(1) /= 2) call IO_error(0,ext_msg='byIndex_asInt') - if(dNeq(n%get_asFloat(2),3.0_pReal)) call IO_error(0,ext_msg='byIndex_asFloat') - if(any(l2%get_asInts(1) /= [2,3])) call IO_error(0,ext_msg='byIndex_asInts') - if(any(dNeq(l2%get_asFloats(1),[2.0_pReal,3.0_pReal]))) call IO_error(0,ext_msg='byIndex_asFloats') - end block - - block - type(tList), target :: l1, l2 - class(tNode), pointer :: n - s1 = 'True' - s2 = 'False' - call l1%append(s1) - call l1%append(s2) - call l2%append(l1) - n=> l1 - - if(any(l1%asBools() .neqv. [.true., .false.])) call IO_error(0,ext_msg='tList_asBools') - if(any(l1%asStrings() /= ['True ','False'])) call IO_error(0,ext_msg='tList_asStrings') - if(n%get_asBool(2)) call IO_error(0,ext_msg='byIndex_asBool') - if(n%get_asString(1) /= 'True') call IO_error(0,ext_msg='byIndex_asString') - if(any(l2%get_asBools(1) .neqv. [.true., .false.])) call IO_error(0,ext_msg='byIndex_asBools') - if(any(l2%get_asStrings(1) /= ['True ','False'])) call IO_error(0,ext_msg='byIndex_asStrings') - end block + block + type(tList), target :: l1 + type(tScalar),pointer :: s3,s4 + class(tNode), pointer :: n + + allocate(tScalar::s1) + allocate(tScalar::s2) + s3 => s1%asScalar() + s4 => s2%asScalar() + s3 = 'True' + s4 = 'False' + + call l1%append(s1) + call l1%append(s2) + n => l1 + + if(any(l1%asBools() .neqv. [.true., .false.])) call IO_error(0,ext_msg='tList_asBools') + if(any(l1%asStrings() /= ['True ','False'])) call IO_error(0,ext_msg='tList_asStrings') + if(n%get_asBool(2)) call IO_error(0,ext_msg='byIndex_asBool') + if(n%get_asString(1) /= 'True') call IO_error(0,ext_msg='byIndex_asString') + end block end subroutine unitTest @@ -676,14 +702,40 @@ function tNode_get_byKey_asStrings(self,k) result(nodeAsStrings) end function tNode_get_byKey_asStrings -!-------------------------------------------------------------------------------------------------- -!> @brief Return scalar as string -!-------------------------------------------------------------------------------------------------- -recursive function tScalar_asFormattedString(self,indent) +!------------------------------------------------------------------------------------------------------- +!> @brief Returns the index of a key in a dictionary +!------------------------------------------------------------------------------------------------------- +function tNode_get_byKey_asIndex(self,key) result(keyIndex) - character(len=:), allocatable :: tScalar_asFormattedString - class(tScalar), intent(in), target :: self - integer, intent(in), optional :: indent + class(tNode), intent(in), target :: self + character(len=*), intent(in) :: key + + integer :: keyIndex + integer :: i + type(tDict), pointer :: dict + type(tItem), pointer :: item + + dict => self%asDict() + item => dict%first + do i = 1, dict%length + if(key == item%key) then + keyIndex = i + exit + else + item => item%next + endif + enddo + +end function tNode_get_byKey_asIndex + + +!-------------------------------------------------------------------------------------------------- +!> @brief Prints scalar as string +!-------------------------------------------------------------------------------------------------- +recursive subroutine tScalar_asFormattedString(self,indent) + + class (tScalar), intent(in), target :: self + integer, intent(in), optional :: indent integer :: indent_ @@ -693,22 +745,21 @@ recursive function tScalar_asFormattedString(self,indent) indent_ = 0 endif - tScalar_asFormattedString = repeat(' ',indent_)//trim(self%value)//IO_EOL + write (6,'(a)') trim(self%value) -end function tScalar_asFormattedString +end subroutine tScalar_asFormattedString !-------------------------------------------------------------------------------------------------- -!> @brief Return list as string (YAML block style) +!> @brief Prints list as string (YAML block style) !-------------------------------------------------------------------------------------------------- -recursive function tList_asFormattedString(self,indent) result(str) +recursive subroutine tList_asFormattedString(self,indent) - class(tList), intent(in), target :: self - integer, intent(in), optional :: indent + class (tList),intent(in),target :: self + integer, intent(in),optional :: indent - class(tItem), pointer :: item - character(len=:), allocatable :: str - integer :: i,indent_ + type (tItem), pointer :: item + integer :: i, indent_ if(present(indent)) then indent_ = indent @@ -718,24 +769,25 @@ recursive function tList_asFormattedString(self,indent) result(str) item => self%first do i = 1, self%length - str = str//repeat(' ',indent_)//'-'//IO_EOL//item%node%asFormattedString(indent_+2) + if( i /= 1) write (6,'(a)',advance='NO') repeat(' ',indent_) + write (6,'(a)',advance='NO') '- ' + call item%node%asFormattedString(indent_+2) item => item%next - enddo + end do -end function tList_asFormattedString +end subroutine tList_asFormattedString !-------------------------------------------------------------------------------------------------- -!> @brief Return dictionary as string (YAML block style) +!> @brief Prints dictionary as string (YAML block style) !-------------------------------------------------------------------------------------------------- -recursive function tDict_asFormattedString(self,indent) result(str) +recursive subroutine tDict_asFormattedString(self,indent) - class(tDict), intent(in), target :: self - integer, intent(in), optional :: indent - - class(tItem), pointer :: item - character(len=:), allocatable :: str - integer :: i,indent_ + class (tDict),intent(in),target :: self + integer, intent(in),optional :: indent + + type (tItem),pointer :: item + integer :: i, indent_ if(present(indent)) then indent_ = indent @@ -745,11 +797,20 @@ recursive function tDict_asFormattedString(self,indent) result(str) item => self%first do i = 1, self%length - str = str//repeat(' ',indent_)//item%key//':'//IO_EOL//item%node%asFormattedString(indent_+2) + if( i /= 1) write (6,'(a)',advance='NO') repeat(' ',indent_) + select type (node_ => item%node) + class is (tScalar) + write (6,'(a)',advance='NO') trim(item%key)//': ' + call node_%asFormattedString(indent_+len_trim(item%key)+2) + class default + write (6,'(a)') trim(item%key)//':' + write (6,'(a)',advance='NO') repeat(' ',indent_+2) + call node_%asFormattedString(indent_+2) + end select item => item%next - enddo + end do -end function tDict_asFormattedString +end subroutine tDict_asFormattedString !-------------------------------------------------------------------------------------------------- @@ -905,8 +966,8 @@ end function tList_asStrings !-------------------------------------------------------------------------------------------------- subroutine tList_append(self,node) - class(tList), intent(inout) :: self - class(tNode), intent(in) :: node + class(tList), intent(inout) :: self + class(tNode), intent(in), target :: node type(tItem), pointer :: item @@ -922,7 +983,7 @@ subroutine tList_append(self,node) item => item%next end if - allocate(item%node,source=node) ! ToDo: Discuss ownership (copy vs referencing) + item%node => node self%length = self%length + 1 end subroutine tList_append @@ -933,9 +994,9 @@ end subroutine tList_append !-------------------------------------------------------------------------------------------------- subroutine tDict_set(self,key,node) - class (tDict), intent(inout) :: self - character(len=*), intent(in) :: key - class(tNode), intent(in) :: node + class (tDict), intent(inout) :: self + character(len=*), intent(in) :: key + class(tNode), intent(in), target :: node type(tItem), pointer :: item @@ -957,7 +1018,7 @@ subroutine tDict_set(self,key,node) end if item%key = key - allocate(item%node,source=node) + item%node => node end subroutine tDict_set @@ -970,17 +1031,21 @@ recursive subroutine tList_finalize(self) type (tList),intent(inout) :: self - type (tItem),pointer :: current, & - next - - current => self%first - do while (associated(current)) - next => current%next - deallocate(current) - current => next - end do + deallocate(self%first) end subroutine tList_finalize +!-------------------------------------------------------------------------------------------------- +!> @brief empties nodes and frees associated memory +!-------------------------------------------------------------------------------------------------- +recursive subroutine tItem_finalize(self) + + type(tItem),intent(inout) :: self + + deallocate(self%node) + if(associated(self%next)) deallocate(self%next) + +end subroutine tItem_finalize + end module YAML_types From 815608ac4213287f6e00a84f87a3f467f741989b Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Thu, 30 Apr 2020 21:34:11 +0200 Subject: [PATCH 149/186] polishing --- src/YAML_types.f90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index 7a53bdbd3..02b2d5fdb 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -205,10 +205,9 @@ subroutine unitTest block class(tNode), pointer :: l1, l2, n - character(len=1) :: test = '2' select type(s1) class is(tScalar) - s1 = test + s1 = '2' endselect select type(s2) From b88f5ec0c8556fff5976c30cd942bbcdda998ffe Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 1 May 2020 14:53:40 +0200 Subject: [PATCH 150/186] clean up --- python/tests/test_mechanics.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/python/tests/test_mechanics.py b/python/tests/test_mechanics.py index ac2ac419e..f7128401f 100644 --- a/python/tests/test_mechanics.py +++ b/python/tests/test_mechanics.py @@ -12,7 +12,6 @@ class TestMechanics: @pytest.mark.parametrize('function',[mechanics.deviatoric_part, mechanics.eigenvalues, mechanics.eigenvectors, - mechanics.deviatoric_part, mechanics.left_stretch, mechanics.maximum_shear, mechanics.Mises_strain, @@ -42,12 +41,13 @@ class TestMechanics: assert np.allclose(mechanics.strain_tensor(F,t,m)[self.c], mechanics.strain_tensor(F[self.c],t,m)) - - def test_Cauchy(self): - """Ensure Cauchy stress is symmetrized 1. Piola-Kirchhoff stress for no deformation.""" + @pytest.mark.parametrize('function',[mechanics.Cauchy, + mechanics.PK2, + ]) + def test_stress_measures(self,function): + """Ensure that all stress measures are equivalent for no deformation.""" P = np.random.rand(self.n,3,3) - assert np.allclose(mechanics.Cauchy(P,np.broadcast_to(np.eye(3),(self.n,3,3))), - mechanics.symmetric(P)) + assert np.allclose(function(P,np.broadcast_to(np.eye(3),(self.n,3,3))),mechanics.symmetric(P)) def test_deviatoric_part(self): I_n = np.broadcast_to(np.eye(3),(self.n,3,3)) @@ -63,12 +63,6 @@ class TestMechanics: assert np.allclose(np.matmul(R,U), np.matmul(V,R)) - def test_PK2(self): - """Ensure 2. Piola-Kirchhoff stress is symmetrized 1. Piola-Kirchhoff stress for no deformation.""" - P = np.random.rand(self.n,3,3) - assert np.allclose(mechanics.PK2(P,np.broadcast_to(np.eye(3),(self.n,3,3))), - mechanics.symmetric(P)) - def test_strain_tensor_no_rotation(self): """Ensure that left and right stretch give same results for no rotation.""" F = np.broadcast_to(np.eye(3),[self.n,3,3])*np.random.rand(self.n,3,3) From 68b6aec5f2f8e26f4c2dcebac8ebee393d205c44 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 1 May 2020 20:12:42 +0200 Subject: [PATCH 151/186] [skip ci] updated version information after successful test of v2.0.3-2402-gb88f5ec0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3cd762d43..6f8955f5c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2390-g524706d3 +v2.0.3-2402-gb88f5ec0 From 2df78e4e2f4b8a018262a9d61a118496c612c597 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 29 Apr 2020 17:52:09 +0200 Subject: [PATCH 152/186] vecorized pyramid function for lambert projection --- python/damask/_rotation.py | 65 +++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 42b32552b..876e59747 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -1064,8 +1064,7 @@ class Rotation: if np.allclose(ho_,0.0,rtol=0.0,atol=1.0e-16): cu = np.zeros(3) else: - p = _get_order(ho_) - xyz3 = ho_[p[0]] + xyz3 = ho_[Rotation._get_order(ho_,'forward')] # inverse M_3 xyz2 = xyz3[0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[2])) ) @@ -1087,7 +1086,7 @@ class Rotation: # inverse M_1 cu = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /_sc # reverse the coordinates back to the regular order according to the original pyramid number - cu = cu[p[1]] + cu = cu[Rotation._get_order(ho_,'backward')] return cu else: @@ -1141,8 +1140,7 @@ class Rotation: ho = np.zeros(3) else: # get pyramide and scale by grid parameter ratio - p = _get_order(cu_) - XYZ = cu_[p[0]] * _sc + XYZ = cu_[Rotation._get_order(cu_,'forward')] * _sc # intercept all the points along the z-axis if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-16): @@ -1164,37 +1162,46 @@ class Rotation: ho = np.array([ T[order[1]] * q, T[order[0]] * q, np.sqrt(6.0/np.pi) * XYZ[2] - c ]) # reverse the coordinates back to the regular order according to the original pyramid number - ho = ho[p[1]] + ho = ho[Rotation._get_order(cu_,'backward')] return ho else: raise NotImplementedError -def _get_order(xyz): - """ - Get order of the coordinates. + @staticmethod + def _get_order(xyz,direction=None): + """ + Get order of the coordinates. - Depending on the pyramid in which the point is located, the order need to be adjusted. + Depending on the pyramid in which the point is located, the order need to be adjusted. - Parameters - ---------- - xyz : numpy.ndarray - coordinates of a point on a uniform refinable grid on a ball or - in a uniform refinable cubical grid. + Parameters + ---------- + xyz : numpy.ndarray + coordinates of a point on a uniform refinable grid on a ball or + in a uniform refinable cubical grid. - References - ---------- - D. Roşca et al., Modelling and Simulation in Materials Science and Engineering 22:075013, 2014 - https://doi.org/10.1088/0965-0393/22/7/075013 + References + ---------- + D. Roşca et al., Modelling and Simulation in Materials Science and Engineering 22:075013, 2014 + https://doi.org/10.1088/0965-0393/22/7/075013 - """ - if (abs(xyz[0])<= xyz[2]) and (abs(xyz[1])<= xyz[2]) or \ - (abs(xyz[0])<=-xyz[2]) and (abs(xyz[1])<=-xyz[2]): - return [[0,1,2],[0,1,2]] - elif (abs(xyz[2])<= xyz[0]) and (abs(xyz[1])<= xyz[0]) or \ - (abs(xyz[2])<=-xyz[0]) and (abs(xyz[1])<=-xyz[0]): - return [[1,2,0],[2,0,1]] - elif (abs(xyz[0])<= xyz[1]) and (abs(xyz[2])<= xyz[1]) or \ - (abs(xyz[0])<=-xyz[1]) and (abs(xyz[2])<=-xyz[1]): - return [[2,0,1],[1,2,0]] + """ + order = {'forward':np.array([[0,1,2],[1,2,0],[2,0,1]]), + 'backward':np.array([[0,1,2],[2,0,1],[1,2,0]])} + if len(xyz.shape) == 1: + if np.maximum(abs(xyz[0]),abs(xyz[1])) <= xyz[2] or \ + np.maximum(abs(xyz[0]),abs(xyz[1])) <=-xyz[2]: + p = 0 + elif np.maximum(abs(xyz[1]),abs(xyz[2])) <= xyz[0] or \ + np.maximum(abs(xyz[1]),abs(xyz[2])) <=-xyz[0]: + p = 1 + elif np.maximum(abs(xyz[2]),abs(xyz[0])) <= xyz[1] or \ + np.maximum(abs(xyz[2]),abs(xyz[0])) <=-xyz[1]: + p = 2 + else: + p = np.where(np.maximum(np.abs(xyz[...,0]),np.abs(xyz[...,1])) <= np.abs(xyz[...,2]),0, + np.where(np.maximum(np.abs(xyz[...,1]),np.abs(xyz[...,2])) <= np.abs(xyz[...,0]),2,3)) + + return order[direction][p] From 47f85402c492fe5c3cae3b5091f74195c2dca9dc Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Sat, 2 May 2020 23:03:11 +0200 Subject: [PATCH 153/186] using function makes it more readable --- src/YAML_types.f90 | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index 02b2d5fdb..f1af2f9cb 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -155,11 +155,12 @@ module YAML_types abstract interface - recursive subroutine asFormattedString(self,indent) + recursive function asFormattedString(self,indent) import tNode + character(len=:), allocatable :: asFormattedString class(tNode), intent(in), target :: self integer, intent(in), optional :: indent - end subroutine asFormattedString + end function asFormattedString end interface @@ -731,8 +732,9 @@ end function tNode_get_byKey_asIndex !-------------------------------------------------------------------------------------------------- !> @brief Prints scalar as string !-------------------------------------------------------------------------------------------------- -recursive subroutine tScalar_asFormattedString(self,indent) +recursive function tScalar_asFormattedString(self,indent) + character(len=:), allocatable :: tScalar_asFormattedString class (tScalar), intent(in), target :: self integer, intent(in), optional :: indent @@ -744,20 +746,21 @@ recursive subroutine tScalar_asFormattedString(self,indent) indent_ = 0 endif - write (6,'(a)') trim(self%value) + tScalar_asFormattedString = trim(self%value)//IO_EOL -end subroutine tScalar_asFormattedString +end function tScalar_asFormattedString !-------------------------------------------------------------------------------------------------- !> @brief Prints list as string (YAML block style) !-------------------------------------------------------------------------------------------------- -recursive subroutine tList_asFormattedString(self,indent) +recursive function tList_asFormattedString(self,indent) result(str) class (tList),intent(in),target :: self integer, intent(in),optional :: indent type (tItem), pointer :: item + character(len=:), allocatable :: str integer :: i, indent_ if(present(indent)) then @@ -768,24 +771,24 @@ recursive subroutine tList_asFormattedString(self,indent) item => self%first do i = 1, self%length - if( i /= 1) write (6,'(a)',advance='NO') repeat(' ',indent_) - write (6,'(a)',advance='NO') '- ' - call item%node%asFormattedString(indent_+2) + if(i /= 1) str = str//repeat(' ',indent_) + str = str//'- '//item%node%asFormattedString(indent_+2) item => item%next end do -end subroutine tList_asFormattedString +end function tList_asFormattedString !-------------------------------------------------------------------------------------------------- !> @brief Prints dictionary as string (YAML block style) !-------------------------------------------------------------------------------------------------- -recursive subroutine tDict_asFormattedString(self,indent) +recursive function tDict_asFormattedString(self,indent) result(str) class (tDict),intent(in),target :: self integer, intent(in),optional :: indent type (tItem),pointer :: item + character(len=:), allocatable :: str integer :: i, indent_ if(present(indent)) then @@ -796,20 +799,17 @@ recursive subroutine tDict_asFormattedString(self,indent) item => self%first do i = 1, self%length - if( i /= 1) write (6,'(a)',advance='NO') repeat(' ',indent_) - select type (node_ => item%node) - class is (tScalar) - write (6,'(a)',advance='NO') trim(item%key)//': ' - call node_%asFormattedString(indent_+len_trim(item%key)+2) + if(i /= 1) str = str//repeat(' ',indent_) + select type(node_1 =>item%node) + class is(tScalar) + str = str//trim(item%key)//': '//item%node%asFormattedString(indent_+len_trim(item%key)+2) class default - write (6,'(a)') trim(item%key)//':' - write (6,'(a)',advance='NO') repeat(' ',indent_+2) - call node_%asFormattedString(indent_+2) - end select + str = str//trim(item%key)//':'//IO_EOL//repeat(' ',indent_+2)//item%node%asFormattedString(indent_+2) + endselect item => item%next end do -end subroutine tDict_asFormattedString +end function tDict_asFormattedString !-------------------------------------------------------------------------------------------------- From 00deddac44df1657bd5b5c312273535cce5ee278 Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Sat, 2 May 2020 23:17:53 +0200 Subject: [PATCH 154/186] initialization needed --- src/YAML_types.f90 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index f1af2f9cb..314c099f8 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -762,7 +762,8 @@ recursive function tList_asFormattedString(self,indent) result(str) type (tItem), pointer :: item character(len=:), allocatable :: str integer :: i, indent_ - + + str = '' if(present(indent)) then indent_ = indent else @@ -791,6 +792,7 @@ recursive function tDict_asFormattedString(self,indent) result(str) character(len=:), allocatable :: str integer :: i, indent_ + str = '' if(present(indent)) then indent_ = indent else From c241eaec15dec1706acebe5fbde6dbee258c68b3 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 3 May 2020 07:23:46 +0200 Subject: [PATCH 155/186] rely on correct input data --- python/damask/_rotation.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 83c790d74..6fe546fd9 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -1061,14 +1061,12 @@ class Rotation: """ if len(ho.shape) == 1: - ho_ = ho/np.linalg.norm(ho)*_R1 if np.isclose(np.linalg.norm(ho),_R1,atol=1e-6) \ - else ho - rs = np.linalg.norm(ho_) + rs = np.linalg.norm(ho) - if np.allclose(ho_,0.0,rtol=0.0,atol=1.0e-16): + if np.allclose(ho,0.0,rtol=0.0,atol=1.0e-16): cu = np.zeros(3) else: - xyz3 = ho_[Rotation._get_order(ho_,'forward')] + xyz3 = ho[Rotation._get_order(ho,'forward')] # inverse M_3 xyz2 = xyz3[0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[2])) ) @@ -1090,7 +1088,7 @@ class Rotation: # inverse M_1 cu = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /_sc # reverse the coordinates back to the regular order according to the original pyramid number - cu = cu[Rotation._get_order(ho_,'backward')] + cu = cu[Rotation._get_order(ho,'backward')] return cu else: @@ -1135,16 +1133,12 @@ class Rotation: """ if len(cu.shape) == 1: - - cu_ = np.clip(cu,None,np.pi**(2./3.) * 0.5) if np.isclose(np.abs(np.max(cu)),np.pi**(2./3.) * 0.5,atol=1e-6) \ - else cu - # transform to the sphere grid via the curved square, and intercept the zero point - if np.allclose(cu_,0.0,rtol=0.0,atol=1.0e-16): + if np.allclose(cu,0.0,rtol=0.0,atol=1.0e-16): ho = np.zeros(3) else: # get pyramide and scale by grid parameter ratio - XYZ = cu_[Rotation._get_order(cu_,'forward')] * _sc + XYZ = cu[Rotation._get_order(cu,'forward')] * _sc # intercept all the points along the z-axis if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-16): @@ -1166,7 +1160,7 @@ class Rotation: ho = np.array([ T[order[1]] * q, T[order[0]] * q, np.sqrt(6.0/np.pi) * XYZ[2] - c ]) # reverse the coordinates back to the regular order according to the original pyramid number - ho = ho[Rotation._get_order(cu_,'backward')] + ho = ho[Rotation._get_order(cu,'backward')] return ho else: From 5d4b554b007be36eb383a1e39ac911f2de4a9fc0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 3 May 2020 07:30:09 +0200 Subject: [PATCH 156/186] WIP: vectorizing --- python/damask/_rotation.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 6fe546fd9..f97e356fc 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -1092,6 +1092,13 @@ class Rotation: return cu else: + q2 = qxy + np.max(np.abs(xyz2))**2 + sq2 = np.sqrt(q2) + q = (_beta/np.sqrt(2.0)/_R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2))*sq2)) + tt = np.clip((np.min(np.abs(xyz2))**2+np.max(np.abs(xyz2))*sq2)/np.sqrt(2.0)/qxy,-1.0,1.0) + Tinv = np.array([1.0,np.arccos(tt)/np.pi*12.0]) if np.abs(xyz2[1]) <= np.abs(xyz2[0]) else \ + np.array([np.arccos(tt)/np.pi*12.0,1.0]) + Tinv = q * np.where(xyz2<0.0,-Tinv,Tinv) raise NotImplementedError('Support for multiple rotations missing') @@ -1164,6 +1171,19 @@ class Rotation: return ho else: + # get pyramide and scale by grid parameter ratio + XYZ = cu[Rotation._get_order(cu,'forward')] * _sc + order = np.where(np.abs(XYZ[...,1]) <= np.abs(XYZ[...,0]), + np.broadcast_to([1,0],XYZ.shape[:-1]+(2,)), + np.broadcast_to([0,1],XYZ.shape[:-1]+(2,))) + q = np.pi/12.0 * XYZ[order[...,0]]/XYZ[order[...,1]] + c = np.cos(q) + s = np.sin(q) + q = _R1*2.0**0.25/_beta * XYZ[order[...,1]] / np.sqrt(np.sqrt(2.0)-c) + T = np.block([ (np.sqrt(2.0)*c - 1.0), np.sqrt(2.0) * s]) * q + s = c * np.pi/24.0 /XYZ[...,2]**2 + c = c * np.sqrt(np.pi/24.0)/XYZ[...,2] + q = np.sqrt( 1.0 - s ) raise NotImplementedError('Support for multiple rotations missing') @staticmethod From 8995faae8ba0c0a4277ca1d2dc67cb018ca998e9 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 3 May 2020 10:49:36 +0200 Subject: [PATCH 157/186] WIP: part of dotState should be in deltaState --- src/constitutive_plastic_nonlocal.f90 | 404 ++++++++++++++++++++++++++ 1 file changed, 404 insertions(+) diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index 77f1556f6..153e12dd1 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -1344,6 +1344,410 @@ module subroutine plastic_nonlocal_dotState(Mp, F, Fp, Temperature,timestep, & end subroutine plastic_nonlocal_dotState +!--------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!--------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_dotState2(Mp, F, Fp, Temperature,timestep, & + instance,of,ip,el) + + real(pReal), dimension(3,3), intent(in) :: & + Mp !< MandelStress + real(pReal), dimension(3,3,homogenization_maxNgrains,discretization_nIP,discretization_nElem), intent(in) :: & + F, & !< elastic deformation gradient + Fp !< plastic deformation gradient + real(pReal), intent(in) :: & + Temperature, & !< temperature + timestep !< substepped crystallite time increment + integer, intent(in) :: & + instance, & + of, & + ip, & !< current integration point + el !< current element number + + integer :: & + ph, & + neighbor_instance, & !< instance of my neighbor's plasticity + ns, & !< short notation for the total number of active slip systems + c, & !< character of dislocation + n, & !< index of my current neighbor + neighbor_el, & !< element number of my neighbor + neighbor_ip, & !< integration point of my neighbor + neighbor_n, & !< neighbor index pointing to me when looking from my neighbor + opposite_neighbor, & !< index of my opposite neighbor + opposite_ip, & !< ip of my opposite neighbor + opposite_el, & !< element index of my opposite neighbor + opposite_n, & !< neighbor index pointing to me when looking from my opposite neighbor + t, & !< type of dislocation + no,& !< neighbor offset shortcut + np,& !< neighbor phase shortcut + topp, & !< type of dislocation with opposite sign to t + s !< index of my current slip system + real(pReal), dimension(param(instance)%sum_N_sl,10) :: & + rho, & + rho0, & !< dislocation density at beginning of time step + rhoDot, & !< density evolution + rhoDotMultiplication, & !< density evolution by multiplication + rhoDotFlux, & !< density evolution by flux + rhoDotSingle2DipoleGlide, & !< density evolution by dipole formation (by glide) + rhoDotAthermalAnnihilation, & !< density evolution by athermal annihilation + rhoDotThermalAnnihilation !< density evolution by thermal annihilation + real(pReal), dimension(param(instance)%sum_N_sl,8) :: & + rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) + neighbor_rhoSgl0, & !< current single dislocation densities of neighboring ip (positive/negative screw and edge without dipoles) + my_rhoSgl0 !< single dislocation densities of central ip (positive/negative screw and edge without dipoles) + real(pReal), dimension(param(instance)%sum_N_sl,4) :: & + v, & !< current dislocation glide velocity + v0, & + neighbor_v0, & !< dislocation glide velocity of enighboring ip + gdot !< shear rates + real(pReal), dimension(param(instance)%sum_N_sl) :: & + tau, & !< current resolved shear stress + vClimb !< climb velocity of edge dipoles + real(pReal), dimension(param(instance)%sum_N_sl,2) :: & + rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) + dLower, & !< minimum stable dipole distance for edges and screws + dUpper !< current maximum stable dipole distance for edges and screws + real(pReal), dimension(3,param(instance)%sum_N_sl,4) :: & + m !< direction of dislocation motion + real(pReal), dimension(3,3) :: & + my_F, & !< my total deformation gradient + neighbor_F, & !< total deformation gradient of my neighbor + my_Fe, & !< my elastic deformation gradient + neighbor_Fe, & !< elastic deformation gradient of my neighbor + Favg !< average total deformation gradient of me and my neighbor + real(pReal), dimension(3) :: & + normal_neighbor2me, & !< interface normal pointing from my neighbor to me in neighbor's lattice configuration + normal_neighbor2me_defConf, & !< interface normal pointing from my neighbor to me in shared deformed configuration + normal_me2neighbor, & !< interface normal pointing from me to my neighbor in my lattice configuration + normal_me2neighbor_defConf !< interface normal pointing from me to my neighbor in shared deformed configuration + real(pReal) :: & + area, & !< area of the current interface + transmissivity, & !< overall transmissivity of dislocation flux to neighboring material point + lineLength, & !< dislocation line length leaving the current interface + selfDiffusion !< self diffusion + + ph = material_phaseAt(1,el) + if (timestep <= 0.0_pReal) then + plasticState(ph)%dotState = 0.0_pReal + return + endif + + associate(prm => param(instance), & + dst => microstructure(instance), & + dot => dotState(instance), & + stt => state(instance)) + ns = prm%sum_N_sl + + tau = 0.0_pReal + gdot = 0.0_pReal + + rho = getRho(instance,of,ip,el) + rhoSgl = rho(:,sgl) + rhoDip = rho(:,dip) + rho0 = getRho0(instance,of,ip,el) + my_rhoSgl0 = rho0(:,sgl) + + forall (s = 1:ns, t = 1:4) v(s,t) = plasticState(ph)%state(iV(s,t,instance),of) + gdot = rhoSgl(:,1:4) * v * spread(prm%burgers,2,4) + +#ifdef DEBUG + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0 & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0 )) then + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> rho / 1/m^2', rhoSgl, rhoDip + write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> gdot / 1/s',gdot + endif +#endif + + !**************************************************************************** + !*** limits for stable dipole height + do s = 1,ns + tau(s) = math_tensordot(Mp, prm%Schmid(1:3,1:3,s)) + dst%tau_back(s,of) + if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal + enddo + + dLower = prm%minDipoleHeight + dUpper(:,1) = prm%mu * prm%burgers/(8.0_pReal * PI * (1.0_pReal - prm%nu) * abs(tau)) + dUpper(:,2) = prm%mu * prm%burgers/(4.0_pReal * PI * abs(tau)) + + where(dNeq0(sqrt(sum(abs(rho(:,edg)),2)))) & + dUpper(:,1) = min(1.0_pReal/sqrt(sum(abs(rho(:,edg)),2)),dUpper(:,1)) + where(dNeq0(sqrt(sum(abs(rho(:,scr)),2)))) & + dUpper(:,2) = min(1.0_pReal/sqrt(sum(abs(rho(:,scr)),2)),dUpper(:,2)) + + dUpper = max(dUpper,dLower) + + !**************************************************************************** + !*** dislocation multiplication + rhoDotMultiplication = 0.0_pReal + isBCC: if (lattice_structure(ph) == LATTICE_bcc_ID) then + forall (s = 1:ns, sum(abs(v(s,1:4))) > 0.0_pReal) + rhoDotMultiplication(s,1:2) = sum(abs(gdot(s,3:4))) / prm%burgers(s) & ! assuming double-cross-slip of screws to be decisive for multiplication + * sqrt(stt%rho_forest(s,of)) / prm%lambda0(s) ! & ! mean free path + ! * 2.0_pReal * sum(abs(v(s,3:4))) / sum(abs(v(s,1:4))) ! ratio of screw to overall velocity determines edge generation + rhoDotMultiplication(s,3:4) = sum(abs(gdot(s,3:4))) /prm%burgers(s) & ! assuming double-cross-slip of screws to be decisive for multiplication + * sqrt(stt%rho_forest(s,of)) / prm%lambda0(s) ! & ! mean free path + ! * 2.0_pReal * sum(abs(v(s,1:2))) / sum(abs(v(s,1:4))) ! ratio of edge to overall velocity determines screw generation + endforall + + else isBCC + rhoDotMultiplication(:,1:4) = spread( & + (sum(abs(gdot(:,1:2)),2) * prm%fEdgeMultiplication + sum(abs(gdot(:,3:4)),2)) & + * sqrt(stt%rho_forest(:,of)) / prm%lambda0 / prm%burgers, 2, 4) + endif isBCC + + forall (s = 1:ns, t = 1:4) v0(s,t) = plasticState(ph)%state0(iV(s,t,instance),of) + + !**************************************************************************** + !*** calculate dislocation fluxes (only for nonlocal plasticity) + rhoDotFlux = 0.0_pReal + if (.not. phase_localPlasticity(material_phaseAt(1,el))) then + + !*** check CFL (Courant-Friedrichs-Lewy) condition for flux + if (any( abs(gdot) > 0.0_pReal & ! any active slip system ... + .and. prm%CFLfactor * abs(v0) * timestep & + > IPvolume(ip,el) / maxval(IParea(:,ip,el)))) then ! ...with velocity above critical value (we use the reference volume and area for simplicity here) +#ifdef DEBUG + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0) then + write(6,'(a,i5,a,i2)') '<< CONST >> CFL condition not fullfilled at el ',el,' ip ',ip + write(6,'(a,e10.3,a,e10.3)') '<< CONST >> velocity is at ', & + maxval(abs(v0), abs(gdot) > 0.0_pReal & + .and. prm%CFLfactor * abs(v0) * timestep & + > IPvolume(ip,el) / maxval(IParea(:,ip,el))), & + ' at a timestep of ',timestep + write(6,'(a)') '<< CONST >> enforcing cutback !!!' + endif +#endif + plasticState(ph)%dotState = IEEE_value(1.0_pReal,IEEE_quiet_NaN) ! -> return NaN and, hence, enforce cutback + return + endif + + + !*** be aware of the definition of slip_transverse = slip_direction x slip_normal !!! + !*** opposite sign to our t vector in the (s,t,n) triplet !!! + + m(1:3,:,1) = prm%slip_direction + m(1:3,:,2) = -prm%slip_direction + m(1:3,:,3) = -prm%slip_transverse + m(1:3,:,4) = prm%slip_transverse + + my_F = F(1:3,1:3,1,ip,el) + my_Fe = matmul(my_F, math_inv33(Fp(1:3,1:3,1,ip,el))) + + neighbors: do n = 1,nIPneighbors + + neighbor_el = IPneighborhood(1,n,ip,el) + neighbor_ip = IPneighborhood(2,n,ip,el) + neighbor_n = IPneighborhood(3,n,ip,el) + np = material_phaseAt(1,neighbor_el) + no = material_phasememberAt(1,neighbor_ip,neighbor_el) + + opposite_neighbor = n + mod(n,2) - mod(n+1,2) + opposite_el = IPneighborhood(1,opposite_neighbor,ip,el) + opposite_ip = IPneighborhood(2,opposite_neighbor,ip,el) + opposite_n = IPneighborhood(3,opposite_neighbor,ip,el) + + if (neighbor_n > 0) then ! if neighbor exists, average deformation gradient + neighbor_instance = phase_plasticityInstance(material_phaseAt(1,neighbor_el)) + neighbor_F = F(1:3,1:3,1,neighbor_ip,neighbor_el) + neighbor_Fe = matmul(neighbor_F, math_inv33(Fp(1:3,1:3,1,neighbor_ip,neighbor_el))) + Favg = 0.5_pReal * (my_F + neighbor_F) + else ! if no neighbor, take my value as average + Favg = my_F + endif + + neighbor_v0 = 0.0_pReal ! needed for check of sign change in flux density below + + !* FLUX FROM MY NEIGHBOR TO ME + !* This is only considered, if I have a neighbor of nonlocal plasticity + !* (also nonlocal constitutive law with local properties) that is at least a little bit + !* compatible. + !* If it's not at all compatible, no flux is arriving, because everything is dammed in front of + !* my neighbor's interface. + !* The entering flux from my neighbor will be distributed on my slip systems according to the + !* compatibility + if (neighbor_n > 0) then + if (phase_plasticity(material_phaseAt(1,neighbor_el)) == PLASTICITY_NONLOCAL_ID .and. & + any(compatibility(:,:,:,n,ip,el) > 0.0_pReal)) then + + forall (s = 1:ns, t = 1:4) + neighbor_v0(s,t) = plasticState(np)%state0(iV (s,t,neighbor_instance),no) + neighbor_rhoSgl0(s,t) = max(plasticState(np)%state0(iRhoU(s,t,neighbor_instance),no),0.0_pReal) + endforall + + where (neighbor_rhoSgl0 * IPvolume(neighbor_ip,neighbor_el) ** 0.667_pReal < prm%significantN & + .or. neighbor_rhoSgl0 < prm%significantRho) & + neighbor_rhoSgl0 = 0.0_pReal + normal_neighbor2me_defConf = math_det33(Favg) * matmul(math_inv33(transpose(Favg)), & + IPareaNormal(1:3,neighbor_n,neighbor_ip,neighbor_el)) ! normal of the interface in (average) deformed configuration (pointing neighbor => me) + normal_neighbor2me = matmul(transpose(neighbor_Fe), normal_neighbor2me_defConf) & + / math_det33(neighbor_Fe) ! interface normal in the lattice configuration of my neighbor + area = IParea(neighbor_n,neighbor_ip,neighbor_el) * norm2(normal_neighbor2me) + normal_neighbor2me = normal_neighbor2me / norm2(normal_neighbor2me) ! normalize the surface normal to unit length + do s = 1,ns + do t = 1,4 + c = (t + 1) / 2 + topp = t + mod(t,2) - mod(t+1,2) + if (neighbor_v0(s,t) * math_inner(m(1:3,s,t), normal_neighbor2me) > 0.0_pReal & ! flux from my neighbor to me == entering flux for me + .and. v0(s,t) * neighbor_v0(s,t) >= 0.0_pReal ) then ! ... only if no sign change in flux density + lineLength = neighbor_rhoSgl0(s,t) * neighbor_v0(s,t) & + * math_inner(m(1:3,s,t), normal_neighbor2me) * area ! positive line length that wants to enter through this interface + where (compatibility(c,:,s,n,ip,el) > 0.0_pReal) & + rhoDotFlux(:,t) = rhoDotFlux(1:ns,t) & + + lineLength/IPvolume(ip,el)*compatibility(c,:,s,n,ip,el)**2.0_pReal ! transferring to equally signed mobile dislocation type + where (compatibility(c,:,s,n,ip,el) < 0.0_pReal) & + rhoDotFlux(:,topp) = rhoDotFlux(:,topp) & + + lineLength/IPvolume(ip,el)*compatibility(c,:,s,n,ip,el)**2.0_pReal ! transferring to opposite signed mobile dislocation type + + endif + enddo + enddo + endif; endif + + + !* FLUX FROM ME TO MY NEIGHBOR + !* This is not considered, if my opposite neighbor has a different constitutive law than nonlocal (still considered for nonlocal law with local properties). + !* Then, we assume, that the opposite(!) neighbor sends an equal amount of dislocations to me. + !* So the net flux in the direction of my neighbor is equal to zero: + !* leaving flux to neighbor == entering flux from opposite neighbor + !* In case of reduced transmissivity, part of the leaving flux is stored as dead dislocation density. + !* That means for an interface of zero transmissivity the leaving flux is fully converted to dead dislocations. + if (opposite_n > 0) then + if (phase_plasticity(material_phaseAt(1,opposite_el)) == PLASTICITY_NONLOCAL_ID) then + + normal_me2neighbor_defConf = math_det33(Favg) & + * matmul(math_inv33(transpose(Favg)),IPareaNormal(1:3,n,ip,el)) ! normal of the interface in (average) deformed configuration (pointing me => neighbor) + normal_me2neighbor = matmul(transpose(my_Fe), normal_me2neighbor_defConf) & + / math_det33(my_Fe) ! interface normal in my lattice configuration + area = IParea(n,ip,el) * norm2(normal_me2neighbor) + normal_me2neighbor = normal_me2neighbor / norm2(normal_me2neighbor) ! normalize the surface normal to unit length + do s = 1,ns + do t = 1,4 + c = (t + 1) / 2 + if (v0(s,t) * math_inner(m(1:3,s,t), normal_me2neighbor) > 0.0_pReal ) then ! flux from me to my neighbor == leaving flux for me (might also be a pure flux from my mobile density to dead density if interface not at all transmissive) + if (v0(s,t) * neighbor_v0(s,t) >= 0.0_pReal) then ! no sign change in flux density + transmissivity = sum(compatibility(c,:,s,n,ip,el)**2.0_pReal) ! overall transmissivity from this slip system to my neighbor + else ! sign change in flux density means sign change in stress which does not allow for dislocations to arive at the neighbor + transmissivity = 0.0_pReal + endif + lineLength = my_rhoSgl0(s,t) * v0(s,t) & + * math_inner(m(1:3,s,t), normal_me2neighbor) * area ! positive line length of mobiles that wants to leave through this interface + rhoDotFlux(s,t) = rhoDotFlux(s,t) - lineLength / IPvolume(ip,el) ! subtract dislocation flux from current type + rhoDotFlux(s,t+4) = rhoDotFlux(s,t+4) & + + lineLength / IPvolume(ip,el) * (1.0_pReal - transmissivity) & + * sign(1.0_pReal, v0(s,t)) ! dislocation flux that is not able to leave through interface (because of low transmissivity) will remain as immobile single density at the material point + endif + enddo + enddo + endif; endif + + enddo neighbors + endif + + + + !**************************************************************************** + !*** calculate dipole formation and annihilation + + !*** formation by glide + do c = 1,2 + rhoDotSingle2DipoleGlide(:,2*c-1) = -2.0_pReal * dUpper(:,c) / prm%burgers & + * ( rhoSgl(:,2*c-1) * abs(gdot(:,2*c)) & ! negative mobile --> positive mobile + + rhoSgl(:,2*c) * abs(gdot(:,2*c-1)) & ! positive mobile --> negative mobile + + abs(rhoSgl(:,2*c+4)) * abs(gdot(:,2*c-1))) ! positive mobile --> negative immobile + + rhoDotSingle2DipoleGlide(:,2*c) = -2.0_pReal * dUpper(:,c) / prm%burgers & + * ( rhoSgl(:,2*c-1) * abs(gdot(:,2*c)) & ! negative mobile --> positive mobile + + rhoSgl(:,2*c) * abs(gdot(:,2*c-1)) & ! positive mobile --> negative mobile + + abs(rhoSgl(:,2*c+3)) * abs(gdot(:,2*c))) ! negative mobile --> positive immobile + + rhoDotSingle2DipoleGlide(:,2*c+3) = -2.0_pReal * dUpper(:,c) / prm%burgers & + * rhoSgl(:,2*c+3) * abs(gdot(:,2*c)) ! negative mobile --> positive immobile + + rhoDotSingle2DipoleGlide(:,2*c+4) = -2.0_pReal * dUpper(:,c) / prm%burgers & + * rhoSgl(:,2*c+4) * abs(gdot(:,2*c-1)) ! positive mobile --> negative immobile + + rhoDotSingle2DipoleGlide(:,c+8) = abs(rhoDotSingle2DipoleGlide(:,2*c+3)) & + + abs(rhoDotSingle2DipoleGlide(:,2*c+4)) & + - rhoDotSingle2DipoleGlide(:,2*c-1) & + - rhoDotSingle2DipoleGlide(:,2*c) + enddo + + + !*** athermal annihilation + rhoDotAthermalAnnihilation = 0.0_pReal + forall (c=1:2) & + rhoDotAthermalAnnihilation(:,c+8) = -2.0_pReal * dLower(:,c) / prm%burgers & + * ( 2.0_pReal * (rhoSgl(:,2*c-1) * abs(gdot(:,2*c)) + rhoSgl(:,2*c) * abs(gdot(:,2*c-1))) & ! was single hitting single + + 2.0_pReal * (abs(rhoSgl(:,2*c+3)) * abs(gdot(:,2*c)) + abs(rhoSgl(:,2*c+4)) * abs(gdot(:,2*c-1))) & ! was single hitting immobile single or was immobile single hit by single + + rhoDip(:,c) * (abs(gdot(:,2*c-1)) + abs(gdot(:,2*c)))) ! single knocks dipole constituent + + ! annihilated screw dipoles leave edge jogs behind on the colinear system + if (lattice_structure(ph) == LATTICE_fcc_ID) & + forall (s = 1:ns, prm%colinearSystem(s) > 0) & + rhoDotAthermalAnnihilation(prm%colinearSystem(s),1:2) = - rhoDotAthermalAnnihilation(s,10) & + * 0.25_pReal * sqrt(stt%rho_forest(s,of)) * (dUpper(s,2) + dLower(s,2)) * prm%edgeJogFactor + + + !*** thermally activated annihilation of edge dipoles by climb + rhoDotThermalAnnihilation = 0.0_pReal + selfDiffusion = prm%Dsd0 * exp(-prm%selfDiffusionEnergy / (kB * Temperature)) + vClimb = prm%atomicVolume * selfDiffusion * prm%mu & + / ( kB * Temperature * PI * (1.0_pReal-prm%nu) * (dUpper(:,1) + dLower(:,1))) + forall (s = 1:ns, dUpper(s,1) > dLower(s,1)) & + rhoDotThermalAnnihilation(s,9) = max(- 4.0_pReal * rhoDip(s,1) * vClimb(s) / (dUpper(s,1) - dLower(s,1)), & + - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & + - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have + + rhoDot = rhoDotFlux & + + rhoDotMultiplication & + + rhoDotSingle2DipoleGlide & + + rhoDotAthermalAnnihilation & + + rhoDotThermalAnnihilation + +#ifdef DEBUG + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0 & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0 )) then + write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> dislocation multiplication', & + rhoDotMultiplication(:,1:4) * timestep + write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation flux', & + rhoDotFlux(:,1:8) * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> dipole formation by glide', & + rhoDotSingle2DipoleGlide * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> athermal dipole annihilation', & + rhoDotAthermalAnnihilation * timestep + write(6,'(a,/,2(12x,12(e12.5,1x),/))') '<< CONST >> thermally activated dipole annihilation', & + rhoDotThermalAnnihilation(:,9:10) * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> total density change', & + rhoDot * timestep + write(6,'(a,/,10(12x,12(f12.5,1x),/))') '<< CONST >> relative density change', & + rhoDot(:,1:8) * timestep / (abs(stt%rho(:,sgl))+1.0e-10), & + rhoDot(:,9:10) * timestep / (stt%rho(:,dip)+1.0e-10) + write(6,*) + endif +#endif + + + if ( any(rho(:,mob) + rhoDot(:,1:4) * timestep < -prm%atol_rho) & + .or. any(rho(:,dip) + rhoDot(:,9:10) * timestep < -prm%atol_rho)) then +#ifdef DEBUG + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0) then + write(6,'(a,i5,a,i2)') '<< CONST >> evolution rate leads to negative density at el ',el,' ip ',ip + write(6,'(a)') '<< CONST >> enforcing cutback !!!' + endif +#endif + plasticState(ph)%dotState = IEEE_value(1.0_pReal,IEEE_quiet_NaN) + else + dot%rho(:,of) = pack(rhoDot,.true.) + dot%gamma(:,of) = sum(gdot,2) + endif + + end associate + +end subroutine plastic_nonlocal_dotState2 + + !-------------------------------------------------------------------------------------------------- !> @brief Compatibility update !> @detail Compatibility is defined as normalized product of signed cosine of the angle between the slip From 6f627892bc9871b73d0ce66c19bdb4cb1365cad7 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 3 May 2020 10:54:57 +0200 Subject: [PATCH 158/186] not needed --- src/constitutive_plastic_nonlocal.f90 | 170 +------------------------- 1 file changed, 4 insertions(+), 166 deletions(-) diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index 153e12dd1..e80f2ceab 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -1347,16 +1347,13 @@ end subroutine plastic_nonlocal_dotState !--------------------------------------------------------------------------------------------------- !> @brief calculates the rate of change of microstructure !--------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_dotState2(Mp, F, Fp, Temperature,timestep, & - instance,of,ip,el) +subroutine plastic_nonlocal_dotState2(F, Fp,timestep, & + instance,of,ip,el) - real(pReal), dimension(3,3), intent(in) :: & - Mp !< MandelStress real(pReal), dimension(3,3,homogenization_maxNgrains,discretization_nIP,discretization_nElem), intent(in) :: & F, & !< elastic deformation gradient Fp !< plastic deformation gradient real(pReal), intent(in) :: & - Temperature, & !< temperature timestep !< substepped crystallite time increment integer, intent(in) :: & instance, & @@ -1385,12 +1382,7 @@ subroutine plastic_nonlocal_dotState2(Mp, F, Fp, Temperature,timestep, & real(pReal), dimension(param(instance)%sum_N_sl,10) :: & rho, & rho0, & !< dislocation density at beginning of time step - rhoDot, & !< density evolution - rhoDotMultiplication, & !< density evolution by multiplication - rhoDotFlux, & !< density evolution by flux - rhoDotSingle2DipoleGlide, & !< density evolution by dipole formation (by glide) - rhoDotAthermalAnnihilation, & !< density evolution by athermal annihilation - rhoDotThermalAnnihilation !< density evolution by thermal annihilation + rhoDotFlux !< density evolution by flux real(pReal), dimension(param(instance)%sum_N_sl,8) :: & rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) neighbor_rhoSgl0, & !< current single dislocation densities of neighboring ip (positive/negative screw and edge without dipoles) @@ -1400,13 +1392,6 @@ subroutine plastic_nonlocal_dotState2(Mp, F, Fp, Temperature,timestep, & v0, & neighbor_v0, & !< dislocation glide velocity of enighboring ip gdot !< shear rates - real(pReal), dimension(param(instance)%sum_N_sl) :: & - tau, & !< current resolved shear stress - vClimb !< climb velocity of edge dipoles - real(pReal), dimension(param(instance)%sum_N_sl,2) :: & - rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) - dLower, & !< minimum stable dipole distance for edges and screws - dUpper !< current maximum stable dipole distance for edges and screws real(pReal), dimension(3,param(instance)%sum_N_sl,4) :: & m !< direction of dislocation motion real(pReal), dimension(3,3) :: & @@ -1423,8 +1408,7 @@ subroutine plastic_nonlocal_dotState2(Mp, F, Fp, Temperature,timestep, & real(pReal) :: & area, & !< area of the current interface transmissivity, & !< overall transmissivity of dislocation flux to neighboring material point - lineLength, & !< dislocation line length leaving the current interface - selfDiffusion !< self diffusion + lineLength !< dislocation line length leaving the current interface ph = material_phaseAt(1,el) if (timestep <= 0.0_pReal) then @@ -1438,63 +1422,16 @@ subroutine plastic_nonlocal_dotState2(Mp, F, Fp, Temperature,timestep, & stt => state(instance)) ns = prm%sum_N_sl - tau = 0.0_pReal gdot = 0.0_pReal rho = getRho(instance,of,ip,el) rhoSgl = rho(:,sgl) - rhoDip = rho(:,dip) rho0 = getRho0(instance,of,ip,el) my_rhoSgl0 = rho0(:,sgl) forall (s = 1:ns, t = 1:4) v(s,t) = plasticState(ph)%state(iV(s,t,instance),of) gdot = rhoSgl(:,1:4) * v * spread(prm%burgers,2,4) -#ifdef DEBUG - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0 & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0 )) then - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> rho / 1/m^2', rhoSgl, rhoDip - write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> gdot / 1/s',gdot - endif -#endif - - !**************************************************************************** - !*** limits for stable dipole height - do s = 1,ns - tau(s) = math_tensordot(Mp, prm%Schmid(1:3,1:3,s)) + dst%tau_back(s,of) - if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal - enddo - - dLower = prm%minDipoleHeight - dUpper(:,1) = prm%mu * prm%burgers/(8.0_pReal * PI * (1.0_pReal - prm%nu) * abs(tau)) - dUpper(:,2) = prm%mu * prm%burgers/(4.0_pReal * PI * abs(tau)) - - where(dNeq0(sqrt(sum(abs(rho(:,edg)),2)))) & - dUpper(:,1) = min(1.0_pReal/sqrt(sum(abs(rho(:,edg)),2)),dUpper(:,1)) - where(dNeq0(sqrt(sum(abs(rho(:,scr)),2)))) & - dUpper(:,2) = min(1.0_pReal/sqrt(sum(abs(rho(:,scr)),2)),dUpper(:,2)) - - dUpper = max(dUpper,dLower) - - !**************************************************************************** - !*** dislocation multiplication - rhoDotMultiplication = 0.0_pReal - isBCC: if (lattice_structure(ph) == LATTICE_bcc_ID) then - forall (s = 1:ns, sum(abs(v(s,1:4))) > 0.0_pReal) - rhoDotMultiplication(s,1:2) = sum(abs(gdot(s,3:4))) / prm%burgers(s) & ! assuming double-cross-slip of screws to be decisive for multiplication - * sqrt(stt%rho_forest(s,of)) / prm%lambda0(s) ! & ! mean free path - ! * 2.0_pReal * sum(abs(v(s,3:4))) / sum(abs(v(s,1:4))) ! ratio of screw to overall velocity determines edge generation - rhoDotMultiplication(s,3:4) = sum(abs(gdot(s,3:4))) /prm%burgers(s) & ! assuming double-cross-slip of screws to be decisive for multiplication - * sqrt(stt%rho_forest(s,of)) / prm%lambda0(s) ! & ! mean free path - ! * 2.0_pReal * sum(abs(v(s,1:2))) / sum(abs(v(s,1:4))) ! ratio of edge to overall velocity determines screw generation - endforall - - else isBCC - rhoDotMultiplication(:,1:4) = spread( & - (sum(abs(gdot(:,1:2)),2) * prm%fEdgeMultiplication + sum(abs(gdot(:,3:4)),2)) & - * sqrt(stt%rho_forest(:,of)) / prm%lambda0 / prm%burgers, 2, 4) - endif isBCC forall (s = 1:ns, t = 1:4) v0(s,t) = plasticState(ph)%state0(iV(s,t,instance),of) @@ -1644,105 +1581,6 @@ subroutine plastic_nonlocal_dotState2(Mp, F, Fp, Temperature,timestep, & enddo neighbors endif - - - !**************************************************************************** - !*** calculate dipole formation and annihilation - - !*** formation by glide - do c = 1,2 - rhoDotSingle2DipoleGlide(:,2*c-1) = -2.0_pReal * dUpper(:,c) / prm%burgers & - * ( rhoSgl(:,2*c-1) * abs(gdot(:,2*c)) & ! negative mobile --> positive mobile - + rhoSgl(:,2*c) * abs(gdot(:,2*c-1)) & ! positive mobile --> negative mobile - + abs(rhoSgl(:,2*c+4)) * abs(gdot(:,2*c-1))) ! positive mobile --> negative immobile - - rhoDotSingle2DipoleGlide(:,2*c) = -2.0_pReal * dUpper(:,c) / prm%burgers & - * ( rhoSgl(:,2*c-1) * abs(gdot(:,2*c)) & ! negative mobile --> positive mobile - + rhoSgl(:,2*c) * abs(gdot(:,2*c-1)) & ! positive mobile --> negative mobile - + abs(rhoSgl(:,2*c+3)) * abs(gdot(:,2*c))) ! negative mobile --> positive immobile - - rhoDotSingle2DipoleGlide(:,2*c+3) = -2.0_pReal * dUpper(:,c) / prm%burgers & - * rhoSgl(:,2*c+3) * abs(gdot(:,2*c)) ! negative mobile --> positive immobile - - rhoDotSingle2DipoleGlide(:,2*c+4) = -2.0_pReal * dUpper(:,c) / prm%burgers & - * rhoSgl(:,2*c+4) * abs(gdot(:,2*c-1)) ! positive mobile --> negative immobile - - rhoDotSingle2DipoleGlide(:,c+8) = abs(rhoDotSingle2DipoleGlide(:,2*c+3)) & - + abs(rhoDotSingle2DipoleGlide(:,2*c+4)) & - - rhoDotSingle2DipoleGlide(:,2*c-1) & - - rhoDotSingle2DipoleGlide(:,2*c) - enddo - - - !*** athermal annihilation - rhoDotAthermalAnnihilation = 0.0_pReal - forall (c=1:2) & - rhoDotAthermalAnnihilation(:,c+8) = -2.0_pReal * dLower(:,c) / prm%burgers & - * ( 2.0_pReal * (rhoSgl(:,2*c-1) * abs(gdot(:,2*c)) + rhoSgl(:,2*c) * abs(gdot(:,2*c-1))) & ! was single hitting single - + 2.0_pReal * (abs(rhoSgl(:,2*c+3)) * abs(gdot(:,2*c)) + abs(rhoSgl(:,2*c+4)) * abs(gdot(:,2*c-1))) & ! was single hitting immobile single or was immobile single hit by single - + rhoDip(:,c) * (abs(gdot(:,2*c-1)) + abs(gdot(:,2*c)))) ! single knocks dipole constituent - - ! annihilated screw dipoles leave edge jogs behind on the colinear system - if (lattice_structure(ph) == LATTICE_fcc_ID) & - forall (s = 1:ns, prm%colinearSystem(s) > 0) & - rhoDotAthermalAnnihilation(prm%colinearSystem(s),1:2) = - rhoDotAthermalAnnihilation(s,10) & - * 0.25_pReal * sqrt(stt%rho_forest(s,of)) * (dUpper(s,2) + dLower(s,2)) * prm%edgeJogFactor - - - !*** thermally activated annihilation of edge dipoles by climb - rhoDotThermalAnnihilation = 0.0_pReal - selfDiffusion = prm%Dsd0 * exp(-prm%selfDiffusionEnergy / (kB * Temperature)) - vClimb = prm%atomicVolume * selfDiffusion * prm%mu & - / ( kB * Temperature * PI * (1.0_pReal-prm%nu) * (dUpper(:,1) + dLower(:,1))) - forall (s = 1:ns, dUpper(s,1) > dLower(s,1)) & - rhoDotThermalAnnihilation(s,9) = max(- 4.0_pReal * rhoDip(s,1) * vClimb(s) / (dUpper(s,1) - dLower(s,1)), & - - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & - - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have - - rhoDot = rhoDotFlux & - + rhoDotMultiplication & - + rhoDotSingle2DipoleGlide & - + rhoDotAthermalAnnihilation & - + rhoDotThermalAnnihilation - -#ifdef DEBUG - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0 & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0 )) then - write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> dislocation multiplication', & - rhoDotMultiplication(:,1:4) * timestep - write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation flux', & - rhoDotFlux(:,1:8) * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> dipole formation by glide', & - rhoDotSingle2DipoleGlide * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> athermal dipole annihilation', & - rhoDotAthermalAnnihilation * timestep - write(6,'(a,/,2(12x,12(e12.5,1x),/))') '<< CONST >> thermally activated dipole annihilation', & - rhoDotThermalAnnihilation(:,9:10) * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> total density change', & - rhoDot * timestep - write(6,'(a,/,10(12x,12(f12.5,1x),/))') '<< CONST >> relative density change', & - rhoDot(:,1:8) * timestep / (abs(stt%rho(:,sgl))+1.0e-10), & - rhoDot(:,9:10) * timestep / (stt%rho(:,dip)+1.0e-10) - write(6,*) - endif -#endif - - - if ( any(rho(:,mob) + rhoDot(:,1:4) * timestep < -prm%atol_rho) & - .or. any(rho(:,dip) + rhoDot(:,9:10) * timestep < -prm%atol_rho)) then -#ifdef DEBUG - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0) then - write(6,'(a,i5,a,i2)') '<< CONST >> evolution rate leads to negative density at el ',el,' ip ',ip - write(6,'(a)') '<< CONST >> enforcing cutback !!!' - endif -#endif - plasticState(ph)%dotState = IEEE_value(1.0_pReal,IEEE_quiet_NaN) - else - dot%rho(:,of) = pack(rhoDot,.true.) - dot%gamma(:,of) = sum(gdot,2) - endif - end associate end subroutine plastic_nonlocal_dotState2 From 53de95798a38e3b85f90b4168a38c74b2671b320 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 3 May 2020 11:49:16 +0200 Subject: [PATCH 159/186] separated local and nonlocal part of dotState --- src/constitutive_plastic_nonlocal.f90 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index e80f2ceab..928800e1d 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -1295,7 +1295,7 @@ module subroutine plastic_nonlocal_dotState(Mp, F, Fp, Temperature,timestep, & - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have - rhoDot = rhoDotFlux & + rhoDot = plastic_nonlocal_dotState2(F,Fp,timestep, instance,of,ip,el) & + rhoDotMultiplication & + rhoDotSingle2DipoleGlide & + rhoDotAthermalAnnihilation & @@ -1347,8 +1347,7 @@ end subroutine plastic_nonlocal_dotState !--------------------------------------------------------------------------------------------------- !> @brief calculates the rate of change of microstructure !--------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_dotState2(F, Fp,timestep, & - instance,of,ip,el) +function plastic_nonlocal_dotState2(F,Fp,timestep, instance,of,ip,el) result(rhoDotFlux) real(pReal), dimension(3,3,homogenization_maxNgrains,discretization_nIP,discretization_nElem), intent(in) :: & F, & !< elastic deformation gradient @@ -1583,7 +1582,7 @@ subroutine plastic_nonlocal_dotState2(F, Fp,timestep, & end associate -end subroutine plastic_nonlocal_dotState2 +end function plastic_nonlocal_dotState2 !-------------------------------------------------------------------------------------------------- From 2a1badb548ccd5979461ab17344ceeec0a4a7976 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 3 May 2020 12:04:57 +0200 Subject: [PATCH 160/186] not needed --- src/constitutive_plastic_nonlocal.f90 | 180 +------------------------- 1 file changed, 1 insertion(+), 179 deletions(-) diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index 928800e1d..08d14a5ce 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -962,39 +962,24 @@ module subroutine plastic_nonlocal_dotState(Mp, F, Fp, Temperature,timestep, & integer :: & ph, & - neighbor_instance, & !< instance of my neighbor's plasticity ns, & !< short notation for the total number of active slip systems c, & !< character of dislocation - n, & !< index of my current neighbor - neighbor_el, & !< element number of my neighbor - neighbor_ip, & !< integration point of my neighbor - neighbor_n, & !< neighbor index pointing to me when looking from my neighbor - opposite_neighbor, & !< index of my opposite neighbor - opposite_ip, & !< ip of my opposite neighbor - opposite_el, & !< element index of my opposite neighbor - opposite_n, & !< neighbor index pointing to me when looking from my opposite neighbor t, & !< type of dislocation - no,& !< neighbor offset shortcut - np,& !< neighbor phase shortcut - topp, & !< type of dislocation with opposite sign to t s !< index of my current slip system real(pReal), dimension(param(instance)%sum_N_sl,10) :: & rho, & rho0, & !< dislocation density at beginning of time step rhoDot, & !< density evolution rhoDotMultiplication, & !< density evolution by multiplication - rhoDotFlux, & !< density evolution by flux rhoDotSingle2DipoleGlide, & !< density evolution by dipole formation (by glide) rhoDotAthermalAnnihilation, & !< density evolution by athermal annihilation rhoDotThermalAnnihilation !< density evolution by thermal annihilation real(pReal), dimension(param(instance)%sum_N_sl,8) :: & rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) - neighbor_rhoSgl0, & !< current single dislocation densities of neighboring ip (positive/negative screw and edge without dipoles) my_rhoSgl0 !< single dislocation densities of central ip (positive/negative screw and edge without dipoles) real(pReal), dimension(param(instance)%sum_N_sl,4) :: & v, & !< current dislocation glide velocity v0, & - neighbor_v0, & !< dislocation glide velocity of enighboring ip gdot !< shear rates real(pReal), dimension(param(instance)%sum_N_sl) :: & tau, & !< current resolved shear stress @@ -1003,23 +988,7 @@ module subroutine plastic_nonlocal_dotState(Mp, F, Fp, Temperature,timestep, & rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) dLower, & !< minimum stable dipole distance for edges and screws dUpper !< current maximum stable dipole distance for edges and screws - real(pReal), dimension(3,param(instance)%sum_N_sl,4) :: & - m !< direction of dislocation motion - real(pReal), dimension(3,3) :: & - my_F, & !< my total deformation gradient - neighbor_F, & !< total deformation gradient of my neighbor - my_Fe, & !< my elastic deformation gradient - neighbor_Fe, & !< elastic deformation gradient of my neighbor - Favg !< average total deformation gradient of me and my neighbor - real(pReal), dimension(3) :: & - normal_neighbor2me, & !< interface normal pointing from my neighbor to me in neighbor's lattice configuration - normal_neighbor2me_defConf, & !< interface normal pointing from my neighbor to me in shared deformed configuration - normal_me2neighbor, & !< interface normal pointing from me to my neighbor in my lattice configuration - normal_me2neighbor_defConf !< interface normal pointing from me to my neighbor in shared deformed configuration real(pReal) :: & - area, & !< area of the current interface - transmissivity, & !< overall transmissivity of dislocation flux to neighboring material point - lineLength, & !< dislocation line length leaving the current interface selfDiffusion !< self diffusion ph = material_phaseAt(1,el) @@ -1094,153 +1063,6 @@ module subroutine plastic_nonlocal_dotState(Mp, F, Fp, Temperature,timestep, & forall (s = 1:ns, t = 1:4) v0(s,t) = plasticState(ph)%state0(iV(s,t,instance),of) - !**************************************************************************** - !*** calculate dislocation fluxes (only for nonlocal plasticity) - rhoDotFlux = 0.0_pReal - if (.not. phase_localPlasticity(material_phaseAt(1,el))) then - - !*** check CFL (Courant-Friedrichs-Lewy) condition for flux - if (any( abs(gdot) > 0.0_pReal & ! any active slip system ... - .and. prm%CFLfactor * abs(v0) * timestep & - > IPvolume(ip,el) / maxval(IParea(:,ip,el)))) then ! ...with velocity above critical value (we use the reference volume and area for simplicity here) -#ifdef DEBUG - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0) then - write(6,'(a,i5,a,i2)') '<< CONST >> CFL condition not fullfilled at el ',el,' ip ',ip - write(6,'(a,e10.3,a,e10.3)') '<< CONST >> velocity is at ', & - maxval(abs(v0), abs(gdot) > 0.0_pReal & - .and. prm%CFLfactor * abs(v0) * timestep & - > IPvolume(ip,el) / maxval(IParea(:,ip,el))), & - ' at a timestep of ',timestep - write(6,'(a)') '<< CONST >> enforcing cutback !!!' - endif -#endif - plasticState(ph)%dotState = IEEE_value(1.0_pReal,IEEE_quiet_NaN) ! -> return NaN and, hence, enforce cutback - return - endif - - - !*** be aware of the definition of slip_transverse = slip_direction x slip_normal !!! - !*** opposite sign to our t vector in the (s,t,n) triplet !!! - - m(1:3,:,1) = prm%slip_direction - m(1:3,:,2) = -prm%slip_direction - m(1:3,:,3) = -prm%slip_transverse - m(1:3,:,4) = prm%slip_transverse - - my_F = F(1:3,1:3,1,ip,el) - my_Fe = matmul(my_F, math_inv33(Fp(1:3,1:3,1,ip,el))) - - neighbors: do n = 1,nIPneighbors - - neighbor_el = IPneighborhood(1,n,ip,el) - neighbor_ip = IPneighborhood(2,n,ip,el) - neighbor_n = IPneighborhood(3,n,ip,el) - np = material_phaseAt(1,neighbor_el) - no = material_phasememberAt(1,neighbor_ip,neighbor_el) - - opposite_neighbor = n + mod(n,2) - mod(n+1,2) - opposite_el = IPneighborhood(1,opposite_neighbor,ip,el) - opposite_ip = IPneighborhood(2,opposite_neighbor,ip,el) - opposite_n = IPneighborhood(3,opposite_neighbor,ip,el) - - if (neighbor_n > 0) then ! if neighbor exists, average deformation gradient - neighbor_instance = phase_plasticityInstance(material_phaseAt(1,neighbor_el)) - neighbor_F = F(1:3,1:3,1,neighbor_ip,neighbor_el) - neighbor_Fe = matmul(neighbor_F, math_inv33(Fp(1:3,1:3,1,neighbor_ip,neighbor_el))) - Favg = 0.5_pReal * (my_F + neighbor_F) - else ! if no neighbor, take my value as average - Favg = my_F - endif - - neighbor_v0 = 0.0_pReal ! needed for check of sign change in flux density below - - !* FLUX FROM MY NEIGHBOR TO ME - !* This is only considered, if I have a neighbor of nonlocal plasticity - !* (also nonlocal constitutive law with local properties) that is at least a little bit - !* compatible. - !* If it's not at all compatible, no flux is arriving, because everything is dammed in front of - !* my neighbor's interface. - !* The entering flux from my neighbor will be distributed on my slip systems according to the - !* compatibility - if (neighbor_n > 0) then - if (phase_plasticity(material_phaseAt(1,neighbor_el)) == PLASTICITY_NONLOCAL_ID .and. & - any(compatibility(:,:,:,n,ip,el) > 0.0_pReal)) then - - forall (s = 1:ns, t = 1:4) - neighbor_v0(s,t) = plasticState(np)%state0(iV (s,t,neighbor_instance),no) - neighbor_rhoSgl0(s,t) = max(plasticState(np)%state0(iRhoU(s,t,neighbor_instance),no),0.0_pReal) - endforall - - where (neighbor_rhoSgl0 * IPvolume(neighbor_ip,neighbor_el) ** 0.667_pReal < prm%significantN & - .or. neighbor_rhoSgl0 < prm%significantRho) & - neighbor_rhoSgl0 = 0.0_pReal - normal_neighbor2me_defConf = math_det33(Favg) * matmul(math_inv33(transpose(Favg)), & - IPareaNormal(1:3,neighbor_n,neighbor_ip,neighbor_el)) ! normal of the interface in (average) deformed configuration (pointing neighbor => me) - normal_neighbor2me = matmul(transpose(neighbor_Fe), normal_neighbor2me_defConf) & - / math_det33(neighbor_Fe) ! interface normal in the lattice configuration of my neighbor - area = IParea(neighbor_n,neighbor_ip,neighbor_el) * norm2(normal_neighbor2me) - normal_neighbor2me = normal_neighbor2me / norm2(normal_neighbor2me) ! normalize the surface normal to unit length - do s = 1,ns - do t = 1,4 - c = (t + 1) / 2 - topp = t + mod(t,2) - mod(t+1,2) - if (neighbor_v0(s,t) * math_inner(m(1:3,s,t), normal_neighbor2me) > 0.0_pReal & ! flux from my neighbor to me == entering flux for me - .and. v0(s,t) * neighbor_v0(s,t) >= 0.0_pReal ) then ! ... only if no sign change in flux density - lineLength = neighbor_rhoSgl0(s,t) * neighbor_v0(s,t) & - * math_inner(m(1:3,s,t), normal_neighbor2me) * area ! positive line length that wants to enter through this interface - where (compatibility(c,:,s,n,ip,el) > 0.0_pReal) & - rhoDotFlux(:,t) = rhoDotFlux(1:ns,t) & - + lineLength/IPvolume(ip,el)*compatibility(c,:,s,n,ip,el)**2.0_pReal ! transferring to equally signed mobile dislocation type - where (compatibility(c,:,s,n,ip,el) < 0.0_pReal) & - rhoDotFlux(:,topp) = rhoDotFlux(:,topp) & - + lineLength/IPvolume(ip,el)*compatibility(c,:,s,n,ip,el)**2.0_pReal ! transferring to opposite signed mobile dislocation type - - endif - enddo - enddo - endif; endif - - - !* FLUX FROM ME TO MY NEIGHBOR - !* This is not considered, if my opposite neighbor has a different constitutive law than nonlocal (still considered for nonlocal law with local properties). - !* Then, we assume, that the opposite(!) neighbor sends an equal amount of dislocations to me. - !* So the net flux in the direction of my neighbor is equal to zero: - !* leaving flux to neighbor == entering flux from opposite neighbor - !* In case of reduced transmissivity, part of the leaving flux is stored as dead dislocation density. - !* That means for an interface of zero transmissivity the leaving flux is fully converted to dead dislocations. - if (opposite_n > 0) then - if (phase_plasticity(material_phaseAt(1,opposite_el)) == PLASTICITY_NONLOCAL_ID) then - - normal_me2neighbor_defConf = math_det33(Favg) & - * matmul(math_inv33(transpose(Favg)),IPareaNormal(1:3,n,ip,el)) ! normal of the interface in (average) deformed configuration (pointing me => neighbor) - normal_me2neighbor = matmul(transpose(my_Fe), normal_me2neighbor_defConf) & - / math_det33(my_Fe) ! interface normal in my lattice configuration - area = IParea(n,ip,el) * norm2(normal_me2neighbor) - normal_me2neighbor = normal_me2neighbor / norm2(normal_me2neighbor) ! normalize the surface normal to unit length - do s = 1,ns - do t = 1,4 - c = (t + 1) / 2 - if (v0(s,t) * math_inner(m(1:3,s,t), normal_me2neighbor) > 0.0_pReal ) then ! flux from me to my neighbor == leaving flux for me (might also be a pure flux from my mobile density to dead density if interface not at all transmissive) - if (v0(s,t) * neighbor_v0(s,t) >= 0.0_pReal) then ! no sign change in flux density - transmissivity = sum(compatibility(c,:,s,n,ip,el)**2.0_pReal) ! overall transmissivity from this slip system to my neighbor - else ! sign change in flux density means sign change in stress which does not allow for dislocations to arive at the neighbor - transmissivity = 0.0_pReal - endif - lineLength = my_rhoSgl0(s,t) * v0(s,t) & - * math_inner(m(1:3,s,t), normal_me2neighbor) * area ! positive line length of mobiles that wants to leave through this interface - rhoDotFlux(s,t) = rhoDotFlux(s,t) - lineLength / IPvolume(ip,el) ! subtract dislocation flux from current type - rhoDotFlux(s,t+4) = rhoDotFlux(s,t+4) & - + lineLength / IPvolume(ip,el) * (1.0_pReal - transmissivity) & - * sign(1.0_pReal, v0(s,t)) ! dislocation flux that is not able to leave through interface (because of low transmissivity) will remain as immobile single density at the material point - endif - enddo - enddo - endif; endif - - enddo neighbors - endif - - !**************************************************************************** !*** calculate dipole formation and annihilation @@ -1454,7 +1276,7 @@ function plastic_nonlocal_dotState2(F,Fp,timestep, instance,of,ip,el) result(rh write(6,'(a)') '<< CONST >> enforcing cutback !!!' endif #endif - plasticState(ph)%dotState = IEEE_value(1.0_pReal,IEEE_quiet_NaN) ! -> return NaN and, hence, enforce cutback + rhoDotFlux = IEEE_value(1.0_pReal,IEEE_quiet_NaN) ! enforce cutback return endif From 520a484df2d81fd3c24e443809c4453082afe67c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 3 May 2020 13:09:49 +0200 Subject: [PATCH 161/186] reasonable name --- src/constitutive_plastic_nonlocal.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index 08d14a5ce..f1994444e 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -1117,7 +1117,7 @@ module subroutine plastic_nonlocal_dotState(Mp, F, Fp, Temperature,timestep, & - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have - rhoDot = plastic_nonlocal_dotState2(F,Fp,timestep, instance,of,ip,el) & + rhoDot = rhoDotFlux(F,Fp,timestep, instance,of,ip,el) & + rhoDotMultiplication & + rhoDotSingle2DipoleGlide & + rhoDotAthermalAnnihilation & @@ -1169,7 +1169,7 @@ end subroutine plastic_nonlocal_dotState !--------------------------------------------------------------------------------------------------- !> @brief calculates the rate of change of microstructure !--------------------------------------------------------------------------------------------------- -function plastic_nonlocal_dotState2(F,Fp,timestep, instance,of,ip,el) result(rhoDotFlux) +function rhoDotFlux(F,Fp,timestep, instance,of,ip,el) real(pReal), dimension(3,3,homogenization_maxNgrains,discretization_nIP,discretization_nElem), intent(in) :: & F, & !< elastic deformation gradient @@ -1404,7 +1404,7 @@ function plastic_nonlocal_dotState2(F,Fp,timestep, instance,of,ip,el) result(rh end associate -end function plastic_nonlocal_dotState2 +end function rhoDotFlux !-------------------------------------------------------------------------------------------------- From 7d1e0850ab217794cca8607942d58eb345f60412 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 3 May 2020 17:04:03 +0200 Subject: [PATCH 162/186] test + resulting bug fix --- python/damask/_rotation.py | 2 +- python/tests/test_Rotation.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index f97e356fc..878face97 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -1219,6 +1219,6 @@ class Rotation: p = 2 else: p = np.where(np.maximum(np.abs(xyz[...,0]),np.abs(xyz[...,1])) <= np.abs(xyz[...,2]),0, - np.where(np.maximum(np.abs(xyz[...,1]),np.abs(xyz[...,2])) <= np.abs(xyz[...,0]),2,3)) + np.where(np.maximum(np.abs(xyz[...,1]),np.abs(xyz[...,2])) <= np.abs(xyz[...,0]),1,2)) return order[direction][p] diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 302e895ee..a46cf1a23 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -264,3 +264,18 @@ class TestRotation: for h,c in zip(ho,co): print(h,c) assert np.allclose(conversion(h),c) + + + @pytest.mark.parametrize('direction',['forward', + 'backward']) + def test_pyramid_vectorization(self,direction): + p = np.random.rand(n,3) + o = Rotation._get_order(p,direction) + for i,o_i in enumerate(o): + assert np.allclose(o_i,Rotation._get_order(p[i],direction)) + + def test_pyramid_invariant(self): + a = np.random.rand(n,3) + f = damask.Rotation._get_order(a,'forward') + b = damask.Rotation._get_order(a,'backward') + assert np.all(np.take_along_axis(np.take_along_axis(a,f,-1),b,-1) == a) From 76d37b5bcd7eba064f9f1f19d36eb9fea37fd9c3 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 3 May 2020 20:38:25 +0200 Subject: [PATCH 163/186] flux debug would need temporary variable --- src/constitutive_plastic_nonlocal.f90 | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index f1994444e..cc5655e78 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -1123,29 +1123,6 @@ module subroutine plastic_nonlocal_dotState(Mp, F, Fp, Temperature,timestep, & + rhoDotAthermalAnnihilation & + rhoDotThermalAnnihilation -#ifdef DEBUG - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0 & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0 )) then - write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> dislocation multiplication', & - rhoDotMultiplication(:,1:4) * timestep - write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation flux', & - rhoDotFlux(:,1:8) * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> dipole formation by glide', & - rhoDotSingle2DipoleGlide * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> athermal dipole annihilation', & - rhoDotAthermalAnnihilation * timestep - write(6,'(a,/,2(12x,12(e12.5,1x),/))') '<< CONST >> thermally activated dipole annihilation', & - rhoDotThermalAnnihilation(:,9:10) * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> total density change', & - rhoDot * timestep - write(6,'(a,/,10(12x,12(f12.5,1x),/))') '<< CONST >> relative density change', & - rhoDot(:,1:8) * timestep / (abs(stt%rho(:,sgl))+1.0e-10), & - rhoDot(:,9:10) * timestep / (stt%rho(:,dip)+1.0e-10) - write(6,*) - endif -#endif - if ( any(rho(:,mob) + rhoDot(:,1:4) * timestep < -prm%atol_rho) & .or. any(rho(:,dip) + rhoDot(:,9:10) * timestep < -prm%atol_rho)) then From 5f3f87cd68b26081b10ad8a96c655b3a56348830 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 3 May 2020 18:51:30 +0200 Subject: [PATCH 164/186] vectorizing cubochoric conversions --- python/damask/_rotation.py | 104 ++++++++++++++++++++++------------ python/tests/test_Rotation.py | 91 +++++++++++++++++------------ 2 files changed, 124 insertions(+), 71 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 878face97..a13a9af0b 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -241,7 +241,7 @@ class Rotation: """Homochoric vector: (h_1, h_2, h_3).""" return Rotation.qu2ho(self.quaternion) - def asCubochoric(self): + def as_cubochoric(self): """Cubochoric vector: (c_1, c_2, c_3).""" return Rotation.qu2cu(self.quaternion) @@ -265,6 +265,7 @@ class Rotation: asMatrix = as_matrix asRodrigues = as_Rodrigues asHomochoric = as_homochoric + asCubochoric = as_cubochoric ################################################################################################ # Static constructors. The input data needs to follow the conventions, options allow to @@ -386,7 +387,7 @@ class Rotation: return Rotation(Rotation.ho2qu(ho)) @staticmethod - def fromCubochoric(cubochoric, + def from_cubochoric(cubochoric, P = -1): cu = np.array(cubochoric,dtype=float) @@ -461,6 +462,7 @@ class Rotation: fromMatrix = from_matrix fromRodrigues = from_Rodrigues fromHomochoric = from_homochoric + fromCubochoric = from_cubochoric fromRandom = from_random #################################################################################################### @@ -1066,7 +1068,7 @@ class Rotation: if np.allclose(ho,0.0,rtol=0.0,atol=1.0e-16): cu = np.zeros(3) else: - xyz3 = ho[Rotation._get_order(ho,'forward')] + xyz3 = ho[Rotation._get_pyramid_order(ho,'forward')] # inverse M_3 xyz2 = xyz3[0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[2])) ) @@ -1087,20 +1089,35 @@ class Rotation: # inverse M_1 cu = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /_sc - # reverse the coordinates back to the regular order according to the original pyramid number - cu = cu[Rotation._get_order(ho,'backward')] - - return cu + cu = cu[Rotation._get_pyramid_order(ho,'backward')] else: - q2 = qxy + np.max(np.abs(xyz2))**2 - sq2 = np.sqrt(q2) - q = (_beta/np.sqrt(2.0)/_R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2))*sq2)) - tt = np.clip((np.min(np.abs(xyz2))**2+np.max(np.abs(xyz2))*sq2)/np.sqrt(2.0)/qxy,-1.0,1.0) - Tinv = np.array([1.0,np.arccos(tt)/np.pi*12.0]) if np.abs(xyz2[1]) <= np.abs(xyz2[0]) else \ - np.array([np.arccos(tt)/np.pi*12.0,1.0]) - Tinv = q * np.where(xyz2<0.0,-Tinv,Tinv) - raise NotImplementedError('Support for multiple rotations missing') + rs = np.linalg.norm(ho,axis=-1,keepdims=True) + xyz3 = np.take_along_axis(ho,Rotation._get_pyramid_order(ho,'forward'),-1) + + with np.errstate(invalid='ignore',divide='ignore'): + # inverse M_3 + xyz2 = xyz3[...,0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[...,2:3])) ) + qxy = np.sum(xyz2**2,axis=-1,keepdims=True) + + q2 = qxy + np.max(np.abs(xyz2),axis=-1,keepdims=True)**2 + sq2 = np.sqrt(q2) + q = (_beta/np.sqrt(2.0)/_R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2),axis=-1,keepdims=True)*sq2)) + tt = np.clip((np.min(np.abs(xyz2),axis=-1,keepdims=True)**2\ + +np.max(np.abs(xyz2),axis=-1,keepdims=True)*sq2)/np.sqrt(2.0)/qxy,-1.0,1.0) + T_inv = np.where(np.abs(xyz2[...,1:2]) <= np.abs(xyz2[...,0:1]), + np.block([np.ones_like(tt),np.arccos(tt)/np.pi*12.0]), + np.block([np.arccos(tt)/np.pi*12.0,np.ones_like(tt)]))*q + T_inv[xyz2<0.0] *= -1.0 + T_inv[np.broadcast_to(np.isclose(qxy,0.0,rtol=0.0,atol=1.0e-12),T_inv.shape)] = 0.0 + cu = np.block([T_inv, np.where(xyz3[...,2:3]<0.0,-np.ones_like(xyz3[...,2:3]),np.ones_like(xyz3[...,2:3])) \ + * rs/np.sqrt(6.0/np.pi), + ])/ _sc + + cu[np.isclose(np.sum(np.abs(ho),axis=-1),0.0,rtol=0.0,atol=1.0e-16)] = 0.0 + cu = np.take_along_axis(cu,Rotation._get_pyramid_order(ho,'backward'),-1) + + return cu #---------- Cubochoric ---------- @staticmethod @@ -1145,7 +1162,7 @@ class Rotation: ho = np.zeros(3) else: # get pyramide and scale by grid parameter ratio - XYZ = cu[Rotation._get_order(cu,'forward')] * _sc + XYZ = cu[Rotation._get_pyramid_order(cu,'forward')] * _sc # intercept all the points along the z-axis if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-16): @@ -1163,31 +1180,46 @@ class Rotation: c = np.sum(T**2) s = c * np.pi/24.0 /XYZ[2]**2 c = c * np.sqrt(np.pi/24.0)/XYZ[2] + q = np.sqrt( 1.0 - s ) ho = np.array([ T[order[1]] * q, T[order[0]] * q, np.sqrt(6.0/np.pi) * XYZ[2] - c ]) - # reverse the coordinates back to the regular order according to the original pyramid number - ho = ho[Rotation._get_order(cu,'backward')] - - return ho + ho = ho[Rotation._get_pyramid_order(cu,'backward')] else: - # get pyramide and scale by grid parameter ratio - XYZ = cu[Rotation._get_order(cu,'forward')] * _sc - order = np.where(np.abs(XYZ[...,1]) <= np.abs(XYZ[...,0]), - np.broadcast_to([1,0],XYZ.shape[:-1]+(2,)), - np.broadcast_to([0,1],XYZ.shape[:-1]+(2,))) - q = np.pi/12.0 * XYZ[order[...,0]]/XYZ[order[...,1]] - c = np.cos(q) - s = np.sin(q) - q = _R1*2.0**0.25/_beta * XYZ[order[...,1]] / np.sqrt(np.sqrt(2.0)-c) - T = np.block([ (np.sqrt(2.0)*c - 1.0), np.sqrt(2.0) * s]) * q - s = c * np.pi/24.0 /XYZ[...,2]**2 - c = c * np.sqrt(np.pi/24.0)/XYZ[...,2] - q = np.sqrt( 1.0 - s ) - raise NotImplementedError('Support for multiple rotations missing') + with np.errstate(invalid='ignore',divide='ignore'): + # get pyramide and scale by grid parameter ratio + XYZ = np.take_along_axis(cu,Rotation._get_pyramid_order(cu,'forward'),-1) * _sc + order = np.abs(XYZ[...,1:2]) <= np.abs(XYZ[...,0:1]) + q = np.pi/12.0 * np.where(order,XYZ[...,1:2],XYZ[...,0:1]) \ + / np.where(order,XYZ[...,0:1],XYZ[...,1:2]) + c = np.cos(q) + s = np.sin(q) + q = _R1*2.0**0.25/_beta/ np.sqrt(np.sqrt(2.0)-c) \ + * np.where(order,XYZ[...,0:1],XYZ[...,1:2]) + + T = np.block([ (np.sqrt(2.0)*c - 1.0), np.sqrt(2.0) * s]) * q + + # transform to sphere grid (inverse Lambert) + c = np.sum(T**2,axis=-1,keepdims=True) + s = c * np.pi/24.0 /XYZ[...,2:3]**2 + c = c * np.sqrt(np.pi/24.0)/XYZ[...,2:3] + q = np.sqrt( 1.0 - s) + + ho = np.where(np.isclose(np.sum(np.abs(XYZ[...,0:2]),axis=-1,keepdims=True),0.0,rtol=0.0,atol=1.0e-16), + np.block([np.zeros_like(XYZ[...,0:2]),np.sqrt(6.0/np.pi) *XYZ[...,2:3]]), + np.block([np.where(order,T[...,0:1],T[...,1:2])*q, + np.where(order,T[...,1:2],T[...,0:1])*q, + np.sqrt(6.0/np.pi) * XYZ[...,2:3] - c]) + ) + + ho[np.isclose(np.sum(np.abs(cu),axis=-1),0.0,rtol=0.0,atol=1.0e-16)] = 0.0 + ho = np.take_along_axis(ho,Rotation._get_pyramid_order(cu,'backward'),-1) + + return ho + @staticmethod - def _get_order(xyz,direction=None): + def _get_pyramid_order(xyz,direction=None): """ Get order of the coordinates. @@ -1206,7 +1238,7 @@ class Rotation: """ order = {'forward':np.array([[0,1,2],[1,2,0],[2,0,1]]), - 'backward':np.array([[0,1,2],[2,0,1],[1,2,0]])} + 'backward':np.array([[0,1,2],[2,0,1],[1,2,0]])} if len(xyz.shape) == 1: if np.maximum(abs(xyz[0]),abs(xyz[1])) <= xyz[2] or \ np.maximum(abs(xyz[0]),abs(xyz[1])) <=-xyz[2]: diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index a46cf1a23..b7442035f 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -78,9 +78,9 @@ def default(): specials_scatter /= np.linalg.norm(specials_scatter,axis=1).reshape(-1,1) specials_scatter[specials_scatter[:,0]<0]*=-1 - return [Rotation.fromQuaternion(s) for s in specials] + \ - [Rotation.fromQuaternion(s) for s in specials_scatter] + \ - [Rotation.fromRandom() for _ in range(n-len(specials)-len(specials_scatter))] + return [Rotation.from_quaternion(s) for s in specials] + \ + [Rotation.from_quaternion(s) for s in specials_scatter] + \ + [Rotation.from_random() for _ in range(n-len(specials)-len(specials_scatter))] @pytest.fixture def reference_dir(reference_dir_base): @@ -92,41 +92,41 @@ class TestRotation: def test_Eulers(self,default): for rot in default: - m = rot.asQuaternion() - o = Rotation.fromEulers(rot.asEulers()).asQuaternion() + m = rot.as_quaternion() + o = Rotation.from_Eulers(rot.as_Eulers()).as_quaternion() ok = np.allclose(m,o,atol=atol) - if np.isclose(rot.asQuaternion()[0],0.0,atol=atol): + if np.isclose(rot.as_quaternion()[0],0.0,atol=atol): ok = ok or np.allclose(m*-1.,o,atol=atol) - print(m,o,rot.asQuaternion()) + print(m,o,rot.as_quaternion()) assert ok and np.isclose(np.linalg.norm(o),1.0) def test_AxisAngle(self,default): for rot in default: - m = rot.asEulers() - o = Rotation.fromAxisAngle(rot.asAxisAngle()).asEulers() + m = rot.as_Eulers() + o = Rotation.from_axis_angle(rot.as_axis_angle()).as_Eulers() u = np.array([np.pi*2,np.pi,np.pi*2]) ok = np.allclose(m,o,atol=atol) ok = ok or np.allclose(np.where(np.isclose(m,u),m-u,m),np.where(np.isclose(o,u),o-u,o),atol=atol) if np.isclose(m[1],0.0,atol=atol) or np.isclose(m[1],np.pi,atol=atol): sum_phi = np.unwrap([m[0]+m[2],o[0]+o[2]]) ok = ok or np.isclose(sum_phi[0],sum_phi[1],atol=atol) - print(m,o,rot.asQuaternion()) + print(m,o,rot.as_quaternion()) assert ok and (np.zeros(3)-1.e-9 <= o).all() and (o <= np.array([np.pi*2.,np.pi,np.pi*2.])+1.e-9).all() def test_Matrix(self,default): for rot in default: - m = rot.asAxisAngle() - o = Rotation.fromAxisAngle(rot.asAxisAngle()).asAxisAngle() + m = rot.as_axis_angle() + o = Rotation.from_axis_angle(rot.as_axis_angle()).as_axis_angle() ok = np.allclose(m,o,atol=atol) if np.isclose(m[3],np.pi,atol=atol): ok = ok or np.allclose(m*np.array([-1.,-1.,-1.,1.]),o,atol=atol) - print(m,o,rot.asQuaternion()) + print(m,o,rot.as_quaternion()) assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) and o[3]<=np.pi++1.e-9 def test_Rodrigues(self,default): for rot in default: - m = rot.asMatrix() - o = Rotation.fromRodrigues(rot.asRodrigues()).asMatrix() + m = rot.as_matrix() + o = Rotation.from_Rodrigues(rot.as_Rodrigues()).as_matrix() ok = np.allclose(m,o,atol=atol) print(m,o) assert ok and np.isclose(np.linalg.det(o),1.0) @@ -134,27 +134,27 @@ class TestRotation: def test_Homochoric(self,default): cutoff = np.tan(np.pi*.5*(1.-1e-4)) for rot in default: - m = rot.asRodrigues() - o = Rotation.fromHomochoric(rot.asHomochoric()).asRodrigues() + m = rot.as_Rodrigues() + o = Rotation.from_homochoric(rot.as_homochoric()).as_Rodrigues() ok = np.allclose(np.clip(m,None,cutoff),np.clip(o,None,cutoff),atol=atol) ok = ok or np.isclose(m[3],0.0,atol=atol) - print(m,o,rot.asQuaternion()) + print(m,o,rot.as_quaternion()) assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) def test_Cubochoric(self,default): for rot in default: - m = rot.asHomochoric() - o = Rotation.fromCubochoric(rot.asCubochoric()).asHomochoric() + m = rot.as_homochoric() + o = Rotation.from_cubochoric(rot.as_cubochoric()).as_homochoric() ok = np.allclose(m,o,atol=atol) - print(m,o,rot.asQuaternion()) + print(m,o,rot.as_quaternion()) assert ok and np.linalg.norm(o) < (3.*np.pi/4.)**(1./3.) + 1.e-9 def test_Quaternion(self,default): for rot in default: - m = rot.asCubochoric() - o = Rotation.fromQuaternion(rot.asQuaternion()).asCubochoric() + m = rot.as_cubochoric() + o = Rotation.from_quaternion(rot.as_quaternion()).as_cubochoric() ok = np.allclose(m,o,atol=atol) - print(m,o,rot.asQuaternion()) + print(m,o,rot.as_quaternion()) assert ok and o.max() < np.pi**(2./3.)*0.5+1.e-9 @pytest.mark.parametrize('function',[Rotation.from_quaternion, @@ -185,9 +185,11 @@ class TestRotation: Rotation.qu2eu, Rotation.qu2ax, Rotation.qu2ro, - Rotation.qu2ho]) + Rotation.qu2ho, + Rotation.qu2cu + ]) def test_quaternion_vectorization(self,default,conversion): - qu = np.array([rot.asQuaternion() for rot in default]) + qu = np.array([rot.as_quaternion() for rot in default]) conversion(qu.reshape(qu.shape[0]//2,-1,4)) co = conversion(qu) for q,c in zip(qu,co): @@ -199,9 +201,10 @@ class TestRotation: Rotation.om2ax, Rotation.om2ro, Rotation.om2ho, + Rotation.om2cu ]) def test_matrix_vectorization(self,default,conversion): - om = np.array([rot.asMatrix() for rot in default]) + om = np.array([rot.as_matrix() for rot in default]) conversion(om.reshape(om.shape[0]//2,-1,3,3)) co = conversion(om) for o,c in zip(om,co): @@ -213,9 +216,10 @@ class TestRotation: Rotation.eu2ax, Rotation.eu2ro, Rotation.eu2ho, + Rotation.eu2cu ]) def test_Euler_vectorization(self,default,conversion): - eu = np.array([rot.asEulers() for rot in default]) + eu = np.array([rot.as_Eulers() for rot in default]) conversion(eu.reshape(eu.shape[0]//2,-1,3)) co = conversion(eu) for e,c in zip(eu,co): @@ -227,9 +231,10 @@ class TestRotation: Rotation.ax2eu, Rotation.ax2ro, Rotation.ax2ho, + Rotation.ax2cu ]) def test_axisAngle_vectorization(self,default,conversion): - ax = np.array([rot.asAxisAngle() for rot in default]) + ax = np.array([rot.as_axis_angle() for rot in default]) conversion(ax.reshape(ax.shape[0]//2,-1,4)) co = conversion(ax) for a,c in zip(ax,co): @@ -242,9 +247,10 @@ class TestRotation: Rotation.ro2eu, Rotation.ro2ax, Rotation.ro2ho, + Rotation.ro2cu ]) def test_Rodrigues_vectorization(self,default,conversion): - ro = np.array([rot.asRodrigues() for rot in default]) + ro = np.array([rot.as_Rodrigues() for rot in default]) conversion(ro.reshape(ro.shape[0]//2,-1,4)) co = conversion(ro) for r,c in zip(ro,co): @@ -256,26 +262,41 @@ class TestRotation: Rotation.ho2eu, Rotation.ho2ax, Rotation.ho2ro, + Rotation.ho2cu ]) def test_homochoric_vectorization(self,default,conversion): - ho = np.array([rot.asHomochoric() for rot in default]) + ho = np.array([rot.as_homochoric() for rot in default]) conversion(ho.reshape(ho.shape[0]//2,-1,3)) co = conversion(ho) for h,c in zip(ho,co): print(h,c) assert np.allclose(conversion(h),c) + @pytest.mark.parametrize('conversion',[Rotation.cu2qu, + Rotation.cu2om, + Rotation.cu2eu, + Rotation.cu2ax, + Rotation.cu2ro, + Rotation.cu2ho + ]) + def test_cubochoric_vectorization(self,default,conversion): + cu = np.array([rot.as_cubochoric() for rot in default]) + conversion(cu.reshape(cu.shape[0]//2,-1,3)) + co = conversion(cu) + for u,c in zip(cu,co): + print(u,c) + assert np.allclose(conversion(u),c) @pytest.mark.parametrize('direction',['forward', 'backward']) def test_pyramid_vectorization(self,direction): p = np.random.rand(n,3) - o = Rotation._get_order(p,direction) + o = Rotation._get_pyramid_order(p,direction) for i,o_i in enumerate(o): - assert np.allclose(o_i,Rotation._get_order(p[i],direction)) + assert np.all(o_i==Rotation._get_pyramid_order(p[i],direction)) def test_pyramid_invariant(self): a = np.random.rand(n,3) - f = damask.Rotation._get_order(a,'forward') - b = damask.Rotation._get_order(a,'backward') + f = Rotation._get_pyramid_order(a,'forward') + b = Rotation._get_pyramid_order(a,'backward') assert np.all(np.take_along_axis(np.take_along_axis(a,f,-1),b,-1) == a) From 0650f46ab1540c3e995df1d188a75a95c8b5ae69 Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Mon, 4 May 2020 16:57:08 +0200 Subject: [PATCH 165/186] Tests for gradient --- python/tests/test_grid_filters.py | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index 84d2ef771..2ee062ee5 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -168,3 +168,63 @@ class TestGridFilters: curl = curl.reshape(tuple(grid) + ((3,3) if len(curl_def)==9 else (3,))) assert np.allclose(curl,grid_filters.curl(size,field)) + + grad_test_data = [(['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]','0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0']), + + (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], + ['0.0', '0.0', '0.0', + '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', + '0.0', '0.0', '0.0' ]), + + (['1.0', '0.0', '2.0*np.cos(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])']), + + (['np.cos(np.pi*2*nodes[...,2]/size[2])', '3.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '-np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', + '0.0', '0.0', '0.0', + '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + + (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.sin(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0', + '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', + '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + + (['np.sin(np.pi*2*nodes[...,0]/size[0])' ], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0' ]) + ] + +# @pytest.mark.parametrize('field_def,grad_def', +# [(['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], +# ['0.0', '0.0', '0.0', +# '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', +# '0.0', '0.0', '0.0' ]) +# ]) + @pytest.mark.parametrize('field_def,grad_def',grad_test_data) + + def test_grad(self,field_def,grad_def): +# size = np.random.random(3)+1.0 +# grid = np.random.randint(8,32,(3)) + size = np.array([1.0,1.0,1.0]) + grid = np.array([2,5,3]) + + nodes = grid_filters.cell_coord0(grid,size) +# print('y nodes are',nodes[...,1]) +# print('inner bracket is',np.pi*2*nodes[...,1]/size[1]) + my_locals = locals() # needed for list comprehension + + print('field length is',len(field_def)) + field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) + print('field initial shape is',field.shape) + field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) + print('field is',field.shape) + grad = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in grad_def], axis=-1) + grad = grad.reshape(tuple(grid) + ((3,3) if len(grad_def)==9 else (3,))) + print('gradient is',grad.shape) + print('code gradient is',grid_filters.gradient(size,field)) + assert np.allclose(grad,grid_filters.gradient(size,field)) + From 307debebd45e2fbad925c297bd2b3d03f2fba8ef Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Tue, 5 May 2020 10:14:27 +0200 Subject: [PATCH 166/186] Correct shapes for gradient calculations --- python/tests/test_grid_filters.py | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index 2ee062ee5..8170ba7af 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -189,42 +189,32 @@ class TestGridFilters: '0.0', '0.0', '0.0', '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), - (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.sin(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])'], + (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.sin(np.pi*2*nodes[...,1]/size[1])',\ + 'np.sin(np.pi*2*nodes[...,2]/size[2])'], ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), (['np.sin(np.pi*2*nodes[...,0]/size[0])' ], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0' ]) + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0' ]), + + (['8.0' ], + ['0.0', '0.0', '0.0' ]) ] -# @pytest.mark.parametrize('field_def,grad_def', -# [(['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], -# ['0.0', '0.0', '0.0', -# '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', -# '0.0', '0.0', '0.0' ]) -# ]) @pytest.mark.parametrize('field_def,grad_def',grad_test_data) def test_grad(self,field_def,grad_def): -# size = np.random.random(3)+1.0 -# grid = np.random.randint(8,32,(3)) - size = np.array([1.0,1.0,1.0]) - grid = np.array([2,5,3]) + size = np.random.random(3)+1.0 + grid = np.random.randint(8,32,(3)) nodes = grid_filters.cell_coord0(grid,size) -# print('y nodes are',nodes[...,1]) -# print('inner bracket is',np.pi*2*nodes[...,1]/size[1]) my_locals = locals() # needed for list comprehension - print('field length is',len(field_def)) field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) - print('field initial shape is',field.shape) - field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) - print('field is',field.shape) + field = field.reshape(tuple(grid) + ((3,) if len(field_def)==3 else (1,))) grad = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in grad_def], axis=-1) grad = grad.reshape(tuple(grid) + ((3,3) if len(grad_def)==9 else (3,))) - print('gradient is',grad.shape) - print('code gradient is',grid_filters.gradient(size,field)) + assert np.allclose(grad,grid_filters.gradient(size,field)) From 4dcec8b309d11a61d2c8fef77c75050b2ebef0ad Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 5 May 2020 11:18:58 +0200 Subject: [PATCH 167/186] not needed --- src/constitutive_plastic_nonlocal.f90 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index cc5655e78..fefb668eb 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -1209,10 +1209,6 @@ function rhoDotFlux(F,Fp,timestep, instance,of,ip,el) lineLength !< dislocation line length leaving the current interface ph = material_phaseAt(1,el) - if (timestep <= 0.0_pReal) then - plasticState(ph)%dotState = 0.0_pReal - return - endif associate(prm => param(instance), & dst => microstructure(instance), & From a5b78dc30af2211b1188407b3b1e277f1c0a0855 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 5 May 2020 11:20:16 +0200 Subject: [PATCH 168/186] potential glitch --- src/constitutive_plastic_nonlocal.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index fefb668eb..65fea24b2 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -1223,7 +1223,7 @@ function rhoDotFlux(F,Fp,timestep, instance,of,ip,el) rho0 = getRho0(instance,of,ip,el) my_rhoSgl0 = rho0(:,sgl) - forall (s = 1:ns, t = 1:4) v(s,t) = plasticState(ph)%state(iV(s,t,instance),of) + forall (s = 1:ns, t = 1:4) v(s,t) = plasticState(ph)%state(iV(s,t,instance),of) !ToDo: MD: I think we should use state0 here gdot = rhoSgl(:,1:4) * v * spread(prm%burgers,2,4) From bd518b28067b75c57d3bb13dbfc6e24327fb4708 Mon Sep 17 00:00:00 2001 From: "f.basile" Date: Wed, 6 May 2020 12:44:56 +0200 Subject: [PATCH 169/186] test_curl done --- python/tests/test_curl.py | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 python/tests/test_curl.py diff --git a/python/tests/test_curl.py b/python/tests/test_curl.py new file mode 100644 index 000000000..52e12d223 --- /dev/null +++ b/python/tests/test_curl.py @@ -0,0 +1,63 @@ +import pytest +import numpy as np +from damask import grid_filters + + +class TestGridFilters: + + + @pytest.mark.parametrize('field_def,curl_def', + [(['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0' ], + ['0.0' , '0.0', '0.0', + 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0', '0.0', + '0.0', '0.0', '0.0'] + ), + (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', + '0.0', '0.0', '0.0', + 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + 'np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0'] + ), + (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', + 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', + 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0'] + ), + (['5.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,1]/size[1])'], + ['0.0', '0.0', '-2*np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0'] + ), + (['4*np.sin(np.pi*2*nodes[...,2]/size[2])', '8*np.sin(np.pi*2*nodes[...,0]/size[0])', '16*np.sin(np.pi*2*nodes[...,1]/size[1])'], + ['16*np.pi*2/size[1]*np.cos(np.pi*2*nodes[...,1]/size[1])', \ + '4*np.pi*2/size[2]*np.cos(np.pi*2*nodes[...,2]/size[2])', \ + '8*np.pi*2/size[0]*np.cos(np.pi*2*nodes[...,0]/size[0])'] + ), + (['0.0', 'np.cos(np.pi*2*nodes[...,0]/size[0])+5*np.cos(np.pi*2*nodes[...,2]/size[2])', '0.0'], + ['5*np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]',\ + '0.0',\ + '-np.sin(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]'] + ) + ]) + def test_curl(self,field_def,curl_def): + size = np.random.random(3)+1.0 + grid = np.random.randint(8,32,(3)) + + nodes = grid_filters.cell_coord0(grid,size) + my_locals = locals() # needed for list comprehension + + field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) + field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) + curl = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in curl_def], axis=-1) + curl = curl.reshape(tuple(grid) + ((3,3) if len(curl_def)==9 else (3,))) + + assert np.allclose(curl,grid_filters.curl(size,field)) + + \ No newline at end of file From 8b4baecdee110da3e54efa6cb40505d437004e83 Mon Sep 17 00:00:00 2001 From: "f.basile" Date: Wed, 6 May 2020 12:54:24 +0200 Subject: [PATCH 170/186] better looking test fields --- python/tests/test_curl.py | 81 ++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/python/tests/test_curl.py b/python/tests/test_curl.py index 52e12d223..c3bcc2682 100644 --- a/python/tests/test_curl.py +++ b/python/tests/test_curl.py @@ -6,46 +6,47 @@ from damask import grid_filters class TestGridFilters: - @pytest.mark.parametrize('field_def,curl_def', - [(['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0' ], - ['0.0' , '0.0', '0.0', - 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0', '0.0', - '0.0', '0.0', '0.0'] - ), - (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', - '0.0', '0.0', '0.0', - 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], - ['0.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - 'np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0'] - ), - (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', - 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', - 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])'], - ['0.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0'] - ), - (['5.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,1]/size[1])'], - ['0.0', '0.0', '-2*np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0'] - ), - (['4*np.sin(np.pi*2*nodes[...,2]/size[2])', '8*np.sin(np.pi*2*nodes[...,0]/size[0])', '16*np.sin(np.pi*2*nodes[...,1]/size[1])'], - ['16*np.pi*2/size[1]*np.cos(np.pi*2*nodes[...,1]/size[1])', \ - '4*np.pi*2/size[2]*np.cos(np.pi*2*nodes[...,2]/size[2])', \ - '8*np.pi*2/size[0]*np.cos(np.pi*2*nodes[...,0]/size[0])'] - ), - (['0.0', 'np.cos(np.pi*2*nodes[...,0]/size[0])+5*np.cos(np.pi*2*nodes[...,2]/size[2])', '0.0'], - ['5*np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]',\ - '0.0',\ - '-np.sin(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]'] - ) - ]) + curl_test_data =[(['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0' ], + ['0.0' , '0.0', '0.0', + 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0', '0.0', + '0.0', '0.0', '0.0'] + ), + (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', + '0.0', '0.0', '0.0', + 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + 'np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0'] + ), + (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', + 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', + 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0'] + ), + (['5.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,1]/size[1])'], + ['0.0', '0.0', '-2*np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0'] + ), + (['4*np.sin(np.pi*2*nodes[...,2]/size[2])', '8*np.sin(np.pi*2*nodes[...,0]/size[0])', '16*np.sin(np.pi*2*nodes[...,1]/size[1])'], + ['16*np.pi*2/size[1]*np.cos(np.pi*2*nodes[...,1]/size[1])', \ + '4*np.pi*2/size[2]*np.cos(np.pi*2*nodes[...,2]/size[2])', \ + '8*np.pi*2/size[0]*np.cos(np.pi*2*nodes[...,0]/size[0])'] + ), + (['0.0', 'np.cos(np.pi*2*nodes[...,0]/size[0])+5*np.cos(np.pi*2*nodes[...,2]/size[2])', '0.0'], + ['5*np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]',\ + '0.0',\ + '-np.sin(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]'])] + + + @pytest.mark.parametrize('field_def,curl_def',curl_test_data) + def test_curl(self,field_def,curl_def): size = np.random.random(3)+1.0 grid = np.random.randint(8,32,(3)) From d4091a21a8becd0e6d5adf1907ef493bdea730ad Mon Sep 17 00:00:00 2001 From: "f.basile" Date: Wed, 6 May 2020 13:05:53 +0200 Subject: [PATCH 171/186] grad test done --- python/tests/test_grad.py | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 python/tests/test_grad.py diff --git a/python/tests/test_grad.py b/python/tests/test_grad.py new file mode 100644 index 000000000..d02c57cdc --- /dev/null +++ b/python/tests/test_grad.py @@ -0,0 +1,49 @@ +import pytest +import numpy as np +from damask import grid_filters + + +class TestGridFilters: + + grad_test_data = [(['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]','0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0']), + (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], + ['0.0', '0.0', '0.0', + '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', + '0.0', '0.0', '0.0' ]), + (['1.0', '0.0', '2.0*np.cos(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])']), + (['np.cos(np.pi*2*nodes[...,2]/size[2])', '3.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '-np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', + '0.0', '0.0', '0.0', + '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.sin(np.pi*2*nodes[...,1]/size[1])',\ + 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0', + '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', + '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])' ], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0' ]), + (['8.0' ], + ['0.0', '0.0', '0.0' ])] + + @pytest.mark.parametrize('field_def,grad_def',grad_test_data) + + def test_grad(self,field_def,grad_def): + size = np.random.random(3)+1.0 + grid = np.random.randint(8,32,(3)) + + nodes = grid_filters.cell_coord0(grid,size) + my_locals = locals() # needed for list comprehension + + field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) + field = field.reshape(tuple(grid) + ((3,) if len(field_def)==3 else (1,))) + grad = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in grad_def], axis=-1) + grad = grad.reshape(tuple(grid) + ((3,3) if len(grad_def)==9 else (3,))) + + assert np.allclose(grad,grid_filters.gradient(size,field)) + \ No newline at end of file From a122a307b9d714eccb2259a78cc7a20a2694571d Mon Sep 17 00:00:00 2001 From: "f.basile" Date: Wed, 6 May 2020 14:14:18 +0200 Subject: [PATCH 172/186] div test done --- python/tests/test_div.py | 63 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 python/tests/test_div.py diff --git a/python/tests/test_div.py b/python/tests/test_div.py new file mode 100644 index 000000000..f703c5371 --- /dev/null +++ b/python/tests/test_div.py @@ -0,0 +1,63 @@ +import pytest +import numpy as np +from damask import grid_filters + + +class TestGridFilters: + + + div_test_data =[(['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0', + '0.0' , '0.0', '0.0', + '0.0' , '0.0', '0.0'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]' ,'0.0', '0.0'] + ), + (['0.0', '0.0', '0.0', + '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', + '0.0', '0.0', '0.0'], + ['0.0', '-np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0'] + ), + (['1.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,2]/size[2])' ], + ['0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])'] + ), + ([ '23.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '100.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]','np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]'] + ), + (['400.0', '0.0', '0.0', + 'np.sin(np.pi*2*nodes[...,0]/size[0])', 'np.sin(np.pi*2*nodes[...,1]/size[1])', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '10.0', '6.0' ], + ['0.0','np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]+np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]+np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]','0.0' ] + ), + (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]',] + ), + (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], + ['-np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]'] + ) + + + ] + + + @pytest.mark.parametrize('field_def,div_def',div_test_data) + + def test_div(self,field_def,div_def): + size = np.random.random(3)+1.0 + grid = np.random.randint(8,32,(3)) + + nodes = grid_filters.cell_coord0(grid,size) + my_locals = locals() # needed for list comprehension + + field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) + field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) + div = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in div_def], axis=-1) + if len(div_def)==3: + div = div.reshape(tuple(grid) + ((3,))) + else: + div=div.reshape(tuple(grid)) + + assert np.allclose(div,grid_filters.divergence(size,field)) + \ No newline at end of file From 26f55781aedede7f2acc6ef1715938b0b1bcfb7c Mon Sep 17 00:00:00 2001 From: "f.basile" Date: Wed, 6 May 2020 14:26:15 +0200 Subject: [PATCH 173/186] merge test into gridFilters --- python/tests/test_div.py | 63 ---------- python/tests/test_grad.py | 49 -------- python/tests/test_grid_filters.py | 188 ++++++++++++++++++++---------- 3 files changed, 126 insertions(+), 174 deletions(-) delete mode 100644 python/tests/test_div.py delete mode 100644 python/tests/test_grad.py diff --git a/python/tests/test_div.py b/python/tests/test_div.py deleted file mode 100644 index f703c5371..000000000 --- a/python/tests/test_div.py +++ /dev/null @@ -1,63 +0,0 @@ -import pytest -import numpy as np -from damask import grid_filters - - -class TestGridFilters: - - - div_test_data =[(['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0', - '0.0' , '0.0', '0.0', - '0.0' , '0.0', '0.0'], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]' ,'0.0', '0.0'] - ), - (['0.0', '0.0', '0.0', - '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', - '0.0', '0.0', '0.0'], - ['0.0', '-np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0'] - ), - (['1.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,2]/size[2])' ], - ['0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])'] - ), - ([ '23.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', - '0.0', '100.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', - '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], - ['np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]','np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]'] - ), - (['400.0', '0.0', '0.0', - 'np.sin(np.pi*2*nodes[...,0]/size[0])', 'np.sin(np.pi*2*nodes[...,1]/size[1])', 'np.sin(np.pi*2*nodes[...,2]/size[2])', - '0.0', '10.0', '6.0' ], - ['0.0','np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]+np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]+np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]','0.0' ] - ), - (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]',] - ), - (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], - ['-np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]'] - ) - - - ] - - - @pytest.mark.parametrize('field_def,div_def',div_test_data) - - def test_div(self,field_def,div_def): - size = np.random.random(3)+1.0 - grid = np.random.randint(8,32,(3)) - - nodes = grid_filters.cell_coord0(grid,size) - my_locals = locals() # needed for list comprehension - - field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) - field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) - div = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in div_def], axis=-1) - if len(div_def)==3: - div = div.reshape(tuple(grid) + ((3,))) - else: - div=div.reshape(tuple(grid)) - - assert np.allclose(div,grid_filters.divergence(size,field)) - \ No newline at end of file diff --git a/python/tests/test_grad.py b/python/tests/test_grad.py deleted file mode 100644 index d02c57cdc..000000000 --- a/python/tests/test_grad.py +++ /dev/null @@ -1,49 +0,0 @@ -import pytest -import numpy as np -from damask import grid_filters - - -class TestGridFilters: - - grad_test_data = [(['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]','0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0']), - (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], - ['0.0', '0.0', '0.0', - '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', - '0.0', '0.0', '0.0' ]), - (['1.0', '0.0', '2.0*np.cos(np.pi*2*nodes[...,2]/size[2])'], - ['0.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])']), - (['np.cos(np.pi*2*nodes[...,2]/size[2])', '3.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], - ['0.0', '0.0', '-np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', - '0.0', '0.0', '0.0', - '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), - (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.sin(np.pi*2*nodes[...,1]/size[1])',\ - 'np.sin(np.pi*2*nodes[...,2]/size[2])'], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0', - '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', - '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), - (['np.sin(np.pi*2*nodes[...,0]/size[0])' ], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0' ]), - (['8.0' ], - ['0.0', '0.0', '0.0' ])] - - @pytest.mark.parametrize('field_def,grad_def',grad_test_data) - - def test_grad(self,field_def,grad_def): - size = np.random.random(3)+1.0 - grid = np.random.randint(8,32,(3)) - - nodes = grid_filters.cell_coord0(grid,size) - my_locals = locals() # needed for list comprehension - - field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) - field = field.reshape(tuple(grid) + ((3,) if len(field_def)==3 else (1,))) - grad = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in grad_def], axis=-1) - grad = grad.reshape(tuple(grid) + ((3,3) if len(grad_def)==9 else (3,))) - - assert np.allclose(grad,grid_filters.gradient(size,field)) - \ No newline at end of file diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index 8170ba7af..6a30481c9 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -139,68 +139,32 @@ class TestGridFilters: assert np.allclose(differential_operator(size,field),0.0) - @pytest.mark.parametrize('field_def,curl_def', - [(['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0' ], - ['0.0' , '0.0', '0.0', - 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0', '0.0', - '0.0', '0.0', '0.0'] - ), - (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', - '0.0', '0.0', '0.0', - 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], - ['0.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - 'np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0'] - ) - ]) - def test_curl(self,field_def,curl_def): - size = np.random.random(3)+1.0 - grid = np.random.randint(8,32,(3)) - - nodes = grid_filters.cell_coord0(grid,size) - my_locals = locals() # needed for list comprehension - - field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) - field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) - curl = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in curl_def], axis=-1) - curl = curl.reshape(tuple(grid) + ((3,3) if len(curl_def)==9 else (3,))) - - assert np.allclose(curl,grid_filters.curl(size,field)) - - grad_test_data = [(['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]','0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0']), - - (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], - ['0.0', '0.0', '0.0', - '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', - '0.0', '0.0', '0.0' ]), - - (['1.0', '0.0', '2.0*np.cos(np.pi*2*nodes[...,2]/size[2])'], - ['0.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])']), - - (['np.cos(np.pi*2*nodes[...,2]/size[2])', '3.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], - ['0.0', '0.0', '-np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', - '0.0', '0.0', '0.0', - '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), - - (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.sin(np.pi*2*nodes[...,1]/size[1])',\ - 'np.sin(np.pi*2*nodes[...,2]/size[2])'], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0', - '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', - '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), - - (['np.sin(np.pi*2*nodes[...,0]/size[0])' ], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0' ]), - - (['8.0' ], - ['0.0', '0.0', '0.0' ]) - ] + grad_test_data = [ + (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]','0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0']), + (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], + ['0.0', '0.0', '0.0', + '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', + '0.0', '0.0', '0.0' ]), + (['1.0', '0.0', '2.0*np.cos(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])']), + (['np.cos(np.pi*2*nodes[...,2]/size[2])', '3.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '-np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', + '0.0', '0.0', '0.0', + '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.sin(np.pi*2*nodes[...,1]/size[1])',\ + 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0', + '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', + '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])' ], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0' ]), + (['8.0' ], + ['0.0', '0.0', '0.0' ])] @pytest.mark.parametrize('field_def,grad_def',grad_test_data) @@ -218,3 +182,103 @@ class TestGridFilters: assert np.allclose(grad,grid_filters.gradient(size,field)) + + curl_test_data =[ + (['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0' ], + ['0.0' , '0.0', '0.0', + 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0', '0.0', + '0.0', '0.0', '0.0']), + (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', + '0.0', '0.0', '0.0', + 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + 'np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', + 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', + 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0']), + (['5.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,1]/size[1])'], + ['0.0', '0.0', '-2*np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0']), + (['4*np.sin(np.pi*2*nodes[...,2]/size[2])', '8*np.sin(np.pi*2*nodes[...,0]/size[0])', '16*np.sin(np.pi*2*nodes[...,1]/size[1])'], + ['16*np.pi*2/size[1]*np.cos(np.pi*2*nodes[...,1]/size[1])', \ + '4*np.pi*2/size[2]*np.cos(np.pi*2*nodes[...,2]/size[2])', \ + '8*np.pi*2/size[0]*np.cos(np.pi*2*nodes[...,0]/size[0])']), + (['0.0', 'np.cos(np.pi*2*nodes[...,0]/size[0])+5*np.cos(np.pi*2*nodes[...,2]/size[2])', '0.0'], + ['5*np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]',\ + '0.0',\ + '-np.sin(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]'])] + + @pytest.mark.parametrize('field_def,curl_def',curl_test_data) + + def test_curl(self,field_def,curl_def): + size = np.random.random(3)+1.0 + grid = np.random.randint(8,32,(3)) + + nodes = grid_filters.cell_coord0(grid,size) + my_locals = locals() # needed for list comprehension + + field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) + field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) + curl = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in curl_def], axis=-1) + curl = curl.reshape(tuple(grid) + ((3,3) if len(curl_def)==9 else (3,))) + + assert np.allclose(curl,grid_filters.curl(size,field)) + + + div_test_data =[ + (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0', + '0.0' , '0.0', '0.0', + '0.0' , '0.0', '0.0'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]' ,'0.0', '0.0']), + (['0.0', '0.0', '0.0', + '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', + '0.0', '0.0', '0.0'], + ['0.0', '-np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0']), + (['1.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,2]/size[2])' ], + ['0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])'] + ), + ([ '23.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '100.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]','np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + (['400.0', '0.0', '0.0', + 'np.sin(np.pi*2*nodes[...,0]/size[0])', 'np.sin(np.pi*2*nodes[...,1]/size[1])', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '10.0', '6.0' ], + ['0.0','np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]+np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]+np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]','0.0' ]), + (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]',]), + (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], + ['-np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]']) + ] + + @pytest.mark.parametrize('field_def,div_def',div_test_data) + + def test_div(self,field_def,div_def): + size = np.random.random(3)+1.0 + grid = np.random.randint(8,32,(3)) + + nodes = grid_filters.cell_coord0(grid,size) + my_locals = locals() # needed for list comprehension + + field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) + field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) + div = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in div_def], axis=-1) + if len(div_def)==3: + div = div.reshape(tuple(grid) + ((3,))) + else: + div=div.reshape(tuple(grid)) + + assert np.allclose(div,grid_filters.divergence(size,field)) + + From d977f2ad254736f36b91e3b05228d9af339ed088 Mon Sep 17 00:00:00 2001 From: "f.basile" Date: Wed, 6 May 2020 14:26:54 +0200 Subject: [PATCH 174/186] already merged --- python/tests/test_curl.py | 64 --------------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 python/tests/test_curl.py diff --git a/python/tests/test_curl.py b/python/tests/test_curl.py deleted file mode 100644 index c3bcc2682..000000000 --- a/python/tests/test_curl.py +++ /dev/null @@ -1,64 +0,0 @@ -import pytest -import numpy as np -from damask import grid_filters - - -class TestGridFilters: - - - curl_test_data =[(['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0' ], - ['0.0' , '0.0', '0.0', - 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0', '0.0', - '0.0', '0.0', '0.0'] - ), - (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', - '0.0', '0.0', '0.0', - 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], - ['0.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - 'np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0'] - ), - (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', - 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', - 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])'], - ['0.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0'] - ), - (['5.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,1]/size[1])'], - ['0.0', '0.0', '-2*np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0'] - ), - (['4*np.sin(np.pi*2*nodes[...,2]/size[2])', '8*np.sin(np.pi*2*nodes[...,0]/size[0])', '16*np.sin(np.pi*2*nodes[...,1]/size[1])'], - ['16*np.pi*2/size[1]*np.cos(np.pi*2*nodes[...,1]/size[1])', \ - '4*np.pi*2/size[2]*np.cos(np.pi*2*nodes[...,2]/size[2])', \ - '8*np.pi*2/size[0]*np.cos(np.pi*2*nodes[...,0]/size[0])'] - ), - (['0.0', 'np.cos(np.pi*2*nodes[...,0]/size[0])+5*np.cos(np.pi*2*nodes[...,2]/size[2])', '0.0'], - ['5*np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]',\ - '0.0',\ - '-np.sin(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]'])] - - - @pytest.mark.parametrize('field_def,curl_def',curl_test_data) - - def test_curl(self,field_def,curl_def): - size = np.random.random(3)+1.0 - grid = np.random.randint(8,32,(3)) - - nodes = grid_filters.cell_coord0(grid,size) - my_locals = locals() # needed for list comprehension - - field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) - field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) - curl = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in curl_def], axis=-1) - curl = curl.reshape(tuple(grid) + ((3,3) if len(curl_def)==9 else (3,))) - - assert np.allclose(curl,grid_filters.curl(size,field)) - - \ No newline at end of file From fcd0028b83ef5428032abfdcbe91ee6dcd8a5ae3 Mon Sep 17 00:00:00 2001 From: "f.basile" Date: Wed, 6 May 2020 14:33:04 +0200 Subject: [PATCH 175/186] avoid line length limit (maximum line length 182 > 132 --- python/tests/test_grid_filters.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index 6a30481c9..3d06ee01c 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -181,7 +181,10 @@ class TestGridFilters: grad = grad.reshape(tuple(grid) + ((3,3) if len(grad_def)==9 else (3,))) assert np.allclose(grad,grid_filters.gradient(size,field)) - + + + + curl_test_data =[ (['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', @@ -208,7 +211,9 @@ class TestGridFilters: ['0.0', '0.0', '-2*np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', '0.0', '0.0', '0.0', '0.0']), - (['4*np.sin(np.pi*2*nodes[...,2]/size[2])', '8*np.sin(np.pi*2*nodes[...,0]/size[0])', '16*np.sin(np.pi*2*nodes[...,1]/size[1])'], + (['4*np.sin(np.pi*2*nodes[...,2]/size[2])', \ + '8*np.sin(np.pi*2*nodes[...,0]/size[0])', \ + '16*np.sin(np.pi*2*nodes[...,1]/size[1])'], ['16*np.pi*2/size[1]*np.cos(np.pi*2*nodes[...,1]/size[1])', \ '4*np.pi*2/size[2]*np.cos(np.pi*2*nodes[...,2]/size[2])', \ '8*np.pi*2/size[0]*np.cos(np.pi*2*nodes[...,0]/size[0])']), @@ -251,11 +256,17 @@ class TestGridFilters: ([ '23.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '100.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], - ['np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]','np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + ['np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]',\ + 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', \ + 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), (['400.0', '0.0', '0.0', - 'np.sin(np.pi*2*nodes[...,0]/size[0])', 'np.sin(np.pi*2*nodes[...,1]/size[1])', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + 'np.sin(np.pi*2*nodes[...,0]/size[0])', \ + 'np.sin(np.pi*2*nodes[...,1]/size[1])', \ + 'np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '10.0', '6.0' ], - ['0.0','np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]+np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]+np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]','0.0' ]), + ['0.0','np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]'\ + '+np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]'\ + '+np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]','0.0' ]), (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]',]), (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], From 58537c478d3edc95f26d392b7ae3cfb77ecdce00 Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 6 May 2020 16:01:35 +0200 Subject: [PATCH 176/186] [skip ci] updated version information after successful test of v2.0.3-2412-g0d03c469 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6f8955f5c..f955915ff 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2402-gb88f5ec0 +v2.0.3-2412-g0d03c469 From 0c70f1a54f1ffe2fb90e76cdd6bc4864bf6e9624 Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Thu, 7 May 2020 21:13:25 +0200 Subject: [PATCH 177/186] polishing --- src/YAML_types.f90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index 314c099f8..aa09364df 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -638,7 +638,7 @@ function tNode_get_byKey_asFloats(self,k) result(nodeAsFloats) class(tNode), pointer :: node type(tList), pointer :: list - node => self%get(k) + node => self%get(k) list => node%asList() nodeAsFloats = list%asFloats() @@ -657,7 +657,7 @@ function tNode_get_byKey_asInts(self,k) result(nodeAsInts) class(tNode), pointer :: node type(tList), pointer :: list - node => self%get(k) + node => self%get(k) list => node%asList() nodeAsInts = list%asInts() @@ -676,7 +676,7 @@ function tNode_get_byKey_asBools(self,k) result(nodeAsBools) class(tNode), pointer :: node type(tList), pointer :: list - node => self%get(k) + node => self%get(k) list => node%asList() nodeAsBools = list%asBools() @@ -695,7 +695,7 @@ function tNode_get_byKey_asStrings(self,k) result(nodeAsStrings) class(tNode), pointer :: node type(tList), pointer :: list - node => self%get(k) + node => self%get(k) list => node%asList() nodeAsStrings = list%asStrings() From 1610a6e12a7e227fad70d8c2c9ebfdb94e83d3f2 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 7 May 2020 23:10:27 +0200 Subject: [PATCH 178/186] editorial changes --- src/YAML_types.f90 | 76 +++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index aa09364df..dc7c09815 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -1,11 +1,10 @@ !-------------------------------------------------------------------------------------------------- -!> @brief yaml_types +!> @author Sharan Roongta, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Data types to create a scalar, a list, and a dictionary/hash !> @details module describes the various functions to store and get the yaml data. -!! tNode is the fundamental derived data type. It can be of tScalar, & -!! tList or tDict. -!! Every 'value' in a key: value pair is of tNode and is a pointer. -!! If 'value' is of tScalar, it can either be a string, real, integer or logical, & -!! functions exist to convert this scalar type to its respective primitive data type. +!! A node is the base class for scalar, list and dictionary, list items and dictionary entries point +!! to a node. !-------------------------------------------------------------------------------------------------- module YAML_types @@ -70,7 +69,7 @@ module YAML_types tNode_get_byKey_asString => tNode_get_byKey_asString procedure :: & tNode_get_byKey_asStrings => tNode_get_byKey_asStrings - procedure :: & + procedure :: & getIndex => tNode_get_byKey_asIndex generic :: & @@ -148,7 +147,7 @@ module YAML_types character(len=:), allocatable :: key class(tNode), pointer :: node => null() class(tItem), pointer :: next => null() - + contains final :: tItem_finalize end type tItem @@ -195,7 +194,7 @@ subroutine unitTest allocate(tScalar::s1) allocate(tScalar::s2) select type(s1) - class is(tScalar) + class is(tScalar) s1 = '1' if(s1%asInt() /= 1) call IO_error(0,ext_msg='tScalar_asInt') if(dNeq(s1%asFloat(),1.0_pReal)) call IO_error(0,ext_msg='tScalar_asFloat') @@ -210,7 +209,7 @@ subroutine unitTest class is(tScalar) s1 = '2' endselect - + select type(s2) class is(tScalar) s2 = '3' @@ -222,44 +221,44 @@ subroutine unitTest call l1%append(s1) call l1%append(s2) n => l1 - if(any(l1%asInts() /= [2,3])) call IO_error(0,ext_msg='tList_asInts') - if(any(dNeq(l1%asFloats(),[2.0_pReal,3.0_pReal]))) call IO_error(0,ext_msg='tList_asFloats') - if(n%get_asInt(1) /= 2) call IO_error(0,ext_msg='byIndex_asInt') - if(dNeq(n%get_asFloat(2),3.0_pReal)) call IO_error(0,ext_msg='byIndex_asFloat') + if(any(l1%asInts() /= [2,3])) call IO_error(0,ext_msg='tList_asInts') + if(any(dNeq(l1%asFloats(),[2.0_pReal,3.0_pReal]))) call IO_error(0,ext_msg='tList_asFloats') + if(n%get_asInt(1) /= 2) call IO_error(0,ext_msg='byIndex_asInt') + if(dNeq(n%get_asFloat(2),3.0_pReal)) call IO_error(0,ext_msg='byIndex_asFloat') endselect - + allocate(tList::l2) select type(l2) class is(tList) call l2%append(l1) - if(any(l2%get_asInts(1) /= [2,3])) call IO_error(0,ext_msg='byIndex_asInts') - if(any(dNeq(l2%get_asFloats(1),[2.0_pReal,3.0_pReal]))) call IO_error(0,ext_msg='byIndex_asFloats') + if(any(l2%get_asInts(1) /= [2,3])) call IO_error(0,ext_msg='byIndex_asInts') + if(any(dNeq(l2%get_asFloats(1),[2.0_pReal,3.0_pReal]))) call IO_error(0,ext_msg='byIndex_asFloats') n => l2 end select deallocate(n) - end block + end block - block + block type(tList), target :: l1 type(tScalar),pointer :: s3,s4 class(tNode), pointer :: n - + allocate(tScalar::s1) allocate(tScalar::s2) s3 => s1%asScalar() s4 => s2%asScalar() s3 = 'True' s4 = 'False' - + call l1%append(s1) call l1%append(s2) n => l1 - - if(any(l1%asBools() .neqv. [.true., .false.])) call IO_error(0,ext_msg='tList_asBools') - if(any(l1%asStrings() /= ['True ','False'])) call IO_error(0,ext_msg='tList_asStrings') - if(n%get_asBool(2)) call IO_error(0,ext_msg='byIndex_asBool') - if(n%get_asString(1) /= 'True') call IO_error(0,ext_msg='byIndex_asString') - end block + + if(any(l1%asBools() .neqv. [.true., .false.])) call IO_error(0,ext_msg='tList_asBools') + if(any(l1%asStrings() /= ['True ','False'])) call IO_error(0,ext_msg='tList_asStrings') + if(n%get_asBool(2)) call IO_error(0,ext_msg='byIndex_asBool') + if(n%get_asString(1) /= 'True') call IO_error(0,ext_msg='byIndex_asString') + end block end subroutine unitTest @@ -531,7 +530,7 @@ function tNode_get_byKey(self,k) result(node) character(len=*), intent(in) :: k class(tNode), pointer :: node - type(tDict), pointer :: self_ + type(tDict), pointer :: self_ type(tItem), pointer :: item integer :: j @@ -702,9 +701,9 @@ function tNode_get_byKey_asStrings(self,k) result(nodeAsStrings) end function tNode_get_byKey_asStrings -!------------------------------------------------------------------------------------------------------- +!-------------------------------------------------------------------------------------------------- !> @brief Returns the index of a key in a dictionary -!------------------------------------------------------------------------------------------------------- +!-------------------------------------------------------------------------------------------------- function tNode_get_byKey_asIndex(self,key) result(keyIndex) class(tNode), intent(in), target :: self @@ -717,6 +716,7 @@ function tNode_get_byKey_asIndex(self,key) result(keyIndex) dict => self%asDict() item => dict%first + keyIndex = -1 do i = 1, dict%length if(key == item%key) then keyIndex = i @@ -730,7 +730,7 @@ end function tNode_get_byKey_asIndex !-------------------------------------------------------------------------------------------------- -!> @brief Prints scalar as string +!> @brief Scalar as string (YAML block style) !-------------------------------------------------------------------------------------------------- recursive function tScalar_asFormattedString(self,indent) @@ -752,7 +752,7 @@ end function tScalar_asFormattedString !-------------------------------------------------------------------------------------------------- -!> @brief Prints list as string (YAML block style) +!> @brief List as string (YAML block style) !-------------------------------------------------------------------------------------------------- recursive function tList_asFormattedString(self,indent) result(str) @@ -762,7 +762,7 @@ recursive function tList_asFormattedString(self,indent) result(str) type (tItem), pointer :: item character(len=:), allocatable :: str integer :: i, indent_ - + str = '' if(present(indent)) then indent_ = indent @@ -781,15 +781,15 @@ end function tList_asFormattedString !-------------------------------------------------------------------------------------------------- -!> @brief Prints dictionary as string (YAML block style) +!> @brief Dictionary as string (YAML block style) !-------------------------------------------------------------------------------------------------- recursive function tDict_asFormattedString(self,indent) result(str) class (tDict),intent(in),target :: self integer, intent(in),optional :: indent - + type (tItem),pointer :: item - character(len=:), allocatable :: str + character(len=:), allocatable :: str integer :: i, indent_ str = '' @@ -801,7 +801,7 @@ recursive function tDict_asFormattedString(self,indent) result(str) item => self%first do i = 1, self%length - if(i /= 1) str = str//repeat(' ',indent_) + if(i /= 1) str = str//repeat(' ',indent_) select type(node_1 =>item%node) class is(tScalar) str = str//trim(item%key)//': '//item%node%asFormattedString(indent_+len_trim(item%key)+2) @@ -1043,7 +1043,7 @@ end subroutine tList_finalize recursive subroutine tItem_finalize(self) type(tItem),intent(inout) :: self - + deallocate(self%node) if(associated(self%next)) deallocate(self%next) From c8701a46657f1d8bee9c096bc44a4b05b04a21bb Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Fri, 8 May 2020 12:15:10 +0200 Subject: [PATCH 179/186] Cleanup/better readability --- python/tests/test_grid_filters.py | 83 +++++++++++++++++++------------ 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index 3d06ee01c..3dbc665c0 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -144,25 +144,31 @@ class TestGridFilters: ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]','0.0', '0.0', '0.0', '0.0', '0.0', '0.0', '0.0', '0.0']), - (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], - ['0.0', '0.0', '0.0', - '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', - '0.0', '0.0', '0.0' ]), - (['1.0', '0.0', '2.0*np.cos(np.pi*2*nodes[...,2]/size[2])'], - ['0.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])']), + + (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], + ['0.0', '0.0', '0.0', + '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', + '0.0', '0.0', '0.0' ]), + + (['1.0', '0.0', '2.0*np.cos(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])']), + (['np.cos(np.pi*2*nodes[...,2]/size[2])', '3.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], ['0.0', '0.0', '-np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0', '0.0', '0.0', '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.sin(np.pi*2*nodes[...,1]/size[1])',\ - 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + 'np.sin(np.pi*2*nodes[...,2]/size[2])'], ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])' ], ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0' ]), + (['8.0' ], ['0.0', '0.0', '0.0' ])] @@ -187,36 +193,41 @@ class TestGridFilters: curl_test_data =[ - (['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0' ], + (['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0'], ['0.0' , '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0', '0.0', '0.0', '0.0', '0.0']), - (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', - '0.0', '0.0', '0.0', - 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + + (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', + '0.0', '0.0', '0.0', + 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], ['0.0', '0.0', '0.0', '0.0', '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])', 'np.sin(np.pi*2*nodes[...,0]/size[0])','np.cos(np.pi*2*nodes[...,1]/size[1])','np.sin(np.pi*2*nodes[...,2]/size[2])'], ['0.0', '0.0', '0.0', '0.0', '0.0', '0.0', '0.0', '0.0', '0.0']), + (['5.0', '0.0', '0.0', '0.0', '0.0', '0.0', '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,1]/size[1])'], ['0.0', '0.0', '-2*np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', '0.0', '0.0', '0.0', '0.0']), + (['4*np.sin(np.pi*2*nodes[...,2]/size[2])', \ '8*np.sin(np.pi*2*nodes[...,0]/size[0])', \ '16*np.sin(np.pi*2*nodes[...,1]/size[1])'], ['16*np.pi*2/size[1]*np.cos(np.pi*2*nodes[...,1]/size[1])', \ - '4*np.pi*2/size[2]*np.cos(np.pi*2*nodes[...,2]/size[2])', \ - '8*np.pi*2/size[0]*np.cos(np.pi*2*nodes[...,0]/size[0])']), + '4*np.pi*2/size[2]*np.cos(np.pi*2*nodes[...,2]/size[2])', \ + '8*np.pi*2/size[0]*np.cos(np.pi*2*nodes[...,0]/size[0])']), + (['0.0', 'np.cos(np.pi*2*nodes[...,0]/size[0])+5*np.cos(np.pi*2*nodes[...,2]/size[2])', '0.0'], ['5*np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]',\ '0.0',\ @@ -240,35 +251,41 @@ class TestGridFilters: div_test_data =[ - (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0', - '0.0' , '0.0', '0.0', - '0.0' , '0.0', '0.0'], + (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0', + '0.0' , '0.0', '0.0', + '0.0' , '0.0', '0.0'], ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]' ,'0.0', '0.0']), - (['0.0', '0.0', '0.0', - '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', - '0.0', '0.0', '0.0'], + + (['0.0', '0.0', '0.0', + '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', + '0.0', '0.0', '0.0'], ['0.0', '-np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0']), - (['1.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,2]/size[2])' ], - ['0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])'] + + (['1.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,2]/size[2])' ], + ['0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])'] ), - ([ '23.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', - '0.0', '100.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', - '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + + ([ '23.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '100.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], ['np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]',\ 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', \ 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + (['400.0', '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,0]/size[0])', \ 'np.sin(np.pi*2*nodes[...,1]/size[1])', \ 'np.sin(np.pi*2*nodes[...,2]/size[2])', - '0.0', '10.0', '6.0' ], + '0.0', '10.0', '6.0'], ['0.0','np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]'\ - '+np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]'\ - '+np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]','0.0' ]), + '+np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]'\ + '+np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0' ]), + (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]',]), + (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], ['-np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]']) ] From 6928a8290fbab2506b53fffed673484f037fbf55 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 10 May 2020 13:02:26 +0200 Subject: [PATCH 180/186] less whitespace, alingment only within one vector/tensor --- python/tests/test_grid_filters.py | 154 ++++++++++++++---------------- 1 file changed, 74 insertions(+), 80 deletions(-) diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index 3dbc665c0..ab60c0446 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -140,44 +140,45 @@ class TestGridFilters: grad_test_data = [ - (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]','0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0']), - (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], - ['0.0', '0.0', '0.0', - '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', - '0.0', '0.0', '0.0' ]), + (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], + ['0.0', '0.0', '0.0', + '0.0', '-np.pi*2/size[1]*np.sin(np.pi*2*nodes[...,1]/size[1])', '0.0', + '0.0', '0.0', '0.0' ]), - (['1.0', '0.0', '2.0*np.cos(np.pi*2*nodes[...,2]/size[2])'], - ['0.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])']), + (['1.0', '0.0', '2.0*np.cos(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])']), - (['np.cos(np.pi*2*nodes[...,2]/size[2])', '3.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], - ['0.0', '0.0', '-np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', - '0.0', '0.0', '0.0', - '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + (['np.cos(np.pi*2*nodes[...,2]/size[2])', '3.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['0.0', '0.0', '-np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', + '0.0', '0.0', '0.0', + '0.0', '0.0', ' np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), - (['np.sin(np.pi*2*nodes[...,0]/size[0])','np.sin(np.pi*2*nodes[...,1]/size[1])',\ - 'np.sin(np.pi*2*nodes[...,2]/size[2])'], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0', - '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', - '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])', + 'np.sin(np.pi*2*nodes[...,1]/size[1])', + 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0', + '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', + '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), - (['np.sin(np.pi*2*nodes[...,0]/size[0])' ], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0' ]), + (['np.sin(np.pi*2*nodes[...,0]/size[0])'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]', '0.0', '0.0']), - (['8.0' ], - ['0.0', '0.0', '0.0' ])] + (['8.0'], + ['0.0', '0.0', '0.0' ]) + ] @pytest.mark.parametrize('field_def,grad_def',grad_test_data) - def test_grad(self,field_def,grad_def): size = np.random.random(3)+1.0 grid = np.random.randint(8,32,(3)) - + nodes = grid_filters.cell_coord0(grid,size) my_locals = locals() # needed for list comprehension @@ -187,22 +188,19 @@ class TestGridFilters: grad = grad.reshape(tuple(grid) + ((3,3) if len(grad_def)==9 else (3,))) assert np.allclose(grad,grid_filters.gradient(size,field)) - - - - - - curl_test_data =[ - (['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '0.0'], + + + curl_test_data = [ + (['np.sin(np.pi*2*nodes[...,2]/size[2])', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '0.0'], ['0.0' , '0.0', '0.0', 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0', '0.0', '0.0', '0.0', '0.0']), - (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', - '0.0', '0.0', '0.0', - 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + (['np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', '0.0', + '0.0', '0.0', '0.0', + 'np.cos(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], ['0.0', '0.0', '0.0', '0.0', '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0', '0.0']), @@ -221,20 +219,22 @@ class TestGridFilters: '0.0', '0.0', '0.0', '0.0', '0.0', '0.0']), - (['4*np.sin(np.pi*2*nodes[...,2]/size[2])', \ - '8*np.sin(np.pi*2*nodes[...,0]/size[0])', \ + ([ '4*np.sin(np.pi*2*nodes[...,2]/size[2])', + '8*np.sin(np.pi*2*nodes[...,0]/size[0])', '16*np.sin(np.pi*2*nodes[...,1]/size[1])'], - ['16*np.pi*2/size[1]*np.cos(np.pi*2*nodes[...,1]/size[1])', \ - '4*np.pi*2/size[2]*np.cos(np.pi*2*nodes[...,2]/size[2])', \ + ['16*np.pi*2/size[1]*np.cos(np.pi*2*nodes[...,1]/size[1])', + '4*np.pi*2/size[2]*np.cos(np.pi*2*nodes[...,2]/size[2])', '8*np.pi*2/size[0]*np.cos(np.pi*2*nodes[...,0]/size[0])']), - (['0.0', 'np.cos(np.pi*2*nodes[...,0]/size[0])+5*np.cos(np.pi*2*nodes[...,2]/size[2])', '0.0'], - ['5*np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]',\ - '0.0',\ - '-np.sin(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]'])] + (['0.0', + 'np.cos(np.pi*2*nodes[...,0]/size[0])+5*np.cos(np.pi*2*nodes[...,2]/size[2])', + '0.0'], + ['5*np.sin(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', + '0.0', + '-np.sin(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]']) + ] - @pytest.mark.parametrize('field_def,curl_def',curl_test_data) - + @pytest.mark.parametrize('field_def,curl_def',curl_test_data) def test_curl(self,field_def,curl_def): size = np.random.random(3)+1.0 grid = np.random.randint(8,32,(3)) @@ -251,47 +251,43 @@ class TestGridFilters: div_test_data =[ - (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0', - '0.0' , '0.0', '0.0', - '0.0' , '0.0', '0.0'], - ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]' ,'0.0', '0.0']), + (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0', + '0.0' , '0.0', '0.0', + '0.0' , '0.0', '0.0'], + ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]','0.0', '0.0']), - (['0.0', '0.0', '0.0', - '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', - '0.0', '0.0', '0.0'], + (['0.0', '0.0', '0.0', + '0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0', + '0.0', '0.0', '0.0'], ['0.0', '-np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]', '0.0']), - (['1.0', '0.0', '0.0', - '0.0', '0.0', '0.0', - '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,2]/size[2])' ], - ['0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])'] + (['1.0', '0.0', '0.0', + '0.0', '0.0', '0.0', + '0.0', '0.0', '2*np.cos(np.pi*2*nodes[...,2]/size[2])' ], + ['0.0', '0.0', '-2.0*np.pi*2/size[2]*np.sin(np.pi*2*nodes[...,2]/size[2])'] ), - ([ '23.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', - '0.0', '100.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', - '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], + ([ '23.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '100.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '0.0', 'np.sin(np.pi*2*nodes[...,2]/size[2])'], ['np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]',\ - 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', \ - 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), + 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', \ + 'np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]']), - (['400.0', '0.0', '0.0', - 'np.sin(np.pi*2*nodes[...,0]/size[0])', \ - 'np.sin(np.pi*2*nodes[...,1]/size[1])', \ - 'np.sin(np.pi*2*nodes[...,2]/size[2])', - '0.0', '10.0', '6.0'], - ['0.0','np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]'\ - '+np.cos(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]'\ - '+np.cos(np.pi*2*nodes[...,2]/size[2])*np.pi*2/size[2]', '0.0' ]), + (['400.0', '0.0', '0.0', + 'np.sin(np.pi*2*nodes[...,0]/size[0])', 'np.sin(np.pi*2*nodes[...,1]/size[1])', 'np.sin(np.pi*2*nodes[...,2]/size[2])', + '0.0', '10.0', '6.0'], + ['0.0','np.sum(np.cos(np.pi*2*nodes/size)*np.pi*2/size,axis=-1)', '0.0' ]), - (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], + (['np.sin(np.pi*2*nodes[...,0]/size[0])', '0.0', '0.0'], ['np.cos(np.pi*2*nodes[...,0]/size[0])*np.pi*2/size[0]',]), - (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], + (['0.0', 'np.cos(np.pi*2*nodes[...,1]/size[1])', '0.0' ], ['-np.sin(np.pi*2*nodes[...,1]/size[1])*np.pi*2/size[1]']) ] - - @pytest.mark.parametrize('field_def,div_def',div_test_data) - + + @pytest.mark.parametrize('field_def,div_def',div_test_data) + def test_div(self,field_def,div_def): size = np.random.random(3)+1.0 grid = np.random.randint(8,32,(3)) @@ -308,5 +304,3 @@ class TestGridFilters: div=div.reshape(tuple(grid)) assert np.allclose(div,grid_filters.divergence(size,field)) - - From 04e7838eb751ddab7b1d87cf0a6f5b8d7d020dd0 Mon Sep 17 00:00:00 2001 From: Test User Date: Sun, 10 May 2020 15:34:31 +0200 Subject: [PATCH 181/186] [skip ci] updated version information after successful test of v2.0.3-2428-g7b89d748 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f955915ff..2b197ce0e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2412-g0d03c469 +v2.0.3-2428-g7b89d748 From 5a94218d234efcf4799e459eceb08a672ebd3373 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 11 May 2020 08:02:34 +0200 Subject: [PATCH 182/186] fixes error: [0]PETSC ERROR: Object is in wrong state [0]PETSC ERROR: Cannot set coordinates until after DMDA has been setup --- src/grid/grid_mech_FEM.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grid/grid_mech_FEM.f90 b/src/grid/grid_mech_FEM.f90 index 9cdf2f5b5..c8bef7ff2 100644 --- a/src/grid/grid_mech_FEM.f90 +++ b/src/grid/grid_mech_FEM.f90 @@ -132,11 +132,11 @@ subroutine grid_mech_FEM_init [grid(1)],[grid(2)],localK, & mech_grid,ierr) CHKERRQ(ierr) - call DMDASetUniformCoordinates(mech_grid,0.0_pReal,geomSize(1),0.0_pReal,geomSize(2),0.0_pReal,geomSize(3),ierr) - CHKERRQ(ierr) call SNESSetDM(mech_snes,mech_grid,ierr); CHKERRQ(ierr) call DMsetFromOptions(mech_grid,ierr); CHKERRQ(ierr) call DMsetUp(mech_grid,ierr); CHKERRQ(ierr) + call DMDASetUniformCoordinates(mech_grid,0.0_pReal,geomSize(1),0.0_pReal,geomSize(2),0.0_pReal,geomSize(3),ierr) + CHKERRQ(ierr) call DMCreateGlobalVector(mech_grid,solution_current,ierr); CHKERRQ(ierr) call DMCreateGlobalVector(mech_grid,solution_lastInc,ierr); CHKERRQ(ierr) call DMCreateGlobalVector(mech_grid,solution_rate ,ierr); CHKERRQ(ierr) From 620154a1a8ab08e0bc42cf515c0a72f006a7da08 Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Mon, 11 May 2020 14:00:19 +0200 Subject: [PATCH 183/186] not needed --- src/YAML_types.f90 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index dc7c09815..07541bc1a 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -738,14 +738,6 @@ recursive function tScalar_asFormattedString(self,indent) class (tScalar), intent(in), target :: self integer, intent(in), optional :: indent - integer :: indent_ - - if(present(indent)) then - indent_ = indent - else - indent_ = 0 - endif - tScalar_asFormattedString = trim(self%value)//IO_EOL end function tScalar_asFormattedString From 1bb819ab3f04352eb177e107e6cb760bf06987df Mon Sep 17 00:00:00 2001 From: Test User Date: Mon, 11 May 2020 14:33:27 +0200 Subject: [PATCH 184/186] [skip ci] updated version information after successful test of v2.0.3-2431-gfe221460 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 2b197ce0e..d7e0378cb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2428-g7b89d748 +v2.0.3-2431-gfe221460 From ae408baf2719996c1d49a967591d64c8fe6ba91c Mon Sep 17 00:00:00 2001 From: Test User Date: Tue, 12 May 2020 11:31:59 +0200 Subject: [PATCH 185/186] [skip ci] updated version information after successful test of v2.0.3-2449-g24c2e5ba --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index d7e0378cb..c998127ba 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2431-gfe221460 +v2.0.3-2449-g24c2e5ba From 45e608e71b12e4113957929c96adce58ca4ee489 Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 13 May 2020 02:07:50 +0200 Subject: [PATCH 186/186] [skip ci] updated version information after successful test of v2.0.3-2464-g90f93d23 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c998127ba..29f305cbe 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-2449-g24c2e5ba +v2.0.3-2464-g90f93d23